commit d1670a3d26fbb9d1edfc2eb42d84b9da946e928c
parent acc8ff2d29e72e99f0b2c8797797986030d984c0
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 18 May 2022 15:33:44 -0700
linker/start: shuffle symbols a bit
- __memory_top now indicates the vaddr of top-of-sdram
- __image_end now indicates the first page after the app
- ex25-kernel now sets up a more correct page table
Diffstat:
4 files changed, 98 insertions(+), 22 deletions(-)
diff --git a/example/ex25-kernel.c b/example/ex25-kernel.c
@@ -39,28 +39,31 @@ paddr_t alloc_ppage(void) {
uint32_t* pdir = 0;
-#define MAP_USER_RW (PTE_D|PTE_A|PTE_U|PTE_R|PTE_W|PTE_V)
-#define MAP_USER_RX (PTE_D|PTE_A|PTE_U|PTE_R|PTE_X|PTE_V)
-#define MAP_USER_RWX (PTE_D|PTE_A|PTE_U|PTE_R|PTE_W|PTE_X|PTE_V)
+#define USER_RW (PTE_D|PTE_A|PTE_U|PTE_R|PTE_W|PTE_V)
+#define USER_RX (PTE_D|PTE_A|PTE_U|PTE_R|PTE_X|PTE_V)
+#define USER_RWX (PTE_D|PTE_A|PTE_U|PTE_R|PTE_W|PTE_X|PTE_V)
+
+#define KERNEL_RO (PTE_D|PTE_A|PTE_R|PTE_V)
+#define KERNEL_RW (PTE_D|PTE_A|PTE_R|PTE_W|PTE_V)
+#define KERNEL_RX (PTE_D|PTE_A|PTE_R|PTE_X|PTE_V)
int map_page(vaddr_t va, paddr_t pa, uint32_t flags) {
uint32_t idx1 = va >> 22;
uint32_t idx0 = (va >> 12) & 0x3FF;
uint32_t *ptbl;
- xprintf("map page va=0x%08x(%d,%d) -> pa=0x%08x\n", va, idx1, idx0, pa);
-
+ //xprintf("map page va=0x%08x(%d,%d) -> pa=0x%08x (4K)\n", va, idx1, idx0, pa);
uint32_t pte = pdir[idx1];
if (pte & PTE_V) { // valid pgdir entry
if (pte & (PTE_X|PTE_W|PTE_R)) {
return -1; // 4MB megapage already here
}
ptbl = pa_to_kva(PTE_PA(pte));
- xprintf("old ptbl pa=0x%08x va=%p\n", PTE_PA(pte), ptbl);
+ //xprintf("old ptbl pa=0x%08x va=%p\n", PTE_PA(pte), ptbl);
} else { // no entry, allocate a pagetable
uint32_t ptbl_pa = alloc_ppage();
ptbl = pa_to_kva(ptbl_pa);
- xprintf("new ptbl pa=0x%08x va=%p\n", ptbl_pa, ptbl);
+ //xprintf("new ptbl pa=0x%08x va=%p\n", ptbl_pa, ptbl);
pdir[idx1] = (ptbl_pa >> 2) | PTE_V;
}
@@ -76,6 +79,20 @@ int map_page(vaddr_t va, paddr_t pa, uint32_t flags) {
return 0;
}
+int map_page_4m(vaddr_t va, paddr_t pa, uint32_t flags) {
+ uint32_t idx1 = va >> 22;
+
+ //xprintf("map page va=0x%08x(%d) -> pa=0x%08x (4M)\n", va, idx1, pa);
+ uint32_t pte = pdir[idx1];
+ if (pte & PTE_V) { // valid pgdir entry
+ return -1;
+ }
+ pdir[idx1] = ((pa & 0xFFFFF000) >> 2) | (flags & 0x3FF);
+
+ tlb_flush_all();
+ return 0;
+}
+
// load general registers from eframe
// save ef + sizeof(eframe_t) as kernel sp for next trap
// enter user mode at ef->pc
@@ -91,13 +108,13 @@ void start_user_program(void) {
xprintf("user.bin %u bytes\n", (__extra_end - __extra_start));
// allocate 16KB (4 pages) for user text/data
- map_page(user_start + 0*PAGE_SIZE, alloc_ppage(), MAP_USER_RWX);
- map_page(user_start + 1*PAGE_SIZE, alloc_ppage(), MAP_USER_RWX);
- map_page(user_start + 2*PAGE_SIZE, alloc_ppage(), MAP_USER_RWX);
- map_page(user_start + 3*PAGE_SIZE, alloc_ppage(), MAP_USER_RWX);
+ map_page(user_start + 0*PAGE_SIZE, alloc_ppage(), USER_RWX);
+ map_page(user_start + 1*PAGE_SIZE, alloc_ppage(), USER_RWX);
+ map_page(user_start + 2*PAGE_SIZE, alloc_ppage(), USER_RWX);
+ map_page(user_start + 3*PAGE_SIZE, alloc_ppage(), USER_RWX);
// allocate a 4KB (1 page) for user stack
- map_page(user_stack - 1*PAGE_SIZE, alloc_ppage(), MAP_USER_RW);
+ map_page(user_stack - 1*PAGE_SIZE, alloc_ppage(), USER_RW);
// allow S-MODE writes to U-MODE pages
csr_set(CSR_SSTATUS, SSTATUS_SUM);
@@ -122,20 +139,75 @@ void start_user_program(void) {
// does not return
}
-void start(void *memtop) {
+extern char __text_start[];
+extern char __rodata_start[];
+extern char __data_start[];
+extern char __bss_start[];
+extern char __bss_end[];
+extern char __image_end[];
+extern char __memory_top[];
+
+// On entry:
+// SP = __memory_top (top of ram)
+// SATP points at __memory_top - 8K
+
+void start(void) {
xprintf("Example 25 - kernel\n\n");
+ xprintf("text %p %u\n", __text_start, __rodata_start - __text_start);
+ xprintf("rodata %p %u\n", __rodata_start, __data_start - __rodata_start);
+ xprintf("data %p %u\n", __data_start, __bss_start - __data_start);
+ xprintf("bss %p %u\n", __bss_start, __bss_end - __bss_start);
+ xprintf("free %p %u\n", __image_end, __memory_top - __image_end);
+ xprintf("memtop %p\n", __memory_top);
+
// set trap vector to trap_entry() in trap-entry-single.S
// it will call exception_handler() or interrupt_handler()
csr_write(CSR_STVEC, (uintptr_t) trap_entry);
- // start allocating from 2 pages down from top of ram
- // since our boot stack starts at top of ram
- // and the initial page directory is just below that
- ppage_next = kva_to_pa(memtop) - 2 * PAGE_SIZE;
- pdir = (void*) (memtop - 2 * PAGE_SIZE);
+ // the topmost page is the boot stack
+ // the second topmost page is the boot page directory
+
+ // setup page allocator to start grabbing pages from the top of ram
+ ppage_next = kva_to_pa(__memory_top) - 2 * PAGE_SIZE;
+
+#if 0
+ // use the boot page table
+ pdir = (void*) __memory_top - 2 * PAGE_SIZE;
+#else
+ // build a more correct page table
+ pdir = pa_to_kva(alloc_ppage());
+
+ char *va = __text_start;
+ // map kernel text RX
+ while (va < __rodata_start) {
+ map_page((vaddr_t) va, kva_to_pa(va), KERNEL_RX);
+ va += PAGE_SIZE;
+ }
+ // map kernel rodata RO
+ while (va < __data_start) {
+ map_page((vaddr_t) va, kva_to_pa(va), KERNEL_RO);
+ va += PAGE_SIZE;
+ }
+ // map kernel data and the rest of ram RW
+ char *end = (void*) ((((uint32_t) __image_end) + 0x003FFFFF) & 0xFFC00000);
+ while (va < end) {
+ map_page((vaddr_t) va, kva_to_pa(va), KERNEL_RW);
+ va += PAGE_SIZE;
+ }
+ // map as much as possible as 4MB megapages
+ while (va < __memory_top) {
+ map_page_4m((vaddr_t) va, kva_to_pa(va), KERNEL_RW);
+ va += 4*1024*1024;
+ }
+ // map mmio region
+ map_page_4m(0xF0000000, 0xF0000000, KERNEL_RW);
+
+ csr_write(CSR_SATP, SATP_MODE_SV32 | (kva_to_pa(pdir) >> 12));
+ tlb_flush_all();
+#endif
- start_user_program();
+ start_user_program();
}
void interrupt_handler(void) {
diff --git a/hw/src/start.S b/hw/src/start.S
@@ -18,7 +18,7 @@ zero_loop:
zero_done:
/* setup initial stack */
- la sp, __stack_top
+ la sp, __memory_top
/* enter C code */
jal start
diff --git a/hw/src/start.mmu.S b/hw/src/start.mmu.S
@@ -94,6 +94,6 @@ zero_done:
j start
stack_top:
- .word __stack_top
+ .word __memory_top
_vstart_addr:
.word _vstart
diff --git a/make/common.ram.ld b/make/common.ram.ld
@@ -4,6 +4,7 @@ ENTRY(_start)
SECTIONS {
/* RX code */
.text : {
+ __text_start = .;
KEEP(*(.start))
*(.text .text*)
*(.gnu.linkonce.t.*)
@@ -46,6 +47,9 @@ SECTIONS {
__bss_end = .;
} > RAM
+ . = ALIGN(4096);
+ __image_end = .;
+
/* initialize stack to top of memory */
- __stack_top = ORIGIN(RAM) + LENGTH(RAM);
+ __memory_top = ORIGIN(RAM) + LENGTH(RAM);
}