diff --git a/src/boot/mod.rs b/src/boot/mod.rs index d8ec989..3b2bf39 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,12 +1,13 @@ use alloc::sync::Arc; use core::marker::PhantomData; -use acpi::{AcpiHandler, PhysicalMapping}; -use crate::{debug, KernelArgs}; +use core::ptr::NonNull; +use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; +use crate::{debug, KernelArgs, println}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; -use x86_64::structures::paging::{FrameAllocator, OffsetPageTable}; -use crate::memory::BootInfoFrameAllocator; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Translate}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER}; pub struct KernelInfo { kernel_start: u64, @@ -16,6 +17,48 @@ pub struct KernelInfo { boot_info: BootInformation, } +#[derive(Clone)] +struct Handler; +impl AcpiHandler for Handler { + unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { + // todo! check if size is too big + debug!("read_phys_memory32: addr {:x} not mapped", physical_address); + // map the page + let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); + debug!("allocated frame: {:?}", frame); + let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; + let page = x86_64::structures::paging::Page::containing_address(initaladdr); + debug!("mapped page: {:?}", page); + let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; + debug!("map_to_result: {:?}", map_to_result); + if map_to_result.is_err() { + panic!("Failed to map page"); + } + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + if let Some(addr) = addr { + // physical start, virtual start, region length, mapped length, Self + PhysicalMapping::new( + physical_address, + NonNull::new_unchecked(addr.as_u64() as *mut T), + size, size, + Self) + } else { + panic!("Failed to map page"); + } + } + + fn unmap_physical_region(region: &PhysicalMapping) { + // get page + let page = x86_64::structures::paging::Page::containing_address(region.start_address()); + // unmap page + let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) }; + // it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail + if res.is_err() { + println!("[WARN] failed to unmap page"); + } + } +} + impl KernelInfo { pub fn init_from_kernel_args(args: KernelArgs) -> Self { #[cfg(feature = "f_multiboot2")] @@ -56,64 +99,29 @@ impl KernelInfo { self.safe_mem_start } - pub fn acpi_get_ioapic_addr(&self, mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator) -> u64 { + pub fn acpi_get_ioapic_addr(&self) -> u32 { #[cfg(feature = "f_multiboot2")] { let acpi_tag = self.boot_info.rsdp_v1_tag().expect("no acpi tag"); let rsdp = acpi_tag; let rsdp = unsafe { &*rsdp }; let rsdt = rsdp.rsdt_address(); - #[derive(Clone)] - struct Handler<'a> { - mem_mapper: Arc<&'a mut OffsetPageTable<'a>>, - frame_allocator: Arc<&'a mut BootInfoFrameAllocator>, + let rsdt = unsafe { + acpi::AcpiTables::from_rsdt( + AcpiHandler, 0, + rsdt) + .expect("failed to get acpi tables") + }; + let platform_info = rsdt.platform_info().expect("failed to get platform info"); + let interrupt_model = platform_info.interrupt_model; + if let InterruptModel::Apic(apic) = interrupt_model { + let ioapics = apic.io_apics; + let ioapic = ioapics.first().expect("no ioapics"); + let ioapic_addr = ioapic.address; + ioapic_addr + } else { + panic!("no ioapic"); } - impl<'a> AcpiHandler for Handler<'a> { - unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { - let frame_allocator = self.frame_allocator.clone(); - debug!("read_phys_memory32: addr {:x} not mapped", physical_address); - // map the page - let frame = frame_allocator.allocate_frame().unwrap(); - debug!("allocated frame: {:?}", frame); - let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; - let page = x86_64::structures::paging::Page::containing_address(initaladdr); - debug!("mapped page: {:?}", page); - let map_to_result = unsafe { mem_mapper.map_to(page, frame, flags, frame_allocator) }; - debug!("map_to_result: {:?}", map_to_result); - if map_to_result.is_err() { - panic!("Failed to map page"); - } - let addr = unsafe { mem_mapper.translate_addr(initaladdr) }; - if let Some(addr) = addr { - let addr = addr.as_u64() as *const u32; - unsafe { *addr } - } else { - panic!("Failed to map page"); - } - } - - fn unmap_physical_region(region: &PhysicalMapping) { - todo!() - } - } - let rsdt = acpi::AcpiTables::from_rsdt(rsdt).expect("failed to get acpi tables"); - let mut ioapic_addr = 0; - for entry in rsdt.entries() { - let entry = unsafe { &*entry }; - if entry.signature() == *b"APIC" { - let apic = entry.as_apic(); - let apic = unsafe { &*apic }; - for entry in apic.entries() { - let entry = unsafe { &*entry }; - if entry.signature() == *b"IOAP" { - let ioapic = entry.as_ioapic(); - let ioapic = unsafe { &*ioapic }; - ioapic_addr = ioapic.address(); - } - } - } - } - ioapic_addr } } } \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index d6eb27a..5ae297c 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -56,12 +56,12 @@ pub fn enable_apic() { write_phys_memory32(sivr_addr, sivr | (1 << 8)); } -pub fn apic_read_io(ioapicaddr: usize, reg: u32) -> u32 { +pub fn apic_read_io(ioapicaddr: u32, reg: u32) -> u32 { write_phys_memory32(ioapicaddr as u32, reg); read_phys_memory32(ioapicaddr as u32 + 0x10) } -pub fn apic_write_io(ioapicaddr: usize, reg: u32, val: u32) { +pub fn apic_write_io(ioapicaddr: u32, reg: u32, val: u32) { write_phys_memory32(ioapicaddr as u32, reg); write_phys_memory32(ioapicaddr as u32 + 0x10, val); } @@ -83,7 +83,7 @@ pub fn disable_pic() { command(0xa1, 0xff); } -pub fn ioapic_set_irq(ioapicaddr: usize, irq: u8, apic_id: u64, vector:u8) { +pub fn ioapic_set_irq(ioapicaddr: u32, irq: u8, apic_id: u64, vector:u8) { let lo_index: u32 = (0x10 + irq*2 ) as u32; let hi_index: u32 = (0x10 + irq*2 + 1) as u32; @@ -136,7 +136,7 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { } // todo! we should abstract this away -pub fn setup_apic_interrupts(ioapicaddr: usize) { +pub fn setup_apic_interrupts(ioapicaddr: u32) { // set keyboard irq to interrupt 40 ioapic_set_irq(ioapicaddr, 1, 0, 40); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 52c66c6..b87a25d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -208,7 +208,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - unsafe { internals::cpu::setup_apic_interrupts() }; + unsafe { internals::cpu::setup_apic_interrupts(kern_info.lock().acpi_get_ioapic_addr()) }; println!("[OK]"); // enable interrupts x86_64::instructions::interrupts::enable();