Implement AcpiOsMapMemory

This commit is contained in:
Mathieu Strypsteen 2024-07-09 13:21:43 +02:00
parent feb4675f41
commit 8a495aa115
4 changed files with 51 additions and 16 deletions

View file

@ -24,9 +24,12 @@ extern "C" {
}
static PAGING_ACTIVE: AtomicBool = AtomicBool::new(false);
static CURRENT_PML4: Mutex<Option<&mut PageTable>> = Mutex::new(None);
static HEAP_PHYS_START: Once<u64> = Once::new();
static PHYSICAL_FRAMES: Mutex<Option<BitVec<u64>>> = Mutex::new(None);
static HEAP_PHYS_MAPPING: Mutex<Vec<u64>> = 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);
}

View file

@ -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() {

View file

@ -16,12 +16,8 @@ pub fn load_kernel(kernel: &[u8], system_table: &SystemTable<Boot>) -> (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;

View file

@ -51,9 +51,7 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> 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;