milestone: desktop path Phases 1-5
Phase 1 (Runtime Substrate): 4 check binaries, --probe, POSIX tests Phase 2 (Wayland Compositor): bounded scaffold, zero warnings Phase 3 (KWin Session): preflight checker (KWin stub, gated on Qt6Quick) Phase 4 (KDE Plasma): 18 KF6 enabled, preflight checker Phase 5 (Hardware GPU): DRM/firmware/Mesa preflight checker Build: zero warnings, all scripts syntax-clean. Oracle-verified.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
use amlserde::{AmlSerde, AmlSerdeValue};
|
||||
use std::{error::Error, fs, process::Command};
|
||||
|
||||
use super::Backend;
|
||||
|
||||
pub struct AcpiBackend {
|
||||
rxsdt: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Backend for AcpiBackend {
|
||||
fn new() -> Result<Self, Box<dyn Error>> {
|
||||
let rxsdt = fs::read("/scheme/kernel.acpi/rxsdt")?;
|
||||
|
||||
// Spawn acpid
|
||||
//TODO: pass rxsdt data to acpid?
|
||||
#[allow(deprecated, reason = "we can't yet move this to init")]
|
||||
daemon::Daemon::spawn(Command::new("acpid"));
|
||||
|
||||
Ok(Self { rxsdt })
|
||||
}
|
||||
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
// Read symbols from acpi scheme
|
||||
let entries = fs::read_dir("/scheme/acpi/symbols")?;
|
||||
// TODO: Reimplement with getdents?
|
||||
let symbols_fd = libredox::Fd::open(
|
||||
"/scheme/acpi/symbols",
|
||||
libredox::flag::O_DIRECTORY | libredox::flag::O_RDONLY,
|
||||
0,
|
||||
)?;
|
||||
for entry_res in entries {
|
||||
let entry = entry_res?;
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with("_CID") || file_name.ends_with("_HID") {
|
||||
let symbol_fd = symbols_fd.openat(file_name, libredox::flag::O_RDONLY, 0)?;
|
||||
let stat = symbol_fd.stat()?;
|
||||
let mut buf: Vec<u8> = vec![0u8; stat.st_size as usize];
|
||||
let count = symbol_fd.read(&mut buf)?;
|
||||
buf.truncate(count);
|
||||
let ron = String::from_utf8(buf)?;
|
||||
let AmlSerde { name, value } = ron::from_str(&ron)?;
|
||||
let id = match value {
|
||||
AmlSerdeValue::Integer(integer) => {
|
||||
let vendor = integer & 0xFFFF;
|
||||
let device = (integer >> 16) & 0xFFFF;
|
||||
let vendor_rev = ((vendor & 0xFF) << 8) | vendor >> 8;
|
||||
let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char;
|
||||
let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char;
|
||||
let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char;
|
||||
//TODO: simplify this nibble swap
|
||||
let device_1 = (device >> 4) & 0xF;
|
||||
let device_2 = (device >> 0) & 0xF;
|
||||
let device_3 = (device >> 12) & 0xF;
|
||||
let device_4 = (device >> 8) & 0xF;
|
||||
format!(
|
||||
"{}{}{}{:01X}{:01X}{:01X}{:01X}",
|
||||
vendor_1,
|
||||
vendor_2,
|
||||
vendor_3,
|
||||
device_1,
|
||||
device_2,
|
||||
device_3,
|
||||
device_4
|
||||
)
|
||||
}
|
||||
AmlSerdeValue::String(string) => string,
|
||||
_ => {
|
||||
log::warn!("{}: unsupported value {:x?}", name, value);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let what = match id.as_str() {
|
||||
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html
|
||||
"ACPI0003" => "Power source",
|
||||
"ACPI0006" => "GPE block",
|
||||
"ACPI0007" => "Processor",
|
||||
"ACPI0010" => "Processor control",
|
||||
// https://uefi.org/sites/default/files/resources/devids%20%285%29.txt
|
||||
"PNP0000" => "AT interrupt controller",
|
||||
"PNP0100" => "AT timer",
|
||||
"PNP0103" => "HPET",
|
||||
"PNP0200" => "AT DMA controller",
|
||||
"PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)",
|
||||
"PNP030B" => "PS/2 keyboard",
|
||||
"PNP0400" => "Standard LPT printer port",
|
||||
"PNP0501" => "16550A-compatible COM port",
|
||||
"PNP0A03" | "PNP0A08" => "PCI bus",
|
||||
"PNP0A05" => "Generic ACPI bus",
|
||||
"PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)",
|
||||
"PNP0B00" => "AT real-time clock",
|
||||
"PNP0C01" => "System board",
|
||||
"PNP0C02" => "Reserved resources",
|
||||
"PNP0C04" => "Math coprocessor",
|
||||
"PNP0C09" => "Embedded controller",
|
||||
"PNP0C0A" => "Battery",
|
||||
"PNP0C0B" => "Fan",
|
||||
"PNP0C0C" => "Power button",
|
||||
"PNP0C0D" => "Lid sensor",
|
||||
"PNP0C0E" => "Sleep button",
|
||||
"PNP0C0F" => "PCI interrupt link",
|
||||
"PNP0C50" => "I2C HID",
|
||||
"PNP0F13" => "PS/2 port for PS/2-style mouse",
|
||||
_ => "?",
|
||||
};
|
||||
log::debug!("{}: {} ({})", name, id, what);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use std::{error::Error, fs};
|
||||
|
||||
use super::Backend;
|
||||
|
||||
pub struct DeviceTreeBackend {
|
||||
dtb: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DeviceTreeBackend {
|
||||
fn dump(node: &fdt::node::FdtNode<'_, '_>, level: usize) {
|
||||
let mut line = String::new();
|
||||
for _ in 0..level {
|
||||
line.push_str(" ");
|
||||
}
|
||||
line.push_str(node.name);
|
||||
if let Some(compatible) = node.compatible() {
|
||||
line.push_str(":");
|
||||
for id in compatible.all() {
|
||||
line.push_str(" ");
|
||||
line.push_str(id);
|
||||
}
|
||||
}
|
||||
log::debug!("{}", line);
|
||||
for child in node.children() {
|
||||
Self::dump(&child, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend for DeviceTreeBackend {
|
||||
fn new() -> Result<Self, Box<dyn Error>> {
|
||||
let dtb = fs::read("/scheme/kernel.dtb")?;
|
||||
let dt = fdt::Fdt::new(&dtb).map_err(|err| format!("failed to parse dtb: {}", err))?;
|
||||
Ok(Self { dtb })
|
||||
}
|
||||
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?;
|
||||
let root = dt
|
||||
.find_node("/")
|
||||
.ok_or_else(|| format!("failed to find root node"))?;
|
||||
Self::dump(&root, 0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use std::error::Error;
|
||||
|
||||
use super::Backend;
|
||||
|
||||
pub struct LegacyBackend;
|
||||
|
||||
impl Backend for LegacyBackend {
|
||||
fn new() -> Result<Self, Box<dyn Error>> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
log::info!("TODO: handle driver spawning from legacy backend");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use std::error::Error;
|
||||
|
||||
mod acpi;
|
||||
mod devicetree;
|
||||
mod legacy;
|
||||
|
||||
pub use self::{acpi::AcpiBackend, devicetree::DeviceTreeBackend, legacy::LegacyBackend};
|
||||
|
||||
pub trait Backend {
|
||||
fn new() -> Result<Self, Box<dyn Error>>
|
||||
where
|
||||
Self: Sized;
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use std::process;
|
||||
|
||||
mod backend;
|
||||
use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend};
|
||||
|
||||
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
common::setup_logging(
|
||||
"misc",
|
||||
"hwd",
|
||||
"hwd",
|
||||
common::output_level(),
|
||||
common::file_level(),
|
||||
);
|
||||
|
||||
// Prefer DTB if available (matches kernel preference)
|
||||
let mut backend: Box<dyn Backend> = match DeviceTreeBackend::new() {
|
||||
Ok(ok) => {
|
||||
log::info!("using devicetree backend");
|
||||
Box::new(ok)
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!("cannot use devicetree backend: {}", err);
|
||||
match AcpiBackend::new() {
|
||||
Ok(ok) => {
|
||||
log::info!("using ACPI backend");
|
||||
Box::new(ok)
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!("cannot use ACPI backend: {}", err);
|
||||
|
||||
log::info!("using legacy backend");
|
||||
Box::new(LegacyBackend)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//TODO: launch pcid based on backend information?
|
||||
// Must launch after acpid but before probe calls /scheme/acpi/symbols
|
||||
#[allow(deprecated, reason = "we can't yet move this to init")]
|
||||
daemon::Daemon::spawn(process::Command::new("pcid"));
|
||||
|
||||
daemon.ready();
|
||||
|
||||
//TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers
|
||||
match backend.probe() {
|
||||
Ok(()) => {
|
||||
process::exit(0);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to probe with error {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
daemon::Daemon::new(daemon);
|
||||
}
|
||||
Reference in New Issue
Block a user