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