feat: acpi, apic, apic timer

This commit is contained in:
Zoe
2026-08-27 13:09:11 -05:00
parent afcef918a3
commit 7dcf244ee6
22 changed files with 2394 additions and 382 deletions
+154 -48
View File
@@ -7,12 +7,99 @@ mod arch;
mod boot;
mod debug;
mod memory;
mod platform;
use crate::{
debug::serial,
memory::{AddressSpace, PagePermissions, PhysicalAddr, VirtualAddr},
memory::{AddressSpace, MemoryRegionKind, VirtualAddr},
};
#[derive(Debug)]
enum KernelStackCreateError {
AddressOverflow,
OutOfFrames,
GuardPageMapped,
Map(memory::MapError),
}
struct KernelStack {
start: memory::VirtualAddr,
pages: usize,
}
const BOOTSTRAP_STACK_TOP: usize = 0xFFFF_FFFE_0000_0000;
const KERNEL_STACK_SIZE: usize = 64 * 1024;
const KERNEL_STACK_GUARD_SIZE: usize = memory::FRAME_SIZE;
const BOOTSTRAP_STACK_START: usize = BOOTSTRAP_STACK_TOP - KERNEL_STACK_SIZE;
const BOOTSTRAP_STACK_GUARD: usize = BOOTSTRAP_STACK_START - KERNEL_STACK_GUARD_SIZE;
impl KernelStack {
fn allocate(
address_space: &mut AddressSpace,
allocator: &mut memory::FrameAllocator,
) -> Result<Self, KernelStackCreateError> {
let kernel_stack_start = VirtualAddr::new(BOOTSTRAP_STACK_START);
let guard_page = VirtualAddr::new(BOOTSTRAP_STACK_GUARD);
if address_space.to_physical(guard_page).is_some() {
// guard page should be *unmapped* so we get a page fault if we try to access it
return Err(KernelStackCreateError::GuardPageMapped);
}
let mut i = 0;
// on error we will just leak the frames
// because like what are going to do if we recover them? Die happily without leaking frames? idgaf
while i < KERNEL_STACK_SIZE {
let frame = allocator
.alloc()
.ok_or(KernelStackCreateError::OutOfFrames)?;
address_space
.map(
frame.frame_address().start_address(),
VirtualAddr::new(
kernel_stack_start
.as_usize()
.checked_add(i)
.ok_or(KernelStackCreateError::AddressOverflow)?,
),
memory::PagePermissions::new(true, false, false),
allocator,
memory::CachePolicy::WriteBack,
)
.map_err(|err| KernelStackCreateError::Map(err))?;
i += memory::FRAME_SIZE;
}
debug_assert!(address_space.to_physical(guard_page).is_none());
Ok(Self {
start: kernel_stack_start,
pages: i / memory::FRAME_SIZE,
})
}
pub fn top(&self) -> Result<VirtualAddr, KernelStackCreateError> {
Ok(VirtualAddr::new(
self.start
.as_usize()
.checked_add(self.pages * memory::FRAME_SIZE)
.ok_or(KernelStackCreateError::AddressOverflow)?,
))
}
}
pub struct KernelHandoff {
allocator: memory::FrameAllocator,
address_space: AddressSpace,
direct_map: memory::DirectMap,
boot_info: boot::BootInfo,
handoff_frame: memory::OwnedFrame,
}
const _: () = assert!(core::mem::size_of::<KernelHandoff>() <= memory::FRAME_SIZE);
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
serial::init().unwrap();
@@ -25,7 +112,7 @@ pub extern "C" fn _start() -> ! {
.expect("failed to create frame allocator");
println!("Initializing page table...");
let mut page_table = AddressSpace::new_kernel(
let mut address_space = AddressSpace::new_kernel(
direct_map,
boot_info.memory_regions(),
&boot_info.kernel_layout,
@@ -34,65 +121,84 @@ pub extern "C" fn _start() -> ! {
)
.expect("failed to create page table");
println!("Activating page table...");
println!("Entering kernel main...");
// safety: trust me bro
unsafe { page_table.activate() };
let bootstrap_stack = KernelStack::allocate(&mut address_space, &mut allocator)
.expect("failed to allocate bootstrap stack");
println!("Allocating a frame...");
let handoff_frame = allocator
.alloc()
.expect("failed to allocate frame for kernel handoff");
let handoff_addr = address_space
.to_virtual(handoff_frame.frame_address().start_address())
.expect("failed to map kernel handoff");
let frame = allocator.alloc().unwrap();
let bootstrap_stack_top = bootstrap_stack.top().unwrap();
let handoff = KernelHandoff {
allocator,
address_space,
direct_map,
boot_info,
handoff_frame,
};
let direct_mapped = direct_map.translate(frame.start_address()).unwrap();
let translated = page_table.translate(direct_mapped).unwrap();
println!("{:?}", translated);
let new_virtual = VirtualAddr::new(0x8000_0000);
assert!(page_table.translate(new_virtual).is_none());
page_table
.map(
frame.start_address(),
new_virtual,
PagePermissions {
writable: true,
executable: false,
user_accessible: true,
},
&mut allocator,
)
.unwrap();
assert_eq!(
page_table.translate(new_virtual),
Some(frame.start_address())
);
assert_eq!(
page_table.translate(VirtualAddr::new(new_virtual.as_usize() + 123)),
Some(PhysicalAddr::new(frame.start_address().as_usize() + 123))
);
// write to the page and read it back via HHDM
unsafe {
core::ptr::write_bytes(new_virtual.as_mut_ptr::<u8>(), 0xFF, 0x1000);
handoff_addr.as_mut_ptr::<KernelHandoff>().write(handoff);
(*handoff_addr.as_mut_ptr::<KernelHandoff>())
.address_space
.activate();
arch::enter_kernel(
bootstrap_stack_top,
handoff_addr.as_mut_ptr::<KernelHandoff>(),
);
}
}
pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
let (mut allocator, mut address_space, direct_map, boot_info, handoff_frame) = unsafe {
let handoff = handoff.read();
(
handoff.allocator,
handoff.address_space,
handoff.direct_map,
handoff.boot_info,
handoff.handoff_frame,
)
};
unsafe {
allocator.dealloc(handoff_frame);
}
let slice = unsafe { core::slice::from_raw_parts(direct_mapped.as_ptr::<u8>(), 0x1000) };
allocator.reclaim_regions(
boot_info.memory_regions(),
MemoryRegionKind::BootloaderReclaimable,
);
assert!(slice.iter().all(|&byte| byte == 0xFF));
println!(
"Initializing local ACPI... {:#X}",
boot_info.rsdp.as_usize()
);
println!("{:#X}", slice[0]);
let acpi = platform::acpi::init(&boot_info, direct_map).expect("failed to initialize ACPI");
let unmapped_frame = unsafe { page_table.unmap(new_virtual, &mut allocator) }.unwrap();
let madt = acpi
.madt()
.expect("failed to parse ACPI")
.expect("MADT not found");
assert_eq!(unmapped_frame, frame);
let interrupt_controller =
arch::init_interrupt_controller(&madt, &mut allocator, &mut address_space)
.expect("failed to initialize interrupt controller");
unsafe { allocator.dealloc(unmapped_frame) };
println!("interrupt controller: {:?}", interrupt_controller);
assert!(page_table.translate(new_virtual).is_none());
println!("delaying 5 seconds...");
interrupt_controller
.delay(core::time::Duration::from_secs(5))
.unwrap();
println!("done!");
hcf();
}