diff --git a/src/arch/aarch64/entry.s b/src/arch/aarch64/entry.s index 14e870ba..9df42ba3 100644 --- a/src/arch/aarch64/entry.s +++ b/src/arch/aarch64/entry.s @@ -79,44 +79,3 @@ el_1_entry: .size _start, . - _start .type _start, function .global _start - -.section .bss - -.global l0_pgtable -.global l1_pgtable -.global l2_pgtable -.global l2k_pgtable -.global l3_pgtable -.global L0mib_pgtable - -.align 12 -l0_pgtable: - .space 512*8, 0 -l1_pgtable: - .space 512*8, 0 -l2_pgtable: - .space 512*8, 0 -l2k_pgtable: - .space 512*8, 0 -l3_pgtable: - .space 512*8, 0 -L0mib_pgtable: - .space 512*8, 0 -L2mib_pgtable: - .space 512*8, 0 -L4mib_pgtable: - .space 512*8, 0 -L6mib_pgtable: - .space 512*8, 0 -L8mib_pgtable: - .space 512*8, 0 -L10mib_pgtable: - .space 512*8, 0 -L12mib_pgtable: - .space 512*8, 0 -L14mib_pgtable: - .space 512*8, 0 -L16mib_pgtable: - .space 512*8, 0 -L18mib_pgtable: - .space 512*8, 0 diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 775cd609..f71e63ca 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -3,13 +3,13 @@ mod console; pub use self::console::Console; pub mod drivers; pub mod entry; +mod page_tables; pub mod paging; use core::arch::asm; use core::ptr; -use aarch64_cpu::asm::barrier::{self, NSH, SY, dmb, dsb, isb}; -use aarch64_cpu::registers::{ReadWriteable, SCTLR_EL1, TTBR0_EL1, TTBR1_EL1, Writeable}; +use aarch64_cpu::asm::barrier::{NSH, SY, dmb, dsb, isb}; use align_address::Align; use fdt::Fdt; use goblin::elf::header::header64::{EI_DATA, ELFDATA2LSB, ELFMAG, Header, SELFMAG}; @@ -22,15 +22,6 @@ use crate::BootInfoExt; use crate::arch::paging::*; use crate::os::CONSOLE; -unsafe extern "C" { - static mut l0_pgtable: u64; - static mut l1_pgtable: u64; - static mut l2_pgtable: u64; - static mut l2k_pgtable: u64; - static mut l3_pgtable: u64; - static mut L0mib_pgtable: u64; -} - /// start address of the RAM at Qemu's virt emulation const RAM_START: u64 = 0x40000000; /// Default stack size of the kernel @@ -40,13 +31,6 @@ const KERNEL_STACK_SIZE: usize = 32_768; /// see const DEVICE_TREE: u64 = RAM_START; -#[allow(dead_code)] -const PT_DEVICE: u64 = 0x707; -const PT_PT: u64 = 0x713; -const PT_MEM: u64 = 0x713; -const PT_MEM_CD: u64 = 0x70F; -const PT_SELF: u64 = 1 << 55; - pub unsafe fn get_memory(_memory_size: u64) -> u64 { let loader_end = crate::os::executable_end().as_ptr(); (loader_end.expose_provenance() as u64).align_up(LargePageSize::SIZE as u64) @@ -102,6 +86,7 @@ pub fn find_kernel() -> &'static [u8] { } } +#[allow(static_mut_refs)] // FIXME: disallow pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { let LoadedKernel { load_info, @@ -118,62 +103,15 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { let uart_address: u32 = CONSOLE.lock().get().get_stdout(); info!("Detect UART at {uart_address:#x}"); - let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l0_pgtable), 512) }; - for i in pgt_slice.iter_mut() { - *i = 0; - } - pgt_slice[0] = ptr::addr_of_mut!(l1_pgtable).expose_provenance() as u64 + PT_PT; - pgt_slice[511] = ptr::addr_of_mut!(l0_pgtable).expose_provenance() as u64 + PT_PT + PT_SELF; - - let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l1_pgtable), 512) }; - for i in pgt_slice.iter_mut() { - *i = 0; - } - pgt_slice[0] = ptr::addr_of_mut!(l2_pgtable).expose_provenance() as u64 + PT_PT; - pgt_slice[1] = ptr::addr_of_mut!(l2k_pgtable).expose_provenance() as u64 + PT_PT; - - let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l2_pgtable), 512) }; - for i in pgt_slice.iter_mut() { - *i = 0; - } - pgt_slice[0] = ptr::addr_of_mut!(l3_pgtable).expose_provenance() as u64 + PT_PT; - - let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l3_pgtable), 512) }; - for i in pgt_slice.iter_mut() { - *i = 0; - } - pgt_slice[1] = uart_address as u64 + PT_MEM_CD; - - // map kernel to __executable_start and stack below the kernel - let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l2k_pgtable), 512) }; - for i in pgt_slice.iter_mut() { - *i = 0; - } - for (i, pgt_slice) in pgt_slice.iter_mut().enumerate().take(10) { - *pgt_slice = ptr::addr_of_mut!(L0mib_pgtable).expose_provenance() as u64 - + (i * BasePageSize::SIZE) as u64 - + PT_PT; - } - - let pgt_slice = - unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(L0mib_pgtable), 10 * 512) }; - for (i, entry) in pgt_slice.iter_mut().enumerate() { - *entry = RAM_START + (i * BasePageSize::SIZE) as u64 + PT_MEM; + unsafe { + page_tables::init(uart_address); } CONSOLE.lock().get().set_stdout(0x1000); - // Load TTBRx - TTBR1_EL1.set(0); - TTBR0_EL1.set(&raw mut l0_pgtable as u64); - barrier::dsb(barrier::SY); - barrier::isb(barrier::SY); - - // Enable paging - SCTLR_EL1.modify(SCTLR_EL1::M::Enable); - barrier::isb(barrier::SY); - - info!("Successfully set up paging."); + unsafe { + page_tables::enable(); + } let fdt = unsafe { Fdt::from_ptr(ptr::with_exposed_provenance(DEVICE_TREE as usize)) diff --git a/src/arch/aarch64/page_tables.rs b/src/arch/aarch64/page_tables.rs new file mode 100644 index 00000000..e18ee115 --- /dev/null +++ b/src/arch/aarch64/page_tables.rs @@ -0,0 +1,149 @@ +use core::ptr; + +use aarch64_cpu::asm::barrier::{SY, dsb, isb}; +use aarch64_cpu::registers::{ReadWriteable, SCTLR_EL1, TTBR0_EL1, TTBR1_EL1, Writeable}; +use log::info; + +use super::RAM_START; +use super::paging::{BasePageSize, PageSize}; + +static mut LEVEL_0_TABLE: PageTable = { + let mut table = [ptr::null_mut(); _]; + + table[0] = (&raw mut LEVEL_1_TABLE) + .wrapping_byte_add(descr::NORMAL) + .cast(); + table[511] = (&raw mut LEVEL_0_TABLE) + .wrapping_byte_add(descr::NORMAL) + .wrapping_byte_add(descr::SELF) + .cast(); + + PageTable(table) +}; + +static mut LEVEL_1_TABLE: PageTable = { + let mut table = [ptr::null_mut(); _]; + + table[0] = (&raw mut LEVEL_2_TABLE_SERIAL) + .wrapping_byte_add(descr::NORMAL) + .cast(); + table[1] = (&raw mut LEVEL_2_TABLE_RAM) + .wrapping_byte_add(descr::NORMAL) + .cast(); + + PageTable(table) +}; + +static mut LEVEL_2_TABLE_SERIAL: PageTable = { + let mut table = [ptr::null_mut(); _]; + + table[0] = (&raw mut LEVEL_3_TABLE_SERIAL) + .wrapping_byte_add(descr::NORMAL) + .cast(); + + PageTable(table) +}; + +static mut LEVEL_2_TABLE_RAM: PageTable = { + let mut table = [ptr::null_mut(); _]; + + let mut entry_i = 0; + while entry_i < 10usize { + let entry = &mut table[entry_i]; + + let level_3_table = unsafe { &raw mut LEVEL_3_TABLES_RAM[entry_i] }; + *entry = level_3_table.wrapping_byte_add(descr::NORMAL).cast(); + + entry_i += 1; + } + + PageTable(table) +}; + +static mut LEVEL_3_TABLE_SERIAL: PageTable = PageTable([ptr::null_mut(); _]); + +static mut LEVEL_3_TABLES_RAM: [PageTable; 10] = { + let mut tables = [PageTable([ptr::null_mut(); _]); _]; + + let mut table_i = 0; + while table_i < tables.len() { + let table = &mut tables[table_i].0; + + let mut entry_i = 0; + while entry_i < table.len() { + let entry = &mut table[entry_i]; + + let addr = (table_i * 512 + entry_i) * BasePageSize::SIZE; + *entry = ptr::with_exposed_provenance_mut::<()>(RAM_START as usize) + .wrapping_byte_add(addr) + .wrapping_byte_add(descr::NORMAL); + + entry_i += 1; + } + + table_i += 1; + } + + tables +}; + +pub unsafe fn init(uart_address: u32) { + unsafe { + LEVEL_3_TABLE_SERIAL.0[1] = ptr::with_exposed_provenance_mut::<()>(uart_address as usize) + .wrapping_byte_add(descr::NON_CACHEABLE); + } +} + +pub unsafe fn enable() { + // Set Translation Table Base Registers (TTBR) + TTBR1_EL1.set(0); + TTBR0_EL1.set((&raw mut LEVEL_0_TABLE).expose_provenance() as u64); + dsb(SY); + isb(SY); + + // Set MMU enable in System Control Register (SCTLR) + SCTLR_EL1.modify(SCTLR_EL1::M::Enable); + isb(SY); + + info!("Successfully set up paging."); +} + +#[derive(Clone, Copy, Debug)] +#[repr(C, align(0x1000))] +struct PageTable([*mut (); 512]); + +/// Descriptor values +/// +/// For reference, see . +mod descr { + pub const NORMAL: usize = AF | SH_INNER | attr_indx(4) | TABLE | VALID; + pub const NON_CACHEABLE: usize = AF | SH_INNER | attr_indx(3) | TABLE | VALID; + + /// Valid descriptor + const VALID: usize = 1; + + /// Table descriptor + const TABLE: usize = 1 << 1; + + /// Attribute index + /// + /// Selects the corresponding `MAIR` memory region attributes. + const fn attr_indx(indx: u8) -> usize { + assert!(indx < 1 << 5); + (indx as usize) << 2 + } + + /// Shareability + /// + /// Inner Shareable + const SH_INNER: usize = 1 << 8 | 1 << 9; + + /// Access flag + const AF: usize = 1 << 10; + + /// A software-defined marker for marking a self-referential entry. + /// + /// This can be used for recursive page tables by the kernel, but is currently not needed. + // FIXME: remove once the kernel set's up it's own page tables. + pub const SELF: usize = 1 << 55; +} diff --git a/src/arch/riscv64/start.rs b/src/arch/riscv64/start.rs index 2abed533..98584fce 100644 --- a/src/arch/riscv64/start.rs +++ b/src/arch/riscv64/start.rs @@ -21,8 +21,7 @@ pub fn get_fdt() -> Fdt<'static> { } pub fn get_stack_ptr() -> *mut u8 { - // SAFETY: We only create a pointer here - let stack_top = ptr::addr_of_mut!(STACK); + let stack_top = &raw mut STACK; // SAFETY: Pointing directly past the object is allowed let stack_bottom = unsafe { stack_top.add(1) }; stack_bottom.cast::()