use crate::sys; use acpi::{AcpiHandler, AcpiTables, PhysicalMapping}; use alloc::boxed::Box; use aml::value::AmlValue; use aml::{AmlContext, AmlName, DebugVerbosity, Handler}; use core::ptr::NonNull; use x86_64::instructions::port::Port; use x86_64::PhysAddr; fn read_addr(addr: usize) -> T where T: Copy { let virtual_address = sys::mem::phys_to_virt(PhysAddr::new(addr as u64)); unsafe { *virtual_address.as_ptr::() } } pub fn shutdown() { let mut pm1a_control_block = 0; let mut slp_typa = 0; let slp_len = 1 << 13; log!("ACPI Shutdown"); let res = unsafe { AcpiTables::search_for_rsdp_bios(MorosAcpiHandler) }; match res { Ok(acpi) => { if let Ok(fadt) = acpi.find_table::() { if let Ok(block) = fadt.pm1a_control_block() { pm1a_control_block = block.address as u32; } } if let Ok(dsdt) = &acpi.dsdt() { let phys_addr = PhysAddr::new(dsdt.address as u64); let virt_addr = sys::mem::phys_to_virt(phys_addr); let ptr = virt_addr.as_ptr(); let table = unsafe { core::slice::from_raw_parts(ptr , dsdt.length as usize) }; let handler = Box::new(MorosAmlHandler); let mut aml = AmlContext::new(handler, DebugVerbosity::None); if aml.parse_table(table).is_ok() { let name = AmlName::from_str("\\_S5").unwrap(); let res = aml.namespace.get_by_path(&name); if let Ok(AmlValue::Package(s5)) = res { if let AmlValue::Integer(value) = s5[0] { slp_typa = value as u16; } } } else { debug!("ACPI: Could not parse AML in DSDT"); // FIXME: AML parsing works on QEMU and Bochs but not // on VirtualBox at the moment, so we use the following // hardcoded value: slp_typa = (5 & 7) << 10; } } else { debug!("ACPI: Could not find DSDT in BIOS"); } } Err(_e) => { debug!("ACPI: Could not find RDSP in BIOS"); } }; let mut port: Port = Port::new(pm1a_control_block as u16); unsafe { port.write(slp_typa | slp_len); } } #[derive(Clone)] pub struct MorosAcpiHandler; impl AcpiHandler for MorosAcpiHandler { unsafe fn map_physical_region( &self, addr: usize, size: usize, ) -> PhysicalMapping { let phys_addr = PhysAddr::new(addr as u64); let virt_addr = sys::mem::phys_to_virt(phys_addr); let ptr = NonNull::new(virt_addr.as_mut_ptr()).unwrap(); PhysicalMapping::new(addr, ptr, size, size, Self) } fn unmap_physical_region(_region: &PhysicalMapping) {} } struct MorosAmlHandler; impl Handler for MorosAmlHandler { fn read_u8(&self, address: usize) -> u8 { read_addr::(address) } fn read_u16(&self, address: usize) -> u16 { read_addr::(address) } fn read_u32(&self, address: usize) -> u32 { read_addr::(address) } fn read_u64(&self, address: usize) -> u64 { read_addr::(address) } fn write_u8(&mut self, _: usize, _: u8) { unimplemented!() } fn write_u16(&mut self, _: usize, _: u16) { unimplemented!() } fn write_u32(&mut self, _: usize, _: u32) { unimplemented!() } fn write_u64(&mut self, _: usize, _: u64) { unimplemented!() } fn read_io_u8(&self, _: u16) -> u8 { unimplemented!() } fn read_io_u16(&self, _: u16) -> u16 { unimplemented!() } fn read_io_u32(&self, _: u16) -> u32 { unimplemented!() } fn write_io_u8(&self, _: u16, _: u8) { unimplemented!() } fn write_io_u16(&self, _: u16, _: u16) { unimplemented!() } fn write_io_u32(&self, _: u16, _: u32) { unimplemented!() } fn read_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u8 { unimplemented!() } fn read_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u16 { unimplemented!() } fn read_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u32 { unimplemented!() } fn write_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u8) { unimplemented!() } fn write_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u16) { unimplemented!() } fn write_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u32) { unimplemented!() } }