From eac9236e44dc01c129908ce023faa3857c9582ad Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 28 Jul 2025 23:26:59 +0200 Subject: [PATCH] Map the kernel to the higher half --- Rakefile | 2 +- arch/riscv/kernel.ld | 32 ++-- arch/riscv/kernel.s | 371 ++++++++++++++++++++++------------------ source/device_tree.elna | 12 -- 4 files changed, 224 insertions(+), 193 deletions(-) diff --git a/Rakefile b/Rakefile index a8ffeca..a105f77 100644 --- a/Rakefile +++ b/Rakefile @@ -385,5 +385,5 @@ task :default do |t| QEMU = 'qemu-system-riscv32' system QEMU, '-machine', 'virt', '-bios', 'default', '-nographic', '-serial', 'mon:stdio', '--no-reboot', - '-kernel', *t.prerequisites + '-kernel', t.prerequisites.last, exception: true end diff --git a/arch/riscv/kernel.ld b/arch/riscv/kernel.ld index 6525e1a..a416e6a 100644 --- a/arch/riscv/kernel.ld +++ b/arch/riscv/kernel.ld @@ -3,35 +3,45 @@ OUTPUT_FORMAT("elf32-littleriscv") ENTRY(_entry) PHDRS { + boot PT_LOAD FLAGS(5); text PT_LOAD FLAGS(5); - data PT_LOAD FLAGS(6); } SECTIONS { - .text 0x80200000 : { + .text.boot 0x80200000 : { KEEP(*(.text.boot)); + . = ALIGN(CONSTANT(MAXPAGESIZE)); + ASSERT(. - ADDR(.text.boot) == 0x1000, "error: stub larger than one page"); + } :boot + + _kernel_offset = 0x3fdff000; + + .text 0xc0000000 : AT(ADDR(.text) - _kernel_offset) { + PROVIDE(__executable_start = . - _kernel_offset); *(.text .text.*); } :text . = ALIGN(CONSTANT(MAXPAGESIZE)); - PROVIDE(etext = .); + PROVIDE(etext = . - _kernel_offset); - .rodata : ALIGN(16) { + .rodata : AT(ADDR(.rodata) - _kernel_offset) ALIGN(16) { *(.rodata .rodata.*); } - .data : ALIGN(16) { - *(.data .data.*); - } :data + . = ALIGN(CONSTANT(MAXPAGESIZE)); + PROVIDE(_data = . - _kernel_offset); - .bss : ALIGN(16) { - __bss = .; + .data : AT(ADDR(.data) - _kernel_offset) ALIGN(16) { + *(.data .data.*); + } + + .bss (NOLOAD) : { + PROVIDE(__bss_start = . - _kernel_offset); *(.bss .bss.* .sbss .sbss.*); - __bss_end = .; } . = ALIGN(CONSTANT(MAXPAGESIZE)); - PROVIDE(end = .); + PROVIDE(end = . - _kernel_offset); /DISCARD/ : { *(.eh_frame) diff --git a/arch/riscv/kernel.s b/arch/riscv/kernel.s index 746d84d..a188c8e 100644 --- a/arch/riscv/kernel.s +++ b/arch/riscv/kernel.s @@ -1,4 +1,4 @@ -.global _entry, __bss, __bss_end, __stack_top +.global _entry .section .rodata @@ -7,163 +7,6 @@ panic_message: .asciz "\nPanic" .section .text -# Maps a page of physical memory to the identical virtual memory. -# -# Parameters: -# a0 - Physical page address. -# a1 - Free memory page that can be used to create a leaf page table. -# a2 - Page table level. If a2 is 0 a superpage is allocated, otherwise a normal page. -# a3 - Flags. -# -# Returns virtual page address in a0. -.type imem_map_at, @function -imem_map_at: - csrr t0, satp - slli t0, t0, 12 # Root table address. - - li t4, 0xfffffc00 - li t5, 0xffc # 10 bit * PTESIZE mask. - li t1, 20 - -.Limem_map_at_loop: - # Multiply VPN[i] by 4 and add to the start address of the page table. - # This gives the physical address of the page table entry. - srl t2, a0, t1 - and t2, t2, t5 # VPN[i] * PTESIZE. - add t2, t0, t2 # a + VPN[i] * PTESIZE. - - beqz a2, .Limem_map_at_leaf - - lw t3, (t2) - andi t6, t3, 0b1 - - beqz t6, .Limem_map_at_create - - and t0, t3, t4 - slli t0, t0, 2 - - j .Limem_map_at_next - -.Limem_map_at_create: - # Take a chunk of free memory and use it as the next page table. - # The beginning addres off the chunk is the base address (a) for the next level. - mv t0, a1 - srli t3, t0, 2 - ori t3, t3, 0b1 - sw t3, (t2) - -.Limem_map_at_next: - # Calculate the next page table address for the next level. - addi t1, t1, -10 - addi a2, a2, -1 - - j .Limem_map_at_loop - -.Limem_map_at_leaf: - srli t3, a0, 2 # Physical page number mapped to 12 bits of the page table entry. - ori a3, a3, 0b1 - or t3, t3, a3 # Execute, write, read and valid. - sw t3, (t2) - - ret - -# Maps multiple pages of physical memory to the identical virtual memory. -# -# Parameters: -# a0 - Start address. -# a1 - End address. -# a2 - Start of the free memory that can be used to create leaf page tables. -# a3 - Page table level. If a2 is 0 a superpage is allocated, otherwise a normal page. -# a4 - Flags. -.type imem_map_range, @function -imem_map_range: - # Prologue. - addi sp, sp, -32 - sw ra, 28(sp) - sw s0, 24(sp) - addi s0, sp, 32 - - sw s1, 20(sp) - sw a2, 16(sp) - sw a3, 12(sp) - sw a4, 8(sp) - - mv s1, a1 - -.Limem_map_range_loop: - bge a0, s1, .Limem_map_range_end - - lw a1, 16(sp) - lw a2, 12(sp) - lw a3, 8(sp) - call imem_map_at - - li t0, 4096 - add a0, a0, t0 - - j .Limem_map_range_loop - -.Limem_map_range_end: - lw s1, 20(sp) - - # Epilogue. - lw ra, 28(sp) - lw s0, 24(sp) - addi sp, sp, 32 - ret - -# Activates paging and creates root page table. -# Allocates enough pages for the kernel and its stack. -# -# Parameters: -# a0 - Start (base) address of the kernel. -# a1 - Page aligned address following the kernel (kernel end). -.type imem_initialize, @function -imem_initialize: - # Prologue. - addi sp, sp, -32 - sw ra, 28(sp) - sw s0, 24(sp) - addi s0, sp, 32 - - sw a0, 20(sp) - sw a1, 16(sp) - - srli t0, a1, 12 - csrw satp, t0 - - la a0, .text.boot - la a1, etext - lw a2, 16(sp) - li t0, 4096 - add a2, a2, t0 - li a3, 1 - li a4, 0b1010 - call imem_map_range - - la a0, etext - lw a1, 16(sp) - li t0, 4096 - add a1, a1, t0 - add a2, a1, t0 - li a3, 1 - li a4, 0b0110 - call imem_map_range - - csrr t0, satp - li t1, 0x80000000 - or t0, t0, t1 - - sfence.vma - csrw satp, t0 - sfence.vma - - # Epilogue. - lw ra, 28(sp) - lw s0, 24(sp) - addi sp, sp, 32 - ret - .type kernel_main, @function kernel_main: # Prologue. @@ -182,9 +25,10 @@ kernel_main: lw a0, 16(sp) li t0, 0xffc00000 and a0, a0, t0 - lw a1, 20(sp) - li a2, 0 - li a3, 0b0010 + mv a1, a0 + lw a2, 20(sp) + li a3, 0 + li a4, 0b0010 call imem_map_at lw a0, 16(sp) @@ -350,18 +194,207 @@ _entry: mv s1, a1 - la a0, .text.boot - mv a1, sp + mv a0, sp call imem_initialize - lw t0, (end) - la t1, next_paddr - sw t0, (t1) + li s2, 0xc0000000 + li s3, 0x80201000 + li s4, 0x1000 - la a0, __bss - la a1, __bss_end +.rept 12 + mv a0, s2 + mv a1, s3 + li t0, 8192 + add a2, sp, t0 + li a3, 1 + li a4, 0b1110 + call imem_map_at + + add s2, s2, s4 + add s3, s3, s4 +.endr + + la a0, __bss_start + la a1, end call bzero mv a0, sp mv a1, s1 - j kernel_main + tail kernel_main + +# Activates paging and creates root page table. +# Allocates enough pages for the kernel and its stack. +# +# Parameters: +# a0 - Page aligned address following the kernel (kernel end). +.type imem_initialize, @function +imem_initialize: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + + sw a0, 20(sp) + + srli t0, a0, 12 + csrw satp, t0 + + la a0, .text.boot + mv a1, a0 + lw a2, 20(sp) + li t0, 4096 + add a2, a2, t0 + li a3, 1 + li a4, 0b1010 + call imem_map_at + + la a0, __executable_start + la a1, etext + lw a2, 20(sp) + li t0, 4096 + add a2, a2, t0 + li a3, 1 + li a4, 0b1010 + call imem_map_range + + la a0, etext + la a1, _data + lw a2, 20(sp) + li t0, 4096 + add a2, a2, t0 + li a3, 1 + li a4, 0b0010 + call imem_map_range + + la a0, _data + lw a1, 20(sp) + li t0, 4096 + add a1, a1, t0 + add a1, a1, t0 + add a1, a1, t0 + add a2, a1, t0 + li a3, 1 + li a4, 0b0110 + call imem_map_range + + csrr t0, satp + li t1, 0x80000000 + or t0, t0, t1 + + sfence.vma + csrw satp, t0 + sfence.vma + + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret + +# Maps multiple pages of physical memory to the identical virtual memory. +# +# Parameters: +# a0 - Start address. +# a1 - End address. +# a2 - Start of the free memory that can be used to create leaf page tables. +# a3 - Page table level. If a3 is 0 a superpage is allocated, otherwise a normal page. +# a4 - Flags. +.type imem_map_range, @function +imem_map_range: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + + sw s1, 20(sp) + sw a2, 16(sp) + sw a3, 12(sp) + sw a4, 8(sp) + + mv s1, a1 + +.Limem_map_range_loop: + bge a0, s1, .Limem_map_range_end + + mv a1, a0 + lw a2, 16(sp) + lw a3, 12(sp) + lw a4, 8(sp) + call imem_map_at + + li t0, 4096 + add a0, a0, t0 + + j .Limem_map_range_loop + +.Limem_map_range_end: + lw s1, 20(sp) + + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret + +# Maps a page of physical memory to the identical virtual memory. +# +# Parameters: +# a0 - Physical page address. +# a1 - Corresponding virtual address. +# a2 - Free memory page that can be used to create a leaf page table. +# a3 - Page table level. If a3 is 0 a superpage is allocated, otherwise a normal page. +# a4 - Flags. +# +# Returns virtual page address in a0. +.type imem_map_at, @function +imem_map_at: + csrr t0, satp + slli t0, t0, 12 # Root table address. + + li t4, 0xfffffc00 + li t5, 0xffc # 10 bit * PTESIZE mask. + li t1, 20 + +.Limem_map_at_loop: + # Multiply VPN[i] by 4 and add to the start address of the page table. + # This gives the physical address of the page table entry. + srl t2, a0, t1 + and t2, t2, t5 # VPN[i] * PTESIZE. + add t2, t0, t2 # a + VPN[i] * PTESIZE. + + beqz a3, .Limem_map_at_leaf + + lw t3, (t2) + andi t6, t3, 0b1 + + beqz t6, .Limem_map_at_create + + and t0, t3, t4 + slli t0, t0, 2 + + j .Limem_map_at_next + +.Limem_map_at_create: + # Take a chunk of free memory and use it as the next page table. + # The beginning addres off the chunk is the base address (a) for the next level. + mv t0, a2 + srli t3, t0, 2 + ori t3, t3, 0b1 + sw t3, (t2) + +.Limem_map_at_next: + # Calculate the next page table address for the next level. + addi t1, t1, -10 + addi a3, a3, -1 + + j .Limem_map_at_loop + +.Limem_map_at_leaf: + srli t3, a1, 2 # Physical page number mapped to 12 bits of the page table entry. + ori a4, a4, 0b1 + or t3, t3, a4 # Execute, write, read and valid. + sw t3, (t2) + + ret diff --git a/source/device_tree.elna b/source/device_tree.elna index c11b729..8ff1a7e 100644 --- a/source/device_tree.elna +++ b/source/device_tree.elna @@ -23,9 +23,6 @@ type nameoff: Word end; -var - next_paddr*: Pointer; - proc write_c(value: Char); extern; proc write_s(value: String); extern; @@ -33,15 +30,6 @@ proc separator*() -> Char; return ',' end; -proc alloc_pages(n: Word) -> Pointer; -var - paddr: Pointer; -begin - next_paddr := next_paddr + n * PAGE_SIZE; - - return paddr -end; - (* Prints a number in the hexadecimal format writing the digits into the sink procedure. If the value is shorter than the padding, pads the output with