os-workshop

same materials and sample source for RV32 OS projects
git clone http://frotz.net/git/os-workshop.git
Log | Files | Refs

kernel.c (4830B)


      1 // Copyright 2022, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0
      3 
      4 #include "kernel.h"
      5 
      6 #include <hw/debug.h>
      7 #include <hw/platform.h>
      8 #include <hw/litex.h>
      9 
     10 #include <string.h>
     11 
     12 // kernel page directory
     13 static uint32_t *kpgdir;
     14 
     15 // load general registers from eframe
     16 // save ef + sizeof(eframe_t) as kernel sp and tp for next trap
     17 // enter user mode at ef->pc
     18 void user_mode_entry(eframe_t* ef);
     19 
     20 extern char __extra_start[];
     21 extern char __extra_end[];
     22 
     23 // the top bits on a kernel stack
     24 typedef struct {
     25 	eframe_t eframe;
     26 	thread_t thread;
     27 } kstack_top_t;
     28 
     29 #define FRAMEBUFFER_SIZE (640*480*2)
     30 
     31 void map_framebuffer(uint32_t* pgdir) {
     32 	paddr_t pa = FRAMEBUFFER_BASE;
     33 	vaddr_t va = 0x20000000;
     34 	for (unsigned n = 0; n < FRAMEBUFFER_SIZE; n += PAGE_SIZE) {
     35 		// TODO: remove the pa from the freelist
     36 		vm_map_4k(pgdir, va + n, pa + n, USER_RW);
     37 	}
     38 }
     39 
     40 void start_user_program(void) {
     41 	vaddr_t user_start = 0x10000000;
     42 	vaddr_t user_stack = 0x10400000;
     43 
     44 	xprintf("user.bin %u bytes\n", (__extra_end - __extra_start));
     45 
     46 	// allocate 16KB (4 pages) for user text/data
     47 	vm_map_4k(kpgdir, user_start + 0*PAGE_SIZE, ppage_alloc_z(), USER_RWX);
     48 	vm_map_4k(kpgdir, user_start + 1*PAGE_SIZE, ppage_alloc_z(), USER_RWX);
     49 	vm_map_4k(kpgdir, user_start + 2*PAGE_SIZE, ppage_alloc_z(), USER_RWX);
     50 	vm_map_4k(kpgdir, user_start + 3*PAGE_SIZE, ppage_alloc_z(), USER_RWX);
     51 
     52 	// allocate a 4KB (1 page) for user stack
     53 	vm_map_4k(kpgdir, user_stack - 1*PAGE_SIZE, ppage_alloc_z(), USER_RW);
     54 
     55 	map_framebuffer(kpgdir);
     56 
     57 	// allow S-MODE writes to U-MODE pages
     58 	csr_set(CSR_SSTATUS, SSTATUS_SUM);
     59 
     60 	// copy embedded user.bin into user memory
     61 	memcpy((void*) user_start, __extra_start, __extra_end - __extra_start);
     62 
     63 	csr_clr(CSR_SSTATUS, SSTATUS_SUM);
     64 
     65 	// allocate a kernel stack page
     66 	// setup an eframe with the initial user register state
     67 	kstack_top_t *kst = kpage_alloc_z() + PAGE_SIZE - sizeof(kstack_top_t);
     68 	kst->eframe.pc = user_start;
     69 	kst->eframe.sp = user_stack;
     70 
     71 	// set previous privilege mode to user (0) 
     72 	csr_clr(CSR_SSTATUS, SSTATUS_SPP);
     73 
     74 	xprintf("\n[ starting user mode program ]\n\n");
     75 
     76 	user_mode_entry(&kst->eframe);
     77 	// does not return
     78 }
     79 
     80 extern char __text_start[];
     81 extern char __rodata_start[];
     82 extern char __data_start[];
     83 extern char __bss_start[];
     84 extern char __bss_end[];
     85 extern char __image_end[];
     86 extern char __memory_top[];
     87 
     88 // On entry:
     89 // SP = __memory_top  (top of ram)
     90 // SATP points at __memory_top - 8K
     91 
     92 void start(void) {
     93 	xprintf("X/OS Kernel v0.1\n\n");
     94 
     95 	xprintf("text   %p %u\n", __text_start, __rodata_start - __text_start);
     96 	xprintf("rodata %p %u\n", __rodata_start, __data_start - __rodata_start);
     97 	xprintf("data   %p %u\n", __data_start, __bss_start - __data_start);
     98 	xprintf("bss    %p %u\n", __bss_start, __bss_end - __bss_start);
     99 	xprintf("free   %p %u\n", __image_end, __memory_top - __image_end);
    100 	xprintf("memtop %p\n", __memory_top);
    101 
    102 	// set trap vector to trap_entry() in trap-entry-single.S
    103 	// it will call exception_handler() or interrupt_handler()
    104 	csr_write(CSR_STVEC, (uintptr_t) trap_entry);
    105 
    106 	// the topmost page is the boot stack
    107 	// the second topmost page is the boot page directory
    108 
    109 	// give all other pages from end-of-kernel to boot pagedir
    110 	// to the virtual memory manager
    111 	vmm_init(kva_to_pa(__image_end), kva_to_pa(__memory_top) - 2 * PAGE_SIZE);
    112 
    113 	// build a more correct page table
    114 	kpgdir = kpage_alloc_z();
    115 
    116 	char *va = __text_start;
    117 	// map kernel text RX
    118 	while (va < __rodata_start) {
    119 		vm_map_4k(kpgdir, (vaddr_t) va, kva_to_pa(va), KERNEL_RX);
    120 		va += PAGE_SIZE;
    121 	}
    122 	// map kernel rodata RO
    123 	while (va < __data_start) {
    124 		vm_map_4k(kpgdir, (vaddr_t) va, kva_to_pa(va), KERNEL_RO);
    125 		va += PAGE_SIZE;
    126 	}
    127 	// map kernel data and the rest of ram RW
    128 	char *end = (void*) ((((uint32_t) __image_end) + 0x003FFFFF) & 0xFFC00000);
    129 	while (va < end) {
    130 		vm_map_4k(kpgdir, (vaddr_t) va, kva_to_pa(va), KERNEL_RW);
    131 		va += PAGE_SIZE;
    132 	}
    133 	// map as much as possible as 4MB megapages
    134 	while (va < __memory_top) {
    135 		vm_map_4m(kpgdir, (vaddr_t) va, kva_to_pa(va), KERNEL_RW);
    136 		va += 4*1024*1024;
    137 	}
    138 	// map mmio region
    139 	vm_map_4m(kpgdir, 0xF0000000, 0xF0000000, KERNEL_RW);
    140 
    141 	csr_write(CSR_SATP, SATP_MODE_SV32 | (kva_to_pa(kpgdir) >> 12));
    142 	tlb_flush_all();
    143 
    144 	start_user_program();
    145 }
    146 
    147 status_t sys_thread_create(handle_t* out, void *entry, void *arg) {
    148 	return XOS_ERR_NOT_SUPPORTED;
    149 }
    150 
    151 void sys_xputc(unsigned ch) {
    152 	xputc(ch);
    153 }
    154 
    155 void sys_exit(int n) {
    156 	xprintf("\n[ user exit (status %d) ]\n", n);
    157 	for (;;) ;
    158 }
    159 
    160 void interrupt_handler(void) {
    161 }
    162 
    163 // if an exception occurs, dump register state and halt
    164 void exception_handler(eframe_t *ef) {
    165 	xprintf("\n** SUPERVISOR EXCEPTION **\n");
    166 	xprint_s_exception(ef);
    167 	xprintf("\nHALT\n");
    168 	for (;;) ;
    169 }
    170 
    171 void panic(const char *msg) {
    172 	xprintf("\n** kernel panic: %s **\n", msg);
    173 	for (;;) ;
    174 }