Refactored ACPI initialisation code to be better conducive to DDB Handle stuff

This commit is contained in:
Connor Wood
2017-08-30 19:03:39 +01:00
parent 9f55367906
commit c3d07e4caa
5 changed files with 294 additions and 81 deletions

View File

@@ -5,6 +5,8 @@ use self::drhd::Drhd;
use memory::Frame;
use paging::{entry, ActivePageTable, PhysicalAddress};
use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
pub mod drhd;
/// The DMA Remapping Table
@@ -17,6 +19,38 @@ pub struct Dmar {
}
impl Dmar {
pub fn init(active_table: &mut ActivePageTable) {
if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
let dmar = if let Some(dmar_sdt) = ptrs.get("DMAR") {
Dmar::new(dmar_sdt)
} else {
println!("Unable to find DMAR");
return;
};
if let Some(dmar) = dmar {
println!(" DMAR: {}: {}", dmar.addr_width, dmar.flags);
for dmar_entry in dmar.iter() {
println!(" {:?}", dmar_entry);
match dmar_entry {
DmarEntry::Drhd(dmar_drhd) => {
let drhd = dmar_drhd.get(active_table);
println!("VER: {:X}", drhd.version);
println!("CAP: {:X}", drhd.cap);
println!("EXT_CAP: {:X}", drhd.ext_cap);
println!("GCMD: {:X}", drhd.gl_cmd);
println!("GSTS: {:X}", drhd.gl_sts);
println!("RT: {:X}", drhd.root_table);
},
_ => ()
}
}
}
}
}
pub fn new(sdt: &'static Sdt) -> Option<Dmar> {
if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags
let addr_width = unsafe { *(sdt.data_address() as *const u8) };

View File

@@ -1,6 +1,10 @@
use core::{mem, ptr};
use collections::string::String;
use super::sdt::Sdt;
use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
use paging::ActivePageTable;
#[repr(packed)]
#[derive(Debug)]
@@ -93,4 +97,26 @@ impl Fadt {
None
}
}
pub fn init(active_table: &mut ActivePageTable) {
if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) {
let fadt = if let Some(fadt_sdt) = ptrs.get("FACP") {
Fadt::new(fadt_sdt)
} else {
println!("Unable to find FADT");
return;
};
if let Some(fadt) = fadt {
println!(" FACP: {:X}", fadt.dsdt);
let dsdt_sdt = get_sdt(fadt.dsdt as usize, active_table);
let signature = String::from_utf8(dsdt_sdt.signature.to_vec()).expect("Error converting signature to string");
ptrs.insert(signature, dsdt_sdt);
let mut fadt_t = ACPI_TABLE.fadt.write();
*fadt_t = Some(fadt);
}
}
}
}

View File

@@ -1,11 +1,13 @@
use core::{mem, ptr};
use super::sdt::Sdt;
use core::intrinsics::{volatile_load, volatile_store};
use memory::Frame;
use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress};
use super::sdt::Sdt;
use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct GenericAddressStructure {
@@ -33,6 +35,24 @@ pub struct Hpet {
}
impl Hpet {
pub fn init(active_table: &mut ActivePageTable) {
if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
let hpet = if let Some(hpet_sdt) = ptrs.get("HPET") {
Hpet::new(hpet_sdt, active_table)
} else {
println!("Unable to find HPET");
return;
};
if let Some(hpet) = hpet {
println!(" HPET: {:X}", hpet.hpet_number);
let mut hpet_t = ACPI_TABLE.hpet.write();
*hpet_t = Some(hpet);
}
}
}
pub fn new(sdt: &'static Sdt, active_table: &mut ActivePageTable) -> Option<Hpet> {
if &sdt.signature == b"HPET" && sdt.length as usize >= mem::size_of::<Hpet>() {
let s = unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) };

View File

@@ -1,6 +1,27 @@
use core::mem;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use super::sdt::Sdt;
use super::{ACPI_TABLE, SDT_POINTERS, AP_STARTUP, TRAMPOLINE};
use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
use collections::btree_map::BTreeMap;
use collections::string::String;
use collections::vec::Vec;
use alloc::boxed::Box;
use syscall::io::{Io, Pio};
use spin::RwLock;
use stop::kstop;
use device::local_apic::LOCAL_APIC;
use interrupt;
use start::{kstart_ap, CPU_COUNT, AP_READY};
/// The Multiple APIC Descriptor Table
#[derive(Debug)]
@@ -11,6 +32,123 @@ pub struct Madt {
}
impl Madt {
pub fn init(active_table: &mut ActivePageTable) {
if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
let madt = if let Some(madt_sdt) = ptrs.get("APIC") {
Madt::new(madt_sdt)
} else {
println!("Unable to find MADT");
return;
};
if let Some(madt) = madt {
println!(" APIC: {:>08X}: {}", madt.local_address, madt.flags);
let local_apic = unsafe { &mut LOCAL_APIC };
let me = local_apic.id() as u8;
if local_apic.x2 {
println!(" X2APIC {}", me);
} else {
println!(" XAPIC {}: {:>08X}", me, local_apic.address);
}
if cfg!(feature = "multi_core"){
let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));
// Map trampoline
let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
result.flush(active_table);
for madt_entry in madt.iter() {
println!(" {:?}", madt_entry);
match madt_entry {
MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
println!(" This is my local APIC");
} else {
if ap_local_apic.flags & 1 == 1 {
// Increase CPU ID
CPU_COUNT.fetch_add(1, Ordering::SeqCst);
// Allocate a stack
let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
let stack_end = stack_start + 64 * 4096;
let ap_ready = TRAMPOLINE as *mut u64;
let ap_cpu_id = unsafe { ap_ready.offset(1) };
let ap_page_table = unsafe { ap_ready.offset(2) };
let ap_stack_start = unsafe { ap_ready.offset(3) };
let ap_stack_end = unsafe { ap_ready.offset(4) };
let ap_code = unsafe { ap_ready.offset(5) };
// Set the ap_ready to 0, volatile
unsafe { atomic_store(ap_ready, 0) };
unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
unsafe { atomic_store(ap_stack_start, stack_start as u64) };
unsafe { atomic_store(ap_stack_end, stack_end as u64) };
unsafe { atomic_store(ap_code, kstart_ap as u64) };
AP_READY.store(false, Ordering::SeqCst);
print!(" AP {}:", ap_local_apic.id);
// Send INIT IPI
{
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;
}
print!(" IPI...");
local_apic.set_icr(icr);
}
// Send START IPI
{
//Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
let ap_segment = (AP_STARTUP >> 12) & 0xFF;
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;
}
print!(" SIPI...");
local_apic.set_icr(icr);
}
// Wait for trampoline ready
print!(" Wait...");
while unsafe { atomic_load(ap_ready) } == 0 {
interrupt::pause();
}
print!(" Trampoline...");
while ! AP_READY.load(Ordering::SeqCst) {
interrupt::pause();
}
println!(" Ready");
active_table.flush_all();
} else {
println!(" CPU Disabled");
}
},
_ => ()
}
}
// Unmap trampoline
let (result, _frame) = active_table.unmap_return(trampoline_page, false);
result.flush(active_table);
}
}
}
}
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) };

View File

@@ -5,6 +5,7 @@ use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
use collections::btree_map::BTreeMap;
use collections::string::String;
use collections::vec::Vec;
use alloc::boxed::Box;
use syscall::io::{Io, Pio};
@@ -27,6 +28,7 @@ use self::sdt::Sdt;
use self::xsdt::Xsdt;
use self::hpet::Hpet;
use self::rxsdt::Rxsdt;
use self::rsdp::RSDP;
use self::aml::{is_aml_table, parse_aml_table, AmlError, AmlValue};
@@ -39,6 +41,7 @@ mod sdt;
mod xsdt;
mod aml;
mod rxsdt;
mod rsdp;
const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;
@@ -235,29 +238,68 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
}
}
/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
fn init_aml_table(sdt: &'static Sdt) {
match parse_aml_table(sdt) {
Ok(_) => println!(": Parsed"),
Err(AmlError::AmlParseError(e)) => println!(": {}", e),
Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"),
Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"),
Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"),
Err(AmlError::AmlFatalError(_, _, _)) => {
println!(": Fatal error occurred");
unsafe { kstop(); }
},
Err(AmlError::AmlHardFatal) => {
println!(": Fatal error occurred");
unsafe { kstop(); }
}
}
}
fn init_namespace() {
{
let mut namespace = ACPI_TABLE.namespace.write();
*namespace = Some(BTreeMap::new());
}
let start_addr = 0xE0000;
let end_addr = 0xFFFFF;
// Map all of the ACPI RSDP space
{
let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
for frame in Frame::range_inclusive(start_frame, end_frame) {
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
result.flush(active_table);
let dsdt: &'static Sdt = if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
if let Some(dsdt_sdt) = ptrs.get("DSDT") {
print!(" DSDT");
dsdt_sdt
} else {
println!("No DSDT found");
return;
}
}
} else {
return;
};
init_aml_table(dsdt);
let ssdt: &'static Sdt = if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
if let Some(ssdt_sdt) = ptrs.get("SSDT") {
print!(" SSDT");
ssdt_sdt
} else {
println!("No SSDT found");
return;
}
} else {
return;
};
init_aml_table(ssdt);
}
/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
{
let mut sdt_ptrs = SDT_POINTERS.write();
*sdt_ptrs = Some(BTreeMap::new());
}
// Search for RSDP
if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
if let Some(rsdp) = RSDP::get_rsdp(active_table) {
let rxsdt = get_sdt(rsdp.sdt_address(), active_table);
for &c in rxsdt.signature.iter() {
@@ -273,40 +315,28 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
println!("UNKNOWN RSDT OR XSDT SIGNATURE");
return;
};
{
let mut rxsdt_ptr = ACPI_TABLE.rxsdt.write();
*rxsdt_ptr = Some(rxsdt);
}
{
let rxsdt_ptr = ACPI_TABLE.rxsdt.read();
if let Some(ref rxsdt) = *rxsdt_ptr {
rxsdt.map_all(active_table);
for sdt_address in rxsdt.iter() {
let sdt = unsafe { &*(sdt_address as *const Sdt) };
parse_sdt(sdt, active_table);
rxsdt.map_all(active_table);
for sdt_address in rxsdt.iter() {
let sdt = unsafe { &*(sdt_address as *const Sdt) };
let signature = String::from_utf8(sdt.signature.to_vec()).expect("Error converting signature to string");
{
if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) {
ptrs.insert(signature, sdt);
}
}
}
Fadt::init(active_table);
Madt::init(active_table);
Dmar::init(active_table);
Hpet::init(active_table);
init_namespace();
} else {
println!("NO RSDP FOUND");
}
/* TODO: Cleanup mapping when looking for RSDP
// Unmap all of the ACPI RSDP space
{
let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
for frame in Frame::range_inclusive(start_frame, end_frame) {
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
let result = active_table.unmap(page);
result.flush(active_table);
}
}
*/
}
pub fn set_global_s_state(state: u8) {
@@ -337,6 +367,8 @@ pub fn set_global_s_state(state: u8) {
}
}
pub static SDT_POINTERS: RwLock<Option<BTreeMap<String, &'static Sdt>>> = RwLock::new(None);
pub struct Acpi {
pub rxsdt: RwLock<Option<Box<Rxsdt + Send + Sync>>>,
pub fadt: RwLock<Option<Fadt>>,
@@ -352,40 +384,3 @@ pub static ACPI_TABLE: Acpi = Acpi {
hpet: RwLock::new(None),
next_ctx: RwLock::new(0),
};
/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
signature: [u8; 8],
checksum: u8,
oemid: [u8; 6],
revision: u8,
rsdt_address: u32,
length: u32,
xsdt_address: u64,
extended_checksum: u8,
reserved: [u8; 3]
}
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 rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
if &rsdp.signature == b"RSD PTR " {
return Some(*rsdp);
}
}
None
}
/// Get the RSDT or XSDT address
pub fn sdt_address(&self) -> usize {
if self.revision >= 2 {
self.xsdt_address as usize
} else {
self.rsdt_address as usize
}
}
}