|
4 | 4 |
|
5 | 5 | use crate::data_types::PhysicalAddress;
|
6 | 6 | use core::ffi::c_void;
|
| 7 | +use core::ops::Deref; |
7 | 8 | use core::ptr::{self, NonNull};
|
| 9 | +use core::slice; |
8 | 10 | use core::sync::atomic::{AtomicPtr, Ordering};
|
9 | 11 | use uefi::{table, Handle, Result, StatusExt};
|
10 | 12 |
|
11 | 13 | #[cfg(doc)]
|
12 | 14 | use uefi::Status;
|
13 | 15 |
|
14 |
| -pub use uefi::table::boot::AllocateType; |
| 16 | +pub use uefi::table::boot::{AllocateType, SearchType}; |
15 | 17 | pub use uefi_raw::table::boot::MemoryType;
|
16 | 18 |
|
17 | 19 | /// Global image handle. This is only set by [`set_image_handle`], and it is
|
@@ -128,3 +130,56 @@ pub unsafe fn free_pool(ptr: NonNull<u8>) -> Result {
|
128 | 130 |
|
129 | 131 | unsafe { (bt.free_pool)(ptr.as_ptr()) }.to_result()
|
130 | 132 | }
|
| 133 | + |
| 134 | +/// Returns an array of handles that support the requested protocol in a |
| 135 | +/// pool-allocated buffer. |
| 136 | +/// |
| 137 | +/// See [`SearchType`] for details of the available search operations. |
| 138 | +/// |
| 139 | +/// # Errors |
| 140 | +/// |
| 141 | +/// * [`Status::NOT_FOUND`]: no matching handles. |
| 142 | +/// * [`Status::OUT_OF_RESOURCES`]: out of memory. |
| 143 | +pub fn locate_handle_buffer(search_ty: SearchType) -> Result<HandleBuffer> { |
| 144 | + let bt = boot_services_raw_panicking(); |
| 145 | + let bt = unsafe { bt.as_ref() }; |
| 146 | + |
| 147 | + let (ty, guid, key) = match search_ty { |
| 148 | + SearchType::AllHandles => (0, ptr::null(), ptr::null()), |
| 149 | + SearchType::ByRegisterNotify(registration) => { |
| 150 | + (1, ptr::null(), registration.0.as_ptr().cast_const()) |
| 151 | + } |
| 152 | + SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null()), |
| 153 | + }; |
| 154 | + |
| 155 | + let mut num_handles: usize = 0; |
| 156 | + let mut buffer: *mut uefi_raw::Handle = ptr::null_mut(); |
| 157 | + unsafe { (bt.locate_handle_buffer)(ty, guid, key, &mut num_handles, &mut buffer) } |
| 158 | + .to_result_with_val(|| HandleBuffer { |
| 159 | + count: num_handles, |
| 160 | + buffer: NonNull::new(buffer.cast()) |
| 161 | + .expect("locate_handle_buffer must not return a null pointer"), |
| 162 | + }) |
| 163 | +} |
| 164 | + |
| 165 | +/// A buffer returned by [`locate_handle_buffer`] that contains an array of |
| 166 | +/// [`Handle`]s that support the requested protocol. |
| 167 | +#[derive(Debug, Eq, PartialEq)] |
| 168 | +pub struct HandleBuffer { |
| 169 | + count: usize, |
| 170 | + buffer: NonNull<Handle>, |
| 171 | +} |
| 172 | + |
| 173 | +impl Drop for HandleBuffer { |
| 174 | + fn drop(&mut self) { |
| 175 | + let _ = unsafe { free_pool(self.buffer.cast::<u8>()) }; |
| 176 | + } |
| 177 | +} |
| 178 | + |
| 179 | +impl Deref for HandleBuffer { |
| 180 | + type Target = [Handle]; |
| 181 | + |
| 182 | + fn deref(&self) -> &Self::Target { |
| 183 | + unsafe { slice::from_raw_parts(self.buffer.as_ptr(), self.count) } |
| 184 | + } |
| 185 | +} |
0 commit comments