diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index 858f281..6028f03 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -24,9 +24,12 @@ extern "C" { } static PAGING_ACTIVE: AtomicBool = AtomicBool::new(false); +static CURRENT_PML4: Mutex> = Mutex::new(None); static HEAP_PHYS_START: Once = Once::new(); static PHYSICAL_FRAMES: Mutex>> = Mutex::new(None); static HEAP_PHYS_MAPPING: Mutex> = Mutex::new(Vec::new()); +pub const KERNEL_MAPPINGS_START: u64 = 0xfffffffd00000000; +pub const KERNEL_MAPPINGS_END: u64 = 0xfffffffe00000000; fn _get_free_frame() -> u64 { let frames_vec = PHYSICAL_FRAMES.lock(); @@ -41,7 +44,7 @@ fn virt_to_phys(virt: u64) -> u64 { if !PAGING_ACTIVE.load(Ordering::Relaxed) { return virt - KERNEL_HEAP_START + HEAP_PHYS_START.get().unwrap(); } - assert!(virt >= KERNEL_VIRT_START); + assert!(virt >= KERNEL_HEAP_START); assert!(virt < KERNEL_HEAP_START + KERNEL_HEAP_INITIAL_SIZE as u64); let heap_map = HEAP_PHYS_MAPPING.lock(); return heap_map[(virt as usize - KERNEL_HEAP_START as usize) / 0x1000] + virt % 0x1000; @@ -61,7 +64,7 @@ fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable { } return table.entries_virt[i].as_mut().unwrap(); } -fn _get_page(pml4: &PageTable, virt: u64) -> Option<&PageEntry> { +fn get_page(pml4: &PageTable, virt: u64) -> Option<&PageEntry> { let virt_page = virt as usize / 0x1000; let table_i = virt_page % 512; let directory_i = virt_page / 512 % 512; @@ -82,10 +85,28 @@ fn _get_page(pml4: &PageTable, virt: u64) -> Option<&PageEntry> { } None } -fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec: bool) { - if virt < 0x1000 { - panic!("First page shouldn't be mapped"); +pub fn find_free_virt_range(mut start: u64, end: u64, size: u64) -> u64 { + assert_eq!(start % 0x1000, 0); + assert_eq!(end % 0x1000, 0); + assert_eq!(size % 0x1000, 0); + let mut current_pml4 = CURRENT_PML4.lock(); + while start < end - size { + let mut free = true; + for i in 0..size { + if get_page(current_pml4.as_mut().unwrap(), start + i).is_some() { + free = false; + start += (i + 1) * 0x1000; + break; + } + } + if free { + return start; + } } + panic!("No free range found"); +} +fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec: bool) { + assert!(virt >= 0x1000, "First page shouldn't be mapped"); { let mut frames_vec = PHYSICAL_FRAMES.lock(); frames_vec.as_mut().unwrap().set(phys as usize / 0x1000, true); @@ -104,6 +125,15 @@ fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec table.entries_phys[table_i].set_execute_disable(!exec as u64); table.entries_phys[table_i].set_present(1); } +pub unsafe fn map_range(virt_start: u64, phys_start: u64, size: u64, user: bool, write: bool, exec: bool) { + assert_eq!(virt_start % 0x1000, 0); + assert_eq!(phys_start % 0x1000, 0); + assert_eq!(size % 0x1000, 0); + let mut current_pml4 = CURRENT_PML4.lock(); + for i in 0..size / 0x1000 { + map(current_pml4.as_mut().unwrap(), virt_start + i * 0x1000, phys_start + i * 0x1000, user, write, exec); + } +} pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64, heap_start: u64) { HEAP_PHYS_START.call_once(|| heap_start); let mut memory_size = 0; @@ -173,5 +203,7 @@ pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64, heap_start: u unsafe { load_cr3(virt_to_phys(pml4 as *const PageTable as u64)); } + let mut current_pml4 = CURRENT_PML4.lock(); + *current_pml4 = Some(pml4); PAGING_ACTIVE.store(true, Ordering::Relaxed); } diff --git a/kernel/src/sys/acpica_osl.rs b/kernel/src/sys/acpica_osl.rs index 2d032c8..4c995db 100644 --- a/kernel/src/sys/acpica_osl.rs +++ b/kernel/src/sys/acpica_osl.rs @@ -1,6 +1,7 @@ use core::{alloc::Layout, ffi::c_void, ptr::null_mut}; use crate::{ + cpu::paging::{find_free_virt_range, map_range, KERNEL_MAPPINGS_END, KERNEL_MAPPINGS_START}, misc::wrapped_alloc::{wrapped_alloc, wrapped_dealloc}, RSDP_ADDRESS, }; @@ -67,8 +68,16 @@ extern "C" fn AcpiOsInstallInterruptHandler() { panic!("Unimplemented"); } #[no_mangle] -extern "C" fn AcpiOsMapMemory() { - panic!("Unimplemented"); +extern "C" fn AcpiOsMapMemory(phys: ACPI_PHYSICAL_ADDRESS, mut size: ACPI_SIZE) -> *mut c_void { + let phys_offset = phys % 0x1000; + let phys_end = (phys + size + 0xfff) / 0x1000 * 0x1000; + let phys_start = phys - phys_offset; + size = phys_end - phys_start; + let virt_start = find_free_virt_range(KERNEL_MAPPINGS_START, KERNEL_MAPPINGS_END, size); + unsafe { + map_range(virt_start, phys_start, size, false, true, false); + } + (virt_start + phys_offset) as *mut c_void } #[no_mangle] extern "C" fn AcpiOsPhysicalTableOverride() { diff --git a/loader/src/elf.rs b/loader/src/elf.rs index 5c4e9ee..704c915 100644 --- a/loader/src/elf.rs +++ b/loader/src/elf.rs @@ -16,12 +16,8 @@ pub fn load_kernel(kernel: &[u8], system_table: &SystemTable) -> (u64, u64 if i.p_type != PT_LOAD { continue; } - if i.p_vaddr < KERNEL_VIRT_START { - panic!("Invalid kernel segments") - } - if i.p_vaddr % 0x1000 != 0 { - panic!("Invalid alignment"); - } + assert!(i.p_vaddr >= KERNEL_VIRT_START, "Invalid kernel segments"); + assert_eq!(i.p_vaddr % 0x1000, 0, "Invalid alignment"); let end_addr = i.p_vaddr - KERNEL_VIRT_START + i.p_memsz; if end_addr > kernel_size { kernel_size = end_addr; diff --git a/loader/src/main.rs b/loader/src/main.rs index 1f61011..b1c3209 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -51,9 +51,7 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { break; } } - if rsdp == 0 { - panic!("RSDP not found"); - } + assert_ne!(rsdp, 0, "RSDP not found"); let memory_map; unsafe { memory_map = system_table.exit_boot_services(MemoryType::LOADER_DATA).1;