commit ddf168c71ef495d152dd68294a1f01328d86fef5
parent abcaf464d3b173bd226284a8c9b9776d9e744540
Author: oblique <psyberbits@gmail.com>
Date: Sat, 4 Aug 2012 18:18:48 +0300
added: MMU, physical page allocator, I/O helpers
changed: kernel entry point
Diffstat:
15 files changed, 442 insertions(+), 26 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -9,3 +9,4 @@
/kernel.syms
/uImage
/usbbootImage
+/voron.tar.gz
diff --git a/Makefile b/Makefile
@@ -16,7 +16,7 @@ NM = $(CROSS_COMPILE)nm
objs = kernel/start.o kernel/kmain.o kernel/rs232.o kernel/print.o \
kernel/debug.o kernel/interrupts.o kernel/syscall_table.o \
- kernel/syscalls.o
+ kernel/syscalls.o kernel/mmu.o kernel/mm.o
all: uImage usbbootImage kernel.syms
@@ -31,12 +31,12 @@ kernel.syms: kernel.elf
@$(NM) $< > $@
uImage: kernel.bin
- @mkimage -A arm -T kernel -C none -a 0x80008000 -e 0x80008000 -n Voron -d $< $@
+ @mkimage -A arm -T kernel -C none -a 0x80000000 -e 0x80000000 -n Voron -d $< $@
usbbootImage: usbboot/usbboot.o usbboot/usbboot.ld usbboot/kernel_image.o
@echo "Creating $@"
@echo "Entry Point: 0x82000000"
- @echo "Load Image: 0x80008000"
+ @echo "Load Image: 0x80000000"
@$(CC) -T usbboot/usbboot.ld -nostdlib -nostdinc -nodefaultlibs -nostartfiles \
-fno-builtin -o __$@ $<
@$(OBJCOPY) __$@ -O binary $@
@@ -56,4 +56,8 @@ usbboot/kernel_image.o: kernel.bin
clean:
@rm -f $(objs) kernel.elf kernel.bin kernel.syms uImage usbbootImage \
- usbboot/kernel_image.o usbboot/usbboot.o
+ usbboot/kernel_image.o usbboot/usbboot.o voron.tar.gz
+
+targz:
+ @git archive --format=tar.gz --prefix=voron/ -o voron.tar.gz HEAD
+ @echo voron.tar.gz created
diff --git a/include/errno.h b/include/errno.h
@@ -0,0 +1,39 @@
+#ifndef __ERRNO_H
+#define __ERRNO_H
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+
+#endif /* __ERRNO_H */
diff --git a/include/inttypes.h b/include/inttypes.h
@@ -35,5 +35,6 @@ typedef long intptr_t;
#define S64_C(x) x ## LL
#define U64_C(x) x ## ULL
+#define PTR_DIFF(a, b) ((uintptr_t)(a) - (uintptr_t)(b))
#endif /* __INTTYPES_H */
diff --git a/include/io.h b/include/io.h
@@ -0,0 +1,36 @@
+#ifndef __IO_H
+#define __IO_H
+
+#include <inttypes.h>
+
+/* data memory barrier */
+#define dmb() asm volatile("dmb" : : : "memory")
+/* data synchronization barrier */
+#define dsb() asm volatile("dsb" : : : "memory")
+/* instruction synchronization barrier */
+#define isb() asm volatile("isb" : : : "memory")
+
+/* memory barrier */
+#define mb() dsb()
+/* read memory barrier */
+#define rmb() dsb()
+/* write memory barrier */
+#define wmb() dsb()
+
+#define readl_relaxed(a) (*(volatile u32*)(a))
+#define readw_relaxed(a) (*(volatile u16*)(a))
+#define readb_relaxed(a) (*(volatile u8*)(a))
+
+#define writel_relaxed(v, a) (*(volatile u32*)(a) = (u32)(v))
+#define writew_relaxed(v, a) (*(volatile u16*)(a) = (u16)(v))
+#define writeb_relaxed(v, a) (*(volatile u8*)(a) = (u8)(v))
+
+#define readl(a) ({ u32 __r = readl_relaxed(a); rmb(); __r; })
+#define readw(a) ({ u16 __r = readw_relaxed(a); rmb(); __r; })
+#define readb(a) ({ u8 __r = readb_relaxed(a); rmb(); __r; })
+
+#define writel(v, a) ({ wmb(); writel_relaxed(v, a); })
+#define writew(v, a) ({ wmb(); writew_relaxed(v, a); })
+#define writeb(v, a) ({ wmb(); writeb_relaxed(v, a); })
+
+#endif /* __IO_H */
diff --git a/include/mm.h b/include/mm.h
@@ -0,0 +1,9 @@
+#ifndef __MM_H
+#define __MM_H
+
+#include <inttypes.h>
+
+void *palloc(uint_t npages);
+int pfree(void *paddr, uint_t npages);
+
+#endif /* __MM_H */
diff --git a/include/mmu.h b/include/mmu.h
@@ -0,0 +1,42 @@
+#ifndef __MMU_H
+#define __MMU_H
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & PAGE_MASK)
+
+#define L1_FAULT 0
+#define L1_PAGE_TABLE 1
+#define L1_SECTION 2
+
+#define L2_PAGE_FAULT 0
+#define L2_LARGE_PAGE 1
+#define L2_SMALL_PAGE 2
+#define L2_TINY_PAGE 3
+
+#define PT_AP0 (1 << 4)
+#define PT_AP1 (1 << 5)
+#define PT_AP2 (1 << 9)
+
+
+/* MMU access permissions
+ * MMU_AP_X_Y
+ * X = access permissions for PL1 or higher
+ * Y = access permissions for PL0 (user mode)
+ */
+typedef enum {
+ MMU_AP_RW_RW,
+ MMU_AP_RW_RO,
+ MMU_AP_RO_RO,
+ MMU_AP_RW_NONE,
+ MMU_AP_RO_NONE,
+ MMU_AP_NONE_NONE
+} mmu_ap_t;
+
+void mmu_init();
+void mmu_enable();
+void mmu_disable();
+int mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms);
+
+#endif /* __MMU_H */
diff --git a/kernel/debug.c b/kernel/debug.c
@@ -1,23 +1,26 @@
#include <inttypes.h>
#include <debug.h>
+#include <io.h>
-static volatile u32 *gpio_wk7 = (u32*)0x4A31E058;
-static volatile u32 *gpio_wk8 = (u32*)0x4A31E05C;
+static u32 *gpio_wk7 = (u32*)0x4A31E058;
+static u32 *gpio_wk8 = (u32*)0x4A31E05C;
void set_led_d1(int on) {
- u32 cur = *gpio_wk7 & 0xffff;
+ u32 cur = readl(gpio_wk7) & 0xffff;
if (on)
- *gpio_wk7 = cur | 0x001B0000;
+ cur |= 0x001B0000;
else
- *gpio_wk7 = cur | 0x00030000;
+ cur |= 0x00030000;
+ writel(cur, gpio_wk7);
}
void set_led_d2(int on) {
- u32 cur = *gpio_wk8 & 0xffff0000;
+ u32 cur = readl(gpio_wk8) & 0xffff0000;
if (on)
- *gpio_wk8 = cur | 0x001B;
+ cur |= 0x001B;
else
- *gpio_wk8 = cur | 0x0003;
+ cur |= 0x0003;
+ writel(cur, gpio_wk8);
}
void set_leds(int on) {
diff --git a/kernel/interrupts.S b/kernel/interrupts.S
@@ -2,7 +2,7 @@
.global init_vector_table
init_vector_table:
mrc p15, 0, r0, c1, c0, 0 @ read CP15 SCTRL register
- bic r0, r0, #(1 << 13) @ set V flag to 0
+ bic r0, r0, #(1 << 13) @ set V flag to 0 (disable high vectors)
mcr p15, 0, r0, c1, c0, 0 @ write CP15 SCTRL register
ldr r0, =vector_table
@@ -41,7 +41,7 @@ undefined_insn:
swi_ex:
stmfd sp!, { r6 - r12, lr }
mrs r6, spsr
- stmfd sp!, { r6 }
+ str r6, [sp, #-4]!
ldr r6, [lr, #-4]
bic r6, r6, #0xff000000
@@ -53,7 +53,7 @@ swi_ex:
.Lsyscall_ret:
add sp, sp, #8
- ldmfd sp!, { r6 }
+ ldr r6, [sp], #4
msr spsr, r6
ldmfd sp!, { r6 - r12, pc }^
@@ -68,7 +68,7 @@ data_abort:
irq_ex:
sub lr, lr, #4
- stmfd sp!, { lr }
+ str lr, [sp, #-4]!
mov r0, #1
bl set_led_d1
ldmfd sp!, { pc }^
@@ -76,7 +76,7 @@ irq_ex:
fiq_ex:
sub lr, lr, #4
- stmfd sp!, { lr }
+ str lr, [sp, #-4]!
mov r0, #1
bl set_led_d2
ldmfd sp!, { pc }^
diff --git a/kernel/linker.ld b/kernel/linker.ld
@@ -3,10 +3,12 @@ OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
- _usr_stack_top = 0x80000000;
+ _ram_start = 0x80000000;
+ _ram_end = 0xbfffffff;
- .text 0x80008000 :
+ .text 0x80000000 :
{
+ _kernel_bin_start = .;
kernel/start.o (.text)
*(.text)
}
@@ -27,10 +29,13 @@ SECTIONS
}
. = ALIGN(4096);
+
. = . + 0x2000;
_svc_stack_top = .;
. = . + 0x2000;
_fiq_stack_top = .;
. = . + 0x2000;
_irq_stack_top = .;
+
+ _kernel_bin_end = .;
}
diff --git a/kernel/mm.c b/kernel/mm.c
@@ -0,0 +1,142 @@
+#include <inttypes.h>
+#include <mmu.h>
+#include <errno.h>
+
+#define ALIGN32(x) (((x) + 31) & ~31)
+
+extern void *_ram_start;
+extern void *_ram_end;
+extern void *_kernel_bin_start;
+extern void *_kernel_bin_end;
+
+static u32 *bitmap;
+static uint_t bitmapsz;
+static uint_t kbound_s;
+static uint_t kbound_e;
+
+/* set range of bits */
+static int set_bitmap_bits(uint_t start_bit, uint_t n, int flag) {
+ uint_t bound_s, bound_e, i;
+ u32 bits;
+
+ if (n == 0)
+ return -EINVAL;
+
+ bound_s = start_bit;
+ bound_e = start_bit + n;
+
+ if (bound_e > bitmapsz * 32)
+ return -EINVAL;
+
+ if (bound_s / 32 != bound_e / 32) {
+ bits = ~((1 << (bound_s % 32)) - 1);
+ if (flag)
+ bitmap[bound_s/32] |= bits;
+ else
+ bitmap[bound_s/32] &= ~bits;
+
+ bits = (1 << (bound_e % 32)) - 1;
+ if (flag)
+ bitmap[bound_e/32] |= bits;
+ else
+ bitmap[bound_e/32] &= ~bits;
+ } else {
+ bits = ~((1 << (bound_s % 32)) - 1);
+ bits &= (1 << (bound_e % 32)) - 1;
+ if (flag)
+ bitmap[bound_s/32] |= bits;
+ else
+ bitmap[bound_s/32] &= ~bits;
+ }
+
+ for (i = (bound_s / 32) + 1; i < bound_e / 32; i++) {
+ if (flag)
+ bitmap[i] = ~0U;
+ else
+ bitmap[i] = 0;
+ }
+
+ return 0;
+}
+
+void mm_init() {
+ uint_t i;
+ size_t ramsz;
+
+ kbound_s = PAGE_ALIGN(PTR_DIFF(&_kernel_bin_start, &_ram_start)) >> PAGE_SHIFT;
+ kbound_e = PAGE_ALIGN(PTR_DIFF(&_kernel_bin_end, &_ram_start)) >> PAGE_SHIFT;
+
+ ramsz = PTR_DIFF(&_ram_end, &_ram_start) + 1;
+ bitmapsz = ALIGN32(ramsz >> PAGE_SHIFT) / 32;
+ bitmap = (u32*)&_kernel_bin_end;
+ kbound_e += PAGE_ALIGN(bitmapsz * 4) >> PAGE_SHIFT;
+
+ for (i = 0; i < bitmapsz; i++)
+ bitmap[i] = 0;
+
+ set_bitmap_bits(kbound_s, kbound_e - kbound_s, 1);
+
+ mmu_init();
+
+ /* map on-chip memory */
+ mmu_map_page((void*)0x40000000, (void*)0x40000000,
+ 0x40000, MMU_AP_RW_NONE);
+ /* map kernel memory */
+ mmu_map_page(&_kernel_bin_start, &_kernel_bin_start,
+ kbound_e - kbound_s, MMU_AP_RW_NONE);
+
+ mmu_enable();
+}
+
+void *palloc(uint_t npages) {
+ uint_t i, j, n;
+ uint_t sbit;
+ int ret;
+
+ if (npages == 0)
+ return (void*)-EINVAL;
+
+ n = 0;
+ for (i = 0; i < bitmapsz; i++) {
+ /* if bitmap[i] has unallocated page */
+ if (bitmap[i] != ~0U) {
+ for (j = 0; j < 32; j++) {
+ if (n > 0 && (bitmap[i] & (1 << j)))
+ n = 0;
+ else if (!(bitmap[i] & (1 << j)))
+ n++;
+ if (n == npages) {
+ sbit = i * 32 + j - n;
+ goto out;
+ }
+ }
+ } else
+ n = 0;
+ }
+
+ return (void*)-EINVAL;
+
+out:
+ ret = set_bitmap_bits(sbit, npages, 1);
+ if (ret < 0)
+ return (void*)ret;
+ return (void*)((uintptr_t)sbit * PAGE_SIZE + (uintptr_t)&_ram_start);
+}
+
+int pfree(void *paddr, uint_t npages) {
+ uintptr_t paddr_a = (uintptr_t)paddr;
+ uint_t sbit;
+
+ if (npages == 0 || paddr_a & (PAGE_SIZE - 1) ||
+ paddr_a < (uintptr_t)&_ram_start ||
+ paddr_a >= (uintptr_t)&_ram_end)
+ return -EINVAL;
+
+ sbit = (paddr_a - (uintptr_t)&_ram_start) >> PAGE_SHIFT;
+
+ /* we cannot free the memory of ourself */
+ if (sbit >= kbound_s && sbit < kbound_e)
+ return -EINVAL;
+
+ return set_bitmap_bits(sbit, npages, 0);
+}
diff --git a/kernel/mmu.c b/kernel/mmu.c
@@ -0,0 +1,125 @@
+#include <inttypes.h>
+#include <mmu.h>
+#include <errno.h>
+#include <debug.h>
+#include <print.h>
+
+static u32 mmu_ttb[4096] __attribute__((__aligned__ (16 * 1024)));
+static u32 l2[4096][256] __attribute__((__aligned__ (1024)));
+
+void mmu_init() {
+ int i;
+
+ for (i = 0; i < 4096; i++)
+ mmu_ttb[i] = L1_FAULT;
+
+ asm volatile (
+ /* invalidate TLB */
+ "mov v1, #0 \n\t"
+ "mcr p15, 0, v1, c8, c7, 0 \n\t"
+ /* set TTBCR */
+ "mov v1, #0 \n\t"
+ "mcr p15, 0, v1, c2, c0, 2 \n\t"
+ /* set TTBR0 */
+ "ldr v1, =mmu_ttb \n\t"
+ "mcr p15, 0, v1, c2, c0, 0 \n\t"
+ /* set DACR */
+ "ldr v1, =0x55555555 \n\t"
+ "mcr p15, 0, v1, c3, c0, 0 \n\t"
+ /* invalidate TLB */
+ "mov v1, #0 \n\t"
+ "mcr p15, 0, v1, c8, c7, 0 \n\t"
+ /* enable AFE */
+ "mrc p15, 0, v1, c1, c0, 0 \n\t"
+ "orr v1, v1, #(1 << 29) \n\t"
+ "mcr p15, 0, v1, c1, c0, 0 \n\t"
+ : : : "v1"
+ );
+}
+
+void mmu_enable() {
+ asm volatile (
+ /* invalidate TLB */
+ "mov v1, #0 \n\t"
+ "mcr p15, 0, v1, c8, c7, 0 \n\t"
+ /* enable MMU */
+ "mrc p15, 0, v1, c1, c0, 0 \n\t"
+ "orr v1, v1, #1 \n\t"
+ "mcr p15, 0, v1, c1, c0, 0 \n\t"
+ : : : "v1"
+ );
+}
+
+void mmu_disable() {
+ asm volatile (
+ /* disable MMU */
+ "mrc p15, 0, v1, c1, c0, 0 \n\t"
+ "bic v1, v1, #1 \n\t"
+ "mcr p15, 0, v1, c1, c0, 0 \n\t"
+ : : : "v1"
+ );
+}
+
+/* map physical memory to virtual memory */
+int mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms) {
+ u32 pte, pte_perms;
+ u32 *pde;
+ uintptr_t phys_a, virt_a;
+ uint_t i, pte_idx, pde_idx;
+
+ phys_a = (uintptr_t)phys;
+ virt_a = (uintptr_t)virt;
+
+ if (npages == 0 || phys_a & (PAGE_SIZE - 1) || virt_a & (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ switch (perms) {
+ case MMU_AP_RW_RW:
+ /* AP[2:0] = 011 */
+ pte_perms = PT_AP0 | PT_AP1;
+ break;
+ case MMU_AP_RW_RO:
+ /* AP[2:0] = 010 */
+ pte_perms = PT_AP1;
+ break;
+ case MMU_AP_RO_RO:
+ /* AP[2:0] = 111 */
+ pte_perms = PT_AP2 | PT_AP1 | PT_AP0;
+ break;
+ case MMU_AP_RW_NONE:
+ /* AP[2:0] = 001 */
+ pte_perms = PT_AP0;
+ break;
+ case MMU_AP_RO_NONE:
+ /* AP[2:0] = 101 */
+ pte_perms = PT_AP2 | PT_AP0;
+ break;
+ case MMU_AP_NONE_NONE:
+ /* AP[2:0] = 000 */
+ pte_perms = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < npages; i++) {
+ pde_idx = virt_a >> 20;
+
+ if (!mmu_ttb[pde_idx]) {
+ int j;
+ mmu_ttb[pde_idx] = (u32)(&l2[pde_idx]) | L1_PAGE_TABLE;
+ for (j = 0; j < 256; j++)
+ l2[pde_idx][j] = L2_PAGE_FAULT;
+ }
+
+ pde = (u32*)(mmu_ttb[pde_idx] & ~0x3ff);
+ pte_idx = (virt_a & 0xff000) >> 12;
+ pte = (phys_a & 0xfffff000) | L2_SMALL_PAGE;
+ pde[pte_idx] = pte | pte_perms;
+
+ phys_a += PAGE_SIZE;
+ virt_a += PAGE_SIZE;
+ }
+
+ return 0;
+}
diff --git a/kernel/rs232.c b/kernel/rs232.c
@@ -1,8 +1,9 @@
#include <inttypes.h>
#include <rs232.h>
#include <uart.h>
+#include <io.h>
-static volatile struct uart *uart = (struct uart*)0x48020000;
+static struct uart *uart = (struct uart*)0x48020000;
int rs232_puts(const char *s) {
int ret = 0;
@@ -17,14 +18,14 @@ int rs232_puts(const char *s) {
int rs232_putchar(int c) {
if (c == '\n') {
- while ((uart->lsr & TX_FIFO_E) == 0)
+ while ((readl(&uart->lsr) & TX_FIFO_E) == 0)
;
- uart->thr = (u32)'\r';
+ writel('\r', &uart->thr);
}
/* while UART TX FIFO is not empty */
- while ((uart->lsr & TX_FIFO_E) == 0)
+ while ((readl(&uart->lsr) & TX_FIFO_E) == 0)
;
/* write the character */
- uart->thr = (u32)c;
+ writel(c, &uart->thr);
return c;
}
diff --git a/kernel/start.S b/kernel/start.S
@@ -17,6 +17,12 @@ _start:
/* initialize vector table */
bl init_vector_table
+ /* disable caches for now */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(1 << 12) @ set I flag to 0 (disable instruction cache)
+ bic r0, r0, #(1 << 2) @ set C flag to 0 (disable data cache)
+ mcr p15, 0, r0, c1, c0, 0
+
cps #CPS_FIQ @ change to FIQ mode
ldr sp, =_fiq_stack_top @ set FIQ stack
@@ -26,6 +32,8 @@ _start:
cps #CPS_SVC @ change to SVC mode
cpsie if @ enable interrupts
+ bl mm_init
+
/* example of calling a system call with at least 6 arguments */
mov r0, #1
mov r1, #2
@@ -37,7 +45,7 @@ _start:
/* example of calling a system call with more than 6 arguments */
mov r0, #7
- stmfd sp!, { r0 }
+ str r0, [sp, #-4]!
mov r0, #1
mov r1, #2
mov r2, #3
diff --git a/usbboot/usbboot.ld b/usbboot/usbboot.ld
@@ -3,7 +3,7 @@ OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
- _image_load_addr = 0x80008000;
+ _image_load_addr = 0x80000000;
.text 0x82000000 :
{