Files
RedBear-OS/acpid/src/main.rs
T
2021-03-10 20:50:16 +01:00

226 lines
7.1 KiB
Rust

#![feature(renamed_spin_loop, seek_convenience)]
use std::convert::{TryFrom, TryInto};
use std::io::prelude::*;
use std::fs::{File, OpenOptions};
use std::mem;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::sync::Arc;
use redox_log::RedoxLogger;
use syscall::scheme::SchemeMut;
use syscall::data::{Event, Packet};
use syscall::flag::EventFlags;
mod acpi;
mod aml;
mod scheme;
// TODO: Perhaps use the acpi and aml crates?
fn monotonic() -> (u64, u64) {
use syscall::call::clock_gettime;
use syscall::data::TimeSpec;
use syscall::flag::CLOCK_MONOTONIC;
let mut timespec = TimeSpec::default();
clock_gettime(CLOCK_MONOTONIC, &mut timespec)
.expect("failed to fetch monotonic time");
(timespec.tv_sec as u64, timespec.tv_nsec as u64)
}
fn setup_logging() -> Option<&'static RedoxLogger> {
use redox_log::OutputBuilder;
let mut logger = RedoxLogger::new()
.with_output(
OutputBuilder::stderr()
.with_filter(log::LevelFilter::Trace) // limit global output to important info
.with_ansi_escape_codes()
.flush_on_newline(true)
.build()
);
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") {
Ok(b) => logger = logger.with_output(
// TODO: Add a configuration file for this
b.with_filter(log::LevelFilter::Trace)
.flush_on_newline(true)
.build()
),
Err(error) => eprintln!("Failed to create xhci.log: {}", error),
}
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") {
Ok(b) => logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build()
),
Err(error) => eprintln!("Failed to create acpid.ansi.log: {}", error),
}
match logger.enable() {
Ok(logger_ref) => {
eprintln!("acpid: enabled logger");
Some(logger_ref)
}
Err(error) => {
eprintln!("acpid: failed to set default logger: {}", error);
None
}
}
}
fn main() {
let mut pipes = [0; 2];
syscall::pipe2(&mut pipes, 0).expect("acpid: failed to create synchronization pipe");
let [read_part, write_part] = pipes;
let mut read_part = unsafe { File::from_raw_fd(read_part as RawFd) };
let mut write_part = unsafe { File::from_raw_fd(write_part as RawFd) };
let pid = unsafe { syscall::clone(syscall::CloneFlags::empty()).expect("failed to daemonize acpid") };
if pid != 0 {
drop(write_part);
let mut res = [0];
let bytes_read = read_part.read(&mut res).expect("acpid: failed to read from sync pipe");
let exit_code = if bytes_read == res.len() {
res[0]
} else {
eprintln!("acpid: daemon pipe EOF");
1
};
drop(read_part);
std::process::exit(exit_code.into());
}
drop(read_part);
let mut scheme_socket = OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open(":acpi")
.expect("acpid: failed to open scheme socket");
let _ = write_part.write(&[0]).expect("acpid: failed to write to sync pipe");
drop(write_part);
setup_logging();
let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt")
.expect("acpid: failed to read `kernel/acpi:rxsdt`")
.into();
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::<u32>())
// TODO: With const generics, the compiler has some way of doing this for static sizes.
.map(|chunk| <[u8; mem::size_of::<u32>()]>::try_from(chunk).unwrap())
.map(|chunk| u32::from_le_bytes(chunk))
.map(u64::from);
&mut thirty_two_bit as &mut dyn Iterator<Item = u64>
}
b"XSDT" => {
sixty_four_bit = sdt.data().chunks(mem::size_of::<u64>())
.map(|chunk| <[u8; mem::size_of::<u64>()]>::try_from(chunk).unwrap())
.map(|chunk| u64::from_le_bytes(chunk));
&mut sixty_four_bit as &mut dyn Iterator<Item = u64>
},
_ => panic!("acpid: expected [RX]SDT from kernel to be either of those"),
};
let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter);
// TODO: I/O permission bitmap
unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3");
let shutdown_pipe = File::open("kernel/acpi:kstop")
.expect("acpid: failed to open `kernel/acpi:kstop`");
let mut event_queue = OpenOptions::new()
.write(true)
.read(true)
.create(false)
.open("event:")
.expect("acpid: failed to open event queue");
syscall::setrens(0, 0).expect("acpid: failed to enter null namespace");
let _ = event_queue.write(&Event {
id: shutdown_pipe.as_raw_fd() as usize,
flags: EventFlags::EVENT_READ,
data: 0,
}).expect("acpid: failed to register shutdown pipe for event queue");
let _ = event_queue.write(&Event {
id: scheme_socket.as_raw_fd() as usize,
flags: EventFlags::EVENT_READ,
data: 1,
}).expect("acpid: failed to register scheme socket for event queue");
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context);
let mut event = Event::default();
let mut packet = Packet::default();
loop {
let _ = event_queue.read(&mut event).expect("acpid: failed to read from event queue");
if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize {
break;
}
if !event.flags.contains(EventFlags::EVENT_READ) || event.id != scheme_socket.as_raw_fd() as usize {
continue;
}
let bytes_read = scheme_socket.read(&mut packet).expect("acpid: failed to read from scheme socket");
if bytes_read == 0 {
log::info!("Terminating acpid driver, without shutting down the main system.");
return;
}
if bytes_read < mem::size_of::<Packet>() {
log::error!("Scheme socket read less than a single packet.");
}
scheme.handle(&mut packet);
let bytes_written = scheme_socket.write(&packet).expect("acpid: failed to write to scheme socket");
if bytes_written == 0 {
log::info!("Terminating acpid driver, without shutting down the main system.");
return;
}
if bytes_written < mem::size_of::<Packet>() {
log::error!("Scheme socket read less than a single packet.");
}
}
drop(shutdown_pipe);
drop(event_queue);
aml::set_global_s_state(&acpi_context, 5);
unreachable!("System should have shut down before this is entered");
}