From 1bcc7f96f42be809792baaf22b487901e4c9d36f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Dec 2016 17:21:16 -0700 Subject: [PATCH] Parse FADT --- arch/x86_64/src/acpi/fadt.rs | 96 ++++++++++++++++++++++++++++++++++++ arch/x86_64/src/acpi/mod.rs | 6 ++- arch/x86_64/src/lib.rs | 3 ++ arch/x86_64/src/stop.rs | 23 +++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/src/acpi/fadt.rs create mode 100644 arch/x86_64/src/stop.rs diff --git a/arch/x86_64/src/acpi/fadt.rs b/arch/x86_64/src/acpi/fadt.rs new file mode 100644 index 0000000..d40d5a1 --- /dev/null +++ b/arch/x86_64/src/acpi/fadt.rs @@ -0,0 +1,96 @@ +use core::{mem, ptr}; + +use super::sdt::Sdt; + +#[repr(packed)] +#[derive(Debug)] +pub struct Fadt { + pub header: Sdt, + pub firmware_ctrl: u32, + pub dsdt: u32, + + // field used in ACPI 1.0; no longer in use, for compatibility only + reserved: u8, + + pub preferred_power_managament: u8, + pub sci_interrupt: u16, + pub smi_command_port: u32, + pub acpi_enable: u8, + pub acpi_disable: u8, + pub s4_bios_req: u8, + pub pstate_control: u8, + pub pm1a_event_block: u32, + pub pm1b_event_block: u32, + pub pm1a_control_block: u32, + pub pm1b_control_block: u32, + pub pm2_control_block: u32, + pub pm_timer_block: u32, + pub gpe0_block: u32, + pub gpe1_block: u32, + pub pm1_event_length: u8, + pub pm1_control_length: u8, + pub pm2_control_length: u8, + pub pm_timer_length: u8, + pub gpe0_ength: u8, + pub gpe1_length: u8, + pub gpe1_base: u8, + pub c_state_control: u8, + pub worst_c2_latency: u16, + pub worst_c3_latency: u16, + pub flush_size: u16, + pub flush_stride: u16, + pub duty_offset: u8, + pub duty_width: u8, + pub day_alarm: u8, + pub month_alarm: u8, + pub century: u8, + + // reserved in ACPI 1.0; used since ACPI 2.0+ + pub boot_architecture_flags: u16, + + reserved2: u8, + pub flags: u32, +} + +/* ACPI 2 structure +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct GenericAddressStructure { + address_space: u8, + bit_width: u8, + bit_offset: u8, + access_size: u8, + address: u64, +} + +{ + // 12 byte structure; see below for details + pub reset_reg: GenericAddressStructure, + + pub reset_value: u8, + reserved3: [u8; 3], + + // 64bit pointers - Available on ACPI 2.0+ + pub x_firmware_control: u64, + pub x_dsdt: u64, + + pub x_pm1a_event_block: GenericAddressStructure, + pub x_pm1b_event_block: GenericAddressStructure, + pub x_pm1a_control_block: GenericAddressStructure, + pub x_pm1b_control_block: GenericAddressStructure, + pub x_pm2_control_block: GenericAddressStructure, + pub x_pm_timer_block: GenericAddressStructure, + pub x_gpe0_block: GenericAddressStructure, + pub x_gpe1_block: GenericAddressStructure, +} +*/ + +impl Fadt { + pub fn new(sdt: &'static Sdt) -> Option { + if &sdt.signature == b"FACP" && sdt.length as usize >= mem::size_of::() { + Some(unsafe { ptr::read((sdt as *const Sdt) as *const Fadt) }) + } else { + None + } + } +} diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs index 8411f1c..87f4416 100644 --- a/arch/x86_64/src/acpi/mod.rs +++ b/arch/x86_64/src/acpi/mod.rs @@ -11,12 +11,14 @@ use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use start::{kstart_ap, CPU_COUNT, AP_READY}; use self::dmar::{Dmar, DmarEntry}; +use self::fadt::Fadt; use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; pub mod dmar; +pub mod fadt; pub mod madt; pub mod rsdt; pub mod sdt; @@ -31,7 +33,9 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { print!("{}", c as char); } - if let Some(madt) = Madt::new(sdt) { + if let Some(fadt) = Fadt::new(sdt) { + println!(": {:#?}", fadt); + } else if let Some(madt) = Madt::new(sdt) { println!(": {:>08X}: {}", madt.local_address, madt.flags); let mut local_apic = unsafe { &mut LOCAL_APIC }; diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 21be1a1..dc30d69 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -316,5 +316,8 @@ pub mod panic; /// Initialization and start function pub mod start; +/// Shutdown function +pub mod stop; + /// Time pub mod time; diff --git a/arch/x86_64/src/stop.rs b/arch/x86_64/src/stop.rs new file mode 100644 index 0000000..5af92ae --- /dev/null +++ b/arch/x86_64/src/stop.rs @@ -0,0 +1,23 @@ +use io::{Io, Pio}; + +#[no_mangle] +pub unsafe extern fn kstop() -> ! { + // (phony) ACPI shutdown (http://forum.osdev.org/viewtopic.php?t=16990) + // Works for qemu and bochs. + for &port in [0x604, 0xB004].iter() { + println!("Shutdown with outw(0x{:X}, 0x{:X})", port, 0x2000); + Pio::::new(port).write(0x2000); + } + + // Magic shutdown code for bochs and qemu (older versions). + for c in "Shutdown".bytes() { + println!("Shutdown with outb(0x{:X}, '{}')", 0x8900, c as char); + Pio::::new(0x8900).write(c); + } + + // Magic code for VMWare. Also a hard lock. + println!("Shutdown with cli hlt"); + asm!("cli; hlt" : : : : "intel", "volatile"); + + unreachable!(); +}