redoing apic stuff

This commit is contained in:
fekhesk 2022-10-27 15:40:21 -07:00
parent 8fcc70bee1
commit 600ba7163a
No known key found for this signature in database
GPG Key ID: D17BA3F38ED319DF
6 changed files with 107 additions and 121 deletions

View File

@ -5,6 +5,11 @@
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="version" value="2" />
</MakefileProjectSettings>
</option>

View File

@ -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 }

View File

@ -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

View File

@ -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<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T> {
// 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<PageSize> = 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");

View File

@ -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,
}
}

View File

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