diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 3b2bf39..d8ec989 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,13 +1,12 @@ use alloc::sync::Arc; use core::marker::PhantomData; -use core::ptr::NonNull; -use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; -use crate::{debug, KernelArgs, println}; +use acpi::{AcpiHandler, PhysicalMapping}; +use crate::{debug, KernelArgs}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Translate}; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER}; +use x86_64::structures::paging::{FrameAllocator, OffsetPageTable}; +use crate::memory::BootInfoFrameAllocator; pub struct KernelInfo { kernel_start: u64, @@ -17,48 +16,6 @@ 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")] @@ -99,29 +56,64 @@ impl KernelInfo { self.safe_mem_start } - pub fn acpi_get_ioapic_addr(&self) -> u32 { + pub fn acpi_get_ioapic_addr(&self, mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator) -> u64 { #[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(); - 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"); + #[derive(Clone)] + struct Handler<'a> { + mem_mapper: Arc<&'a mut OffsetPageTable<'a>>, + frame_allocator: Arc<&'a mut BootInfoFrameAllocator>, } + 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 5ae297c..8fdd444 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -47,23 +47,23 @@ pub fn get_apic_base() -> usize { ((edx as usize) << 32) | (eax as usize) } -pub fn enable_apic() { +pub fn enable_apic(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator) { // PIC should be disabled by now // now enable local apic // 1. set bit 8 of spurious interrupt vector register let sivr_addr = 0xfee000f0; - let sivr = read_phys_memory32(sivr_addr); - write_phys_memory32(sivr_addr, sivr | (1 << 8)); + let sivr = read_phys_memory32(mem_mapper, frame_alloc, sivr_addr); + write_phys_memory32(mem_mapper, frame_alloc, sivr_addr, sivr | (1 << 8)); } -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_read_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32) -> u32 { + write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg); + read_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32 + 0x10) } -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); +pub fn apic_write_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32, val: u32) { + write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg); + write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32 + 0x10, val); } pub fn disable_pic() { @@ -83,17 +83,17 @@ pub fn disable_pic() { command(0xa1, 0xff); } -pub fn ioapic_set_irq(ioapicaddr: u32, irq: u8, apic_id: u64, vector:u8) { +pub fn ioapic_set_irq(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, 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; - let mut high = apic_read_io(ioapicaddr, hi_index); + let mut high = apic_read_io(mem_mapper, frame_alloc, ioapicaddr, hi_index); // set apic id high &= !(0xff000000); high |= (apic_id as u32) << 24; - apic_write_io(ioapicaddr, hi_index, high); + apic_write_io(mem_mapper, frame_alloc, ioapicaddr, hi_index, high); - let mut low = apic_read_io( ioapicaddr, lo_index); + let mut low = apic_read_io(mem_mapper, frame_alloc, ioapicaddr, lo_index); // unmask low &= !(1 << 16); @@ -105,7 +105,7 @@ pub fn ioapic_set_irq(ioapicaddr: u32, irq: u8, apic_id: u64, vector:u8) { low &= !(0xff); low |= vector as u32; - apic_write_io(ioapicaddr, lo_index, low); + apic_write_io(mem_mapper, frame_alloc, ioapicaddr, lo_index, low); } pub fn apic_eoi() { @@ -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: u32) { +pub fn setup_apic_interrupts(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize) { // set keyboard irq to interrupt 40 - ioapic_set_irq(ioapicaddr, 1, 0, 40); + ioapic_set_irq(mem_mapper, frame_alloc, ioapicaddr, 1, 0, 40); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b87a25d..35409fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ use x86_64::registers::segmentation::{CS, Segment, SS}; use x86_64::structures::paging::Translate; use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; use crate::serial::terminal::ST; mod font; @@ -166,15 +165,17 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args)); // memory stuff + let mut mapper = None; + let mut frame_allocator = None; { print!("initialising mapper..."); - MEM_MAPPER.lock().replace(unsafe { memory::init(VirtAddr::new(0)) }); + mapper = Some(unsafe { memory::init(VirtAddr::new(0)) }); println!("[OK]"); print!("initialising frame allocator..."); - FRAME_ALLOC.lock().replace(unsafe { memory::BootInfoFrameAllocator::init(kern_info) }); + frame_allocator = Some(unsafe { memory::BootInfoFrameAllocator::init(kern_info) }); println!("[OK]"); print!("initialising heap..."); - memory::allocator::init_heap(MEM_MAPPER.lock().as_mut().unwrap(), FRAME_ALLOC.lock().as_mut().unwrap()).expect("heap init failed"); + memory::allocator::init_heap(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()).expect("heap init failed"); println!("[OK]"); print!("testing heap..."); @@ -205,10 +206,10 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { unsafe { internals::cpu::disable_pic() }; println!("[OK]"); print!("initialising apic..."); - unsafe { internals::cpu::enable_apic() }; + unsafe { internals::cpu::enable_apic(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()) }; println!("[OK]"); print!("setting up apic interrupts..."); - unsafe { internals::cpu::setup_apic_interrupts(kern_info.lock().acpi_get_ioapic_addr()) }; + unsafe { internals::cpu::setup_apic_interrupts(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()) }; println!("[OK]"); // enable interrupts x86_64::instructions::interrupts::enable(); diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 1755dec..9b2a305 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -2,15 +2,9 @@ pub mod allocator; use alloc::boxed::Box; use alloc::sync::Arc; -use lazy_static::lazy_static; use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate}; use x86_64::{PhysAddr, VirtAddr}; -lazy_static!{ - pub static ref MEM_MAPPER: Mutex> = Mutex::new(None); - pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); -} - pub struct Locked { inner: spin::Mutex, } @@ -92,26 +86,26 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { } } -pub fn read_phys_memory32(addr: u32) -> u32 { +pub fn read_phys_memory32(mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator, addr: u32) -> u32 { let initaladdr = VirtAddr::new(addr as u64); - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + let addr = unsafe { mem_mapper.translate_addr(initaladdr) }; if let Some(addr) = addr { let addr = addr.as_u64() as *const u32; unsafe { *addr } } else { debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); // map the page - let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); + 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.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; + 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.lock().as_mut().unwrap().translate_addr(initaladdr) }; + let addr = unsafe { mem_mapper.translate_addr(initaladdr) }; if let Some(addr) = addr { let addr = addr.as_u64() as *const u32; unsafe { *addr } @@ -121,26 +115,26 @@ pub fn read_phys_memory32(addr: u32) -> u32 { } } -pub fn write_phys_memory32(addr: u32, value: u32) { +pub fn write_phys_memory32(mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator, addr: u32, value: u32) { let initaladdr = VirtAddr::new(addr as u64); - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + let addr = unsafe { mem_mapper.translate_addr(initaladdr) }; if let Some(addr) = addr { let addr = addr.as_u64() as *mut u32; unsafe { *addr = value }; } else { debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); // map the page - let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); + 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.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; + 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.lock().as_mut().unwrap().translate_addr(initaladdr) }; + let addr = unsafe { mem_mapper.translate_addr(initaladdr) }; if let Some(addr) = addr { let addr = addr.as_u64() as *mut u32; unsafe { *addr = value }; diff --git a/src/serial/mod.rs b/src/serial/mod.rs index ab39655..a2628a4 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -74,17 +74,6 @@ pub fn read(port: u16) -> u8 { data } -// dummy functions for non-x86 -#[cfg(not(any(target_arch="x86", target_arch="x86_64")))] -pub fn command(port: u16, data: u8) { - unimplemented!() -} - -#[cfg(not(any(target_arch="x86", target_arch="x86_64")))] -pub fn read(port: u16) -> u8 { - unimplemented!() -} - impl Port { fn is_transmit_empty(&self) -> bool { let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);