92 lines
2.8 KiB
Rust

// Physical memory layout
// QEMU -machine virt is setup like this,
// based on QEMU's hw/riscv/virt.c
//
// 00001000 - boot ROM, provided by qemu
// 02000000 - CLINT
// 0C000000 - PLIC
// 10000000 - uart0
// 10001000 - virtio disk
// 80000000 - boot ROM jumps here in machine mode (kernel loads the kernel here)
// unused after 8000000
// The kernel uses physical memory as so:
// 80000000 - entry.S, then kernel text and data
// end - start of kernel page allocation data
// PHYSTOP - end of RAM used by the kernel
pub type PagetableEntry = u64;
pub type Pagetable = *mut [PagetableEntry; 512];
/// The PagetableEntry is valid.
pub const PTE_V: i32 = 1 << 0;
/// The PagetableEntry is readable.
pub const PTE_R: i32 = 1 << 1;
/// The PagetableEntry is writable.
pub const PTE_W: i32 = 1 << 2;
/// The PagetableEntry is executable.
pub const PTE_X: i32 = 1 << 3;
/// The PagetableEntry is user-accessible.
pub const PTE_U: i32 = 1 << 4;
/// Page-based 39-bit virtual addressing.
/// Details at section 5.4 of the RISC-V specification.
pub const SATP_SV39: u64 = 8 << 60;
pub fn make_satp(pagetable: Pagetable) -> u64 {
SATP_SV39 | (pagetable as usize as u64 >> 12)
}
/// Bytes per page.
pub const PAGE_SIZE: usize = 4096;
/// Bits of offset within a page
const PAGE_OFFSET: usize = 12;
/// The kernel starts here.
pub const KERNEL_BASE: usize = 0x8000_0000;
/// The end of physical memory.
pub const PHYSICAL_END: usize = KERNEL_BASE + (128 * 1024 * 1024);
/// The maximum virtual address.
///
/// VIRTUAL_MAX is actually one bit less than the max allowed by
/// Sv39 to avoid having to sign-extend virtual addresses
/// that have the high bit set.
pub const VIRTUAL_MAX: usize = 1 << (9 + 9 + 9 + 12 - 1);
/// Map the trampoline page to the highest
/// address in both user and kernel space.
pub const TRAMPOLINE: usize = VIRTUAL_MAX - PAGE_SIZE;
/// Map kernel stacks beneath the trampoline,
/// each surrounded by invalid guard pages.
pub fn kstack(page: usize) -> usize {
TRAMPOLINE - (page + 1) * 2 * PAGE_SIZE
}
/// User memory layout.
/// Address zero first:
/// - text
/// - original data and bss
/// - fixed-size stack
/// - expandable heap
/// ...
/// - TRAPFRAME (p->trapframe, used by the trampoline)
/// - TRAMPOLINE (the same page as in the kernel)
pub const TRAPFRAME: usize = TRAMPOLINE - PAGE_SIZE;
// Convert a physical address to a PagetableEntry.
pub fn pa2pte(pa: usize) -> usize {
(pa >> 12) << 10
}
// Convert a PagetableEntry to a physical address.
pub fn pte2pa(pte: usize) -> usize {
(pte >> 10) << 12
}
// Extract the three 9-bit page table indices from a virtual address.
const PXMASK: usize = 0x1ffusize; // 9 bits.
fn pxshift(level: usize) -> usize {
PAGE_OFFSET + (level * 9)
}
pub fn px(level: usize, virtual_addr: usize) -> usize {
(virtual_addr >> pxshift(level)) & PXMASK
}