FILE
resource.rs
File preview with syntax highlighting.
linux-6.19.14/rust/kernel/io/resource.rs
1// SPDX-License-Identifier: GPL-2.0 2 3//! Abstractions for [system 4//! resources](https://docs.kernel.org/core-api/kernel-api.html#resources-management). 5//! 6//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h) 7 8use core::{ 9 ops::Deref, 10 ptr::NonNull, // 11}; 12 13use crate::{ 14 prelude::*, 15 str::CString, 16 types::Opaque, // 17}; 18 19pub use super::{ 20 PhysAddr, 21 ResourceSize, // 22}; 23 24/// A region allocated from a parent [`Resource`]. 25/// 26/// # Invariants 27/// 28/// - `self.0` points to a valid `bindings::resource` that was obtained through 29/// `bindings::__request_region`. 30pub struct Region { 31 /// The resource returned when the region was requested. 32 resource: NonNull<bindings::resource>, 33 /// The name that was passed in when the region was requested. We need to 34 /// store it for ownership reasons. 35 _name: CString, 36} 37 38impl Deref for Region { 39 type Target = Resource; 40 41 fn deref(&self) -> &Self::Target { 42 // SAFETY: Safe as per the invariant of `Region`. 43 unsafe { Resource::from_raw(self.resource.as_ptr()) } 44 } 45} 46 47impl Drop for Region { 48 fn drop(&mut self) { 49 let (flags, start, size) = { 50 let res = &**self; 51 (res.flags(), res.start(), res.size()) 52 }; 53 54 let release_fn = if flags.contains(Flags::IORESOURCE_MEM) { 55 bindings::release_mem_region 56 } else { 57 bindings::release_region 58 }; 59 60 // SAFETY: Safe as per the invariant of `Region`. 61 unsafe { release_fn(start, size) }; 62 } 63} 64 65// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from 66// any thread. 67unsafe impl Send for Region {} 68 69// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are 70// safe to be used from any thread. 71unsafe impl Sync for Region {} 72 73/// A resource abstraction. 74/// 75/// # Invariants 76/// 77/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`. 78#[repr(transparent)] 79pub struct Resource(Opaque<bindings::resource>); 80 81impl Resource { 82 /// Creates a reference to a [`Resource`] from a valid pointer. 83 /// 84 /// # Safety 85 /// 86 /// The caller must ensure that for the duration of 'a, the pointer will 87 /// point at a valid `bindings::resource`. 88 /// 89 /// The caller must also ensure that the [`Resource`] is only accessed via the 90 /// returned reference for the duration of 'a. 91 pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self { 92 // SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`. 93 unsafe { &*ptr.cast() } 94 } 95 96 /// Requests a resource region. 97 /// 98 /// Exclusive access will be given and the region will be marked as busy. 99 /// Further calls to [`Self::request_region`] will return [`None`] if 100 /// the region, or a part of it, is already in use. 101 pub fn request_region( 102 &self, 103 start: PhysAddr, 104 size: ResourceSize, 105 name: CString, 106 flags: Flags, 107 ) -> Option<Region> { 108 // SAFETY: 109 // - Safe as per the invariant of `Resource`. 110 // - `__request_region` will store a reference to the name, but that is 111 // safe as we own it and it will not be dropped until the `Region` is 112 // dropped. 113 let region = unsafe { 114 bindings::__request_region( 115 self.0.get(), 116 start, 117 size, 118 name.as_char_ptr(), 119 flags.0 as c_int, 120 ) 121 }; 122 123 Some(Region { 124 resource: NonNull::new(region)?, 125 _name: name, 126 }) 127 } 128 129 /// Returns the size of the resource. 130 pub fn size(&self) -> ResourceSize { 131 let inner = self.0.get(); 132 // SAFETY: Safe as per the invariants of `Resource`. 133 unsafe { bindings::resource_size(inner) } 134 } 135 136 /// Returns the start address of the resource. 137 pub fn start(&self) -> PhysAddr { 138 let inner = self.0.get(); 139 // SAFETY: Safe as per the invariants of `Resource`. 140 unsafe { (*inner).start } 141 } 142 143 /// Returns the name of the resource. 144 pub fn name(&self) -> Option<&CStr> { 145 let inner = self.0.get(); 146 147 // SAFETY: Safe as per the invariants of `Resource`. 148 let name = unsafe { (*inner).name }; 149 150 if name.is_null() { 151 return None; 152 } 153 154 // SAFETY: In the C code, `resource::name` either contains a null 155 // pointer or points to a valid NUL-terminated C string, and at this 156 // point we know it is not null, so we can safely convert it to a 157 // `CStr`. 158 Some(unsafe { CStr::from_char_ptr(name) }) 159 } 160 161 /// Returns the flags associated with the resource. 162 pub fn flags(&self) -> Flags { 163 let inner = self.0.get(); 164 // SAFETY: Safe as per the invariants of `Resource`. 165 let flags = unsafe { (*inner).flags }; 166 167 Flags(flags) 168 } 169} 170 171// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is 172// safe to be used from any thread. 173unsafe impl Send for Resource {} 174 175// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references 176// to which are safe to be used from any thread. 177unsafe impl Sync for Resource {} 178 179/// Resource flags as stored in the C `struct resource::flags` field. 180/// 181/// They can be combined with the operators `|`, `&`, and `!`. 182/// 183/// Values can be used from the associated constants such as 184/// [`Flags::IORESOURCE_IO`]. 185#[derive(Clone, Copy, PartialEq)] 186pub struct Flags(c_ulong); 187 188impl Flags { 189 /// Check whether `flags` is contained in `self`. 190 pub fn contains(self, flags: Flags) -> bool { 191 (self & flags) == flags 192 } 193} 194 195impl core::ops::BitOr for Flags { 196 type Output = Self; 197 fn bitor(self, rhs: Self) -> Self::Output { 198 Self(self.0 | rhs.0) 199 } 200} 201 202impl core::ops::BitAnd for Flags { 203 type Output = Self; 204 fn bitand(self, rhs: Self) -> Self::Output { 205 Self(self.0 & rhs.0) 206 } 207} 208 209impl core::ops::Not for Flags { 210 type Output = Self; 211 fn not(self) -> Self::Output { 212 Self(!self.0) 213 } 214} 215 216impl Flags { 217 /// PCI/ISA I/O ports. 218 pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO); 219 220 /// Resource is software muxed. 221 pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED); 222 223 /// Resource represents a memory region. 224 pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM); 225 226 /// Resource represents a memory region that must be ioremaped using `ioremap_np`. 227 pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED); 228 229 // Always inline to optimize out error path of `build_assert`. 230 #[inline(always)] 231 const fn new(value: u32) -> Self { 232 crate::build_assert!(value as u64 <= c_ulong::MAX as u64); 233 Flags(value as c_ulong) 234 } 235}
~/
Read-only file preview.