From 8011f3f648827f5911bec211e34e92ea8b90e18c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jun 2026 13:34:17 +0200 Subject: [PATCH] Simplify acpi scheme. --- Cargo.lock | 41 +++--- Cargo.toml | 5 +- src/scheme/acpi.rs | 336 ++++++++++--------------------------------- src/scheme/mod.rs | 4 +- src/scheme/proc.rs | 1 + src/syscall/debug.rs | 2 +- 6 files changed, 107 insertions(+), 282 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8d073374d..f505f0c76c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,15 +40,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "cc" -version = "1.2.60" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "shlex", @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "indexmap" @@ -99,7 +99,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", ] [[package]] @@ -108,7 +108,7 @@ version = "0.5.12" dependencies = [ "arrayvec", "bitfield", - "bitflags 2.11.1", + "bitflags 2.12.1", "cc", "fdt", "hashbrown 0.14.5", @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "object" @@ -201,18 +201,17 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" [[package]] name = "redox_syscall" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" +version = "0.8.1" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#79cb6d9057642be31623677458a93aa88145864f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] name = "rmm" version = "0.1.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -282,9 +281,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "slab" @@ -402,18 +401,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 4dd3b99a24..3d6aed15f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ fdt = { git = "https://github.com/repnop/fdt.git", rev = "2fb1409edd1877c714a0aa hashbrown = { version = "0.14.3", default-features = false, features = ["ahash", "inline-more"] } linked_list_allocator = "0.9.0" redox-path = "0.2.0" -redox_syscall = { version = "0.8.0", default-features = false } +#redox_syscall = { version = "0.8.1", default-features = false } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", default-features = false } rmm = { path = "rmm", default-features = false } slab = { version = "0.4", default-features = false } smallvec = { version = "1.15.1", default-features = false } @@ -85,7 +86,7 @@ default = [ "x86_kvm_pv", #"busy_panic", #"drop_panic", - #"syscall_debug" + #"syscall_debug", ] # Activates some limited code-overwriting optimizations, based on CPU features. diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index 6b941625c9..3032389ad5 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -1,78 +1,59 @@ -use alloc::{boxed::Box, vec::Vec}; -use core::convert::TryInto; +use alloc::boxed::Box; +use core::sync::atomic::{AtomicBool, Ordering}; -use spin::{Mutex, Once}; -use syscall::{ - data::GlobalSchemes, - dirent::{DirEntry, DirentBuf, DirentKind}, - EIO, -}; +use crate::sync::ordered::{Mutex, L4}; +use spin::Once; + +use syscall::data::GlobalSchemes; use crate::{ acpi::{RxsdtEnum, RXSDT_ENUM}, context::file::InternalFlags, - event, - sync::{CleanLockToken, RwLock, WaitCondition, L1}, + scheme::{SchemeExt, StrOrBytes}, + sync::CleanLockToken, }; use crate::syscall::{ - data::Stat, - error::{Error, Result, EACCES, EBADF, EBADFD, EINTR, EINVAL, EISDIR, ENOENT, ENOTDIR, EROFS}, - flag::{ - EventFlags, EVENT_READ, MODE_CHR, MODE_DIR, MODE_FILE, O_ACCMODE, O_CREAT, O_DIRECTORY, - O_EXCL, O_RDONLY, O_STAT, O_SYMLINK, - }, - usercopy::UserSliceWo, + error::{Error, Result, EACCES, EBADFD, EINVAL, ENOENT}, + flag::{AcpiVerb, CallFlags, EventFlags}, + usercopy::UserSliceRw, }; -use super::{CallerCtx, HandleMap, KernelScheme, OpenResult, SchemeExt, StrOrBytes}; +use super::{CallerCtx, KernelScheme, OpenResult}; -/// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function. +/// A scheme used to access the RSDT or XSDT, and listen for shutdown, which is needed for e.g. `acpid` to function. pub struct AcpiScheme; -#[derive(Clone, Copy)] -struct Handle { - kind: HandleKind, - stat: bool, -} -#[derive(Clone, Copy, Eq, PartialEq)] -enum HandleKind { - TopLevel, - Rxsdt, - ShutdownPipe, - SchemeRoot, +bitflags! { + #[derive(PartialEq)] + struct HandleBits: usize { + const CAN_READ_RXSDT = 1; + const CAN_REGISTER_KSTOP = 2; + + // mutually exclusive with the other flags + const KSTOP_HANDLE = 4; + } } -static HANDLES: RwLock> = RwLock::new(HandleMap::new()); +static RXSDT_DATA: Once> = Once::new(); -static DATA: Once> = Once::new(); - -static KSTOP_WAITCOND: WaitCondition = WaitCondition::new(); -static KSTOP_FLAG: Mutex = Mutex::new(false); +static KSTOP_FLAG: Mutex = Mutex::new(false); +static EXISTS_KSTOP_HANDLE: AtomicBool = AtomicBool::new(false); pub fn register_kstop(token: &mut CleanLockToken) -> bool { - *KSTOP_FLAG.lock() = true; - let mut waiters_awoken = KSTOP_WAITCOND.notify(token); + *KSTOP_FLAG.lock(token.token()) = true; - let fds: Vec = { - HANDLES - .read(token.token()) - .iter() - .filter(|(_, handle)| handle.kind == HandleKind::ShutdownPipe) - .map(|(fd, _)| *fd) - .collect() - }; - - for fd in fds { - event::trigger(GlobalSchemes::Acpi.scheme_id(), fd, EVENT_READ, token); - waiters_awoken += 1; - } - - if waiters_awoken == 0 { + if !EXISTS_KSTOP_HANDLE.load(Ordering::Relaxed) { error!("No userspace ACPI handler was notified when trying to shutdown. This is bad."); // Let the kernel shutdown without ACPI. return false; } + crate::event::trigger( + GlobalSchemes::Acpi.scheme_id(), + HandleBits::KSTOP_HANDLE.bits(), + EventFlags::EVENT_READ, + token, + ); // TODO: Context switch directly to the waiting context, to avoid annoying timeouts. true @@ -86,7 +67,7 @@ impl AcpiScheme { let mut data_init = false; - DATA.call_once(|| { + RXSDT_DATA.call_once(|| { data_init = true; let table = match RXSDT_ENUM.get() { @@ -108,229 +89,70 @@ impl AcpiScheme { } impl KernelScheme for AcpiScheme { - fn scheme_root(&self, token: &mut CleanLockToken) -> Result { - let fd = HANDLES.write(token.token()).insert(Handle { - kind: HandleKind::SchemeRoot, - stat: false, - }); - - Ok(fd) + fn scheme_root(&self, _token: &mut CleanLockToken) -> Result { + Ok((HandleBits::CAN_READ_RXSDT | HandleBits::CAN_REGISTER_KSTOP).bits()) } fn kopenat( &self, id: usize, - user_buf: StrOrBytes, - flags: usize, + path: StrOrBytes, + _flags: usize, _fcntl_flags: u32, - ctx: CallerCtx, - token: &mut CleanLockToken, + caller: CallerCtx, + _token: &mut CleanLockToken, ) -> Result { - if !matches!( - HANDLES.read(token.token()).get(id)?.kind, - HandleKind::SchemeRoot - ) { - return Err(Error::new(EACCES)); - } + let bits = HandleBits::from_bits_retain(id); - let path = user_buf - .as_str() - .or(Err(Error::new(EINVAL)))? - .trim_start_matches('/'); - - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - if flags & O_CREAT == O_CREAT { - return Err(Error::new(EROFS)); - } - if flags & O_EXCL == O_EXCL || flags & O_SYMLINK == O_SYMLINK { - return Err(Error::new(EINVAL)); - } - if flags & O_ACCMODE != O_RDONLY && flags & O_STAT != O_STAT { - return Err(Error::new(EROFS)); - } - let (handle_kind, int_flags) = match path { - "" => { - if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(EISDIR)); + let new_bits = match path.as_bytes() { + b"" | b"/" => bits, + b"kstop" | b"/kstop" => { + // TODO: can the uid check be removed? + if caller.uid != 0 || !bits.contains(HandleBits::CAN_REGISTER_KSTOP) { + return Err(Error::new(EACCES)); } - - (HandleKind::TopLevel, InternalFlags::POSITIONED) - } - "rxsdt" => { - if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(ENOTDIR)); - } - (HandleKind::Rxsdt, InternalFlags::POSITIONED) - } - "kstop" => { - if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(ENOTDIR)); - } - (HandleKind::ShutdownPipe, InternalFlags::empty()) + EXISTS_KSTOP_HANDLE.store(true, Ordering::Relaxed); + HandleBits::KSTOP_HANDLE } _ => return Err(Error::new(ENOENT)), }; - - let fd = HANDLES.write(token.token()).insert(Handle { - kind: handle_kind, - // TODO: Redundant - stat: flags & O_STAT == O_STAT, - }); - - Ok(OpenResult::SchemeLocal(fd, int_flags)) + Ok(OpenResult::SchemeLocal( + new_bits.bits(), + InternalFlags::empty(), + )) } - fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result { - let handles = HANDLES.read(token.token()); - let handle = handles.get(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - Ok(match handle.kind { - HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?.len() as u64, - HandleKind::ShutdownPipe => 1, - HandleKind::TopLevel => 0, - HandleKind::SchemeRoot => return Err(Error::new(EBADF))?, - }) - } - // TODO - fn fevent( + fn kcall( &self, - id: usize, - _flags: EventFlags, - token: &mut CleanLockToken, - ) -> Result { - let handles = HANDLES.read(token.token()); - let handle = handles.get(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - Ok(EventFlags::empty()) - } - fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> { - HANDLES.write(token.token()).remove(id)?; - Ok(()) - } - fn kreadoff( - &self, - id: usize, - dst_buf: UserSliceWo, - offset: u64, - _flags: u32, - _stored_flags: u32, + fds: &[usize], + payload: UserSliceRw, + flags: CallFlags, + metadata: &[u64], token: &mut CleanLockToken, ) -> Result { - let Ok(offset) = usize::try_from(offset) else { - return Ok(0); - }; + let [handle] = <&[usize; 1]>::try_from(fds) + .map_err(|_| Error::new(EINVAL))? + .map(HandleBits::from_bits_retain); + let verb = metadata + .get(0) + .copied() + .and_then(AcpiVerb::try_from_raw) + .ok_or(Error::new(EINVAL))?; - let handle = *HANDLES.read(token.token()).get(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - let data = match handle.kind { - HandleKind::ShutdownPipe => { - if dst_buf.is_empty() { - return Ok(0); + match verb { + AcpiVerb::ReadRxsdt => { + if !handle.contains(HandleBits::CAN_READ_RXSDT) || !flags.contains(CallFlags::READ) + { + return Err(Error::new(EINVAL)); } - - loop { - let flag_guard = KSTOP_FLAG.lock(); - let mut token = token.downgrade(); - - if *flag_guard { - break; - } else if !KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop", &mut token) { - return Err(Error::new(EINTR)); - } - } - - return dst_buf.copy_exactly(&[0x42]).map(|()| 1); + let src = RXSDT_DATA.get().ok_or(Error::new(EBADFD))?; + payload.copy_common_bytes_from_slice(src)?; + Ok(src.len()) } - HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?, - HandleKind::TopLevel => return Err(Error::new(EISDIR)), - HandleKind::SchemeRoot => return Err(Error::new(EBADF)), - }; - - let src_offset = core::cmp::min(offset, data.len()); - let src_buf = data - .get(src_offset..) - .expect("expected data to be at least data.len() bytes long"); - - dst_buf.copy_common_bytes_from_slice(src_buf) - } - fn getdents( - &self, - id: usize, - buf: UserSliceWo, - header_size: u16, - opaque: u64, - token: &mut CleanLockToken, - ) -> Result { - let Handle { - kind: HandleKind::TopLevel, - .. - } = HANDLES.read(token.token()).get(id)? - else { - return Err(Error::new(ENOTDIR)); - }; - - let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?; - if opaque == 0 { - buf.entry(DirEntry { - kind: DirentKind::Regular, - name: "rxsdt", - inode: 0, - next_opaque_id: 1, - })?; - } - if opaque <= 1 { - buf.entry(DirEntry { - kind: DirentKind::Socket, - name: "kstop", - inode: 0, - next_opaque_id: u64::MAX, - })?; - } - Ok(buf.finalize()) - } - fn kfpath(&self, _id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result { - //TODO: construct useful path? - buf.copy_common_bytes_from_slice("/scheme/kernel.acpi/".as_bytes()) - } - fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> { - let handles = HANDLES.read(token.token()); - let handle = handles.get(id)?; - - buf.copy_exactly(&match handle.kind { - HandleKind::Rxsdt => { - let data = DATA.get().ok_or(Error::new(EBADFD))?; - - Stat { - st_mode: MODE_FILE, - st_size: data.len().try_into().unwrap_or(u64::MAX), - ..Default::default() + AcpiVerb::CheckShutdown => { + if handle != HandleBits::KSTOP_HANDLE { + return Err(Error::new(EINVAL)); } + Ok(usize::from(*KSTOP_FLAG.lock(token.token()))) } - HandleKind::TopLevel => Stat { - st_mode: MODE_DIR, - st_size: 0, - ..Default::default() - }, - HandleKind::ShutdownPipe => Stat { - st_mode: MODE_CHR, - st_size: 1, - ..Default::default() - }, - HandleKind::SchemeRoot => return Err(Error::new(EBADF)), - })?; - - Ok(()) + } } } diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index fee07540e9..4dc63b3a1d 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -589,7 +589,9 @@ pub trait KernelScheme: Send + Sync + 'static { ) -> Result { Err(Error::new(EBADF)) } - fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result; + fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result { + Err(Error::new(EOPNOTSUPP)) + } fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> { Err(Error::new(EBADF)) } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index f9b27476a3..a115fe488d 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -668,6 +668,7 @@ impl KernelScheme for ProcScheme { ProcSchemeVerb::Iopl => context::current() .write(token.token()) .set_userspace_io_allowed(true), + _ => return Err(Error::new(EINVAL)), } Ok(0) } diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index 2a555e6b6b..753d910961 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -208,7 +208,7 @@ pub fn debug_start([a, b, c, d, e, f, g]: [usize; 7], token: &mut CleanLockToken && crate::context::current() .read(token.token()) .name - .contains("init") + .contains("acpid") { if a == SYS_CLOCK_GETTIME || a == SYS_YIELD || a == SYS_FUTEX { false