use std::convert::TryFrom; use std::fs::File; use std::mem; use std::ops::ControlFlow; use std::os::unix::io::AsRawFd; use std::sync::Arc; use ::acpi::aml::op_region::{RegionHandler, RegionSpace}; use event::{EventFlags, RawEventQueue}; use redox_scheme::{scheme::register_sync_scheme, Socket}; use scheme_utils::Blocking; mod acpi; mod aml_physmem; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod ec; mod scheme; fn daemon(daemon: daemon::Daemon) -> ! { common::setup_logging( "misc", "acpi", "acpid", common::output_level(), common::file_level(), ); log::info!("acpid start"); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") .into(); if rxsdt_raw_data.is_empty() { log::info!("System doesn't use ACPI"); daemon.ready(); std::process::exit(0); } let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT"); let mut thirty_two_bit; let mut sixty_four_bit; let physaddrs_iter = match &sdt.signature { b"RSDT" => { thirty_two_bit = sdt .data() .chunks(mem::size_of::()) // TODO: With const generics, the compiler has some way of doing this for static sizes. .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) .map(|chunk| u32::from_le_bytes(chunk)) .map(u64::from); &mut thirty_two_bit as &mut dyn Iterator } b"XSDT" => { sixty_four_bit = sdt .data() .chunks(mem::size_of::()) .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) .map(|chunk| u64::from_le_bytes(chunk)); &mut sixty_four_bit as &mut dyn Iterator } _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), }; let region_handlers: Vec<(RegionSpace, Box)> = vec![ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] (RegionSpace::EmbeddedControl, Box::new(ec::Ec::new())), ]; let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter, region_handlers); // TODO: I/O permission bitmap? #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop") .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`"); let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue"); let socket = Socket::nonblock().expect("acpid: failed to create disk scheme"); let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket); let mut handler = Blocking::new(&socket, 16); event_queue .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) .expect("acpid: failed to register shutdown pipe for event queue"); event_queue .subscribe(socket.inner().raw(), 1, EventFlags::READ) .expect("acpid: failed to register scheme socket for event queue"); register_sync_scheme(&socket, "acpi", &mut scheme) .expect("acpid: failed to register acpi scheme to namespace"); daemon.ready(); libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); let mut mounted = true; while mounted { let Some(event) = event_queue .next() .transpose() .expect("acpid: failed to read event file") else { break; }; if event.fd == socket.inner().raw() { loop { match handler .process_requests_nonblocking(&mut scheme) .expect("acpid: failed to process requests") { ControlFlow::Continue(()) => {} ControlFlow::Break(()) => break, } } } else if event.fd == shutdown_pipe.as_raw_fd() as usize { log::info!("Received shutdown request from kernel."); mounted = false; } else { log::debug!("Received request to unknown fd: {}", event.fd); continue; } } drop(shutdown_pipe); drop(event_queue); acpi_context.set_global_s_state(5); unreachable!("System should have shut down before this is entered"); } fn main() { common::init(); daemon::Daemon::new(daemon); }