From 600ba7163ac8f040a79f99540f0d79403257079e Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 15:40:21 -0700 Subject: [PATCH] redoing apic stuff --- .idea/misc.xml | 5 ++ Cargo.toml | 1 + serial.log | 43 +++++++++++-- src/boot/mod.rs | 22 +++---- src/internals/cpu.rs | 149 ++++++++++++++----------------------------- src/lib.rs | 8 +-- 6 files changed, 107 insertions(+), 121 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 6afde3a..85603ba 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,6 +5,11 @@ diff --git a/Cargo.toml b/Cargo.toml index f7dd3b1..a3e9061 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ crate-type = ["staticlib"] [dependencies] spin = "0.9.1" x86_64 = "0.14.10" +x86 = "0.52.0" rlibc = "1.0" multiboot2 = { version = "0.14.0", optional = true } acpi = { version = "4.1.1", optional = true } diff --git a/serial.log b/serial.log index 3b30c1c..38a858c 100644 --- a/serial.log +++ b/serial.log @@ -21,10 +21,43 @@ initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] checking for apic compatibility...[OK] -disabling PIC...[OK] -initialising apic...[debug] read_phys_memory32: addr fee000f0 not mapped +initialising apic...[debug] read_phys_memory32: addr fffe0000 not mapped [debug] allocated frame: PhysFrame[4KiB](0x1c000) -[debug] mapped page: Page[4KiB](0xfee00000) -[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfee00000))) +[debug] mapped page: Page[4KiB](0xfffe0000) +[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfffe0000))) +[debug] xapic id: 0 +[debug] xapic version: 0 +[OK] +setting up apic interrupts...[debug] acpi tag: RsdpV1Tag { typ: AcpiV1, size: 28, signature: [82, 83, 68, 32, 80, 84, 82, 32], checksum: 172, oem_id: [66, 79, 67, 72, 83, 32], revision: 0, rsdt_address: 532140032 } +[debug] rsdt: 532140032 +[debug] read_phys_memory32: addr 1fb7d000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb7d000 not mapped +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[debug] read_phys_memory32: addr 1fb7b000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb79000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb78000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb77000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb76000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] loaded rsdt +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[debug] read_phys_memory32: addr 1fb79000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] ioapic addr: fec00000 +[debug] ioapicaddr: 0xfec00000 +[debug] read_phys_memory32: addr fec00000 not mapped +[debug] allocated frame: PhysFrame[4KiB](0x1f000) +[debug] mapped page: Page[4KiB](0xfec00000) +[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfec00000))) +[debug] ioapic supported interrupts: 1 [OK] -setting up apic interrupts...[debug] read_phys_memory32: addr 1fb7d000 not mapped diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 9d65346..2ee2989 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -8,7 +8,7 @@ use crate::{debug, KernelArgs, println}; 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}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32}; pub struct KernelInfo { kernel_start: u64, @@ -24,19 +24,13 @@ 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: Page = Page::containing_address(VirtAddr::new(physical_address as u64)); - 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 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 { + if let Some(addr) = addr.clone() { // physical start, virtual start, region length, mapped length, Self PhysicalMapping::new( physical_address, @@ -104,21 +98,25 @@ impl KernelInfo { #[cfg(feature = "f_multiboot2")] { let acpi_tag = self.boot_info.rsdp_v1_tag().expect("no acpi tag"); + debug!("acpi tag: {:?}", acpi_tag); let rsdp = acpi_tag; let rsdp = unsafe { &*rsdp }; let rsdt = rsdp.rsdt_address(); + debug!("rsdt: {:?}", rsdt); let rsdt = unsafe { acpi::AcpiTables::from_rsdt( Handler, 0, rsdt) .expect("failed to get acpi tables") }; + debug!("loaded rsdt"); 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; + debug!("ioapic addr: {:x}", ioapic_addr); ioapic_addr } else { panic!("no ioapic"); diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index 5ae297c..5d42b2d 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,13 +1,23 @@ use core::arch::asm; -use x86_64::{PhysAddr, VirtAddr}; +use x86::apic::{xapic::XAPIC, ioapic::IoApic, ApicControl}; +use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; -use x86_64::structures::paging::OffsetPageTable; -use crate::{debug, print, println}; +use x86_64::structures::paging::PhysFrame; +use crate::{debug, KERN_INFO, print, println}; use crate::memory::{BootInfoFrameAllocator, read_phys_memory32, write_phys_memory32}; 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; @@ -21,101 +31,31 @@ pub fn check_apic_compat() -> bool { } } -pub fn set_apic_base(apic: usize) { - const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800; - let mut edx = 0u32; - let mut eax = (apic & 0xfffff0000) as u32 | IA32_APIC_BASE_MSR_ENABLE; - unsafe { - asm!("wrmsr", - in("ecx") 0x1b, - in("eax") eax, - in("edx") edx, - ); - } -} +pub fn enable_apic() -> WAPICManager { + // 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(); -pub fn get_apic_base() -> usize { - let mut edx = 0u32; - let mut eax = 0u32; - unsafe { - asm!("rdmsr", - in("ecx") 0x1b, - lateout("eax") eax, - lateout("edx") edx, - ); - } - ((edx as usize) << 32) | (eax as usize) -} - -pub fn enable_apic() { - // 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)); -} - -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: u32, reg: u32, val: u32) { - write_phys_memory32(ioapicaddr as u32, reg); - write_phys_memory32(ioapicaddr as u32 + 0x10, val); -} - -pub fn disable_pic() { - command(0x20, 0x11); - command(0xa0, 0x11); - - command(0x21, 0xe0); - command(0xa1, 0xe8); - - command(0x21, 0x04); - command(0xa1, 0x02); - - command(0x21, 0x01); - command(0xa1, 0x01); - - command(0x21, 0xff); - command(0xa1, 0xff); -} - -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; - - let mut high = apic_read_io(ioapicaddr, hi_index); - // set apic id - high &= !(0xff000000); - high |= (apic_id as u32) << 24; - apic_write_io(ioapicaddr, hi_index, high); - - let mut low = apic_read_io( ioapicaddr, lo_index); - - // unmask - low &= !(1 << 16); - // set to physical delivery - low &= !(1 << 11); - // set to fixed delivery - low &= !(0x700); - // set vector - low &= !(0xff); - low |= vector as u32; - - apic_write_io(ioapicaddr, lo_index, low); -} - -pub fn apic_eoi() { - unsafe { - asm!("mov eax, 0", - "mov ecx, 0xb0", - "wrmsr", - in("ecx") 0x80b, - in("eax") 0, - ); + // get xapic id to ensure it's working + let id = xapic.id(); + debug!("xapic id: {}", id); + debug!("xapic version: {}", xapic.version()); + + WAPICManager { + xapic, + id, } } @@ -136,7 +76,16 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { } // todo! we should abstract this away -pub fn setup_apic_interrupts(ioapicaddr: u32) { - // set keyboard irq to interrupt 40 - ioapic_set_irq(ioapicaddr, 1, 0, 40); +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); + + // return + WIOAPICManager { + ioapic, + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index caeb948..3a813e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![feature(asm_const)] #![feature(const_mut_refs)] #![feature(alloc_error_handler)] +#![feature(const_slice_from_raw_parts_mut)] #![no_std] #![no_main] @@ -202,14 +203,13 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!("[FAIL]"); panic!("apic required at the moment"); } - print!("disabling PIC..."); - unsafe { internals::cpu::disable_pic() }; - println!("[OK]"); print!("initialising apic..."); unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - unsafe { internals::cpu::setup_apic_interrupts(KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr()) }; + 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();