Changes to allow for detection and init of ASPs
This commit is contained in:
parent
7b2acdd79c
commit
08900d56c8
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ bochs: build/harddrive.bin
|
|||
bochs -f bochs.$(ARCH)
|
||||
|
||||
qemu: build/harddrive.bin
|
||||
qemu-system-$(ARCH) -enable-kvm -cpu host -machine q35 \
|
||||
qemu-system-$(ARCH) -enable-kvm -cpu host -smp 4 -machine q35 \
|
||||
-serial mon:stdio -drive file=$<,format=raw,index=0,media=disk \
|
||||
-nographic -d guest_errors
|
||||
#-device intel-iommu
|
||||
|
|
51
arch/x86_64/src/acpi/local_apic.rs
Normal file
51
arch/x86_64/src/acpi/local_apic.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use x86::msr::*;
|
||||
|
||||
bitflags! {
|
||||
pub flags LocalApicIcr: u64 {
|
||||
const ICR_VECTOR = 0xFF,
|
||||
|
||||
const ICR_FIXED = 0b000 << 8,
|
||||
const ICR_SMI = 0b010 << 8,
|
||||
const ICR_NMI = 0b100 << 8,
|
||||
const ICR_INIT = 0b101 << 8,
|
||||
const ICR_START = 0b110 << 8,
|
||||
|
||||
const ICR_PHYSICAL = 0 << 11,
|
||||
const ICR_LOGICAL = 1 << 11,
|
||||
|
||||
const ICR_DEASSERT = 0 << 14,
|
||||
const ICR_ASSERT = 1 << 14,
|
||||
|
||||
const ICR_EDGE = 0 << 15,
|
||||
const ICR_LEVEL = 1 << 15,
|
||||
|
||||
const ICR_DESTINATION = 0b1111 << 56,
|
||||
}
|
||||
}
|
||||
|
||||
/// Local APIC
|
||||
#[repr(packed)]
|
||||
pub struct LocalApic;
|
||||
|
||||
impl LocalApic {
|
||||
pub fn new() -> Self {
|
||||
unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10) }
|
||||
LocalApic
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
|
||||
}
|
||||
|
||||
pub fn version(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
|
||||
}
|
||||
|
||||
pub fn icr(&self) -> u64 {
|
||||
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
||||
}
|
||||
|
||||
pub fn set_icr(&mut self, value: u64) {
|
||||
unsafe { wrmsr(IA32_X2APIC_ICR, value) }
|
||||
}
|
||||
}
|
133
arch/x86_64/src/acpi/madt.rs
Normal file
133
arch/x86_64/src/acpi/madt.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
use core::mem;
|
||||
|
||||
use super::sdt::Sdt;
|
||||
|
||||
/// The Multiple APIC Descriptor Table
|
||||
#[derive(Debug)]
|
||||
pub struct Madt {
|
||||
sdt: &'static Sdt,
|
||||
pub local_address: u32,
|
||||
pub flags: u32
|
||||
}
|
||||
|
||||
impl Madt {
|
||||
pub fn new(sdt: &'static Sdt) -> Option<Madt> {
|
||||
if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags
|
||||
let local_address = unsafe { *(sdt.data_address() as *const u32) };
|
||||
let flags = unsafe { *(sdt.data_address() as *const u32).offset(1) };
|
||||
|
||||
Some(Madt {
|
||||
sdt: sdt,
|
||||
local_address: local_address,
|
||||
flags: flags
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> MadtIter {
|
||||
MadtIter {
|
||||
sdt: self.sdt,
|
||||
i: 8 // Skip local controller address and flags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
/// MADT Local APIC
|
||||
#[derive(Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct MadtLocalApic {
|
||||
/// Processor ID
|
||||
pub processor: u8,
|
||||
/// Local APIC ID
|
||||
pub id: u8,
|
||||
/// Flags. 1 means that the processor is enabled
|
||||
pub flags: u32
|
||||
}
|
||||
|
||||
/// MADT I/O APIC
|
||||
#[derive(Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct MadtIoApic {
|
||||
/// I/O APIC ID
|
||||
pub id: u8,
|
||||
/// reserved
|
||||
reserved: u8,
|
||||
/// I/O APIC address
|
||||
pub address: u32,
|
||||
/// Global system interrupt base
|
||||
pub gsi_base: u32
|
||||
}
|
||||
|
||||
/// MADT Interrupt Source Override
|
||||
#[derive(Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct MadtIntSrcOverride {
|
||||
/// Bus Source
|
||||
pub bus_source: u8,
|
||||
/// IRQ Source
|
||||
pub irq_source: u8,
|
||||
/// Global system interrupt base
|
||||
pub gsi_base: u32,
|
||||
/// Flags
|
||||
pub flags: u16
|
||||
}
|
||||
|
||||
/// MADT Entries
|
||||
#[derive(Debug)]
|
||||
pub enum MadtEntry {
|
||||
LocalApic(&'static MadtLocalApic),
|
||||
InvalidLocalApic(usize),
|
||||
IoApic(&'static MadtIoApic),
|
||||
InvalidIoApic(usize),
|
||||
IntSrcOverride(&'static MadtIntSrcOverride),
|
||||
InvalidIntSrcOverride(usize),
|
||||
Unknown
|
||||
}
|
||||
|
||||
pub struct MadtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
}
|
||||
|
||||
impl Iterator for MadtIter {
|
||||
type Item = MadtEntry;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.i + 1 < self.sdt.data_len() {
|
||||
let entry_type = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize) };
|
||||
let entry_len = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize + 1) } as usize;
|
||||
|
||||
if self.i + entry_len <= self.sdt.data_len() {
|
||||
let item = match entry_type {
|
||||
0 => if entry_len == mem::size_of::<MadtLocalApic>() + 2 {
|
||||
MadtEntry::LocalApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApic) })
|
||||
} else {
|
||||
MadtEntry::InvalidLocalApic(entry_len)
|
||||
},
|
||||
1 => if entry_len == mem::size_of::<MadtIoApic>() + 2 {
|
||||
MadtEntry::IoApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIoApic) })
|
||||
} else {
|
||||
MadtEntry::InvalidIoApic(entry_len)
|
||||
},
|
||||
2 => if entry_len == mem::size_of::<MadtIntSrcOverride>() + 2 {
|
||||
MadtEntry::IntSrcOverride(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIntSrcOverride) })
|
||||
} else {
|
||||
MadtEntry::InvalidIntSrcOverride(entry_len)
|
||||
},
|
||||
_ => MadtEntry::Unknown
|
||||
};
|
||||
|
||||
self.i += entry_len;
|
||||
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,18 +4,74 @@
|
|||
use memory::{Frame, FrameAllocator};
|
||||
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
|
||||
|
||||
use self::rsdt::RSDT;
|
||||
use self::sdt::SDT;
|
||||
use self::xsdt::XSDT;
|
||||
use self::local_apic::{LocalApic, LocalApicIcr};
|
||||
use self::madt::{Madt, MadtEntry};
|
||||
use self::rsdt::Rsdt;
|
||||
use self::sdt::Sdt;
|
||||
use self::xsdt::Xsdt;
|
||||
|
||||
pub mod local_apic;
|
||||
pub mod madt;
|
||||
pub mod rsdt;
|
||||
pub mod sdt;
|
||||
pub mod xsdt;
|
||||
|
||||
pub fn init_sdt(sdt: &'static Sdt) {
|
||||
print!(" ");
|
||||
for &c in sdt.signature.iter() {
|
||||
print!("{}", c as char);
|
||||
}
|
||||
println!(":");
|
||||
|
||||
if let Some(madt) = Madt::new(sdt) {
|
||||
println!(" {:>016X}: {}", madt.local_address, madt.flags);
|
||||
|
||||
let mut local_apic = LocalApic::new();
|
||||
|
||||
let me = local_apic.id() as u8;
|
||||
|
||||
for madt_entry in madt.iter() {
|
||||
println!(" {:?}", madt_entry);
|
||||
match madt_entry {
|
||||
MadtEntry::LocalApic(asp_local_apic) => if asp_local_apic.id == me {
|
||||
println!(" This is my local APIC");
|
||||
} else {
|
||||
if asp_local_apic.flags & 1 == 1 {
|
||||
{
|
||||
let icr = 0x00004500 | (asp_local_apic.id as u64) << 32;
|
||||
println!(" Sending IPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
||||
local_apic.set_icr(icr);
|
||||
}
|
||||
{
|
||||
let icr = 0x00004600 | (asp_local_apic.id as u64) << 32;
|
||||
println!(" Sending SIPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr));
|
||||
local_apic.set_icr(icr);
|
||||
}
|
||||
} else {
|
||||
println!(" CPU Disabled");
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}else {
|
||||
println!(" {:?}", sdt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the ACPI tables to gather CPU, interrupt, and timer information
|
||||
pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> Option<Acpi>
|
||||
where A: FrameAllocator
|
||||
{
|
||||
// Stupidity of enormous proportion. Write the halt opcode to the 0'th physical address
|
||||
// so that START IPI's can halt the processor
|
||||
{
|
||||
if active_table.translate_page(Page::containing_address(VirtualAddress::new(0))).is_none() {
|
||||
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0)), entry::PRESENT | entry::WRITABLE, allocator);
|
||||
}
|
||||
unsafe { *(0 as *mut u8) = 0xF4 };
|
||||
}
|
||||
|
||||
let start_addr = 0xE0000;
|
||||
let end_addr = 0xFFFFF;
|
||||
|
||||
|
@ -34,12 +90,12 @@ pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) ->
|
|||
if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
|
||||
println!("{:?}", rsdp);
|
||||
|
||||
let mut get_sdt = |sdt_address: usize| -> &'static SDT {
|
||||
let mut get_sdt = |sdt_address: usize| -> &'static Sdt {
|
||||
if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() {
|
||||
let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address));
|
||||
active_table.identity_map(sdt_frame, entry::PRESENT | entry::NO_EXECUTE, allocator);
|
||||
}
|
||||
unsafe { &*(sdt_address as *const SDT) }
|
||||
&*(sdt_address as *const Sdt)
|
||||
};
|
||||
|
||||
let rxsdt = get_sdt(rsdp.sdt_address());
|
||||
|
@ -48,25 +104,13 @@ pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) ->
|
|||
print!("{}", c as char);
|
||||
}
|
||||
println!(":");
|
||||
if let Some(rsdt) = RSDT::new(rxsdt) {
|
||||
println!("{:?}", rsdt);
|
||||
if let Some(rsdt) = Rsdt::new(rxsdt) {
|
||||
for sdt_address in rsdt.iter() {
|
||||
let sdt = get_sdt(sdt_address);
|
||||
for &c in sdt.signature.iter() {
|
||||
print!("{}", c as char);
|
||||
init_sdt(get_sdt(sdt_address));
|
||||
}
|
||||
println!(":");
|
||||
println!("{:?}", sdt);
|
||||
}
|
||||
} else if let Some(xsdt) = XSDT::new(rxsdt) {
|
||||
println!("{:?}", xsdt);
|
||||
} else if let Some(xsdt) = Xsdt::new(rxsdt) {
|
||||
for sdt_address in xsdt.iter() {
|
||||
let sdt = get_sdt(sdt_address);
|
||||
for &c in sdt.signature.iter() {
|
||||
print!("{}", c as char);
|
||||
}
|
||||
println!(":");
|
||||
println!("{:?}", sdt);
|
||||
init_sdt(get_sdt(sdt_address));
|
||||
}
|
||||
} else {
|
||||
println!("UNKNOWN RSDT OR XSDT SIGNATURE");
|
||||
|
@ -99,7 +143,7 @@ impl RSDP {
|
|||
/// Search for the RSDP
|
||||
pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
|
||||
for i in 0 .. (end_addr + 1 - start_addr)/16 {
|
||||
let mut rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
|
||||
let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
|
||||
if &rsdp.signature == b"RSD PTR " {
|
||||
return Some(*rsdp);
|
||||
}
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
use core::mem;
|
||||
|
||||
use super::sdt::SDT;
|
||||
use super::sdt::Sdt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RSDT(&'static SDT);
|
||||
pub struct Rsdt(&'static Sdt);
|
||||
|
||||
impl RSDT {
|
||||
pub fn new(sdt: &'static SDT) -> Option<RSDT> {
|
||||
impl Rsdt {
|
||||
pub fn new(sdt: &'static Sdt) -> Option<Rsdt> {
|
||||
if &sdt.signature == b"RSDT" {
|
||||
Some(RSDT(sdt))
|
||||
Some(Rsdt(sdt))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> RSDTIter {
|
||||
RSDTIter {
|
||||
pub fn iter(&self) -> RsdtIter {
|
||||
RsdtIter {
|
||||
sdt: self.0,
|
||||
i: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RSDTIter {
|
||||
sdt: &'static SDT,
|
||||
pub struct RsdtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
}
|
||||
|
||||
impl Iterator for RSDTIter {
|
||||
impl Iterator for RsdtIter {
|
||||
type Item = usize;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.i < self.sdt.data_len()/mem::size_of::<u32>() {
|
||||
|
|
|
@ -2,7 +2,7 @@ use core::mem;
|
|||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct SDT {
|
||||
pub struct Sdt {
|
||||
pub signature: [u8; 4],
|
||||
pub length: u32,
|
||||
pub revision: u8,
|
||||
|
@ -14,16 +14,16 @@ pub struct SDT {
|
|||
pub creator_revision: u32
|
||||
}
|
||||
|
||||
impl SDT {
|
||||
impl Sdt {
|
||||
/// Get the address of this tables data
|
||||
pub fn data_address(&'static self) -> usize {
|
||||
self as *const _ as usize + mem::size_of::<SDT>()
|
||||
self as *const _ as usize + mem::size_of::<Sdt>()
|
||||
}
|
||||
|
||||
/// Get the length of this tables data
|
||||
pub fn data_len(&'static self) -> usize {
|
||||
let total_size = self.length as usize;
|
||||
let header_size = mem::size_of::<SDT>();
|
||||
let header_size = mem::size_of::<Sdt>();
|
||||
if total_size >= header_size {
|
||||
total_size - header_size
|
||||
} else {
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
use core::mem;
|
||||
|
||||
use super::sdt::SDT;
|
||||
use super::sdt::Sdt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XSDT(&'static SDT);
|
||||
pub struct Xsdt(&'static Sdt);
|
||||
|
||||
impl XSDT {
|
||||
pub fn new(sdt: &'static SDT) -> Option<XSDT> {
|
||||
impl Xsdt {
|
||||
pub fn new(sdt: &'static Sdt) -> Option<Xsdt> {
|
||||
if &sdt.signature == b"XSDT" {
|
||||
Some(XSDT(sdt))
|
||||
Some(Xsdt(sdt))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> XSDTIter {
|
||||
XSDTIter {
|
||||
pub fn iter(&self) -> XsdtIter {
|
||||
XsdtIter {
|
||||
sdt: self.0,
|
||||
i: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XSDTIter {
|
||||
sdt: &'static SDT,
|
||||
pub struct XsdtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
}
|
||||
|
||||
impl Iterator for XSDTIter {
|
||||
impl Iterator for XsdtIter {
|
||||
type Item = usize;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.i < self.sdt.data_len()/mem::size_of::<u64>() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use core::mem;
|
||||
|
||||
use interrupt::halt;
|
||||
|
||||
pub static mut IDTR: IdtDescriptor = IdtDescriptor {
|
||||
size: 0,
|
||||
offset: 0
|
||||
|
@ -12,6 +14,8 @@ pub unsafe fn init() {
|
|||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||
entry.set_offset(8, exception as usize);
|
||||
}
|
||||
IDT[13].set_offset(8, protection_fault as usize);
|
||||
IDT[14].set_offset(8, page_fault as usize);
|
||||
for entry in IDT[32..].iter_mut() {
|
||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||
entry.set_offset(8, blank as usize);
|
||||
|
@ -26,7 +30,24 @@ interrupt!(blank, {
|
|||
});
|
||||
|
||||
interrupt!(exception, {
|
||||
panic!("EXCEPTION");
|
||||
println!("EXCEPTION");
|
||||
loop {
|
||||
halt();
|
||||
}
|
||||
});
|
||||
|
||||
interrupt_error!(protection_fault, {
|
||||
println!("PROTECTION FAULT");
|
||||
loop {
|
||||
halt();
|
||||
}
|
||||
});
|
||||
|
||||
interrupt_error!(page_fault, {
|
||||
println!("PAGE FAULT");
|
||||
loop {
|
||||
halt();
|
||||
}
|
||||
});
|
||||
|
||||
bitflags! {
|
||||
|
|
|
@ -39,6 +39,7 @@ macro_rules! interrupt {
|
|||
($name:ident, $func:block) => {
|
||||
#[naked]
|
||||
pub unsafe extern fn $name () {
|
||||
#[inline(never)]
|
||||
unsafe fn inner() {
|
||||
$func
|
||||
}
|
||||
|
@ -76,6 +77,51 @@ macro_rules! interrupt {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! interrupt_error {
|
||||
($name:ident, $func:block) => {
|
||||
#[naked]
|
||||
pub unsafe extern fn $name () {
|
||||
#[inline(never)]
|
||||
unsafe fn inner() {
|
||||
$func
|
||||
}
|
||||
|
||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||
|
||||
// Push scratch registers, grab stack pointer
|
||||
asm!("push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rdi
|
||||
push rsi
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11"
|
||||
: : : : "intel", "volatile");
|
||||
|
||||
|
||||
// Call inner rust function
|
||||
inner();
|
||||
|
||||
// Pop scratch registers, error code, and return
|
||||
asm!("pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
add rsp, 8
|
||||
iretq"
|
||||
: : : : "intel", "volatile");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// ACPI table parsing
|
||||
pub mod acpi;
|
||||
|
||||
|
|
Loading…
Reference in a new issue