Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISC-V 64 paging, virtual memory and stuff #5

Draft
wants to merge 37 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d5719c3
initial boot page table
Apr 16, 2023
088022c
riscv: remove unnecessary cast in virt devcons
orangecms Apr 29, 2023
19325bb
riscv: reduce change in uart16550
orangecms Apr 25, 2023
4421527
riscv: print in platform init
orangecms Apr 25, 2023
b6b203b
riscv: linker script cleanup
orangecms Apr 25, 2023
c7764cd
riscv: DT/regblock/MMIO tests
orangecms Apr 28, 2023
839fb3e
riscv: rework, add address mapping debug helper
orangecms Apr 29, 2023
c89e7ee
riscv64: elaborate on SATP
orangecms Apr 29, 2023
8e10827
WIP: riscv: try initializing UART natively
orangecms Apr 29, 2023
05ba8c7
riscv: reduce UART MMIO debug prints
orangecms Apr 29, 2023
61f5df3
riscv: document PTE
orangecms Apr 29, 2023
b335422
riscv: factor out walk_dt, print binary sections
orangecms May 1, 2023
99d5b93
riscv: dump start of text region
orangecms May 1, 2023
3dfa646
riscv/memory: debug print address translation
orangecms May 2, 2023
8b85dae
riscv/platform/virt: fix up memory address offset
orangecms May 2, 2023
6cc96be
port/fdt: debug DT parsing
orangecms May 2, 2023
612a817
riscv: rework again, debug more...
orangecms May 2, 2023
78a5e5f
I KNOW KUNG FU (kinda)
orangecms May 2, 2023
53da6a3
BACK TO NATIVE UART
orangecms May 2, 2023
c7add63
awesome ASCII art
orangecms May 2, 2023
2ad165c
rework logo
orangecms May 2, 2023
a8627cc
riscv/platform/virt/devcons: remove unnecessary mut
orangecms May 2, 2023
7615cc4
fixi
orangecms Sep 9, 2023
79a7265
Implement page table reading and writing
mraerino Sep 9, 2023
90cc2ee
WIP
orangecms Sep 19, 2023
159f049
whatever
orangecms Sep 19, 2023
8b9a383
WIP
orangecms Sep 19, 2023
40f9b81
WIP
orangecms Sep 20, 2023
4e327e9
WIP: RISC-V paging
orangecms Nov 24, 2023
200a3f7
CHECKPOINT we got to d00dfeed
orangecms Apr 13, 2024
ec7e31e
I know vmem-fu
orangecms Apr 13, 2024
8be5720
this is nice
orangecms Apr 14, 2024
a302bbd
NOW WE'RE TALKiNG
orangecms Apr 16, 2024
604ff0d
play more with PTs, PTEs and VM
orangecms Apr 17, 2024
4471edb
fix up initial PT
orangecms Apr 17, 2024
dd82988
we're getting further
orangecms Apr 17, 2024
ee70a95
yeat that's it https://www.youtube.com/watch?v=wK2UAG0Cdh8
orangecms Apr 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions aarch64/src/l.S
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ PT_ISH = (3<<8) // Inner shareable (shared across CPUs)
// This defines the kernel's virtual address location.
// This value splits a 48 bit address space exactly in half, with the half
// beginning with 1 going to the kernel.
KZERO = 0xffff800000000000
KZERO = 0xffff800000000000
MiB = (1<<20)
GiB = (1<<30)
KTZERO = (KZERO + 2*MiB) // Virtual base of kernel text

// Constants for early uart setup
MMIO_BASE_RPI3 = 0x3f000000
Expand Down
12 changes: 11 additions & 1 deletion port/src/fdt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::println;
use core::{
ffi::CStr,
mem::{self, MaybeUninit},
};

const DEBUG_DT_PARSING: bool = false;

#[derive(Debug)]
pub enum ParseError {
InvalidHeader,
Expand Down Expand Up @@ -66,6 +69,9 @@ impl<'a> DeviceTree<'a> {
/// Given a pointer to the dtb as a u64, return a DeviceTree struct.
pub unsafe fn from_u64(ptr: u64) -> Result<Self> {
let u8ptr = ptr as *const mem::MaybeUninit<u8>;
if DEBUG_DT_PARSING {
println!(" DT @ {u8ptr:x?}");
}

// Extract the real length from the header
let dtb_buf_for_header: &[mem::MaybeUninit<u8>] =
Expand All @@ -77,7 +83,11 @@ impl<'a> DeviceTree<'a> {
// Extract the buffer for real
let dtb_buf: &[mem::MaybeUninit<u8>] =
unsafe { core::slice::from_raw_parts(u8ptr as *const MaybeUninit<u8>, len) };
FdtHeader::new(dtb_buf, false).map(|header| Self { data: dtb_buf, header })
let h = FdtHeader::new(dtb_buf, false);
if DEBUG_DT_PARSING {
println!(" DT header {:#x?}", h);
}
h.map(|header| Self { data: dtb_buf, header })
}

/// Return slice containing `structs` area in FDT
Expand Down
2 changes: 2 additions & 0 deletions riscv64/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ default-target = "riscv64imac-unknown-none-elf"

[dependencies]
port = { path = "../port" }
bitflags = "2.3.3"
bit_field = "0.10.2"

[features]
opensbi = []
2 changes: 1 addition & 1 deletion riscv64/lib/config_default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildflags = [
[link]
arch = 'riscv'
script = 'riscv64/lib/kernel.ld'
load-address = '0x80200000'
load-address = '0xffffffffc0200000'

[config]
platform = "virt"
18 changes: 10 additions & 8 deletions riscv64/lib/kernel.ld
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,38 @@ ENTRY(start)

SECTIONS {
. = ${LOAD-ADDRESS};

text = .;
.text : ALIGN(4096) {
*(.text.entry)
*(.text*)
. = ALIGN(2097152);
PROVIDE(etext = .);
etext = .;
}

rodata = .;
.rodata : ALIGN(4096) {
*(.rodata*)
*(.srodata*)
. = ALIGN(2097152);
PROVIDE(erodata = .);
erodata = .;
}

data = .;
.data : ALIGN(4096) {
*(.data*)
*(.sdata*)
. = ALIGN(2097152);
PROVIDE(edata = .);
edata = .;
}

bss = .;
.bss : ALIGN(4096) {
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(2097152);
PROVIDE(end = .);
}
end = .;

/DISCARD/ : {
*(.eh_frame)
*(.eh_frame .note.GNU-stack)
}
}
119 changes: 111 additions & 8 deletions riscv64/src/l.S
Original file line number Diff line number Diff line change
@@ -1,15 +1,118 @@
// 0xFFFFFFFF40000000
.equ PHYSICAL_MEMORY_OFFSET, (0xFFFFFFFFC0000000 - 0x80000000)

.section .text.entry
.globl start
start:
bnez a0, 1f
la sp, stack // set the stack pointer
li t0, 4096 * 4
add sp, sp, t0 // add stack length
call main9
// a0 == hartid
// pc == 0x80200000
// sp == 0x800xxxxx

// 1. set sp
// sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 16
lui sp, %hi(bootstack)
add sp, sp, t0 // add stack length

// enable paging
// satp = (8 << 60) | PPN(boot_page_table)
// SATP = Supervisor Address Translation and Protection
// Register definition:
// | MODE | ASID | PPN |
// |[63..60]|[59..44]|[43..0]|
// PPN = Physical Page Number (of root page table)
// ASID = Address Space Identifier
// Volume II: RISC-V Privileged Architectures V20211203 p75
// SXLEN 64, MODE 8: Sv39 aka Page-based 39-bit virtual addressing
lui t0, %hi(boot_page_table)
// page size is 4k (2^12) - drop lowest 12 bits
srli t4, t0, 12

// subtract offset to get the physical address of the root page table
li t1, PHYSICAL_MEMORY_OFFSET
sub t2, t0, t1

// page size is 4k (2^12) - drop lowest 12 bits
srli t3, t2, 12
// final SATP
li t1, 8 << 60 // mode Sv39
or t0, t3, t1

// t3 holds the root page table physical address divided by 4k; shift for flags
slli t1, t4, 10
ori t1, t4, 0xc1 // DAGU XWRV
sd t1, 8*255(t2) // #255

// flush TLB
sfence.vma
csrw satp, t0
// flush TLB
sfence.vma

// 3. jump to main9 (absolute address)
lui t0, %hi(main9)
addi t0, t0, %lo(main9)
jr t0

1:
wfi
j 1b

.bss
.balign 4096
stack: .space 4096 * 4
/* STACK */
.section .bss.stack
.align 12 # page align
.global bootstack

bootstack:
.space 4096 * 4 * 8
.global bootstacktop

bootstacktop:
.section .data
.align 12 // page align

/* PAGING */
boot_page_table:
// PTE (Page Table Entry) definition (SV39)
// A virtual address (VA) in SV39 consists of 3 parts plus the final offset.
// Those parts make up the _virtual page number_ (VPN).
// Each VPN part is 9 bits long, used to point to an entry in a page table.
// The VA offset is another 12 bits, so that it can point to any of 4K bytes.
// 9 + 9 + 9 + 12 = 39
//
// NOTE: A page table entry is 8 bytes; 512 entries are 512*8=4k.
//
// N is reserved for Svnapot, PBMT is Page-based Memory Types
// | N | PBMT | Rsvd. |
// |[63]|[62..61]|[60..54]|
// The Physical Page Number (PPN) is 26 + 9 + 9 = 44 bits long.
// | PPN[2] | PPN[1] | PPN[0] |
// |[53..28]|[27..19]|[18..10]|
// RSW is reserved for supervisor software control.
// D - dirty, A - accessed, G - global mapping, U - user mode access,
// XWR - exec/write/read (table 4.5, p80), V - entry is valid
// | RSW | D | A | G | U | X | W | R | V |
// |[9..8]|[7]|[6]|[5]|[4]|[3]|[2]|[1]|[0]|
//
// NOTE: quad = 4 words = 4 double bytes = 8 bytes
// https://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html#SEC115
// Those are leaf pages (at least on of RWX set), 1G (0x4000_0000) each.

// Identity map in the beginning
// 1st page: 0x00000000_00000000 -> 0x00000000 (1G)
.quad (0x00000 << 10) | 0xcf // VRWXAD
// 2nd page: 0x00000000_40000000 -> 0x40000000 (1G)
.quad (0x40000 << 10) | 0xcf // VRWXAD
// 3rd page: 0x00000000_80000000 -> 0x80000000 (1G)
.quad (0x80000 << 10) | 0xcf // VRWXAD
// 504 empty entries

// Remap first 3GB in the end
.zero 506 * 8
// 3rd last page: 0xffffffff_40000000 -> 0x00000000 (1G)
.quad (0x00000 << 10) | 0xcf // VRWXAD
// 2nd last page: 0xffffffff_80000000 -> 0x40000000 (1G)
.quad (0x40000 << 10) | 0xcf // VRWXAD
// very last page: 0xffffffff_c0000000 -> 0x80000000 (1G)
.quad (0x80000 << 10) | 0xcf // VRWXAD
Loading