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 pub 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`. 30 pub 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 38 impl Deref for Region { 39 type Target = Resource; 40 deref(&self) -> &Self::Target41 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 47 impl Drop for Region { drop(&mut self)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. 67 unsafe 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. 71 unsafe 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)] 79 pub struct Resource(Opaque<bindings::resource>); 80 81 impl 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. from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self91 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. request_region( &self, start: PhysAddr, size: ResourceSize, name: CString, flags: Flags, ) -> Option<Region>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. size(&self) -> ResourceSize130 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. start(&self) -> PhysAddr137 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. name(&self) -> Option<&CStr>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. flags(&self) -> Flags162 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. 173 unsafe 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. 177 unsafe 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)] 186 pub struct Flags(c_ulong); 187 188 impl Flags { 189 /// Check whether `flags` is contained in `self`. contains(self, flags: Flags) -> bool190 pub fn contains(self, flags: Flags) -> bool { 191 (self & flags) == flags 192 } 193 } 194 195 impl core::ops::BitOr for Flags { 196 type Output = Self; bitor(self, rhs: Self) -> Self::Output197 fn bitor(self, rhs: Self) -> Self::Output { 198 Self(self.0 | rhs.0) 199 } 200 } 201 202 impl core::ops::BitAnd for Flags { 203 type Output = Self; bitand(self, rhs: Self) -> Self::Output204 fn bitand(self, rhs: Self) -> Self::Output { 205 Self(self.0 & rhs.0) 206 } 207 } 208 209 impl core::ops::Not for Flags { 210 type Output = Self; not(self) -> Self::Output211 fn not(self) -> Self::Output { 212 Self(!self.0) 213 } 214 } 215 216 impl 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 new(value: u32) -> Self229 const fn new(value: u32) -> Self { 230 crate::build_assert!(value as u64 <= c_ulong::MAX as u64); 231 Flags(value as c_ulong) 232 } 233 } 234