42-archive/kernel-rs/src/acpi/mod.rs
2019-02-02 18:46:41 +01:00

167 lines
4.2 KiB
Rust

mod rsdp;
mod rsdt;
mod xsdt;
mod fadt;
mod dsdt;
use core;
use core::mem;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct ACPISDTHeader {
signature: [u8; 4],
length: u32,
revision: u8,
checksum: u8,
oemid: [u8; 6],
oemtableid: [u8; 8],
oemrevision: u32,
creatorid: u32,
creatorrevision: u32,
}
impl ACPISDTHeader {
pub fn valid(addr: u32, signature: &str) -> bool {
if check_signature(addr, signature) {
let ptr_tmp = addr as *const ACPISDTHeader;
if check_checksum(addr, unsafe { (*ptr_tmp).length } as usize) {
return true;
}
}
return false;
}
}
static mut ACPI: Acpi = Acpi {
valid: false,
v2: false,
};
struct Acpi {
valid: bool,
v2: bool,
}
impl Acpi {
fn common_init(&mut self) -> Result<(), &'static str> {
if self.v2 {
// Xsdt Address:
// 64-bit physical address of the XSDT table. If you detect ACPI Version 2.0 you should use this table instead of RSDT even on x86, casting the address to uint32_t.
xsdt::init(rsdp::xsdtaddr()?)?;
fadt::init(xsdt::iter()?)?;
} else {
rsdt::init(rsdp::rsdtaddr()?)?;
fadt::init(rsdt::iter()?)?;
}
dsdt::init(fadt::dsdtaddr()?)?;
self.valid = true;
Ok(())
}
fn init(&mut self) -> Result<(), &'static str> {
self.v2 = rsdp::init()?;
self.common_init()
}
fn load(&mut self, rsdp_addr: u32) -> Result<(), &'static str> {
self.v2 = rsdp::load(rsdp_addr)?;
self.common_init()
}
}
fn check_signature(addr: u32, id: &str) -> bool {
let signature = match core::str::from_utf8(unsafe {
core::slice::from_raw_parts_mut(addr as *mut u8, id.len())
}) {
Ok(y) => y,
Err(_) => return false,
};
return signature == id;
}
fn check_checksum(addr: u32, len: usize) -> bool {
let byte_array = unsafe { core::slice::from_raw_parts_mut(addr as *mut u8, len) };
let mut sum: u32 = 0;
for byte in byte_array {
sum += *byte as u32;
}
return sum as u8 == 0;
}
pub struct ACPISDTIter {
pos: usize,
width: usize,
sdt: u32,
len: usize,
}
impl ACPISDTIter {
fn new(
acpi_sdt: Option<*const ACPISDTHeader>,
ptr_len: usize,
) -> Result<ACPISDTIter, &'static str> {
match acpi_sdt {
None => Err("There is no ACPI System Description Table (ACPISDTHeader) to iter on."),
Some(ptr) => Ok(ACPISDTIter {
pos: 0,
width: ptr_len,
sdt: ptr as u32 + mem::size_of::<ACPISDTHeader>() as u32,
len: (unsafe { (*ptr).length } as usize - mem::size_of::<ACPISDTHeader>())
/ ptr_len,
}),
}
}
}
impl Iterator for ACPISDTIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.pos += 1;
if self.pos > self.len {
return None;
}
let ret = Some(unsafe { *(self.sdt as *const u32) });
self.sdt += self.width as u32;
return ret;
}
}
/// Initalized the ACPI module
pub fn init() -> Result<(), &'static str> {
if unsafe{ACPI.valid} { return Ok(()); }
unsafe { ACPI.init() }
}
/// Load the ACPI module, addr given is a ptr to RSDP
pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
if unsafe{!ACPI.valid} { return Ok(()); }
unsafe { ACPI.load(rsdp_addr) }
}
/// Proceed to ACPI shutdown
/// This function doesn't work with Virtual Box yet
pub fn shutdown() {
if unsafe{!ACPI.valid} { return; }
dsdt::shutdown(fadt::get_controlblock().unwrap()).unwrap();
}
/// Proceed to ACPI reboot
/// This function need ACPI in v2
pub fn reboot() {
if unsafe {!ACPI.valid} { println!("ACPI not initialized"); }
if unsafe { ACPI.v2 } {
fadt::reboot().unwrap()
} else {
println!("ACPI reboot only available in ACPI v2+");
}
}
/// Display state of ACPI
pub fn info() {
if unsafe { !ACPI.valid } { println!("ACPI not initialized"); return }
match fadt::is_enable() {
Ok(true) => println!("ACPI is disabled"),
Ok(false) => println!("ACPI is disabled"),
Err(msg) => println!("error while checking ACPI: {}", msg)
}
}