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