Support both X2 and XAPIC modes
This commit is contained in:
parent
a4da0121ea
commit
f706dda8af
|
@ -1,5 +1,10 @@
|
||||||
|
use core::intrinsics::{volatile_load, volatile_store};
|
||||||
|
use x86::cpuid::CpuId;
|
||||||
use x86::msr::*;
|
use x86::msr::*;
|
||||||
|
|
||||||
|
use memory::Frame;
|
||||||
|
use paging::{entry, ActivePageTable, PhysicalAddress};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub flags LocalApicIcr: u64 {
|
pub flags LocalApicIcr: u64 {
|
||||||
const ICR_VECTOR = 0xFF,
|
const ICR_VECTOR = 0xFF,
|
||||||
|
@ -25,27 +30,81 @@ bitflags! {
|
||||||
|
|
||||||
/// Local APIC
|
/// Local APIC
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct LocalApic;
|
pub struct LocalApic {
|
||||||
|
address: u32,
|
||||||
|
pub x2: bool
|
||||||
|
}
|
||||||
|
|
||||||
impl LocalApic {
|
impl LocalApic {
|
||||||
pub fn new() -> Self {
|
pub fn new(active_table: &mut ActivePageTable) -> Self {
|
||||||
unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 11 | 1 << 10) }
|
let mut apic = LocalApic {
|
||||||
LocalApic
|
address: (unsafe { rdmsr(IA32_APIC_BASE) as u32 } & 0xFFFF0000),
|
||||||
|
x2: false
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("APIC BASE: {:>08X}", apic.address);
|
||||||
|
|
||||||
|
unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) & !(1 << 11 | 1 << 10)) };
|
||||||
|
|
||||||
|
unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 11) };
|
||||||
|
|
||||||
|
if CpuId::new().get_feature_info().unwrap().has_x2apic() {
|
||||||
|
unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10) };
|
||||||
|
apic.x2 = true;
|
||||||
|
println!("X2APIC {:X}", unsafe { rdmsr(IA32_APIC_BASE) });
|
||||||
|
} else {
|
||||||
|
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(apic.address as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||||
|
|
||||||
|
println!("XAPIC {:X}", unsafe { rdmsr(IA32_APIC_BASE) });
|
||||||
|
}
|
||||||
|
|
||||||
|
apic
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read(&self, reg: u32) -> u32 {
|
||||||
|
volatile_load((self.address + reg) as *const u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write(&self, reg: u32, value: u32) {
|
||||||
|
volatile_store((self.address + reg) as *mut u32, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> u32 {
|
pub fn id(&self) -> u32 {
|
||||||
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
|
if self.x2 {
|
||||||
|
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
|
||||||
|
} else {
|
||||||
|
unsafe { self.read(0x20) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version(&self) -> u32 {
|
pub fn version(&self) -> u32 {
|
||||||
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
|
if self.x2 {
|
||||||
|
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
|
||||||
|
} else {
|
||||||
|
unsafe { self.read(0x30) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn icr(&self) -> u64 {
|
pub fn icr(&self) -> u64 {
|
||||||
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
if self.x2 {
|
||||||
|
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
(self.read(0x310) as u64) << 32 | self.read(0x300) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_icr(&mut self, value: u64) {
|
pub fn set_icr(&mut self, value: u64) {
|
||||||
unsafe { wrmsr(IA32_X2APIC_ICR, value) }
|
if self.x2 {
|
||||||
|
unsafe { wrmsr(IA32_X2APIC_ICR, value); }
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
while self.read(0x300) & 1 << 12 == 1 << 12 {}
|
||||||
|
self.write(0x310, (value >> 32) as u32);
|
||||||
|
self.write(0x300, value as u32);
|
||||||
|
while self.read(0x300) & 1 << 12 == 1 << 12 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
|
||||||
if let Some(madt) = Madt::new(sdt) {
|
if let Some(madt) = Madt::new(sdt) {
|
||||||
println!(" {:>016X}: {}", madt.local_address, madt.flags);
|
println!(" {:>016X}: {}", madt.local_address, madt.flags);
|
||||||
|
|
||||||
let mut local_apic = LocalApic::new();
|
let mut local_apic = LocalApic::new(active_table);
|
||||||
|
|
||||||
let me = local_apic.id() as u8;
|
let me = local_apic.id() as u8;
|
||||||
|
|
||||||
|
@ -74,15 +74,28 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
|
||||||
|
|
||||||
// Send INIT IPI
|
// Send INIT IPI
|
||||||
{
|
{
|
||||||
let icr = 0x00004500 | (ap_local_apic.id as u64) << 32;
|
let mut icr = 0x4500;
|
||||||
|
if local_apic.x2 {
|
||||||
|
icr |= (ap_local_apic.id as u64) << 32;
|
||||||
|
} else {
|
||||||
|
icr |= (ap_local_apic.id as u64) << 56;
|
||||||
|
}
|
||||||
println!(" Sending IPI to {}: {:>016X} {:?}", ap_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
println!(" Sending IPI to {}: {:>016X} {:?}", ap_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
||||||
local_apic.set_icr(icr);
|
local_apic.set_icr(icr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send START IPI
|
// Send START IPI
|
||||||
{
|
{
|
||||||
|
//Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
|
||||||
let ap_segment = (AP_STARTUP >> 12) & 0xFF;
|
let ap_segment = (AP_STARTUP >> 12) & 0xFF;
|
||||||
let icr = 0x00004600 | ((ap_local_apic.id as u64) << 32) | ap_segment as u64; //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
|
let mut icr = 0x4600 | ap_segment as u64;
|
||||||
|
|
||||||
|
if local_apic.x2 {
|
||||||
|
icr |= (ap_local_apic.id as u64) << 32;
|
||||||
|
} else {
|
||||||
|
icr |= (ap_local_apic.id as u64) << 56;
|
||||||
|
}
|
||||||
|
|
||||||
println!(" Sending SIPI to {}: {:>016X} {:?}", ap_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
println!(" Sending SIPI to {}: {:>016X} {:?}", ap_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
||||||
local_apic.set_icr(icr);
|
local_apic.set_icr(icr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue