Paging works, can now run main from virtual(ish) memory

This commit is contained in:
ivajon
2026-05-11 18:47:11 +02:00
parent 4c2a5b1068
commit d0a95dfd9c
3 changed files with 75 additions and 64 deletions

View File

@@ -11,7 +11,7 @@ use kernel::{
},
print,
};
use x86_drivers::gdt::{DPL, GdtEntry, GdtPointer, GdtSelector};
use x86_drivers::{gdt::{DPL, GdtEntry, GdtPointer, GdtSelector}, paging::PageMapLevel4};
pub use x86_drivers::prelude::*;
#[unsafe(no_mangle)]
@@ -123,11 +123,39 @@ extern "efiapi" fn efi_main(handle: Handle, table: *mut EfiSystemTable) -> UefiS
let res = alloc.request_pages(&RegionRequest::new(2));
print!("Region request returned ({res:?})\r\n");
let sp = reserve_kernel_pages(image_info.0, image_info.1, 4096, &mut alloc);
let (sp, plm4) = reserve_kernel_pages(image_info.0, image_info.1, 4096, &mut alloc).unwrap();
print!("Potential new stack pointer: {sp:?}\r\n");
let new_stack_pointer = unsafe { sp.cast::<u8>().add(4096) };
unsafe { specify_kernel(sp, plm4) };
}
#[allow(clippy::empty_loop)]
loop {}
unsafe fn specify_kernel(sp: *const u8, plm4_phys: *const PageMapLevel4) -> ! {
unsafe {
core::arch::asm!(
"mov rsp, {sp}",
"mov rbp, {sp}",
"mov cr3, {plm4}",
"jmp {main}",
sp = in(reg) sp,
plm4 = in(reg) plm4_phys,
main = sym kernel_main,
options(nostack,preserves_flags,noreturn))
}
}
fn kernel_main() -> ! {
let sp:u32;
let bp:u32;
unsafe {
core::arch::asm!(
"mov {sp}, rsp",
"mov {bp}, rbp",
sp = out(reg) sp,
bp = out(reg) bp,
options(nostack,preserves_flags))
}
print!("Running from main!, with {sp:#X} {bp:#X} \r\n");
todo!();
}
static GDT_TABLE: [GdtEntry; 3] = [

View File

@@ -1,7 +1,4 @@
use core::{
char::MAX,
sync::atomic::{AtomicBool, AtomicU8},
};
use core::sync::atomic::AtomicU8;
use x86_drivers::paging::{
BanExecution, Cache, CacheWriteThrough, KernelMode, Page, PageAttributeTable, PageDirectory,
@@ -40,72 +37,58 @@ pub fn reserve_kernel_pages<const MAX_REGIONS: usize>(
app_size: u64,
stack_size: usize,
allocator: &mut RegionAllocator<MAX_REGIONS>,
) -> Result<*const super::Page, super::Error> {
) -> Result<(*const u8, *const PageMapLevel4), super::Error> {
// TODO: This is going to bite me, need to track the addresses in some in memory abstraction.
const M2_PAGE_SIZE: u64 = (2 * 1024 * 1024);
let page_ptr = (app_ptr as u64 % PAGE_SIZE as u64) as *const [u8; PAGE_SIZE];
let pages = app_size as usize / PAGE_SIZE;
for page in 0..pages {
unsafe {
KERNEL_PAGE_TABLE
.register(
page as usize,
Page::new(
page_ptr.add(page) as *const _,
x86_drivers::paging::Mutable::Yes,
// Think this is a good idea, we should keep memory in sync?
CacheWriteThrough::On,
// Generally we do not
Cache::On,
PageAttributeTable::On,
get_max_addr().into(),
BanExecution::No,
),
)
.unwrap();
}
let page_ptr =
(app_ptr as u64 & (!(M2_PAGE_SIZE - 1))) as *const [u8; { M2_PAGE_SIZE as usize }];
let page_2m_idx = (page_ptr as u64 / M2_PAGE_SIZE);
let app_pages = (app_size / M2_PAGE_SIZE) + 1;
unsafe {
KERNEL_PHYSMAP_PAGE_DIRECTORY
.register_page(
page_2m_idx as usize,
Page::new(
page_ptr as *const _,
x86_drivers::paging::Mutable::Yes,
// Think this is a good idea, we should keep memory in sync?
CacheWriteThrough::Off,
// Generally we do not
Cache::On,
PageAttributeTable::Off,
get_max_addr().into(),
BanExecution::No,
),
)
.unwrap();
}
let stack_pages = stack_size / PAGE_SIZE;
// TODO: Make some better upper bound here :(
let result = allocator.request_pages(&super::RegionRequest::new_with_address_filter(
stack_pages,
unsafe { page_ptr.add(pages) as u64 },
unsafe { page_ptr.add(app_pages as usize + 1) as u64 },
u64::MAX / 2,
))?;
for page in 0..stack_pages {
let offset_in_table = pages + page;
print!("IDX {offset_in_table}");
unsafe {
KERNEL_PAGE_TABLE
.register(
offset_in_table,
Page::new(
result.start.add(page) as *const _,
x86_drivers::paging::Mutable::Yes,
// Not sure if we should have write through on here? a bunch of invalidation
CacheWriteThrough::On,
Cache::On,
PageAttributeTable::On,
get_max_addr().into(),
BanExecution::Yes,
),
)
.unwrap();
}
}
let page_2m_idx = (result.start as u64 / M2_PAGE_SIZE);
unsafe {
KERNEL_PHYSMAP_PAGE_DIRECTORY
.register_nested(
0,
PdEntry::new(
core::ptr::addr_of!(KERNEL_PAGE_TABLE).cast(),
.register_page(
page_2m_idx as usize,
Page::new(
result.start as *const _,
x86_drivers::paging::Mutable::Yes,
// Not sure if we should have write through on here? a bunch of invalidation
CacheWriteThrough::Off,
Cache::On,
PageAttributeTable::Off,
get_max_addr().into(),
BanExecution::Yes,
),
)
.unwrap();
@@ -116,7 +99,7 @@ pub fn reserve_kernel_pages<const MAX_REGIONS: usize>(
.register_nested(
0,
PdptEntry::new(
core::ptr::addr_of!(KERNEL_PAGE_TABLE).cast(),
core::ptr::addr_of!(KERNEL_PHYSMAP_PAGE_DIRECTORY),
CacheWriteThrough::Off,
Cache::On,
get_max_addr().into(),
@@ -127,9 +110,9 @@ pub fn reserve_kernel_pages<const MAX_REGIONS: usize>(
unsafe {
PML4.register(
511,
Pml4Entry::<KernelMode>::new(
core::ptr::addr_of!(KERNEL_PAGE_TABLE).cast(),
0,
Pml4Entry::new(
core::ptr::addr_of!(KERNEL_PHYSMAP_PDPT),
CacheWriteThrough::Off,
Cache::On,
get_max_addr().into(),
@@ -137,5 +120,5 @@ pub fn reserve_kernel_pages<const MAX_REGIONS: usize>(
)
.unwrap();
}
Ok(result.start)
unsafe { Ok((result.start.cast(), core::ptr::addr_of!(PML4))) }
}

View File

@@ -320,8 +320,8 @@ impl PageMapLevel4 {
return Err(RegisterError::IndexOutOfBounds);
};
match (M::MODE, offset) {
(UserOrSupervisor::Supervisor, 256..) => (),
(UserOrSupervisor::User, ..256) => (),
(UserOrSupervisor::User, 256..) => (),
(UserOrSupervisor::Supervisor, ..256) => (),
_ => return Err(RegisterError::InvalidIndexForPrivilegeLevel),
}
*val = page.0;