diff --git a/Makefile b/Makefile index 09b3a90..ab261a7 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ clean: # Build the different OSes build: build-$(BUILD_DEFAULT_TARGET) -buildall: build-chainloader build-thorn +buildall: build-chainloader build-thorn build-bulb build-chainloader: $(MAKE) -C chainloader build diff --git a/thorn/include/common/font.h b/thorn/include/common/font.h index b732416..89b011b 100644 --- a/thorn/include/common/font.h +++ b/thorn/include/common/font.h @@ -1,8 +1,10 @@ #ifndef _ROSE_C_FONT_H #define _ROSE_C_FONT_H +#ifndef __ASSEMBLER__ + #define FONT_SIZE 8 -#define FONT_FACTOR 2 +#define FONT_FACTOR 3 #define FONT_REAL_WIDTH (FONT_SIZE * FONT_FACTOR) // Spacing between lines in pixels @@ -32,6 +34,7 @@ static volatile color_t font_fg; const unsigned long long int * font (int c); void printc (char c); +void prints (char const * str); void printc_location (point_t point, char c); void putc_screen (void * p, char c); @@ -39,4 +42,7 @@ void putc_screen (void * p, char c); void font_set_normal (void); void font_set_error (void); +void test_print (); + #endif +#endif \ No newline at end of file diff --git a/thorn/include/common/utils.h b/thorn/include/common/utils.h index 29b53a1..411746e 100644 --- a/thorn/include/common/utils.h +++ b/thorn/include/common/utils.h @@ -9,4 +9,8 @@ extern unsigned int get32 (unsigned long); extern int get_el (void); +extern void set_pgd (unsigned long pgd); + +extern unsigned long get_pgd (void); + #endif /*_ROSE_C_BOOT_H */ diff --git a/thorn/include/kernel/arm/sysregs.h b/thorn/include/kernel/arm/sysregs.h index 98acd8b..ccdda11 100644 --- a/thorn/include/kernel/arm/sysregs.h +++ b/thorn/include/kernel/arm/sysregs.h @@ -43,7 +43,9 @@ // ESR_EL1, Exception Syndrome Register (EL1). Page 2431 of AArch64-Reference-Manual. // *************************************** -#define ESR_ELx_EC_SHIFT 26 -#define ESR_ELx_EC_SVC64 0x15 +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_DABT_SAME 0b100101 #endif /*_ROSE_K_A_SYSREGS_H*/ diff --git a/thorn/include/kernel/irq.h b/thorn/include/kernel/irq.h index d95cc0b..47652e8 100644 --- a/thorn/include/kernel/irq.h +++ b/thorn/include/kernel/irq.h @@ -13,7 +13,7 @@ void enable_interrupt_controller (void); -void show_invalid_entry_message (int type, ptr_t esr, ptr_t address); +void show_invalid_entry_message (int type, ptr_t esr, ptr_t elr, ptr_t far); void irq_vector_init (void); diff --git a/thorn/include/kernel/mm.h b/thorn/include/kernel/mm.h index d2f325a..642bc3e 100644 --- a/thorn/include/kernel/mm.h +++ b/thorn/include/kernel/mm.h @@ -11,7 +11,7 @@ #define PAGE_SIZE (1 << PAGE_SHIFT) #define SECTION_SIZE (1 << SECTION_SHIFT) -#define LOW_MEMORY (2 * SECTION_SIZE) +#define LOW_MEMORY (1 * SECTION_SIZE) #define HIGH_MEMORY 0x70000000 #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEMORY) diff --git a/thorn/include/kernel/mmu.h b/thorn/include/kernel/mmu.h new file mode 100644 index 0000000..07c5c6e --- /dev/null +++ b/thorn/include/kernel/mmu.h @@ -0,0 +1,53 @@ +#ifndef _ROSE_MMU_H +#define _ROSE_MMU_H + +#ifndef __ASSEMBLER__ + +// Implementation taken from +// https://github.com/bztsrc/raspi3-tutorial/blob/master/10_virtualmemory/mmu.c + +#include "common/font.h" +#include "common/logging.h" +#include "common/status_led.h" +#include "kernel/irq.h" +#include "kernel/mini_uart.h" +#include "kernel/peripherals/base.h" +#include "kernel/sched.h" + +#define PAGESIZE 4096 + +// granularity +#define PT_PAGE 0b11// 4k granule +#define PT_BLOCK 0b01// 2M granule +// accessibility +#define PT_KERNEL (0 << 6) // privileged, supervisor EL1 access only +#define PT_USER (1 << 6) // unprivileged, EL0 access allowed +#define PT_RW (0 << 7) // read-write +#define PT_RO (1 << 7) // read-only +#define PT_AF (1 << 10) // accessed flag +#define PT_NX (1UL << 54)// no execute +// shareability +#define PT_OSH (2 << 8)// outter shareable +#define PT_ISH (3 << 8)// inner shareable +// defined in MAIR register +#define PT_MEM (0 << 2)// normal memory +#define PT_DEV (1 << 2)// device MMIO +#define PT_NC (2 << 2)// non-cachable + +#define TTBR_CNP 1 + +#define RAM_IN_GB 8 + +// get addresses from linker +extern volatile unsigned char _data; +extern volatile unsigned char _end; + +static volatile unsigned int __attribute__ ((aligned (16))) buffer[32]; + +void init_pages (); +void init_mmu (void); + +void data_abort_el0 (ptr_t far, ptr_t esr, ptr_t elr); + +#endif +#endif//_ROSE_MMU_H \ No newline at end of file diff --git a/thorn/include/kernel/sched.h b/thorn/include/kernel/sched.h index b2b1734..a01b136 100644 --- a/thorn/include/kernel/sched.h +++ b/thorn/include/kernel/sched.h @@ -1,6 +1,7 @@ #ifndef _ROSE_K_SCHED_H #define _ROSE_K_SCHED_H +#include "common/font.h" #include "common/stddef.h" #define THREAD_CPU_CONTEXT 0// offset of cpu_context in task_struct @@ -39,14 +40,29 @@ struct cpu_context { unsigned long pc; }; +#define MAX_PROCESS_PAGES 16 + +struct user_page { + unsigned long phys_addr; + unsigned long virt_addr; +}; + +struct mm_struct { + unsigned long pgd; + int user_pages_count; + struct user_page user_pages[MAX_PROCESS_PAGES]; + int kernel_pages_count; + unsigned long kernel_pages[MAX_PROCESS_PAGES]; +}; + struct task_struct { struct cpu_context cpu_context; long state; long counter; long priority; long preempt_count; - ptr_t stack; - ptr_t flags; + unsigned long flags; + struct mm_struct mm; }; extern void sched_init (void); @@ -65,6 +81,8 @@ extern void cpu_switch_to (struct task_struct * prev, struct task_struct * next) extern void exit_process (void); +extern void kill_process (void); + extern void task_init (void); #define INIT_TASK \ diff --git a/thorn/src/common/font.c b/thorn/src/common/font.c index 86addf5..a093572 100644 --- a/thorn/src/common/font.c +++ b/thorn/src/common/font.c @@ -191,6 +191,12 @@ void printc (char c) { } } +void prints (char const * str) { + while (*str) { + printc (*str++); + } +} + void font_set_normal (void) { font_fg = font_normal_fg; } @@ -201,3 +207,7 @@ void font_set_error (void) { void putc_screen (void * p, char c) { printc (c); } + +void test_print () { + prints ("test\r\n"); +} diff --git a/thorn/src/common/printf.c b/thorn/src/common/printf.c index 059ee24..80549a9 100644 --- a/thorn/src/common/printf.c +++ b/thorn/src/common/printf.c @@ -206,6 +206,19 @@ void tfp_format (void * putp, putcf putf, char * fmt, va_list va) { unsigned int), 16, (ch == 'P'), bf); putchw (putp, putf, w, lz, bf); break; + case 'b': + case 'B': + putf (putp, '0'); + putf (putp, 'b'); +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a (va_arg (va, unsigned long int), 2, (ch == 'B'), bf); + else +#endif + ui2a (va_arg (va, + unsigned int), 2, (ch == 'B'), bf); + putchw (putp, putf, w, lz, bf); + break; case '%': putf (putp, ch); default: diff --git a/thorn/src/common/utils.S b/thorn/src/common/utils.S index 44be485..d6a9596 100644 --- a/thorn/src/common/utils.S +++ b/thorn/src/common/utils.S @@ -1,3 +1,5 @@ +#include "common/font.h" + .globl get_el get_el: mrs x0, CurrentEL @@ -19,3 +21,20 @@ delay: subs x0, x0, #1 bne delay ret + +.globl set_pgd +set_pgd: + msr ttbr0_el1, x0 +// tlbi vmalle1is // Crashes CPU + dsb ish // ensure completion of TLB invalidation + isb + ret + +.globl get_pgd +get_pgd: + mov x1, 0 + ldr x0, [x1] + mov x0, 0x1000 + msr ttbr0_el1, x0 + ldr x0, [x1] + ret diff --git a/thorn/src/kernel/boot.S b/thorn/src/kernel/boot.S index abfd307..50f40d2 100644 --- a/thorn/src/kernel/boot.S +++ b/thorn/src/kernel/boot.S @@ -15,22 +15,23 @@ _start: b master init_bss: - adr x0, bss_begin - adr x1, bss_end + adr x0, __bss_start + adr x1, __bss_end sub x1, x1, x0 bl memzero adr x0, move_to_el1 - mov x1, #0xe0 - str x0, [x1] - mov x1, #0xe8 - str x0, [x1] - - mov x1, #0xf0 - str x0, [x1] - - sev +// mov x1, #0xe0 +// str x0, [x1] +// +// mov x1, #0xe8 +// str x0, [x1] +// +// mov x1, #0xf0 +// str x0, [x1] +// +// sev b move_to_el1 diff --git a/thorn/src/kernel/entry.S b/thorn/src/kernel/entry.S index 4f44a25..e37bd6c 100644 --- a/thorn/src/kernel/entry.S +++ b/thorn/src/kernel/entry.S @@ -1,12 +1,14 @@ #include "kernel/arm/sysregs.h" #include "kernel/entry.h" #include "kernel/sys.h" +#include "kernel/mmu.h" .macro handle_invalid_entry el, type kernel_entry \el mov x0, #\type mrs x1, esr_el1 mrs x2, elr_el1 + mrs x3, far_el1 bl show_invalid_entry_message b err_hang .endm @@ -91,19 +93,19 @@ vectors: ventry error_invalid_el1t // Error EL1t ventry sync_invalid_el1h // Synchronous EL1h - ventry el1_irq // IRQ EL1h + ventry el1_irq // IRQ EL1h ventry fiq_invalid_el1h // FIQ EL1h ventry error_invalid_el1h // Error EL1h - ventry el0_sync // Synchronous 64-bit EL0 - ventry el0_irq // IRQ 64-bit EL0 + ventry el0_sync // Synchronous 64-bit EL0 + ventry el0_irq // IRQ 64-bit EL0 ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 - ventry error_invalid_el0_64 // Error 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 ventry irq_invalid_el0_32 // IRQ 32-bit EL0 ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 - ventry error_invalid_el0_32 // Error 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 sync_invalid_el1t: handle_invalid_entry 1, SYNC_INVALID_EL1t @@ -156,38 +158,50 @@ el0_irq: el0_sync: kernel_entry 0 - mrs x25, esr_el1 // read the syndrome register - lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class - cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state - b.eq el0_svc + mrs x25, esr_el1 // read the syndrome register + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state + b.eq el0_svc + cmp x24, #ESR_ELx_EC_DABT_LOW + b.eq el0_da handle_invalid_entry 0, SYNC_ERROR -sc_nr .req x25 // number of system calls -scno .req x26 // syscall number -stbl .req x27 // syscall table pointer +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer el0_svc: - adr stbl, sys_call_table // load syscall table pointer + adr stbl, sys_call_table // load syscall table pointer uxtw scno, w8 // syscall number in w8 mov sc_nr, #__NR_syscalls bl enable_irq - cmp scno, sc_nr // check upper syscall limit + cmp scno, sc_nr // check upper syscall limit b.hs ni_sys - ldr x16, [stbl, scno, lsl #3] // address in the syscall table - blr x16 // call sys_* routine + ldr x16, [stbl, scno, lsl #3] // address in the syscall table + blr x16 // call sys_* routine b ret_from_syscall ni_sys: handle_invalid_entry 0, SYSCALL_ERROR ret_from_syscall: bl disable_irq - str x0, [sp, #S_X0] // returned x0 + str x0, [sp, #S_X0] // returned x0 kernel_exit 0 +el0_da: + bl preempt_disable + mrs x0, far_el1 + mrs x1, esr_el1 + mrs x2, elr_el1 + bl data_abort_el0 + bl preempt_enable + bl disable_irq + eret + .globl ret_from_fork ret_from_fork: bl schedule_tail - cbz x19, ret_to_user // not a kernel thread + cbz x19, ret_to_user // not a kernel thread mov x0, x20 blr x19 ret_to_user: @@ -195,4 +209,4 @@ ret_to_user: kernel_exit 0 .globl err_hang -err_hang: b err_hang +err_hang: b err_hang \ No newline at end of file diff --git a/thorn/src/kernel/fork.c b/thorn/src/kernel/fork.c index 799f931..8f95645 100644 --- a/thorn/src/kernel/fork.c +++ b/thorn/src/kernel/fork.c @@ -1,4 +1,5 @@ #include "kernel/fork.h" +#include "common/font.h" #include "common/printf.h" #include "common/utils.h" #include "kernel/entry.h" @@ -14,6 +15,11 @@ int copy_process (ptr_t clone_flags, ptr_t fn, ptr_t arg, ptr_t stack) { return -1; } + p->mm.pgd = get_free_page (); + if (!p->mm.pgd) { + return -1; + } + struct pt_regs * childregs = task_pt_regs (p); memzero ((ptr_t) childregs, sizeof (struct pt_regs)); memzero ((ptr_t) &p->cpu_context, sizeof (struct cpu_context)); @@ -26,13 +32,12 @@ int copy_process (ptr_t clone_flags, ptr_t fn, ptr_t arg, ptr_t stack) { *childregs = *cur_regs; childregs->regs[0] = 0; childregs->sp = stack + PAGE_SIZE; - p->stack = stack; } p->flags = clone_flags; p->priority = current->priority; p->state = TASK_RUNNING; p->counter = p->priority; - p->preempt_count = 1;//disable preemtion until schedule_tail + p->preempt_count = 1;//disable preemption until schedule_tail p->cpu_context.pc = (ptr_t) ret_from_fork; p->cpu_context.sp = (ptr_t) childregs; @@ -45,15 +50,9 @@ int copy_process (ptr_t clone_flags, ptr_t fn, ptr_t arg, ptr_t stack) { int move_to_user_mode (ptr_t pc) { struct pt_regs * regs = task_pt_regs (current); - memzero ((ptr_t) regs, sizeof (*regs)); - regs->pc = pc; - regs->pstate = PSR_MODE_EL0t; - ptr_t stack = get_free_page ();//allocate new user stack - if (!stack) { - return -1; - } - regs->sp = stack + PAGE_SIZE; - current->stack = stack; + regs->pc = pc; + regs->pstate = PSR_MODE_EL0t; + regs->sp = 2 * PAGE_SIZE; return 0; } diff --git a/thorn/src/kernel/irq.c b/thorn/src/kernel/irq.c index b893bda..98a4239 100644 --- a/thorn/src/kernel/irq.c +++ b/thorn/src/kernel/irq.c @@ -1,7 +1,7 @@ #include "kernel/irq.h" const char * entry_error_messages[] = { - "SYNC_INVALID_EL1t", "IRQ_INVALID_EL1t", "FIQ_INVALID_EL1t", "ERROR_INVALID_EL1T", "SYNC_INVALID_EL1h", "IRQ_INVALID_EL1h", "FIQ_INVALID_EL1h", "ERROR_INVALID_EL1h", "SYNC_INVALID_EL0_64", "IRQ_INVALID_EL0_64", "FIQ_INVALID_EL0_64", "ERROR_INVALID_EL0_64", "SYNC_INVALID_EL0_32", "IRQ_INVALID_EL0_32", "FIQ_INVALID_EL0_32", "ERROR_INVALID_EL0_32"}; + "SYNC_INVALID_EL1t", "IRQ_INVALID_EL1t", "FIQ_INVALID_EL1t", "ERROR_INVALID_EL1T", "SYNC_INVALID_EL1h", "IRQ_INVALID_EL1h", "FIQ_INVALID_EL1h", "ERROR_INVALID_EL1h", "SYNC_INVALID_EL0_64", "IRQ_INVALID_EL0_64", "FIQ_INVALID_EL0_64", "ERROR_INVALID_EL0_64", "SYNC_INVALID_EL0_32", "IRQ_INVALID_EL0_32", "FIQ_INVALID_EL0_32", "ERROR_INVALID_EL0_32", "SYNC_ERROR", "SYSCALL_ERROR"}; void enable_interrupt (unsigned int irq) { printf ("Interrupt pointer %p\r\n", irq); @@ -19,8 +19,8 @@ void assign_target (unsigned int irq, unsigned int cpu) { put32 (targetRegister, get32 (targetRegister) | (1 << 8)); } -void show_invalid_entry_message (int type, ptr_t esr, ptr_t address) { - printf ("Type %s, ESR: %p, address, %p\r\n", entry_error_messages[type], (void *) esr, (void *) address); +void show_invalid_entry_message (int type, ptr_t esr, ptr_t elr, ptr_t far) { + printf ("Type %s, FAR: %p, ESR: %p, ELR: %p\r\n", entry_error_messages[type], (void *) far, (void *) (esr >> 0), (void *) elr); } void enable_interrupt_controller () { diff --git a/thorn/src/kernel/kernel.c b/thorn/src/kernel/kernel.c index 9e37699..15d7abf 100644 --- a/thorn/src/kernel/kernel.c +++ b/thorn/src/kernel/kernel.c @@ -1,3 +1,5 @@ +#include "kernel/mini_uart.h" +// KEEP THIS #include "common/font.h" #include "common/gpu.h" #include "common/logging.h" @@ -8,12 +10,17 @@ #include "common/utils.h" #include "kernel/fork.h" #include "kernel/irq.h" -#include "kernel/mini_uart.h" #include "kernel/mm.h" +#include "kernel/mmu.h" #include "kernel/sched.h" #include "kernel/sys.h" #include "kernel/timer.h" +void multiplex_print (void * p, char c) { + printc (c); + // uart_send (c); +} + void user_process1 (char * array) { char buf[2] = {0}; while (1) { @@ -53,7 +60,7 @@ void user_process () { } void kernel_process () { - // printf ("Kernel process started. EL %d\r\n", get_el ()); + printf ("Kernel process started.\n\r"); int err = move_to_user_mode ((unsigned long) &user_process); if (err < 0) { printf ("Error while moving process to user mode\n\r"); @@ -63,10 +70,6 @@ void kernel_process () { void kernel_init (void) { uart_init (); init_printf (0, putc); - irq_vector_init (); - timer_init (); - enable_interrupt_controller (); - enable_irq (); task_init (); // Turn status led OFF and power led ON @@ -82,15 +85,18 @@ void kernel_init (void) { printf ("Error: Invalid Framebuffer received\r\n"); } else { font_set_normal (); - init_printf (0, putc_screen); + init_printf (0, multiplex_print); printf ("Frame buffer: %p\r\n", get_fb ()); printf ("Width resolution: %d\r\n", get_fb_info ()->virtual_width); printf ("Height resolution: %d\r\n", get_fb_info ()->virtual_height); } } + irq_vector_init (); + timer_init (); + enable_interrupt_controller (); + enable_irq (); - printf ("|...|...|...|...|\r\n"); - printf ("|\t|\t|\t|\t|\r\n"); + init_pages (); LOG ("Initialisation done"); ERROR ("I'm important!"); @@ -106,8 +112,12 @@ void kernel_main (int processor_id) { // Synchronisation to prevent concurrent print while (processor_id != current_processor) {} printf ("Hello, from processor %d in EL %d\n\r", processor_id, get_el ()); - current_processor++; - while (current_processor != 4) {} + init_mmu (); + + // current_processor++; + // while (current_processor != 4) {} + + CHECKPOINT switch (processor_id) { case 0: { @@ -125,6 +135,7 @@ void kernel_main (int processor_id) { case 2: case 3: default: + while (1) {} printf ("Undefined behaviour on processor %d\r\n", processor_id); } printf ("Processor %d going out of scope\r\n", processor_id); diff --git a/thorn/src/kernel/mmu.c b/thorn/src/kernel/mmu.c new file mode 100644 index 0000000..4d74945 --- /dev/null +++ b/thorn/src/kernel/mmu.c @@ -0,0 +1,157 @@ +#include "kernel/mmu.h" + +static volatile unsigned int buffer[] = {32, 0, 0x00038041, 8, 0, 42, 1, 0}; + +void init_pages () { + unsigned long data_page = (unsigned long) &_data / PAGESIZE; + unsigned long r, b, *paging = (unsigned long *) &_end; + + unsigned long * PUD0 = paging + 0 * 512; + unsigned long * PMD0 = paging + 2 * 512; + unsigned long * PTE0 = paging + 1 * 512; + + /* create MMU translation tables at _end */ + // TTBR0, identity L1 + b = PBASE >> 21; + for (int i = 0; i < RAM_IN_GB; i++) { + PUD0[i] = (unsigned long) ((unsigned char *) &_end + (2 + i) * PAGESIZE) |// physical address + PT_PAGE | // it has the "Present" flag, which must be set, and we have area in it mapped by pages + PT_AF | // accessed flag. Without this we're going to have a Data Abort exception + PT_USER | // non-privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + unsigned int offset = i * 512; + // identity L2 2M blocks + for (r = 0; r < 512; r++) + PMD0[i * 512 + r] = (unsigned long) ((offset + r) << 21) | // physical address + PT_BLOCK | // map 2M block + PT_AF | // accessed flag + PT_USER | // non-privileged + (offset + r >= b ? PT_OSH | PT_DEV : PT_ISH | PT_MEM);// different attributes for device memory + } + + // identity L2, first 2M block + PMD0[0] = (unsigned long) ((unsigned char *) &_end + PAGESIZE) |// physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_NX | // non-executable + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // identity L3 + for (r = 0; r < 512; r++) + PTE0[r] = (unsigned long) (r * PAGESIZE) | // physical address + PT_PAGE | // map 4k + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_ISH | // inner shareable + ((r < 0x80 || r >= data_page) ? PT_RW | PT_NX : PT_RO);// different for code and data +} + +void init_mmu () { + unsigned long data_page = (unsigned long) &_data / PAGESIZE; + unsigned long r, b, *paging = (unsigned long *) &_end; + + /* okay, now we have to set system registers to enable MMU */ + // check for 4k granule and at least 36 bits physical address bus */ + asm volatile("mrs %0, id_aa64mmfr0_el1" + : "=r"(r)); + b = r & 0xF; + if (r & (0xF << 28) /*4k*/ || b < 1 /*36 bits*/) { + ERROR ("ERROR: 4k granule or 36 bit address space not supported\n"); + return; + } + LOG ("4k granule and 36bit address bus ensured"); + + // first, set Memory Attributes array, indexed by PT_MEM, PT_DEV, PT_NC in our example + r = (0xFF << 0) |// AttrIdx=0: normal, IWBWA, OWBWA, NTR + (0x04 << 8) |// AttrIdx=1: device, nGnRE (must be OSH too) + (0x44 << 16);// AttrIdx=2: non cacheable + asm volatile("msr mair_el1, %0" + : + : "r"(r)); + LOG ("MAIR attributes written"); + + // next, specify mapping characteristics in translate control register + r = (0b00LL << 37) |// TBI=0, no tagging + (b << 32) | // IPS=autodetected + (0b10LL << 30) |// TG1=4k + (0b11LL << 28) |// SH1=3 inner + (0b01LL << 26) |// ORGN1=1 write back + (0b01LL << 24) |// IRGN1=1 write back + (0b0LL << 23) | // EPD1 enable higher half + (25LL << 16) | // T1SZ=25, 3 levels (512G) + (0b00LL << 14) |// TG0=4k + (0b11LL << 12) |// SH0=3 inner + (0b01LL << 10) |// ORGN0=1 write back + (0b01LL << 8) | // IRGN0=1 write back + (0b0LL << 7) | // EPD0 enable lower half + (25LL << 0); // T0SZ=25, 3 levels (512G) + asm volatile("msr tcr_el1, %0; isb" + : + : "r"(r)); + LOG ("Translation control register written"); + + // tell the MMU where our translation tables are. TTBR_CNP bit not documented, but required + // lower half, user space + asm volatile("msr ttbr0_el1, %0" + : + : "r"((unsigned long) &_end + TTBR_CNP)); + LOG ("TTBR0 written"); + + // upper half, kernel space + asm volatile("msr ttbr1_el1, %0" + : + : "r"((unsigned long) &_end + TTBR_CNP)); + LOG ("TTBR1 written"); + + // finally, toggle some bits in system control register to enable page translation + asm volatile("dsb ish; isb; mrs %0, sctlr_el1" + : "=r"(r)); + r |= 0xC00800; // set mandatory reserved bits + r &= ~((1 << 25) |// clear EE, little endian translation tables + (1 << 24) |// clear E0E + (1 << 19) |// clear WXN + (1 << 12) |// clear I, no instruction cache + (1 << 4) | // clear SA0 + (1 << 3) | // clear SA + (1 << 2) | // clear C, no cache at all + (1 << 1)); // clear A, no aligment check + r |= (1 << 0); // set M, enable MMU + + LOG ("Read out system control register"); + + asm volatile("msr sctlr_el1, %0; isb" + : + : "r"(r)); + + LOG ("Set SCTLR flags and enable MMU"); +} + +void data_abort_el0 (ptr_t far, ptr_t esr, ptr_t elr) { + byte_t type = (esr >> 2) & 0b11; + byte_t level = esr & 0b11; + esr &= 0b111111; + + printf ("ELR_EL1: %p - ", elr); + printf ("FAR_EL1: %p - ", far); + printf ("ESR_EL1: %b\r\n", esr); + + switch (type) { + case 0b00:// Address size fault + printf ("Address size fault during level %u of table walk on lookup of address %p.\r\n", level, far); + break; + case 0b01:// Translation fault + printf ("Translation fault during level %u of table walk on lookup of address %p.\r\n", level, far); + break; + case 0b10:// Access flag fault + printf ("Access flag fault during level %u of table walk on lookup of address %p.\r\n", level, far); + break; + case 0b11:// Permission fault + printf ("Permission fault during level %u of table walk on lookup of address %p.\r\n", level, far); + break; + } + exit_process (); +} \ No newline at end of file diff --git a/thorn/src/kernel/sched.c b/thorn/src/kernel/sched.c index ff408dc..79fb818 100644 --- a/thorn/src/kernel/sched.c +++ b/thorn/src/kernel/sched.c @@ -1,4 +1,5 @@ #include "kernel/sched.h" +#include "common/debug.h" #include "common/printf.h" #include "common/utils.h" #include "kernel/fork.h" @@ -20,15 +21,17 @@ void preempt_enable (void) { current->preempt_count--; } - void _schedule (void) { preempt_disable (); - int next, c; + long next, c, cur; struct task_struct * p; while (1) { c = -1; next = 0; + cur; for (int i = 0; i < NR_TASKS; i++) { + if (task[i] == current) + cur = i; p = task[i]; if (p && p->state == TASK_RUNNING && p->counter > c) { c = p->counter; @@ -54,13 +57,17 @@ void schedule (void) { _schedule (); } - void switch_to (struct task_struct * next, int index) { if (current == next) { return; } struct task_struct * prev = current; current = next; + // asm volatile("msr ttbr0_el1, %0" + // : + // : "r"(next->mm.pgd)); + // asm volatile("DSB ISH"); + // asm volatile ("isb"); cpu_switch_to (prev, next); } @@ -87,14 +94,10 @@ void exit_process () { break; } } - if (current->stack) { - free_page (current->stack); - } preempt_enable (); schedule (); } - void task_init () { memzero ((ptr_t) current, sizeof (struct task_struct)); current->priority = 1; diff --git a/thorn/src/linker.ld b/thorn/src/linker.ld index b0868c4..69512aa 100644 --- a/thorn/src/linker.ld +++ b/thorn/src/linker.ld @@ -4,9 +4,16 @@ SECTIONS .text.boot : { *(.text.boot) } .text : { *(.text) } .rodata : { *(.rodata) } + PROVIDE(_data = .); .data : { *(.data) } - . = ALIGN(0x8); - bss_begin = .; - .bss : { *(.bss*) } - bss_end = .; -} \ No newline at end of file + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + . = ALIGN(4096); + _end = .; +} +__bss_size = (__bss_end - __bss_start) >> 3;