142 lines
4.2 KiB
Rust
142 lines
4.2 KiB
Rust
use core::arch::asm;
|
|
use x86_64::{PhysAddr, VirtAddr};
|
|
use x86_64::structures::idt::InterruptStackFrame;
|
|
use x86_64::structures::paging::OffsetPageTable;
|
|
use crate::{debug, 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 fn check_apic_compat() -> bool {
|
|
unsafe {
|
|
let mut eax: u32;
|
|
let mut edx: u32;
|
|
asm!("cpuid",
|
|
in("eax") 1,
|
|
lateout("eax") eax,
|
|
lateout("edx") edx,
|
|
);
|
|
edx & (1 << 9) != 0
|
|
}
|
|
}
|
|
|
|
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 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(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator) {
|
|
// 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(mem_mapper, frame_alloc, sivr_addr);
|
|
write_phys_memory32(mem_mapper, frame_alloc, sivr_addr, sivr | (1 << 8));
|
|
}
|
|
|
|
pub fn apic_read_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32) -> u32 {
|
|
write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg);
|
|
read_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32 + 0x10)
|
|
}
|
|
|
|
pub fn apic_write_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32, val: u32) {
|
|
write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg);
|
|
write_phys_memory32(mem_mapper, frame_alloc, 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(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, 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(mem_mapper, frame_alloc, ioapicaddr, hi_index);
|
|
// set apic id
|
|
high &= !(0xff000000);
|
|
high |= (apic_id as u32) << 24;
|
|
apic_write_io(mem_mapper, frame_alloc, ioapicaddr, hi_index, high);
|
|
|
|
let mut low = apic_read_io(mem_mapper, frame_alloc, 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(mem_mapper, frame_alloc, ioapicaddr, lo_index, low);
|
|
}
|
|
|
|
pub fn apic_eoi() {
|
|
unsafe {
|
|
asm!("mov eax, 0",
|
|
"mov ecx, 0xb0",
|
|
"wrmsr",
|
|
in("ecx") 0x80b,
|
|
in("eax") 0,
|
|
);
|
|
}
|
|
}
|
|
|
|
// 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");
|
|
unsafe { asm!("iretq"); }
|
|
let scancode = read(0x60);
|
|
|
|
print!("ksc: {},", scancode);
|
|
|
|
// reset keyboard controller
|
|
let mut a = read(0x61);
|
|
a |= 0x82;
|
|
command(0x61, a);
|
|
a &= 0x7f;
|
|
command(0x61, a);
|
|
}
|
|
|
|
// todo! we should abstract this away
|
|
pub fn setup_apic_interrupts(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize) {
|
|
// set keyboard irq to interrupt 40
|
|
ioapic_set_irq(mem_mapper, frame_alloc, ioapicaddr, 1, 0, 40);
|
|
} |