Messages in this thread Patch in this message |  | | From | Albab Hasan <> | | Subject | [PATCH] rust: io: convert `PhysAddr` type alias to newtype | | Date | Mon, 4 May 2026 10:57:03 +0600 |
| |
Makes `PhysAddr` a newtype wrapper around `bindings::phys_addr_t`. This restricts what operations are possible with physical address values, helping prevent mistakes such as mixing them with other integer quantities.
Arithmetic operations are intentionally not provided; none of the current users perform address arithmetic in Rust.
Suggested-by: Miguel Ojeda <ojeda@kernel.org> Link: https://github.com/Rust-for-Linux/linux/issues/1204 Signed-off-by: Albab Hasan <albabhasan276@gmail.com> --- rust/kernel/devres.rs | 4 +-- rust/kernel/io.rs | 52 ++++++++++++++++++++++++++++++++---- rust/kernel/io/resource.rs | 6 ++--- rust/kernel/iommu/pgtable.rs | 2 +- 4 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 6afe196be42c..0de69157877b 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -72,10 +72,10 @@ /// /// /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs /// /// virtual address space. -/// unsafe fn new(paddr: usize) -> Result<Self>{ +/// unsafe fn new(paddr: PhysAddr) -> Result<Self>{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr.into(), SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index e5fba6bf6db0..7c35537edf43 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -4,6 +4,8 @@ //! //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) +use core::num::TryFromIntError; + use crate::{ bindings, prelude::*, // @@ -17,9 +19,48 @@ /// Physical address type. /// -/// This is a type alias to either `u32` or `u64` depending on the config option +/// This is a transparent wrapper around either `u32` or `u64` depending on the config option /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. -pub type PhysAddr = bindings::phys_addr_t; +/// +/// # Examples +/// +/// ``` +/// use kernel::{bindings, io::PhysAddr}; +/// +/// let raw: bindings::phys_addr_t = 0x1000; +/// let paddr = PhysAddr::from(raw); +/// let raw2: bindings::phys_addr_t = paddr.into(); +/// assert_eq!(raw, raw2); +/// +/// let size = usize::try_from(paddr).unwrap(); +/// assert_eq!(size, 0x1000); +/// ``` +#[repr(transparent)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct PhysAddr(bindings::phys_addr_t); + +impl From<bindings::phys_addr_t> for PhysAddr { + #[inline] + fn from(value: bindings::phys_addr_t) -> Self { + Self(value) + } +} + +impl From<PhysAddr> for bindings::phys_addr_t { + #[inline] + fn from(value: PhysAddr) -> Self { + value.0 + } +} + +impl TryFrom<PhysAddr> for usize { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: PhysAddr) -> Result<Self, Self::Error> { + usize::try_from(value.0) + } +} /// Resource Size type. /// @@ -97,10 +138,10 @@ pub fn maxsize(&self) -> usize { /// /// /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs /// /// virtual address space. -/// unsafe fn new(paddr: usize) -> Result<Self>{ +/// unsafe fn new(paddr: PhysAddr) -> Result<Self>{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr.into(), SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } @@ -127,7 +168,8 @@ pub fn maxsize(&self) -> usize { /// ///# fn no_run() -> Result<(), Error> { /// // SAFETY: Invalid usage for example purposes. -/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; +/// let addr = PhysAddr::from(0xBAAAAAAD as bindings::phys_addr_t); +/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(addr)? }; /// iomem.write32(0x42, 0x0); /// assert!(iomem.try_write32(0x42, 0x0).is_ok()); /// assert!(iomem.try_write32(0x42, 0x4).is_err()); diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index b7ac9faf141d..d703c7317980 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -58,7 +58,7 @@ fn drop(&mut self) { }; // SAFETY: Safe as per the invariant of `Region`. - unsafe { release_fn(start, size) }; + unsafe { release_fn(start.into(), size) }; } } @@ -113,7 +113,7 @@ pub fn request_region( let region = unsafe { bindings::__request_region( self.0.get(), - start, + start.into(), size, name.as_char_ptr(), flags.0 as c_int, @@ -137,7 +137,7 @@ pub fn size(&self) -> ResourceSize { pub fn start(&self) -> PhysAddr { let inner = self.0.get(); // SAFETY: Safe as per the invariants of `Resource`. - unsafe { (*inner).start } + unsafe { (*inner).start }.into() } /// Returns the name of the resource. diff --git a/rust/kernel/iommu/pgtable.rs b/rust/kernel/iommu/pgtable.rs index c88e38fd938a..1d75c09c47bb 100644 --- a/rust/kernel/iommu/pgtable.rs +++ b/rust/kernel/iommu/pgtable.rs @@ -182,7 +182,7 @@ pub unsafe fn map_pages( (map_pages)( self.raw_ops(), iova, - paddr, + paddr.into(), pgsize, pgcount, prot as i32, -- 2.43.0
|  |