From d11d5ddd9750a11899e931f42ffce3622e86cb4c Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 20:08:32 -0700 Subject: [PATCH] wtf double fault ): --- Cargo.toml | 2 +- serial.log | 45 +++++++++++++++++++++++- src/boot/mod.rs | 59 ++++++++++++++++++------------- src/internals/cpu.rs | 84 +++++++++++++++++++++----------------------- src/main.rs | 24 ++++++++----- src/memory/mod.rs | 9 +++-- 6 files changed, 143 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06f8013..15a9816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] spin = "0.9.1" x86_64 = "0.14.10" -x86 = "0.52.0" +x2apic = "0.4.1" rlibc = "1.0" limine = { version = "0.1.9", optional = true } acpi = { version = "4.1.1", optional = true } diff --git a/serial.log b/serial.log index 9129c8d..cee038e 100644 --- a/serial.log +++ b/serial.log @@ -12,7 +12,50 @@ debug: IDT loaded welcome to wukkOS! (c) 2022 Real Microsoft, LLC -initialising mapper...[OK] +initialising mapper...[debug] kernel physical address: 0x19b3d000 +[debug] kernel virtual address: 0xffffffff80000000 +[OK] initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] +checking for apic compatibility...[OK] +initialising apic...[debug] Mapping physical region: 1fb7e014 - 1fb7e038 +[debug] Mapping physical region: 1fb7d0e8 - 1fb7d10c +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb7d0e8 - 1fb7d134 +[debug] Mapping physical region: 1fb7a000 - 1fb7a024 +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb7a000 - 1fb7a114 +[debug] Mapping physical region: 1fb7b000 - 1fb7b024 +[WARN] failed to unmap page (this is normal) +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb79000 - 1fb79024 +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb78000 - 1fb78024 +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb77000 - 1fb77024 +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb76000 - 1fb76024 +[WARN] failed to unmap page (this is normal) +[WARN] failed to unmap page (this is normal) +[WARN] failed to unmap page (this is normal) +[debug] Mapping physical region: 1fb7a000 - 1fb7a074 +[debug] Mapping physical region: 1fb79000 - 1fb79078 +[WARN] failed to unmap page (this is normal) +[WARN] failed to unmap page (this is normal) +[OK] +setting up apic interrupts...[debug] ioapicaddr: 0xfec00000 +[OK] +---KERNEL FUCKY WUKKY UWU--- +double fault! +stack frame: InterruptStackFrame { + instruction_pointer: VirtAddr( + 0xffffffff80004729, + ), + code_segment: 8, + cpu_flags: 0x282, + stack_pointer: VirtAddr( + 0xffff800019b3bd00, + ), + stack_segment: 16, +} diff --git a/src/boot/mod.rs b/src/boot/mod.rs index ed79a07..8028f98 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,39 +1,36 @@ use alloc::sync::Arc; use core::marker::PhantomData; use core::ptr::NonNull; -use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; -use limine::LimineTerminalResponse; -use crate::{debug, println, TERMINAL_REQUEST}; +use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; +use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest}; +use crate::{debug, println}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; use x86_64::VirtAddr; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET}; use crate::serial::terminal::ST; +pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); +pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); +pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); +pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0); +pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0); + #[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); - let mut i = 0; - while i < size { - let _ = read_phys_memory32(physical_address as u32 + i as u32); - i += 4; - } - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(VirtAddr::new(physical_address as u64)) }; - if let Some(addr) = addr.clone() { - // 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"); - } + unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { // todo! check if size is too big + // only get lower 32 bits of physical address + let physical_address = physical_address as u32; + debug!("Mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32); + let _ = read_phys_memory32(physical_address as u32) as usize; + PhysicalMapping::new( + physical_address as usize, + NonNull::new_unchecked(physical_address as *mut T), + size, size, + Self) } fn unmap_physical_region(region: &PhysicalMapping) { @@ -42,8 +39,9 @@ impl AcpiHandler for Handler { // 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"); + println!("[WARN] failed to unmap page (this is normal)"); } } } @@ -68,4 +66,17 @@ impl core::fmt::Write for LimineWriter { } Ok(()) } +} + +pub fn get_ioapic_addr() -> u32 { + let rsdp = RSDP_REQUEST.get_response().get().unwrap(); + let rsdp_ptr = rsdp.address.get().unwrap() as *const u8; + let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() }; + let platform_info = tables.platform_info().expect("no platform info"); + let interrupt_model = platform_info.interrupt_model; + let ioapic_addr = match interrupt_model { + InterruptModel::Apic(apic) => apic.io_apics[0].address, + _ => panic!("unsupported interrupt model"), + }; + ioapic_addr } \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index dd5dba1..40ff5d2 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,5 +1,6 @@ use core::arch::asm; -use x86::apic::{xapic::XAPIC, ioapic::IoApic, ApicControl}; +use x2apic::ioapic::{IoApic, IrqFlags, IrqMode, RedirectionTableEntry}; +use x2apic::lapic::{LocalApicBuilder, xapic_base}; use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; use x86_64::structures::paging::PhysFrame; @@ -9,15 +10,6 @@ use crate::serial::{command, read}; // todo! maybe abstract this into different sections for different parts of cpu func? -pub struct WAPICManager { - pub xapic: XAPIC, - pub id: u32, -} - -pub struct WIOAPICManager { - pub ioapic: IoApic, -} - pub fn check_apic_compat() -> bool { unsafe { let mut eax: u32; @@ -31,34 +23,35 @@ pub fn check_apic_compat() -> bool { } } -pub fn enable_apic() -> WAPICManager { +pub fn enable_apic() { // we need to get the xapic region - let mut XAPIC_REGION: &'static mut [u32] = unsafe { - // region should be FFFE0000H to FFFE0FFFH - let region_start = 0xFFFE_0000u32; - let region_end = 0xFFFE_0FFFu32; - let region_size = region_end - region_start; - let region_size = region_size as usize; - let region_start = region_start as *mut u32; - // read to make sure it gets mapped - let _ = read_phys_memory32(region_start as u32); - let _ = read_phys_memory32(region_end as u32); - core::slice::from_raw_parts_mut(region_start, region_size) - }; - let mut xapic = unsafe { XAPIC::new(XAPIC_REGION) }; - xapic.attach(); + let phys_addr = unsafe { xapic_base() }; - // get xapic id to ensure it's working - let id = xapic.id(); - debug!("xapic id: {}", id); - debug!("xapic version: {}", xapic.version()); - - WAPICManager { - xapic, - id, + let mut lapic = LocalApicBuilder::new() + .timer_vector(0x40) + .error_vector(0x41) + .spurious_vector(0x42) + .set_xapic_base(phys_addr) + .build() + .unwrap_or_else(|e| panic!("failed to build local apic: {}", e)); + + unsafe { + lapic.enable(); } } +pub extern "x86-interrupt" fn timer(stack_frame: InterruptStackFrame) { + println!("timer interrupt"); +} + +pub extern "x86-interrupt" fn error(stack_frame: InterruptStackFrame) { + println!("error interrupt"); +} + +pub extern "x86-interrupt" fn spurious(stack_frame: InterruptStackFrame) { + println!("spurious interrupt"); +} + // todo! in the future this will be removed, it is only for testing basic apic functionality pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { debug!("keyboard interrupt"); @@ -76,16 +69,21 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { } // todo! we should abstract this away -pub fn setup_ioapic(ioapicaddr: u32) -> WIOAPICManager { - let mut ioapic = unsafe { IoApic::new(ioapicaddr as usize) }; - let _ = read_phys_memory32(ioapicaddr); - // assert that supported interrupts is greater than 1 - debug!("ioapic supported interrupts: {}", ioapic.supported_interrupts()); - // setup keyboard irq (interrupt 0x40) - ioapic.enable(1, 0x40); +pub fn setup_ioapic(ioapicaddr: u32) { + let mut ioapic = unsafe { + IoApic::new(ioapicaddr as u64) + }; + // setup keyboard interrupt + unsafe { + // init with irq offset + ioapic.init(0x50); + let mut entry = RedirectionTableEntry::default(); + entry.set_mode(IrqMode::Fixed); + entry.set_flags(IrqFlags::LEVEL_TRIGGERED | IrqFlags::LOW_ACTIVE | IrqFlags::MASKED); + entry.set_dest(0); + ioapic.set_table_entry(1, entry); - // return - WIOAPICManager { - ioapic, + ioapic.enable_irq(1); } + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 16d049f..a6cbe81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ use x86_64::structures::tss::TaskStateSegment; use x86_64::{PhysAddr, VirtAddr}; use x86_64::registers::segmentation::{CS, Segment, SS}; use x86_64::structures::paging::Translate; +use crate::boot::{get_ioapic_addr, KERNEL_ADDRESS}; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; use crate::serial::terminal::ST; @@ -36,10 +37,6 @@ mod boot; mod memory; mod macros; -static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); -static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); -static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); - lazy_static! { //pub static ref KERN_INFO: Mutex> = Mutex::new(None); static ref GDT: Mutex = { @@ -51,7 +48,11 @@ lazy_static! { idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception); idt.double_fault.set_handler_fn(internals::errors::double_fault); idt.page_fault.set_handler_fn(internals::errors::page_fault); - idt[40].set_handler_fn(internals::cpu::keyboard_irq); + idt[40].set_handler_fn(internals::cpu::timer); + idt[41].set_handler_fn(internals::cpu::error); + idt[42].set_handler_fn(internals::cpu::spurious); + idt[50].set_handler_fn(internals::cpu::timer); + idt[51].set_handler_fn(internals::cpu::keyboard_irq); idt }; } @@ -168,6 +169,11 @@ pub extern "C" fn kernel_main() -> ! { // memory stuff { print!("initialising mapper..."); + let kernel_physical_address = KERNEL_ADDRESS.get_response().get().unwrap().physical_base; + let kernel_virtual_address = KERNEL_ADDRESS.get_response().get().unwrap().virtual_base; + debug!("kernel physical address: {:#x}", kernel_physical_address); + debug!("kernel virtual address: {:#x}", kernel_virtual_address); + let offset = (kernel_virtual_address as i64) as usize;// - kernel_physical_address as i64) as usize; MEM_MAPPER.lock().replace(unsafe { memory::init(VirtAddr::new(0)) }); println!("[OK]"); print!("initialising frame allocator..."); @@ -192,7 +198,7 @@ pub extern "C" fn kernel_main() -> ! { } // apic stuff - /*{ + { print!("checking for apic compatibility..."); let apic_compatible = unsafe { internals::cpu::check_apic_compat() }; if apic_compatible { @@ -202,16 +208,16 @@ pub extern "C" fn kernel_main() -> ! { panic!("apic required at the moment"); } print!("initialising apic..."); + let ioapicaddr = get_ioapic_addr(); unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - let ioapicaddr = KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr(); debug!("ioapicaddr: {:#x}", ioapicaddr); unsafe { internals::cpu::setup_ioapic(ioapicaddr) }; println!("[OK]"); // enable interrupts - x86_64::instructions::interrupts::enable(); - }*/ + //x86_64::instructions::interrupts::enable(); + } loop { } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 70c9ca5..053eaf5 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -3,7 +3,8 @@ 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 limine::LimineMemoryMapEntryType; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate}; use x86_64::{PhysAddr, VirtAddr}; lazy_static!{ @@ -11,6 +12,8 @@ lazy_static!{ pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); } +pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000; + pub type PageSize = Size4KiB; pub struct Locked { @@ -47,7 +50,8 @@ unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTa } use spin::Mutex; -use crate::{debug, MEM_MAP, print, println}; +use crate::{debug, print, println}; +use crate::boot::{KERNEL_ADDRESS, MEM_MAP}; pub struct BootInfoFrameAllocator { next: usize, @@ -67,6 +71,7 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { let mmap = MEM_MAP.get_response().get().expect("failed to get memory map") .memmap(); let mut usable_frames = mmap.iter() + .filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable) .map(|area| { let frame_addr = area.base; let frame_end = area.base + area.len;