Simplify acpi scheme.

This commit is contained in:
4lDO2
2026-06-02 13:34:17 +02:00
parent 6fc2d32497
commit 8011f3f648
6 changed files with 107 additions and 282 deletions
Generated
+20 -21
View File
@@ -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",
+3 -2
View File
@@ -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.
+79 -257
View File
@@ -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<L1, HandleMap<Handle>> = RwLock::new(HandleMap::new());
static RXSDT_DATA: Once<Box<[u8]>> = Once::new();
static DATA: Once<Box<[u8]>> = Once::new();
static KSTOP_WAITCOND: WaitCondition = WaitCondition::new();
static KSTOP_FLAG: Mutex<bool> = Mutex::new(false);
static KSTOP_FLAG: Mutex<L4, bool> = 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<usize> = {
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<usize> {
let fd = HANDLES.write(token.token()).insert(Handle {
kind: HandleKind::SchemeRoot,
stat: false,
});
Ok(fd)
fn scheme_root(&self, _token: &mut CleanLockToken) -> Result<usize> {
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<OpenResult> {
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<u64> {
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<EventFlags> {
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<usize> {
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<usize> {
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<usize> {
//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(())
}
}
}
+3 -1
View File
@@ -589,7 +589,9 @@ pub trait KernelScheme: Send + Sync + 'static {
) -> Result<usize> {
Err(Error::new(EBADF))
}
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize>;
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
Err(Error::new(EBADF))
}
+1
View File
@@ -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)
}
+1 -1
View File
@@ -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