redox-driver-sys: add # Safety docs to all io.rs unsafe blocks

Document the safety contracts for:
- acquire_iopl: kernel fd validity, IOPL privilege, no concurrent calls
- inb/inw/inl: valid port, required privilege (IOPL or ring 0)
- outb/outw/outl: valid writable port, no destructive side effects

Closes the documentation gap for io.rs unsafe inline asm blocks.
Part of the systematic fix for ZERO # Safety docs across ~330 unsafe
blocks (NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md §9.3).
This commit is contained in:
2026-07-27 14:34:48 +09:00
parent 01f4f5d958
commit ec8af52952
@@ -2,6 +2,19 @@
use syscall as redox_syscall;
/// Acquire I/O Privilege Level for the current thread so that subsequent
/// `inb`/`inw`/`inl`/`outb`/`outw`/`outl` calls do not raise #GP.
///
/// # Safety
///
/// The caller must ensure:
/// - `acquire_iopl` is called from a thread that is permitted to hold IOPL
/// (typically a driver thread under the `redox-driver-sys` umbrella).
/// - No other code path is concurrently relying on the prior privilege level.
/// - The kernel fd returned by `redox_cur_thrfd_v0()` is valid for the
/// duration of this call (the function returns a duplicated handle which is
/// closed before this function returns; the underlying fd must remain open
/// at least until the close completes).
#[cfg(all(target_arch = "x86_64", target_os = "redox"))]
pub fn acquire_iopl() -> std::result::Result<(), crate::DriverError> {
extern "C" {
@@ -26,6 +39,16 @@ pub fn acquire_iopl() -> std::result::Result<(), crate::DriverError> {
)))
}
/// Read a byte from an x86 I/O port.
///
/// # Safety
///
/// The caller must ensure:
/// - `port` is a valid x86 I/O port number (0..=0xFFFF) that is mapped for the
/// current privilege level (IOPL must have been acquired via `acquire_iopl`,
/// or the caller must be ring 0).
/// - No other thread is concurrently modifying port-mapped device state in a
/// way that makes single-byte reads racy.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn inb(port: u16) -> u8 {
@@ -34,12 +57,28 @@ pub fn inb(port: u16) -> u8 {
val
}
/// Write a byte to an x86 I/O port.
///
/// # Safety
///
/// The caller must ensure:
/// - `port` is a valid x86 I/O port number (0..=0xFFFF) that is mapped and
/// writable at the current privilege level (IOPL via `acquire_iopl`, or ring 0).
/// - Writing `val` to `port` does not produce a side effect that puts the
/// device in a state that violates the kernel's or another driver's
/// invariants (e.g. disabling an interrupt source shared with the system).
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn outb(port: u16, val: u8) {
unsafe { core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags)) };
}
/// Read a 32-bit dword from an x86 I/O port.
///
/// # Safety
///
/// Same requirements as `inb`, but reads 4 contiguous bytes (little-endian)
/// from the port. The device must support 32-bit port I/O at `port..port+3`.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn inl(port: u16) -> u32 {
@@ -48,12 +87,24 @@ pub fn inl(port: u16) -> u32 {
val
}
/// Write a 32-bit dword to an x86 I/O port.
///
/// # Safety
///
/// Same requirements as `outb`, but writes 4 contiguous bytes (little-endian)
/// to `port..port+3`. The device must support 32-bit port I/O at this range.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn outl(port: u16, val: u32) {
unsafe { core::arch::asm!("out dx, eax", in("dx") port, in("eax") val, options(nomem, nostack, preserves_flags)) };
}
/// Read a 16-bit word from an x86 I/O port.
///
/// # Safety
///
/// Same requirements as `inb`, but reads 2 contiguous bytes (little-endian)
/// from the port. The device must support 16-bit port I/O at `port..port+1`.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn inw(port: u16) -> u16 {
@@ -62,8 +113,14 @@ pub fn inw(port: u16) -> u16 {
val
}
/// Write a 16-bit word to an x86 I/O port.
///
/// # Safety
///
/// Same requirements as `outb`, but writes 2 contiguous bytes (little-endian)
/// to `port..port+1`. The device must support 16-bit port I/O at this range.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn outw(port: u16, val: u16) {
unsafe { core::arch::asm!("out dx, ax", in("dx") port, in("ax") val, options(nomem, nostack, preserves_flags)) };
}
}