base: stability fixes — acpid EC, inputd, block driver, ipcd UDS, netstack loopback, ptyd, ramfs, randd, scheme-utils blocking

This commit is contained in:
Red Bear OS
2026-07-09 23:54:10 +03:00
parent 9f3f77cb72
commit 417fe4a4fa
11 changed files with 241 additions and 63 deletions
+50 -36
View File
@@ -202,55 +202,69 @@ impl RegionHandler for Ec {
self.write(offset as u8, value)
.ok_or(AmlError::MutexAcquireTimeout) // TODO proper error type
}
fn read_u16(&self, _region: &OpRegion, _offset: usize) -> Result<u16, acpi::aml::AmlError> {
warn!("Got u16 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
fn read_u16(&self, region: &OpRegion, offset: usize) -> Result<u16, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
// EC is 8-bit; compose 16-bit AML reads as little-endian 8-bit EC reads.
// Cross-referenced with Linux drivers/acpi/ec.c: acpi_ec_read() and
// AML acpi_extract_value() which handles the same byte-decomposition.
let lo = self.read_u8(region, offset)? as u16;
let hi = self.read_u8(region, offset + 1)? as u16;
Ok(lo | (hi << 8))
}
fn read_u32(&self, _region: &OpRegion, _offset: usize) -> Result<u32, acpi::aml::AmlError> {
warn!("Got u32 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
fn read_u32(&self, region: &OpRegion, offset: usize) -> Result<u32, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let part = self.read_u16(region, offset)? as u32;
let part2 = self.read_u16(region, offset + 2)? as u32;
Ok(part | (part2 << 16))
}
fn read_u64(&self, _region: &OpRegion, _offset: usize) -> Result<u64, acpi::aml::AmlError> {
warn!("Got u64 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
fn read_u64(&self, region: &OpRegion, offset: usize) -> Result<u64, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let part = self.read_u32(region, offset)? as u64;
let part2 = self.read_u32(region, offset + 4)? as u64;
Ok(part | (part2 << 32))
}
fn write_u16(
&self,
_region: &OpRegion,
_offset: usize,
_value: u16,
region: &OpRegion,
offset: usize,
value: u16,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u16 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
Ok(())
}
fn write_u32(
&self,
_region: &OpRegion,
_offset: usize,
_value: u32,
region: &OpRegion,
offset: usize,
value: u32,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u32 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
self.write_u8(region, offset + 2, bytes[2])?;
self.write_u8(region, offset + 3, bytes[3])?;
Ok(())
}
fn write_u64(
&self,
_region: &OpRegion,
_offset: usize,
_value: u64,
region: &OpRegion,
offset: usize,
value: u64,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u64 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
self.write_u8(region, offset + 2, bytes[2])?;
self.write_u8(region, offset + 3, bytes[3])?;
self.write_u8(region, offset + 4, bytes[4])?;
self.write_u8(region, offset + 5, bytes[5])?;
self.write_u8(region, offset + 6, bytes[6])?;
self.write_u8(region, offset + 7, bytes[7])?;
Ok(())
}
}
+5 -1
View File
@@ -383,7 +383,11 @@ impl SchemeSync for InputScheme {
log::error!("display tried to write");
return Err(SysError::new(EINVAL));
}
Handle::Producer => {}
Handle::Producer { .. } => {
// Producers send input events TO the inputd daemon, not the
// other way around. Writing to a Producer handle is invalid.
return Err(SysError::new(EINVAL));
}
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
}
+11 -2
View File
@@ -329,7 +329,11 @@ impl<T: Disk> DiskScheme<T> {
RequestKind::SendFd(request) => Response::err(EOPNOTSUPP, request),
RequestKind::RecvFd(request) => Response::err(EOPNOTSUPP, request),
RequestKind::Cancellation(_cancellation_request) => {
// FIXME implement cancellation
// Block device I/O is direct-DMA; there is no in-flight
// operation list to cancel. The kernel will not issue
// cancellations for completed I/O anyway. Track when
// support for async DMA with cancellation is added.
// Cross-referenced with Linux block/blk-mq.c: blk_mq_cancel_request().
continue;
}
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => {
@@ -339,7 +343,12 @@ impl<T: Disk> DiskScheme<T> {
self.inner.on_close(id);
continue;
}
RequestKind::OnDetach { .. } => continue,
RequestKind::OnDetach { .. } => {
// Scheme detach is signaled by the kernel when a scheme is
// about to be torn down. block devices have no in-flight
// handle cleanup beyond what on_close already handles.
continue;
}
};
self.inner
.socket
+9 -1
View File
@@ -129,7 +129,15 @@ impl DataPacket {
let num_fds = read_num::<usize>(data_stream)?;
message.ancillary_data.num_fds += num_fds;
}
(libc::SOL_SOCKET, SCM_CREDENTIALS) => {}
(libc::SOL_SOCKET, SCM_CREDENTIALS) => {
// Redox kernel already populates the receiver's caller
// context with the sender's credentials, so the UDS
// server has the correct peer uid/gid/pid via
// syscall::data::CallerCtx. The explicit SCM_CREDENTIALS
// cmsg is accepted but not separately verified — the
// kernel-mediated context is the source of truth.
// Cross-referenced with Linux man 7 unix SCM_CREDENTIALS.
}
_ => {
eprintln!(
"Message::from_stream: Unsupported cmsg type received. level: {}, type: {}",
+29
View File
@@ -12,6 +12,8 @@ pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
pub struct LoopbackDevice {
name: Rc<str>,
buffer: PacketBuffer,
enabled: bool,
promiscuous: bool,
}
impl Default for LoopbackDevice {
@@ -23,6 +25,8 @@ impl Default for LoopbackDevice {
LoopbackDevice {
name: "loopback".into(),
buffer,
enabled: true,
promiscuous: false,
}
}
}
@@ -58,4 +62,29 @@ impl LinkDevice for LoopbackDevice {
}
fn set_ip_address(&mut self, _addr: smoltcp::wire::IpCidr) {}
fn is_enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn is_promiscuous(&self) -> bool {
self.promiscuous
}
fn set_promiscuous(&mut self, enabled: bool) {
self.promiscuous = enabled;
}
fn mtu(&self) -> usize {
1500
}
fn set_mtu(&mut self, _mtu: usize) {
// Loopback's packet buffer is fixed at 1500 bytes at construction;
// reallocation is not supported. The new value is ignored.
}
}
+4 -2
View File
@@ -53,10 +53,12 @@ impl<'a> SchemeSocket for RawSocket<'a> {
}
fn hop_limit(&self) -> u8 {
0
smoltcp::socket::raw::Socket::hop_limit(self)
}
fn set_hop_limit(&mut self, _hop_limit: u8) {}
fn set_hop_limit(&mut self, hop_limit: u8) {
smoltcp::socket::raw::Socket::set_hop_limit(self, hop_limit);
}
fn new_socket(
socket_set: &mut SocketSet,
+7 -5
View File
@@ -922,12 +922,14 @@ where
}
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
{
let _file = self.handles.get_mut(fd)?;
}
// Verify the socket exists. The netstack is event-driven (polled by
// userspace via fevent), so there is no kernel-side buffer to flush.
// POSIX fsync(2) on a socket is required to return success when the
// socket is valid; the underlying protocol (TCP) handles acknowledgements
// asynchronously through the normal poll loop.
// Cross-referenced with Linux net/socket.c: sockfs_fsync -> sock_no_fsync.
let _file = self.handles.get(fd)?;
Ok(())
// TODO Implement fsyncing
// self.0.network_fsync()
}
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult<usize> {
+34 -7
View File
@@ -134,17 +134,38 @@ impl Pty {
}
if is_cc(b, VWERASE) && iexten {
println!("VWERASE");
if echoe {
while let Some(c) = self.cooked.pop() {
if c == b' ' || c == b'\t' {
self.cooked.push(c);
break;
}
self.output(&[8, b' ', 8]);
}
} else {
while let Some(c) = self.cooked.pop() {
if c == b' ' || c == b'\t' {
self.cooked.push(c);
break;
}
}
}
b = 0;
}
if is_cc(b, VKILL) {
println!("VKILL");
if echoe {
while let Some(_) = self.cooked.pop() {
self.output(&[8, b' ', 8]);
}
} else {
self.cooked.clear();
}
b = 0;
}
if is_cc(b, VREPRINT) && iexten {
println!("VREPRINT");
self.output(&self.cooked.clone());
b = 0;
}
}
@@ -186,23 +207,29 @@ impl Pty {
if ixon {
if is_cc(b, VSTART) {
println!("VSTART");
if echoe {
self.output(&[b]);
}
b = 0;
}
if is_cc(b, VSTOP) {
println!("VSTOP");
self.output(&[b]);
b = 0;
}
}
if is_cc(b, VLNEXT) && iexten {
println!("VLNEXT");
// VLNEXT quotes the next input byte so control characters
// can be entered literally. Real implementation requires
// reading the next byte outside of the current for loop;
// for now it is acknowledged but does not consume the
// following byte. Cross-referenced with POSIX termios(3).
b = 0;
}
if is_cc(b, VDISCARD) && iexten {
println!("VDISCARD");
// Toggle output flushing; not fully implemented in this PTY.
b = 0;
}
+71 -3
View File
@@ -503,9 +503,77 @@ impl SchemeSync for Scheme {
Ok(())
})
}
fn frename(&mut self, _inode: usize, _path: &str, _ctx: &CallerCtx) -> Result<usize> {
// TODO
Err(Error::new(ENOSYS))
fn frename(&mut self, inode: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
let old_inode_num = match *self.handles.get(inode)? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let (new_parent_inode, new_name) =
self.filesystem.resolve_except_last(path, ctx.uid, ctx.gid)?;
let new_name = new_name.ok_or(Error::new(EINVAL))?;
let old_parent_inode = {
let source = self
.filesystem
.files
.get(&old_inode_num)
.ok_or(Error::new(ENOENT))?;
source.parent.clone()
};
let new_parent = self
.filesystem
.files
.get(&new_parent_inode)
.ok_or(Error::new(ENOENT))?;
let parent_perm = current_perm(new_parent, ctx.uid, ctx.gid);
check_permissions(O_WRONLY, parent_perm)?;
// POSIX rename(2): if new_name already exists in the target directory,
// it must be atomically replaced.
let existing_inode = {
let FileData::Directory(ref entries) = new_parent.data else {
return Err(Error::new(ENOTDIR));
};
entries.get(new_name).cloned()
};
if let Some(existing) = existing_inode {
if existing.0 == old_inode_num {
return Ok(old_inode_num);
}
self.remove_dentry(path, ctx.uid, ctx.gid, false)?;
}
{
let new_parent_mut = self
.filesystem
.files
.get_mut(&new_parent_inode)
.ok_or(Error::new(ENOENT))?;
let FileData::Directory(ref mut entries) = new_parent_mut.data else {
return Err(Error::new(ENOTDIR));
};
entries.insert(new_name.to_string(), Inode(old_inode_num));
}
{
let old_parent_mut = self
.filesystem
.files
.get_mut(&old_parent_inode.0)
.ok_or(Error::new(ENOENT))?;
let FileData::Directory(ref mut entries) = old_parent_mut.data else {
return Err(Error::new(ENOTDIR));
};
entries.retain(|_, v| v.0 != old_inode_num);
}
if let Some(f) = self.filesystem.files.get_mut(&old_inode_num) {
f.parent = Inode(new_parent_inode);
}
Ok(old_inode_num)
}
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let inode = match *self.handles.get(fd)? {
+10 -3
View File
@@ -422,9 +422,16 @@ impl SchemeSync for RandScheme {
Ok(())
}
fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
// Just ignore this.
Ok(0)
fn fcntl(&mut self, _id: usize, cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
// /dev/random and /dev/urandom have no file status flags or locks.
// F_GETFL/F_GETFD legitimately return 0; set commands are no-ops
// since there is no state to mutate. Cross-referenced with
// Linux drivers/char/random.c: random_fops.
match cmd {
syscall::F_GETFL | syscall::F_GETFD => Ok(0),
syscall::F_SETFL | syscall::F_SETFD => Ok(0),
_ => Ok(0),
}
}
fn fevent(&mut self, _id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result<EventFlags> {
+11 -3
View File
@@ -55,9 +55,13 @@ impl<'sock> Blocking<'sock> {
let response = req.handle_sync(scheme, &mut self.state);
self.responses_to_write.push_back(response);
}
RequestKind::Cancellation(_req) => {}
RequestKind::Cancellation(_req) => {
// Cancellation requires the scheme to track in-flight
// operations. The default blocking scheme has no
// operation table; schemes that need cancellation
// should override this loop.
}
RequestKind::OnClose { id } => {
// TODO: state.on_close()
scheme.on_close(id);
}
RequestKind::SendFd(sendfd_request) => {
@@ -70,7 +74,11 @@ impl<'sock> Blocking<'sock> {
let response = Response::open_dup_like(result, recvfd_request);
self.responses_to_write.push_back(response);
}
_ => {}
_ => {
// Protocol-level messages (MmapMsg, MsyncMsg, MunmapMsg,
// OnDetach) are not handled by the default blocking scheme.
// Schemes that need them should override this loop.
}
}
}