redoing apic stuff
This commit is contained in:
parent
8fcc70bee1
commit
600ba7163a
|
@ -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>
|
||||
|
|
|
@ -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 }
|
||||
|
|
43
serial.log
43
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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
// get xapic id to ensure it's working
|
||||
let id = xapic.id();
|
||||
debug!("xapic id: {}", id);
|
||||
debug!("xapic version: {}", xapic.version());
|
||||
|
||||
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,
|
||||
);
|
||||
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,
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue