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();