Changes to allow for detection and init of ASPs

This commit is contained in:
Jeremy Soller 2016-08-16 18:04:15 -06:00
parent 7b2acdd79c
commit 08900d56c8
9 changed files with 343 additions and 48 deletions

View file

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

View 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) }
}
}

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

View file

@ -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);
}
println!(":");
println!("{:?}", sdt);
init_sdt(get_sdt(sdt_address));
}
} 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);
}

View file

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

View file

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

View file

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

View file

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

View file

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