b9874d0941
Add redbear-usb-storage-check in-guest binary that validates USB mass storage read and write I/O: discovers /scheme/disk/ devices, writes a test pattern to sector 2048, reads it back, verifies match, restores original content. Updates test-usb-storage-qemu.sh with write-proof verification step. Includes all accumulated Red Bear OS work: kernel patches, relibc patches, driver infrastructure, DRM/GPU, KDE recipes, firmware, validation tooling, build system hardening, and documentation.
144 lines
4.6 KiB
Rust
144 lines
4.6 KiB
Rust
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::<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 region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler + 'static>)> = 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);
|
|
}
|