diff --git a/kernel/src/arch/x86_64/cpu/apic.rs b/kernel/src/arch/x86_64/cpu/apic.rs index 3672f38..57c7d55 100644 --- a/kernel/src/arch/x86_64/cpu/apic.rs +++ b/kernel/src/arch/x86_64/cpu/apic.rs @@ -1,12 +1,12 @@ use core::arch::x86_64::__cpuid; use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET; -use crate::{serial_print, serial_println}; +use crate::{debugln, serial_print, serial_println}; use x86_64::{ PhysAddr, VirtAddr, structures::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB}, }; - +use x86_64::structures::paging::Translate; use crate::arch::x86_64::cpu::msr::*; use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE}; @@ -26,9 +26,11 @@ const CPUID_FEAT_EDX_APIC: u64 = 1 << 9; // the cpuid instruction will return th fn set_apic_base_enable(apic: PhysAddr) { let rax = (apic.as_u64() & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE; + debugln!("apic {:?}", PhysAddr::new(rax)); cpu_set_msr(IA32_APIC_BASE_MSR, rax); } +#[allow(dead_code)] fn set_apic_base_disable(apic: PhysAddr) { let rax = (apic.as_u64() & 0xfffff0000) & IA32_APIC_BASE_MSR_DISABLE; cpu_set_msr(IA32_APIC_BASE_MSR, rax); @@ -37,22 +39,27 @@ fn set_apic_base_disable(apic: PhysAddr) { fn get_apic_base() -> PhysAddr { let mut value: u64 = 0; cpu_get_msr(IA32_APIC_BASE_MSR, &mut value); + + debugln!("apic base {:#x}", value); + PhysAddr::new(value & 0xfffff0000) } -fn write_apic_register(apic_base: &PhysAddr, reg: u8, value: u32) { +fn write_apic_register(apic_base: &PhysAddr, reg: u64, value: u32) { let apic_base = apic_base.as_u64(); - let reg_addr = (apic_base & 0xFFFFF0000) + reg as u64; + let reg_addr = (apic_base & 0xFFFFF0000) + reg; + let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) }; + + let phys_check = OFFSET_PAGE_TABLE.get().unwrap().lock().translate(virt_addr); + debugln!("{:?}", phys_check); + unsafe { *(virt_addr.as_u64() as *mut u32) = value }; } -fn read_apic_register(apic_base: &PhysAddr, reg: u8) -> u32 { +fn read_apic_register(apic_base: &PhysAddr, reg: u64) -> u32 { let apic_base = apic_base.as_u64(); - let reg_addr = (apic_base & 0xFFFFF0000) + reg as u64; - - serial_println!("reading: {:?}", VirtAddr::new(reg_addr)); - + let reg_addr = (apic_base & 0xFFFFF0000) + reg; let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) }; unsafe { *(virt_addr.as_u64() as *const u32) } } @@ -70,23 +77,22 @@ unsafe fn phys_to_virt(phys: PhysAddr) -> VirtAddr { } pub fn enable_apic() { - let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); - let mut frame_allocator = FRAME_ALLOCATOR.get().unwrap().lock(); + let apic_base_physical_addr = get_apic_base(); + set_apic_base_enable(apic_base_physical_addr); - let apic_phys_addr = get_apic_base(); - set_apic_base_enable(apic_phys_addr); - // map virt address of apic - let apic_virt = unsafe { phys_to_virt(apic_phys_addr) }; + debugln!("{:?}", apic_base_physical_addr); + enable_timer(); - serial_println!("Trying to map: {:?} -> {:?}", apic_virt, apic_phys_addr); + write_apic_register( + &apic_base_physical_addr, + 0xF0, + read_apic_register(&apic_base_physical_addr, 0xF0) | 0x1FF + ); - // FIXME: this causes a page fault - // TODO: map to virtual memory - - let reg = read_apic_register(&apic_phys_addr, 0xF0); - write_apic_register(&apic_phys_addr, 0xF0, reg | 0x100); } -pub struct Apic {} - -pub enum ApicVector {} +pub fn enable_timer() { + let apic_base = get_apic_base(); + let current = read_apic_register(&apic_base, 0x320); + write_apic_register(&get_apic_base(), 0x320, (current & 0xFFFFFF00) | 0x20); +} diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index 0e385f3..2849e65 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,4 +1,4 @@ -use crate::serial_print; +use crate::{debug, serial_print}; use pic8259::ChainedPics; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; @@ -117,6 +117,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac } extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { + debug!("Timer Interrupt"); unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); diff --git a/kernel/src/arch/x86_64/memory/allocation/heap_alloc.rs b/kernel/src/arch/x86_64/memory/allocation/heap_alloc.rs index 96c5274..59b6026 100644 --- a/kernel/src/arch/x86_64/memory/allocation/heap_alloc.rs +++ b/kernel/src/arch/x86_64/memory/allocation/heap_alloc.rs @@ -1,8 +1,13 @@ +use crate::{debugln, serial_print}; use core::alloc::{GlobalAlloc, Layout}; use core::ptr; use spin::{Mutex, MutexGuard}; -use x86_64::structures::paging::{Size4KiB, mapper::MapToError}; -use crate::arch::x86_64::memory::{HEAP_SIZE, HEAP_VIRTUAL_SPACE}; +use x86_64::structures::paging::{Size4KiB, mapper::MapToError, PageTableFlags}; +use x86_64::VirtAddr; +use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, HEAP_SIZE, HEAP_VIRTUAL_SPACE}; +use crate::arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator; +use crate::arch::x86_64::memory::units::MemoryUnits; +use crate::serial_println; /// We are currently using a linked list heap allocator which uses our underlying page allocator. #[global_allocator] @@ -10,7 +15,27 @@ use crate::arch::x86_64::memory::{HEAP_SIZE, HEAP_VIRTUAL_SPACE}; static ALLOCATOR: Locked = Locked::new(FoundryAllocator::new()); -/// Sets up the heap using the backing page frame allocator. +/// Initializes the heap. +/// +/// This function must be called once, before any functions that +/// require a heap are called. It sets up the heap by allocating +/// the necessary frames from the page allocator. The heap is +/// then ready for use. +/// +/// # Safety +/// +/// This function must be called only once, and must be called before any types +/// are constructed that require dynamic memory allocation. +/// +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// Returns a `Result` containing a `MapToError` if the heap +/// could not be initialized, or `Ok` if the heap was +/// initialized successfully. pub unsafe fn init_heap() -> Result<(), MapToError> { unsafe { // code to allocate frames is now done in the page fault interrupt handler! @@ -66,6 +91,9 @@ impl FoundryAllocator { /// /// This function is unsafe because it does not check whether the given heap start address and size are valid. pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { + debugln!(" => Start: {:?}", VirtAddr::new(heap_start as u64)); + debugln!(" => Size: {}", MemoryUnits::from_bytes(heap_size)); + unsafe { self.fallback.lock().init(heap_start, heap_size); } @@ -90,7 +118,9 @@ unsafe impl GlobalAlloc for Locked { match allocator.list_heads[index].take() { Some(node) => { allocator.list_heads[index] = node.next.take(); - node as *mut ListNode as *mut u8 + let ptr = node as *mut ListNode as *mut u8; + ensure_mapped(VirtAddr::new(ptr as u64)); + ptr } None => { // no block exists in list => allocate new block @@ -161,6 +191,11 @@ impl FoundryFallbackAllocator { } } + /// Initializes the allocator with a given heap start address and size. + /// + /// # Safety + /// + /// This function is unsafe because it does not check whether the given heap start address and size are valid. pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { unsafe { self.add_region(heap_start, heap_size) }; } @@ -169,6 +204,10 @@ impl FoundryFallbackAllocator { unsafe { let mut node = FallbackListNode::new(size); node.next = self.head.next.take(); + + let virt_addr = VirtAddr::new(addr as u64); + ensure_mapped(virt_addr); + let node_ptr = addr as *mut FallbackListNode; node_ptr.write(node); self.head.next = Some(&mut *node_ptr); @@ -242,7 +281,9 @@ unsafe impl GlobalAlloc for Locked { if excess_size > 0 { unsafe { allocator.add_region(alloc_end, excess_size) }; } - alloc_start as *mut u8 + let ptr = alloc_start as *mut u8; + ensure_mapped(VirtAddr::new(ptr as u64)); + ptr } else { ptr::null_mut() } @@ -250,10 +291,16 @@ unsafe impl GlobalAlloc for Locked { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { let mut allocator = self.lock(); - + // perform layout adjustments let (size, _) = FoundryFallbackAllocator::size_align(layout); - unsafe { allocator.add_region(ptr as usize, size) } } } + +fn ensure_mapped(virt_addr: VirtAddr) { + if ! FoundryOSFrameAllocator::is_mapped(virt_addr) { + let mut foundry_alloc = FRAME_ALLOCATOR.get().unwrap().lock(); + foundry_alloc.allocate_page(virt_addr, PageTableFlags::PRESENT | PageTableFlags::WRITABLE).unwrap(); + } +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs b/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs index 3fa9aae..37e1185 100644 --- a/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs +++ b/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs @@ -1,9 +1,9 @@ -use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB}; +use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB, Translate}; use limine::response::MemoryMapResponse; use spin::Mutex; use limine::memory_map::EntryType; use x86_64::{PhysAddr, VirtAddr}; -use x86_64::structures::paging::mapper::MapToError; +use x86_64::structures::paging::mapper::{MapToError, TranslateResult}; use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE}; pub struct FoundryOSFrameAllocator { @@ -24,19 +24,23 @@ impl FoundryOSFrameAllocator { })); } - pub fn count_usable_frames(&self) -> u32 { - self.usable_frames().count() as u32 + pub fn count_usable_frames(&self) -> u64 { + self.usable_frames().count() as u64 } pub fn available_memory(&self) -> u64 { - ( self.memory_map.entries().len() * 4096 ) as u64 // multiply the number of physical frames by 4096 to get the memory size + self.memory_map + .entries() + .iter() + .map(|region| region.base..region.base + region.length) + .flat_map(|r| r.step_by(4096)).count() as u64 * 4096 } /// An iterator over all usable frames in the memory map. /// /// Yields one `PhysFrame` for each available 4KiB frame in the memory map. /// - /// This function is used to allocate frames for the pagemap. + /// This function is used to allocate frames for the page map. fn usable_frames(&self) -> impl Iterator + use<> { let regions = self.memory_map.entries().iter(); let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE); @@ -45,15 +49,20 @@ impl FoundryOSFrameAllocator { frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap()) } + pub(crate) fn is_mapped(virt_addr: VirtAddr) -> bool { + let mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); + matches!(mapper.translate(virt_addr), TranslateResult::Mapped { .. }) + } + + pub(crate) fn allocate_page(&mut self, start_addr: VirtAddr, flags: PageTableFlags) -> Result<(), MapToError> { + let page = Page::containing_address(start_addr); + let frame = self.allocate_frame().ok_or(MapToError::::FrameAllocationFailed)?; + let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); + + unsafe { + mapper.map_to(page, frame, flags, self)? + }.flush(); - - fn allocate_page(&mut self, start_addr: VirtAddr, flags: PageTableFlags) -> Result<(), MapToError> { - let page = Page::from_start_address(start_addr).map_err(|_| MapToError::FrameAllocationFailed)?; - let frame = self.allocate_frame().ok_or(MapToError::FrameAllocationFailed)?; - let _ = unsafe { - let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); - mapper.map_to(page, frame, flags, &mut *FRAME_ALLOCATOR.get().unwrap().lock())? - }; Ok(()) } } @@ -71,6 +80,9 @@ unsafe impl FrameAllocator for FoundryOSFrameAllocator { /// - `None`: If there are no more usable frames to allocate. fn allocate_frame(&mut self) -> Option { let frame = self.usable_frames().nth(self.next); + if frame.is_none() { + panic!("this shouldnt happen!"); + } self.next += 1; frame } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 1a692bc..995df90 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -23,6 +23,11 @@ use limine::BaseRevision; use x86_64::VirtAddr; use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator; use crate::arch::x86_64::cpu::apic::enable_apic; +use crate::arch::x86_64::drivers::ascii::screensize_chars; +use crate::arch::x86_64::drivers::framebuffer::display::screensize_px; +use crate::arch::x86_64::memory::allocation::heap_alloc::FoundryAllocator; +use crate::arch::x86_64::memory::FRAME_ALLOCATOR; +use crate::arch::x86_64::memory::units::MemoryUnits; pub mod arch; pub mod resources; @@ -32,8 +37,9 @@ pub mod util; pub mod prelude { pub use crate::std::io::{_print, _print_log, _serial_write}; + pub use crate::std::debug::_debug; pub use crate::{ - print, print_log, printerr, println, println_log, printlnerr, serial_print, serial_println, + print, print_log, printerr, println, println_log, printlnerr, serial_print, serial_println, debug }; } @@ -71,50 +77,59 @@ pub fn boot() -> Result<(), &'static str> { let memory_map = mapping::get_memory_map(); print_log!(" Initialising Serial... "); - if arch::x86_64::drivers::serial::init().is_err() { - println_log!("[Not Detected]") + let res = arch::x86_64::drivers::serial::init(); + serial_print!(" Initialising Serial... "); + if res.is_err() { + debugln!("[Not Detected]") } else { - println_log!("[Success]"); + debugln!("[Success]"); } - print_log!(" Setting Up Global Descriptor Table... "); + debugln!(" Display..."); + let dimensions = screensize_chars(); + let dimensions2 = screensize_px(); + debugln!(" => (px) : {}x{} ", dimensions2.0, dimensions2.1); + debugln!(" => (chars) : {}x{} ", dimensions.0, dimensions.1); + debugln!(" [Success]"); + + debug!(" Setting Up Global Descriptor Table... "); gdt::init(); - println_log!("[Success]"); + debugln!("[Success]"); - print_log!(" Setting Up Interrupt Descriptor Table... "); + debug!(" Setting Up Interrupt Descriptor Table... "); interrupts::init_idt(); - println_log!("[Success]"); + debugln!("[Success]"); - print_log!(" Initialising Memory Subsystem... "); + debugln!(" Initialising Memory Subsystem... "); let physical_memory_offset = VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET); init_page_table(physical_memory_offset); - println_log!("[Success]"); - - print_log!(" Setting Up Page Table... "); FoundryOSFrameAllocator::init(memory_map); - println_log!("[Success]"); + let available_bytes = FRAME_ALLOCATOR.get().unwrap().lock().available_memory(); + debugln!(" => Available Memory: {}", MemoryUnits::from_bytes(available_bytes as usize)); - print_log!(" Initialising Heap... "); + debugln!("[Success]"); + + debugln!(" Initialising Heap... "); if unsafe { init_heap() }.is_err() { return Err("Failed to initialise heap: error"); } - println_log!("[Success]"); + debugln!(" [Success]"); - // print_log!(" Enabling PICs... "); + // debug!(" Enabling PICs... "); // interrupts::enable_pic(); - // println_log!("[Success]"); + // debugln!("[Success]"); - // print_log!(" Disabling PICs... "); - // interrupts::disable_pic(); - // println_log!("[Success]"); + debug!(" Disabling PICs... "); + interrupts::disable_pic(); + debugln!("[Success]"); - print_log!(" Initialising APIC... "); + debug!(" Initialising APIC... "); enable_apic(); - println_log!("[Success]"); + debugln!("[Success]"); - print_log!(" Enabling Interrupts... "); + debug!(" Enabling Interrupts... "); x86_64::instructions::interrupts::enable(); - println_log!("[Success]"); + debugln!("[Success]"); Ok(()) } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 65572c5..114e257 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -15,14 +15,8 @@ extern "C" fn kmain() -> ! { panic!("{}", err); } - println_log!("[ Kernel Initialised Successfully ] "); - - let dimensions = screensize_chars(); - let dimensions2 = screensize_px(); - - println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1); - println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); - + println_log!(" [ Kernel Initialised Successfully ] "); + // println!("TESTING :: Allocation"); // let somevec = vec![0; 1_000_000]; // println!("{:?}", somevec); diff --git a/kernel/src/std/debug.rs b/kernel/src/std/debug.rs new file mode 100644 index 0000000..a6ad975 --- /dev/null +++ b/kernel/src/std/debug.rs @@ -0,0 +1,22 @@ +use core::fmt; +use x86_64::instructions::interrupts; +use crate::prelude::{_print_log, _serial_write}; + +#[macro_export] +macro_rules! debugln { + () => ($crate::print_log!("\n")); + ($($arg:tt)*) => ($crate::debug!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! debug { + ($($arg:tt)*) => ($crate::prelude::_debug(format_args!($($arg)*))); +} + +pub fn _debug(args: fmt::Arguments) { + interrupts::without_interrupts(|| { + _print_log(args); + _serial_write(args); + }); +} + diff --git a/kernel/src/std/io.rs b/kernel/src/std/io.rs index 4719ec5..10f1f7f 100644 --- a/kernel/src/std/io.rs +++ b/kernel/src/std/io.rs @@ -2,7 +2,6 @@ pub use crate::arch::x86_64::drivers::{ ascii::{_print, _print_err, _print_log}, serial::_serial_write, }; - pub mod stdin { use crate::arch::x86_64::drivers::{ ascii::WRITER, diff --git a/kernel/src/std/mod.rs b/kernel/src/std/mod.rs index f174d93..eb09545 100644 --- a/kernel/src/std/mod.rs +++ b/kernel/src/std/mod.rs @@ -2,3 +2,4 @@ pub mod application; pub mod ascii; pub mod io; pub mod maths; +pub mod debug;