feat: acpi, apic, apic timer
This commit is contained in:
+154
-48
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user