From: Fiona Behrens <me@xxxxxxxxxx> Add `rust::io::PortIo` implementing the `IoAccess` trait. Signed-off-by: Fiona Behrens <me@xxxxxxxxxx> Signed-off-by: Andrew Ballance <andrewjballance@xxxxxxxxx> --- rust/helpers/io.c | 20 +++++++++++ rust/kernel/io.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/rust/helpers/io.c b/rust/helpers/io.c index 525af02f209e..d439b61c672e 100644 --- a/rust/helpers/io.c +++ b/rust/helpers/io.c @@ -51,3 +51,23 @@ define_rust_mmio_write_helper(writel_relaxed, u32); #ifdef CONFIG_64BIT define_rust_mmio_write_helper(writeq_relaxed, u64); #endif + +#define define_rust_pio_read_helper(name, type) \ + type rust_helper_##name(unsigned long port) \ + { \ + return name(port); \ + } + +#define define_rust_pio_write_helper(name, type) \ + void rust_helper_##name(type value, unsigned long port) \ + { \ + name(value, port); \ + } + +define_rust_pio_read_helper(inb, u8); +define_rust_pio_read_helper(inw, u16); +define_rust_pio_read_helper(inl, u32); + +define_rust_pio_write_helper(outb, u8); +define_rust_pio_write_helper(outw, u16); +define_rust_pio_write_helper(outl, u32); diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 09440dd3e73b..70621a016a87 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -395,3 +395,91 @@ impl<const SIZE: usize> IoAccess64Relaxed<SIZE> for MMIo<SIZE> { read64_relaxed_unchecked, readq_relaxed, write64_relaxed_unchecked, writeq_relaxed, u64; ); } + +/// Port-IO, starting at the base address [`addr`] and spanning [`maxsize`] bytes. +/// +/// The creator is responsible for performing an additional region request, etc. +/// +/// # Invariants +/// +/// [`addr`] is the start and [`maxsize`] the length of a valid port io region of size [`maxsize`]. +/// +/// [`addr`] is valid to access with the C [`in`]/[`out`] family of functions. +/// +/// [`addr`]: IoAccess::addr +/// [`maxsize`]: IoAccess::maxsize +/// [`in`]: https://docs.kernel.org/driver-api/device-io.html#differences-between-i-o-access-functions +/// [`out`]: https://docs.kernel.org/driver-api/device-io.html#differences-between-i-o-access-functions +#[derive(Debug)] +#[repr(transparent)] +pub struct PortIo<const SIZE: usize = 0>(IoRaw<SIZE>); + +impl<const SIZE: usize> PortIo<SIZE> { + /// Convert a [`IoRaw`] into an [`PortIo`] instance, providing the accessors to the + /// PortIo mapping. + /// + /// # Safety + /// + /// Callers must ensure that `addr` is the start of a valid Port I/O region of size `maxsize`. + /// + /// # Examples + /// + /// ``` + /// use kernel::io::{IoRaw, PortIo, IoAccess}; + /// + /// let raw = IoRaw::<2>::new(0xDEADBEEFC0DE, 2).unwrap(); + /// // SAFETY: test, value is not actually written to. + /// let pio: PortIo<2> = unsafe { PortIo::from_raw(raw) }; + /// # assert_eq!(0xDEADBEEFC0DE, pio.addr()); + /// # assert_eq!(2, pio.maxsize()); + /// ``` + #[inline] + pub unsafe fn from_raw(raw: IoRaw<SIZE>) -> Self { + Self(raw) + } + + /// Convert a ref to [`IoRaw`] into an [`PortIo`] instance, providing the accessors to + /// the PortIo mapping. + /// + /// # Safety + /// + /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of + /// size `maxsize`. + /// + /// # Examples + /// + /// ``` + /// use kernel::io::{IoRaw, PortIo, IoAccess}; + /// + /// let raw = IoRaw::<2>::new(0xDEADBEEFC0DE, 2).unwrap(); + /// // SAFETY: test, value is not actually written to. + /// let pio: &PortIo<2> = unsafe { PortIo::from_raw_ref(&raw) }; + /// # assert_eq!(raw.addr(), pio.addr()); + /// # assert_eq!(raw.maxsize(), pio.maxsize()); + /// ``` + #[inline] + pub unsafe fn from_raw_ref(raw: &IoRaw<SIZE>) -> &Self { + // SAFETY: `PortIo` is a transparent wrapper around `IoRaw`. + unsafe { &*core::ptr::from_ref(raw).cast() } + } +} + +// SAFETY: as per invariant `raw` is valid +unsafe impl<const SIZE: usize> IoAccess<SIZE> for PortIo<SIZE> { + #[inline] + fn maxsize(&self) -> usize { + self.0.maxsize() + } + + #[inline] + fn addr(&self) -> usize { + self.0.addr() + } + + #[rustfmt::skip] + impl_accessor_fn!( + read8_unchecked, inb, write8_unchecked, outb, u8; + read16_unchecked, inw, write16_unchecked, outw, u16; + read32_unchecked, inl, write32_unchecked, outl, u32; + ); +} -- 2.49.0