aboutsummaryrefslogtreecommitdiff
path: root/kernel/lib
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/lib')
-rw-r--r--kernel/lib/kmem.c38
-rw-r--r--kernel/lib/mmu.S45
-rw-r--r--kernel/lib/mmu.c33
-rw-r--r--kernel/lib/queue.c55
-rw-r--r--kernel/lib/strings.c119
5 files changed, 290 insertions, 0 deletions
diff --git a/kernel/lib/kmem.c b/kernel/lib/kmem.c
new file mode 100644
index 0000000..9861f12
--- /dev/null
+++ b/kernel/lib/kmem.c
@@ -0,0 +1,38 @@
+#include <globals.h>
+#include <drivers/uart.h>
+#include <lib/kmem.h>
+
+// Output longs at address
+void kmemshow32(void* data, unsigned long length)
+{
+ unsigned long* ptr = data;
+ for(unsigned long i = 0; i < length; i++) {
+ uart_hex(*ptr);
+ ptr+=1;
+ if (i != length-1)
+ uart_char(' ');
+ }
+ uart_char('\n');
+}
+
+// Output bytes at address
+void kmemshow(void* data, unsigned long length)
+{
+ unsigned char* ptr = data;
+ for(unsigned long i = 0; i < length; i++) {
+ char tmp = *ptr>>4;
+ tmp += 0x30;
+ if (tmp > 0x39)
+ tmp += 0x7;
+ uart_char(tmp);
+ tmp = *ptr&0xF;
+ tmp += 0x30;
+ if (tmp > 0x39)
+ tmp += 0x7;
+ uart_char(tmp);
+ ptr+=1;
+ if (i != length-1)
+ uart_char(' ');
+ }
+ uart_char('\n');
+}
diff --git a/kernel/lib/mmu.S b/kernel/lib/mmu.S
new file mode 100644
index 0000000..faca3cc
--- /dev/null
+++ b/kernel/lib/mmu.S
@@ -0,0 +1,45 @@
+.section .text
+.globl mmu_start
+mmu_start:
+ mov r2, #0
+ // Invalidate Caches
+ mcr p15,0,r2,c7,c1,6
+ // Invalidate TLB entries
+ mcr p15,0,r2,c8,c7,0
+ // Data synchronisation barrier
+ mcr p15,0,r2,c7,c10,4
+
+ // Set all domains to 0b11
+ mvn r2, #0
+ bic r2, #0xC
+ mcr p15,0,r2,c3,c0,0
+
+ // Set the translation table base address (remember to align 16 KiB!)
+ mcr p15,0,r0,c2,c0,0
+ mcr p15,0,r0,c2,c0,1
+ mov r3, #0
+ mcr p15,0,r3,c2,c0,2
+
+ // Set the bits mentioned above
+ mrc p15,0,r2,c1,c0,0
+ orr r2,r2,r1
+ mcr p15,0,r2,c1,c0,0
+ bx lr
+
+.globl mmu_stop
+mmu_stop:
+ mrc p15,0,r2,c1,c0,0
+ bic r2,#0x1000
+ bic r2,#0x0004
+ bic r2,#0x0001
+ mcr p15,0,r2,c1,c0,0
+ bx lr
+
+.globl tlb_invalidate
+tlb_invalidate:
+ mov r2, #0
+ // Invalidate Entries
+ mcr p15, 0, r2, c8, c7, 0
+ // DSB
+ mcr p15, 0, r2, c7, c10, 4
+ bx lr
diff --git a/kernel/lib/mmu.c b/kernel/lib/mmu.c
new file mode 100644
index 0000000..e9dda7a
--- /dev/null
+++ b/kernel/lib/mmu.c
@@ -0,0 +1,33 @@
+#include <lib/mmu.h>
+
+#define CACHABLE 0x08
+#define BUFFERABLE 0x04
+#define NO_PERMISSIONS_REQUIRED 0b11 << 10
+#define MMU_TABLE_BASE 0x00004000
+
+void mmu_start(unsigned long base, unsigned long flags);
+
+void mmu_section(unsigned long virtual, unsigned long physical, unsigned long flags)
+{
+ unsigned long offset = virtual >> 20;
+ unsigned long* entry = (unsigned long*)(MMU_TABLE_BASE | (offset << 2));
+ unsigned long physval = (physical & 0xFFF00000) | (flags & 0x7FFC) | 0x00C02;
+ *entry = physval;
+}
+
+extern unsigned long __bss_end;
+void mmu_init(void)
+{
+ for (unsigned long addr = 0x00000000;; addr += 0x00100000) {
+ if (addr < (unsigned long)&__bss_end + 0x00100000) {
+ mmu_section(addr, addr, CACHABLE | BUFFERABLE);
+ } else {
+ mmu_section(addr, addr, NO_PERMISSIONS_REQUIRED);
+ }
+ if (addr == 0x02000000)
+ mmu_section(addr, addr, CACHABLE | BUFFERABLE | NO_PERMISSIONS_REQUIRED);
+ if (addr == 0xFFF00000)
+ break;
+ }
+ mmu_start(MMU_TABLE_BASE,0x00000001|0x1000|0x0004);
+}
diff --git a/kernel/lib/queue.c b/kernel/lib/queue.c
new file mode 100644
index 0000000..1fc35f6
--- /dev/null
+++ b/kernel/lib/queue.c
@@ -0,0 +1,55 @@
+#include <lib/queue.h>
+
+void push_to_queue(struct Entry* e, struct Queue* q)
+{
+ q->end.next->next = e;
+ q->end.next = e;
+ e->next = &q->end;
+}
+
+void prepend_to_queue(struct Entry* e, struct Queue* q)
+{
+ e->next = q->start.next;
+ q->start.next = e;
+ if (e->next->entry_type == END_ENTRY)
+ q->end.next = e;
+}
+
+struct Entry* pop_from_queue(struct Queue* q)
+{
+ if (q->start.next->entry_type == END_ENTRY)
+ return 0;
+ struct Entry* e = q->start.next;
+ q->start.next = e->next;
+ if (e->next->entry_type == END_ENTRY)
+ q->end.next = &q->start;
+ return e;
+}
+
+struct Entry* remove_next_from_queue(struct Entry* e)
+{
+ struct Entry* prev = e;
+ struct Entry* remove = e->next;
+ struct Entry* next = remove->next;
+ if (remove->entry_type != VALUE_ENTRY)
+ return 0;
+ prev->next = next;
+ if (next->entry_type == END_ENTRY)
+ next->next = prev;
+ return remove;
+}
+
+struct Entry* find_value(void* value, struct Queue* q)
+{
+ struct Entry* prev;
+ struct Entry* entry;
+ prev = &q->start;
+ entry = prev->next;
+ while (entry->entry_type != END_ENTRY) {
+ if (entry->value == value)
+ return prev;
+ prev = entry;
+ entry = prev->next;
+ }
+ return 0;
+}
diff --git a/kernel/lib/strings.c b/kernel/lib/strings.c
new file mode 100644
index 0000000..674af19
--- /dev/null
+++ b/kernel/lib/strings.c
@@ -0,0 +1,119 @@
+#include <lib/kmem.h>
+#include <lib/strings.h>
+
+unsigned long strlen(string_t s)
+{
+ unsigned long len = 0;
+ while (s[len] != 0) {
+ len += 1;
+ }
+ return len;
+}
+
+void strcpy(string_t src, string_t dest)
+{
+ unsigned long idx = 0;
+ while (src[idx] != 0) {
+ dest[idx] = src[idx];
+ idx++;
+ }
+ dest[idx] = src[idx];
+}
+
+unsigned char strcmp(string_t a, string_t b)
+{
+ unsigned long idx = 0;
+ while (a[idx] != 0 && b[idx] != 0) {
+ if (a[idx] != b[idx]) {
+ return 0;
+ }
+ idx += 1;
+ }
+ return a[idx] == b[idx];
+}
+
+unsigned char strcmpn(string_t a, string_t b, unsigned int n)
+{
+ unsigned long idx = 0;
+ while (a[idx] != 0 && b[idx] != 0 && idx+1 < n) {
+ if (a[idx] != b[idx]) {
+ return 0;
+ }
+ idx += 1;
+ }
+ return a[idx] == b[idx];
+}
+
+char* zhex32_to_str(unsigned long value)
+{
+ static char data[10];
+ char tmp = 0;
+ char isz = -1;
+ for (int i = 0; i < 8; i++) {
+ tmp = (value >> 4*(8-i-1))&0xF;
+ if (isz == 0xFF && tmp != 0)
+ isz = i;
+ if(tmp > 0x9)
+ tmp += 7;
+ tmp += 0x30;
+ data[i] = tmp;
+ }
+ return data+isz;
+}
+
+char* hex32_to_str(unsigned long value)
+{
+ static char data[10];
+ char tmp = 0;
+ for (int i = 0; i < 8; i++) {
+ tmp = (value >> 4*(8-i-1))&0xF;
+ if(tmp > 0x9)
+ tmp += 7;
+ tmp += 0x30;
+ data[i] = tmp;
+ }
+ return data;
+}
+
+char* u32_to_str(unsigned long value)
+{
+ unsigned long t = value;
+ unsigned long c;
+ static char data[12];
+ char* dptr = data + 9;
+ for (int i = 0; i <= 10; i++) {
+ c = t%10;
+ *dptr = 0x30 + (c&0xF);
+ t /= 10;
+ if (t==0)
+ break;
+ dptr -= 1;
+ }
+ return dptr;
+}
+
+char* s32_to_str(unsigned long value)
+{
+ long t = value;
+ unsigned long c;
+ char is_neg = 0;
+ if (t < 0) {
+ t = -t;
+ is_neg = 1;
+ }
+ static char data[13];
+ char* dptr = data + 10;
+ for (int i = 0; i <= 10; i++) {
+ c = t%10;
+ *dptr = 0x30 + (c&0xF);
+ t /= 10;
+ if (t==0)
+ break;
+ dptr -= 1;
+ }
+ if (is_neg) {
+ dptr -= 1;
+ *dptr = '-';
+ }
+ return dptr;
+}