92 lines
2.8 KiB
Rust
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
|
|
}
|