Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1,261 @@
diff --git a/drivers/inputd/src/main.rs b/drivers/inputd/src/main.rs
--- a/drivers/inputd/src/main.rs
+++ b/drivers/inputd/src/main.rs
@@ -35,6 +35,9 @@
enum Handle {
Producer,
+ NamedProducer {
+ name: String,
+ },
Consumer {
events: EventFlags,
pending: Vec<u8>,
@@ -58,9 +61,11 @@
struct InputScheme {
handles: BTreeMap<usize, Handle>,
+ devices: BTreeMap<String, u32>,
next_id: AtomicUsize,
next_vt_id: AtomicUsize,
+ next_device_id: AtomicUsize,
display: Option<String>,
vts: BTreeSet<usize>,
@@ -73,13 +78,30 @@
has_new_events: bool,
}
+const RESERVED_DEVICE_NAMES: [&str; 7] = [
+ "producer",
+ "consumer",
+ "consumer_bootlog",
+ "events",
+ "handle",
+ "handle_early",
+ "control",
+];
+
+enum ProducerKind {
+ Legacy,
+ Named(String),
+}
+
impl InputScheme {
fn new() -> Self {
Self {
handles: BTreeMap::new(),
+ devices: BTreeMap::new(),
next_id: AtomicUsize::new(0),
next_vt_id: AtomicUsize::new(2), // VT 1 is reserved for the bootlog
+ next_device_id: AtomicUsize::new(0),
display: None,
vts: BTreeSet::new(),
@@ -91,6 +113,46 @@
rshift: false,
has_new_events: false,
}
+ }
+
+ fn register_named_producer(&mut self, name: &str) -> syscall::Result<Handle> {
+ if name.is_empty() || RESERVED_DEVICE_NAMES.contains(&name) {
+ return Err(SysError::new(EINVAL));
+ }
+
+ if self.devices.contains_key(name) {
+ return Err(SysError::new(EEXIST));
+ }
+
+ let device_id = self.next_device_id.fetch_add(1, Ordering::SeqCst) as u32;
+ self.devices.insert(name.to_owned(), device_id);
+ Ok(Handle::NamedProducer {
+ name: name.to_owned(),
+ })
+ }
+
+ fn route_legacy_consumer_events(&mut self, buf: &[u8]) {
+ if let Some(active_vt) = self.active_vt {
+ for handle in self.handles.values_mut() {
+ match handle {
+ Handle::Consumer {
+ pending,
+ notified,
+ vt,
+ ..
+ } if *vt == active_vt => {
+ pending.extend_from_slice(buf);
+ *notified = false;
+ }
+ _ => continue,
+ }
+ }
+ }
+ }
+
+ fn route_named_producer_events(&mut self, _name: &str, _buf: &[u8]) {
+ // DeviceConsumer routing is added in a follow-up patch. Named producers already share the
+ // legacy consumer path, so existing callers continue to receive these events.
}
fn switch_vt(&mut self, new_active: usize) {
@@ -175,7 +237,13 @@
let command = path_parts.next().ok_or(SysError::new(EINVAL))?;
let handle_ty = match command {
- "producer" => Handle::Producer,
+ "producer" => match path_parts.next() {
+ None => Handle::Producer,
+ Some(name) if !name.is_empty() && path_parts.next().is_none() => {
+ self.register_named_producer(name)?
+ }
+ _ => return Err(SysError::new(EINVAL)),
+ },
"consumer" => {
let vt = self.next_vt_id.fetch_add(1, Ordering::Relaxed);
self.vts.insert(vt);
@@ -338,7 +406,7 @@
}
}
- Handle::Producer => {
+ Handle::Producer | Handle::NamedProducer { .. } => {
log::error!("producer tried to read");
return Err(SysError::new(EINVAL));
}
@@ -360,9 +428,7 @@
) -> syscall::Result<usize> {
self.has_new_events = true;
- let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
-
- match handle {
+ let producer_kind = match self.handles.get(&id).ok_or(SysError::new(EINVAL))? {
Handle::Control => {
if buf.len() != size_of::<ControlEvent>() {
log::error!("control tried to write incorrectly sized command");
@@ -391,9 +457,10 @@
log::error!("display tried to write");
return Err(SysError::new(EINVAL));
}
- Handle::Producer => {}
+ Handle::Producer => ProducerKind::Legacy,
+ Handle::NamedProducer { name } => ProducerKind::Named(name.clone()),
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
- }
+ };
if buf.len() == 1 && buf[0] > 0xf4 {
return Ok(1);
@@ -445,9 +512,6 @@
}
}
- let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
- assert!(matches!(handle, Handle::Producer));
-
let buf = unsafe {
core::slice::from_raw_parts(
(events.as_ptr()) as *const u8,
@@ -455,26 +519,11 @@
)
};
- if let Some(active_vt) = self.active_vt {
- for handle in self.handles.values_mut() {
- match handle {
- Handle::Consumer {
- pending,
- notified,
- vt,
- ..
- } => {
- if *vt != active_vt {
- continue;
- }
-
- pending.extend_from_slice(buf);
- *notified = false;
- }
- _ => continue,
- }
- }
- }
+ if let ProducerKind::Named(name) = &producer_kind {
+ self.route_named_producer_events(name, buf);
+ }
+
+ self.route_legacy_consumer_events(buf);
Ok(buf.len())
}
@@ -506,7 +555,7 @@
*notified = false;
Ok(EventFlags::empty())
}
- Handle::Producer | Handle::Control => {
+ Handle::Producer | Handle::NamedProducer { .. } | Handle::Control => {
log::error!("producer or control tried to use an event queue");
Err(SysError::new(EINVAL))
}
@@ -515,9 +564,15 @@
}
fn on_close(&mut self, id: usize) {
- let handle = self.handles.remove(&id).unwrap();
+ let Some(handle) = self.handles.remove(&id) else {
+ log::warn!("received close for unknown input handle {id}");
+ return;
+ };
match handle {
+ Handle::NamedProducer { name } => {
+ self.devices.remove(&name);
+ }
Handle::Consumer { vt, .. } => {
self.vts.remove(&vt);
if self.active_vt == Some(vt) {
diff --git a/drivers/inputd/src/lib.rs b/drivers/inputd/src/lib.rs
--- a/drivers/inputd/src/lib.rs
+++ b/drivers/inputd/src/lib.rs
@@ -197,6 +197,38 @@
pub vt: usize,
}
+/// Handle for opening a named producer on the input scheme.
+/// Opens /scheme/input/producer/{name}
+pub struct NamedProducerHandle {
+ fd: File,
+}
+
+impl NamedProducerHandle {
+ pub fn new(name: &str) -> io::Result<Self> {
+ if name.is_empty() {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "input producer name must not be empty",
+ ));
+ }
+
+ if name.contains('/') {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "input producer name must not contain '/'",
+ ));
+ }
+
+ let path = format!("/scheme/input/producer/{name}");
+ File::open(path).map(|fd| Self { fd })
+ }
+
+ pub fn write_event(&mut self, event: &orbclient::Event) -> io::Result<()> {
+ self.fd.write(unsafe { any_as_u8_slice(event) })?;
+ Ok(())
+ }
+}
+
pub struct ProducerHandle(File);
impl ProducerHandle {
@@ -0,0 +1,450 @@
diff --git a/drivers/inputd/src/main.rs b/drivers/inputd/src/main.rs
--- a/drivers/inputd/src/main.rs
+++ b/drivers/inputd/src/main.rs
@@ -17,7 +17,7 @@
use std::mem::transmute;
use std::sync::atomic::{AtomicUsize, Ordering};
-use inputd::{ControlEvent, VtEvent, VtEventKind};
+use inputd::{ControlEvent, HotplugEventHeader, VtEvent, VtEventKind};
use libredox::errno::ESTALE;
use redox_scheme::scheme::{SchemeState, SchemeSync};
@@ -47,6 +47,17 @@
notified: bool,
vt: usize,
},
+ DeviceConsumer {
+ device_name: String,
+ events: EventFlags,
+ pending: Vec<u8>,
+ notified: bool,
+ },
+ HotplugEvents {
+ events: EventFlags,
+ pending: Vec<u8>,
+ notified: bool,
+ },
Display {
events: EventFlags,
pending: Vec<VtEvent>,
@@ -88,6 +99,9 @@
"control",
];
+const DEVICE_ADD: u32 = 1;
+const DEVICE_REMOVE: u32 = 2;
+
enum ProducerKind {
Legacy,
Named(String),
@@ -116,7 +130,7 @@
}
fn register_named_producer(&mut self, name: &str) -> syscall::Result<Handle> {
- if name.is_empty() || RESERVED_DEVICE_NAMES.contains(&name) {
+ if name.is_empty() || name.contains('/') || RESERVED_DEVICE_NAMES.contains(&name) {
return Err(SysError::new(EINVAL));
}
@@ -126,11 +140,57 @@
let device_id = self.next_device_id.fetch_add(1, Ordering::SeqCst) as u32;
self.devices.insert(name.to_owned(), device_id);
+ self.queue_hotplug_event(DEVICE_ADD, device_id, name)?;
Ok(Handle::NamedProducer {
name: name.to_owned(),
})
}
+ fn drain_pending_bytes(pending: &mut Vec<u8>, buf: &mut [u8]) -> usize {
+ let copy = core::cmp::min(pending.len(), buf.len());
+
+ for (i, byte) in pending.drain(..copy).enumerate() {
+ buf[i] = byte;
+ }
+
+ copy
+ }
+
+ fn queue_hotplug_event(
+ &mut self,
+ kind: u32,
+ device_id: u32,
+ name: &str,
+ ) -> syscall::Result<()> {
+ let name_len = u32::try_from(name.len()).map_err(|_| SysError::new(EINVAL))?;
+ let header = HotplugEventHeader {
+ kind,
+ device_id,
+ name_len,
+ _reserved: 0,
+ };
+ let header_bytes = unsafe {
+ core::slice::from_raw_parts(
+ (&header as *const HotplugEventHeader).cast::<u8>(),
+ size_of::<HotplugEventHeader>(),
+ )
+ };
+
+ for handle in self.handles.values_mut() {
+ if let Handle::HotplugEvents {
+ pending, notified, ..
+ } = handle
+ {
+ pending.extend_from_slice(header_bytes);
+ pending.extend_from_slice(name.as_bytes());
+ *notified = false;
+ }
+ }
+
+ self.has_new_events = true;
+ Ok(())
+ }
+
fn route_legacy_consumer_events(&mut self, buf: &[u8]) {
if let Some(active_vt) = self.active_vt {
for handle in self.handles.values_mut() {
@@ -150,9 +210,21 @@
}
}
- fn route_named_producer_events(&mut self, _name: &str, _buf: &[u8]) {
- // DeviceConsumer routing is added in a follow-up patch. Named producers already share the
- // legacy consumer path, so existing callers continue to receive these events.
+ fn route_named_producer_events(&mut self, name: &str, buf: &[u8]) {
+ for handle in self.handles.values_mut() {
+ match handle {
+ Handle::DeviceConsumer {
+ device_name,
+ pending,
+ notified,
+ ..
+ } if device_name == name => {
+ pending.extend_from_slice(buf);
+ *notified = false;
+ }
+ _ => continue,
+ }
+ }
}
fn switch_vt(&mut self, new_active: usize) {
@@ -324,7 +396,24 @@
is_earlyfb: command == "handle_early",
}
}
+ "events" if path_parts.next().is_none() => Handle::HotplugEvents {
+ events: EventFlags::empty(),
+ pending: Vec::new(),
+ notified: false,
+ },
"control" => Handle::Control,
+ device_name
+ if !device_name.is_empty()
+ && !RESERVED_DEVICE_NAMES.contains(&device_name)
+ && path_parts.next().is_none() =>
+ {
+ Handle::DeviceConsumer {
+ device_name: device_name.to_owned(),
+ events: EventFlags::empty(),
+ pending: Vec::new(),
+ notified: false,
+ }
+ }
_ => {
log::error!("invalid path '{path}'");
@@ -380,13 +469,11 @@
return Err(SysError::new(ESTALE));
}
- let copy = core::cmp::min(pending.len(), buf.len());
-
- for (i, byte) in pending.drain(..copy).enumerate() {
- buf[i] = byte;
- }
+ Ok(Self::drain_pending_bytes(pending, buf))
+ }
- Ok(copy)
+ Handle::DeviceConsumer { pending, .. } | Handle::HotplugEvents { pending, .. } => {
+ Ok(Self::drain_pending_bytes(pending, buf))
}
Handle::Display { pending, .. } => {
@@ -453,6 +540,10 @@
log::error!("consumer tried to write");
return Err(SysError::new(EINVAL));
}
+ Handle::DeviceConsumer { .. } | Handle::HotplugEvents { .. } => {
+ log::error!("consumer or hotplug handle tried to write");
+ return Err(SysError::new(EINVAL));
+ }
Handle::Display { .. } => {
log::error!("display tried to write");
return Err(SysError::new(EINVAL));
@@ -541,6 +632,16 @@
ref mut events,
ref mut notified,
..
+ }
+ | Handle::DeviceConsumer {
+ ref mut events,
+ ref mut notified,
+ ..
+ }
+ | Handle::HotplugEvents {
+ ref mut events,
+ ref mut notified,
+ ..
} => {
*events = flags;
*notified = false;
@@ -571,7 +672,12 @@
match handle {
Handle::NamedProducer { name } => {
- self.devices.remove(&name);
+ if let Some(device_id) = self.devices.remove(&name) {
+ self.queue_hotplug_event(DEVICE_REMOVE, device_id, &name)
+ .unwrap_or_else(|err| {
+ log::error!("failed to queue removal hotplug event for {name}: {err}");
+ });
+ }
}
Handle::Consumer { vt, .. } => {
self.vts.remove(&vt);
@@ -658,6 +764,28 @@
socket_file.write_response(
Response::post_fevent(*id, EventFlags::EVENT_READ.bits()),
SignalBehavior::Restart,
+ )?;
+
+ *notified = true;
+ }
+ Handle::DeviceConsumer {
+ events,
+ pending,
+ ref mut notified,
+ ..
+ }
+ | Handle::HotplugEvents {
+ events,
+ pending,
+ ref mut notified,
+ } => {
+ if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) {
+ continue;
+ }
+
+ socket_file.write_response(
+ Response::post_fevent(*id, EventFlags::EVENT_READ.bits()),
+ SignalBehavior::Restart,
)?;
*notified = true;
diff --git a/drivers/inputd/src/lib.rs b/drivers/inputd/src/lib.rs
--- a/drivers/inputd/src/lib.rs
+++ b/drivers/inputd/src/lib.rs
@@ -1,5 +1,5 @@
use std::fs::{File, OpenOptions};
-use std::io::{self, Read, Write};
+use std::io::{self, ErrorKind, Read, Write};
use std::mem::size_of;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
use std::os::unix::fs::OpenOptionsExt;
@@ -31,6 +31,24 @@
slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::<T>())
}
+fn validate_input_name(kind: &str, name: &str) -> io::Result<()> {
+ if name.is_empty() {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ format!("input {kind} name must not be empty"),
+ ));
+ }
+
+ if name.contains('/') {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ format!("input {kind} name must not contain '/'"),
+ ));
+ }
+
+ Ok(())
+}
+
pub struct ConsumerHandle(File);
pub enum ConsumerHandleEvent<'a> {
@@ -197,6 +215,22 @@
pub vt: usize,
}
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct HotplugEventHeader {
+ pub kind: u32,
+ pub device_id: u32,
+ pub name_len: u32,
+ pub _reserved: u32,
+}
+
+#[derive(Debug, Clone)]
+pub struct HotplugEvent {
+ pub kind: u32,
+ pub device_id: u32,
+ pub name: String,
+}
+
/// Handle for opening a named producer on the input scheme.
/// Opens /scheme/input/producer/{name}
pub struct NamedProducerHandle {
@@ -205,19 +239,7 @@
impl NamedProducerHandle {
pub fn new(name: &str) -> io::Result<Self> {
- if name.is_empty() {
- return Err(io::Error::new(
- io::ErrorKind::InvalidInput,
- "input producer name must not be empty",
- ));
- }
-
- if name.contains('/') {
- return Err(io::Error::new(
- io::ErrorKind::InvalidInput,
- "input producer name must not contain '/'",
- ));
- }
+ validate_input_name("producer", name)?;
let path = format!("/scheme/input/producer/{name}");
File::open(path).map(|fd| Self { fd })
@@ -229,6 +251,124 @@
}
}
+pub struct DeviceConsumerHandle {
+ fd: File,
+}
+
+impl DeviceConsumerHandle {
+ pub fn new(device_name: &str) -> io::Result<Self> {
+ validate_input_name("device", device_name)?;
+
+ let fd = OpenOptions::new()
+ .read(true)
+ .custom_flags(O_NONBLOCK as i32)
+ .open(format!("/scheme/input/{device_name}"))?;
+
+ Ok(Self { fd })
+ }
+
+ pub fn event_handle(&self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
+ }
+
+ pub fn read_event(&mut self) -> io::Result<Option<orbclient::Event>> {
+ let mut raw = [0_u8; size_of::<orbclient::Event>()];
+
+ match self.fd.read(&mut raw) {
+ Ok(0) => Ok(None),
+ Ok(read) => {
+ assert_eq!(read, raw.len());
+ Ok(Some(unsafe {
+ core::ptr::read_unaligned(raw.as_ptr().cast::<orbclient::Event>())
+ }))
+ }
+ Err(err) if err.kind() == ErrorKind::WouldBlock => Ok(None),
+ Err(err) => Err(err),
+ }
+ }
+}
+
+pub struct HotplugHandle {
+ fd: File,
+ partial: Vec<u8>,
+}
+
+impl HotplugHandle {
+ pub fn new() -> io::Result<Self> {
+ let fd = OpenOptions::new()
+ .read(true)
+ .custom_flags(O_NONBLOCK as i32)
+ .open("/scheme/input/events")?;
+
+ Ok(Self {
+ fd,
+ partial: Vec::new(),
+ })
+ }
+
+ pub fn event_handle(&self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
+ }
+
+ pub fn read_event(&mut self) -> io::Result<Option<HotplugEvent>> {
+ let mut buf = [0_u8; 1024];
+
+ loop {
+ if let Some(event) = Self::try_parse_event(&mut self.partial)? {
+ return Ok(Some(event));
+ }
+
+ match self.fd.read(&mut buf) {
+ Ok(0) => return Ok(None),
+ Ok(read) => self.partial.extend_from_slice(&buf[..read]),
+ Err(err) if err.kind() == ErrorKind::WouldBlock => return Ok(None),
+ Err(err) => return Err(err),
+ }
+ }
+ }
+
+ fn try_parse_event(partial: &mut Vec<u8>) -> io::Result<Option<HotplugEvent>> {
+ if partial.len() < size_of::<HotplugEventHeader>() {
+ return Ok(None);
+ }
+
+ let header =
+ unsafe { core::ptr::read_unaligned(partial.as_ptr().cast::<HotplugEventHeader>()) };
+ let name_len = usize::try_from(header.name_len).map_err(|_| {
+ io::Error::new(
+ io::ErrorKind::InvalidData,
+ "invalid input hotplug name length",
+ )
+ })?;
+ let total_len = size_of::<HotplugEventHeader>()
+ .checked_add(name_len)
+ .ok_or_else(|| {
+ io::Error::new(io::ErrorKind::InvalidData, "input hotplug event too large")
+ })?;
+
+ if partial.len() < total_len {
+ return Ok(None);
+ }
+
+ let name = std::str::from_utf8(&partial[size_of::<HotplugEventHeader>()..total_len])
+ .map_err(|_| {
+ io::Error::new(
+ io::ErrorKind::InvalidData,
+ "input hotplug name is not UTF-8",
+ )
+ })?
+ .to_owned();
+
+ partial.drain(..total_len);
+
+ Ok(Some(HotplugEvent {
+ kind: header.kind,
+ device_id: header.device_id,
+ name,
+ }))
+ }
+}
+
pub struct ProducerHandle(File);
impl ProducerHandle {
+78 -32
View File
@@ -1,5 +1,5 @@
diff --git a/drivers/acpid/src/acpi.rs b/drivers/acpid/src/acpi.rs
index 94a1eb17..c3a5bfdc 100644
index 94a1eb17..3fd91156 100644
--- a/drivers/acpid/src/acpi.rs
+++ b/drivers/acpid/src/acpi.rs
@@ -25,6 +25,8 @@ use amlserde::{AmlSerde, AmlSerdeValue};
@@ -24,7 +24,7 @@ index 94a1eb17..c3a5bfdc 100644
aml_symbols: RwLock<AmlSymbols>,
@@ -424,6 +432,62 @@ impl AcpiContext {
@@ -424,6 +432,63 @@ impl AcpiContext {
.flatten()
}
@@ -35,7 +35,8 @@ index 94a1eb17..c3a5bfdc 100644
+ args: &[u64],
+ ) -> Result<Vec<u64>, AmlEvalError> {
+ let full_path = format!("{path}.{method}");
+ let aml_name = AmlName::from_str(&full_path).map_err(|_| AmlEvalError::DeserializationError)?;
+ let aml_name =
+ AmlName::from_str(&full_path).map_err(|_| AmlEvalError::DeserializationError)?;
+ let args = args
+ .iter()
+ .copied()
@@ -87,7 +88,7 @@ index 94a1eb17..c3a5bfdc 100644
pub fn init(
rxsdt_physaddrs: impl Iterator<Item = u64>,
ec: Vec<(RegionSpace, Box<dyn RegionHandler>)>,
@@ -444,6 +508,12 @@ impl AcpiContext {
@@ -444,6 +509,12 @@ impl AcpiContext {
tables,
dsdt: None,
fadt: None,
@@ -100,7 +101,7 @@ index 94a1eb17..c3a5bfdc 100644
// Temporary values
aml_symbols: RwLock::new(AmlSymbols::new(ec)),
@@ -458,7 +528,10 @@ impl AcpiContext {
@@ -458,7 +529,10 @@ impl AcpiContext {
}
Fadt::init(&mut this);
@@ -112,7 +113,7 @@ index 94a1eb17..c3a5bfdc 100644
this
}
@@ -562,92 +635,83 @@ impl AcpiContext {
@@ -562,92 +636,83 @@ impl AcpiContext {
aml_symbols.symbol_cache = FxHashMap::default();
}
@@ -268,7 +269,7 @@ index 94a1eb17..c3a5bfdc 100644
loop {
core::hint::spin_loop();
}
@@ -707,7 +771,7 @@ unsafe impl plain::Plain for FadtStruct {}
@@ -707,7 +772,7 @@ unsafe impl plain::Plain for FadtStruct {}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, Default)]
@@ -277,7 +278,7 @@ index 94a1eb17..c3a5bfdc 100644
address_space: u8,
bit_width: u8,
bit_offset: u8,
@@ -715,11 +779,67 @@ pub struct GenericAddressStructure {
@@ -715,11 +780,77 @@ pub struct GenericAddressStructure {
address: u64,
}
@@ -290,14 +291,23 @@ index 94a1eb17..c3a5bfdc 100644
+ pub fn write_u8(&self, value: u8) {
+ match self.address_space {
+ 0 => {
+ let Ok(address) = usize::try_from(self.address) else {
+ log::error!("Reset register physical address is invalid: {:#X}", self.address);
+ let address_val = self.address;
+ let Ok(address) = usize::try_from(address_val) else {
+ log::error!(
+ "Reset register physical address is invalid: {:#X}",
+ address_val
+ );
+ return;
+ };
+ let page = address / PAGE_SIZE * PAGE_SIZE;
+ let offset = address % PAGE_SIZE;
+ let virt = unsafe {
+ common::physmap(page, PAGE_SIZE, common::Prot::RW, common::MemoryType::default())
+ common::physmap(
+ page,
+ PAGE_SIZE,
+ common::Prot::RW,
+ common::MemoryType::default(),
+ )
+ };
+
+ match virt {
@@ -315,7 +325,8 @@ index 94a1eb17..c3a5bfdc 100644
+ Pio::<u8>::new(port).write(value);
+ }
+ Err(_) => {
+ log::error!("Reset register I/O port is invalid: {:#X}", self.address);
+ let address_val = self.address;
+ log::error!("Reset register I/O port is invalid: {:#X}", address_val);
+ }
+ },
+ address_space => {
@@ -346,7 +357,7 @@ index 94a1eb17..c3a5bfdc 100644
pub reset_value: u8,
reserved3: [u8; 3],
@@ -728,14 +848,14 @@ pub struct FadtAcpi2Struct {
@@ -728,14 +859,14 @@ pub struct FadtAcpi2Struct {
pub x_firmware_control: u64,
pub x_dsdt: u64,
@@ -369,7 +380,7 @@ index 94a1eb17..c3a5bfdc 100644
}
unsafe impl plain::Plain for FadtAcpi2Struct {}
@@ -793,9 +913,25 @@ impl Fadt {
@@ -793,9 +924,27 @@ impl Fadt {
None => usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize"),
};
@@ -379,7 +390,9 @@ index 94a1eb17..c3a5bfdc 100644
+ let pm1a_cnt_blk = u64::from(fadt.pm1a_control_block);
+ let pm1b_cnt_blk = u64::from(fadt.pm1b_control_block);
+ let (reset_reg, reset_value) = match fadt.acpi_2_struct() {
+ Some(fadt2) if !fadt2.reset_reg.is_empty() => (Some(fadt2.reset_reg), fadt2.reset_value),
+ Some(fadt2) if !fadt2.reset_reg.is_empty() => {
+ (Some(fadt2.reset_reg), fadt2.reset_value)
+ }
+ _ => (None, 0),
+ };
@@ -397,22 +410,24 @@ index 94a1eb17..c3a5bfdc 100644
Ok(dsdt) => dsdt,
Err(error) => {
log::error!("Failed to load DSDT: {}", error);
@@ -803,8 +939,46 @@ impl Fadt {
@@ -803,8 +952,48 @@ impl Fadt {
}
};
+ let (slp_typa_s5, slp_typb_s5) = match AmlName::from_str("\\_S5") {
+ Ok(s5_name) => match context.aml_eval(s5_name, Vec::new()) {
+ Ok(AmlSerdeValue::Package { contents }) => match (contents.get(0), contents.get(1)) {
+ (Some(AmlSerdeValue::Integer(slp_typa)), Some(AmlSerdeValue::Integer(slp_typb))) => {
+ match (u8::try_from(*slp_typa), u8::try_from(*slp_typb)) {
+ (Ok(slp_typa_s5), Ok(slp_typb_s5)) => (slp_typa_s5, slp_typb_s5),
+ _ => {
+ log::warn!("\\_S5 values do not fit in u8: {:?}", contents);
+ (0, 0)
+ }
+ Ok(AmlSerdeValue::Package { contents }) => match (contents.get(0), contents.get(1))
+ {
+ (
+ Some(AmlSerdeValue::Integer(slp_typa)),
+ Some(AmlSerdeValue::Integer(slp_typb)),
+ ) => match (u8::try_from(*slp_typa), u8::try_from(*slp_typb)) {
+ (Ok(slp_typa_s5), Ok(slp_typb_s5)) => (slp_typa_s5, slp_typb_s5),
+ _ => {
+ log::warn!("\\_S5 values do not fit in u8: {:?}", contents);
+ (0, 0)
+ }
+ }
+ },
+ _ => {
+ log::warn!("\\_S5 package did not contain two integers: {:?}", contents);
+ (0, 0)
@@ -557,7 +572,7 @@ index 0933f638..d4b0f3d0 100644
fn main() {
diff --git a/drivers/pcid/src/scheme.rs b/drivers/pcid/src/scheme.rs
index ce55b33f..c06bdec4 100644
index c2caf804..95acdb57 100644
--- a/drivers/pcid/src/scheme.rs
+++ b/drivers/pcid/src/scheme.rs
@@ -21,6 +21,7 @@ enum Handle {
@@ -591,7 +606,7 @@ index ce55b33f..c06bdec4 100644
}
fn is_scheme_root(&self) -> bool {
matches!(self, Self::SchemeRoot)
@@ -153,6 +160,7 @@ impl SchemeSync for PciScheme {
@@ -132,6 +139,7 @@ impl SchemeSync for PciScheme {
let (len, mode) = match handle.inner {
Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755),
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
@@ -599,7 +614,7 @@ index ce55b33f..c06bdec4 100644
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
Handle::SchemeRoot => return Err(Error::new(EBADF)),
};
@@ -177,6 +185,18 @@ impl SchemeSync for PciScheme {
@@ -156,6 +164,18 @@ impl SchemeSync for PciScheme {
match handle.inner {
Handle::TopLevel { .. } => Err(Error::new(EISDIR)),
Handle::Device => Err(Error::new(EISDIR)),
@@ -618,7 +633,7 @@ index ce55b33f..c06bdec4 100644
Handle::Channel {
addr: _,
ref mut st,
@@ -214,7 +234,9 @@ impl SchemeSync for PciScheme {
@@ -193,7 +213,9 @@ impl SchemeSync for PciScheme {
return Ok(buf);
}
Handle::Device => DEVICE_CONTENTS,
@@ -629,7 +644,7 @@ index ce55b33f..c06bdec4 100644
Handle::SchemeRoot => return Err(Error::new(EBADF)),
};
@@ -244,6 +266,20 @@ impl SchemeSync for PciScheme {
@@ -223,6 +245,20 @@ impl SchemeSync for PciScheme {
}
match handle.inner {
@@ -650,7 +665,7 @@ index ce55b33f..c06bdec4 100644
Handle::Channel { addr, ref mut st } => {
Self::write_channel(&self.pcie, &mut self.tree, addr, st, buf)
}
@@ -339,6 +375,10 @@ impl PciScheme {
@@ -318,6 +354,10 @@ impl PciScheme {
func.enabled = false;
}
}
@@ -661,7 +676,7 @@ index ce55b33f..c06bdec4 100644
_ => {}
}
}
@@ -365,6 +405,7 @@ impl PciScheme {
@@ -343,6 +383,7 @@ impl PciScheme {
let path = &after[1..];
match path {
@@ -669,3 +684,34 @@ index ce55b33f..c06bdec4 100644
"channel" => {
if func.enabled {
return Err(Error::new(ENOLCK));
diff --git a/init/src/scheduler.rs b/init/src/scheduler.rs
index 670a5526..24ce3d68 100644
--- a/init/src/scheduler.rs
+++ b/init/src/scheduler.rs
@@ -1,8 +1,8 @@
use std::collections::VecDeque;
-use crate::InitConfig;
use crate::script::Command;
use crate::unit::{Unit, UnitId, UnitKind, UnitStore};
+use crate::InitConfig;
pub struct Scheduler {
pending: VecDeque<Job>,
@@ -96,14 +96,9 @@ fn run(unit: &mut Unit, config: &mut InitConfig) {
eprintln!("Skipping '{} {}'", service.cmd, service.args.join(" "));
return;
}
- if config.log_debug {
- eprintln!(
- "Starting {} ({})",
- unit.info.description.as_ref().unwrap_or(&unit.id.0),
- service.cmd,
- );
- }
+ eprintln!("init: starting {} ({:?})", service.cmd, &service.type_,);
service.spawn(&config.envs);
+ eprintln!("init: started {} done", service.cmd,);
}
UnitKind::Target {} => {
if config.log_debug {