|
4 | 4 |
|
5 | 5 | use crate::data_types::PhysicalAddress;
|
6 | 6 | use crate::mem::memory_map::{MemoryMapBackingMemory, MemoryMapKey, MemoryMapMeta, MemoryMapOwned};
|
| 7 | +use crate::polyfill::maybe_uninit_slice_assume_init_ref; |
7 | 8 | use crate::proto::device_path::DevicePath;
|
8 | 9 | use crate::proto::{Protocol, ProtocolPointer};
|
9 | 10 | use crate::table::Revision;
|
10 | 11 | use crate::util::opt_nonnull_to_ptr;
|
11 | 12 | use core::ffi::c_void;
|
| 13 | +use core::mem::MaybeUninit; |
12 | 14 | use core::ops::{Deref, DerefMut};
|
13 | 15 | use core::ptr::{self, NonNull};
|
14 | 16 | use core::sync::atomic::{AtomicPtr, Ordering};
|
15 | 17 | use core::{mem, slice};
|
16 | 18 | use uefi::{table, Char16, Error, Event, Guid, Handle, Result, Status, StatusExt};
|
17 | 19 | use uefi_raw::table::boot::InterfaceType;
|
18 | 20 |
|
| 21 | +#[cfg(feature = "alloc")] |
| 22 | +use {alloc::vec::Vec, uefi::ResultExt}; |
| 23 | + |
19 | 24 | #[cfg(doc)]
|
20 | 25 | use {
|
21 | 26 | crate::proto::device_path::LoadedImageDevicePath, crate::proto::loaded_image::LoadedImage,
|
@@ -667,6 +672,47 @@ pub fn locate_device_path<P: ProtocolPointer + ?Sized>(
|
667 | 672 | }
|
668 | 673 | }
|
669 | 674 |
|
| 675 | +/// Enumerates all handles installed on the system which match a certain query. |
| 676 | +/// |
| 677 | +/// # Errors |
| 678 | +/// |
| 679 | +/// * [`Status::NOT_FOUND`]: no matching handles found. |
| 680 | +/// * [`Status::BUFFER_TOO_SMALL`]: the buffer is not large enough. The required |
| 681 | +/// size (in number of handles, not bytes) will be returned in the error data. |
| 682 | +pub fn locate_handle<'buf>( |
| 683 | + search_ty: SearchType, |
| 684 | + buffer: &'buf mut [MaybeUninit<Handle>], |
| 685 | +) -> Result<&'buf [Handle], Option<usize>> { |
| 686 | + let bt = boot_services_raw_panicking(); |
| 687 | + let bt = unsafe { bt.as_ref() }; |
| 688 | + |
| 689 | + // Obtain the needed data from the parameters. |
| 690 | + let (ty, guid, key) = match search_ty { |
| 691 | + SearchType::AllHandles => (0, ptr::null(), ptr::null()), |
| 692 | + SearchType::ByRegisterNotify(registration) => { |
| 693 | + (1, ptr::null(), registration.0.as_ptr().cast_const()) |
| 694 | + } |
| 695 | + SearchType::ByProtocol(guid) => (2, guid as *const Guid, ptr::null()), |
| 696 | + }; |
| 697 | + |
| 698 | + let mut buffer_size = buffer.len() * mem::size_of::<Handle>(); |
| 699 | + let status = |
| 700 | + unsafe { (bt.locate_handle)(ty, guid, key, &mut buffer_size, buffer.as_mut_ptr().cast()) }; |
| 701 | + |
| 702 | + let num_handles = buffer_size / mem::size_of::<Handle>(); |
| 703 | + |
| 704 | + match status { |
| 705 | + Status::SUCCESS => { |
| 706 | + let buffer = &buffer[..num_handles]; |
| 707 | + // SAFETY: the entries up to `num_handles` have been initialized. |
| 708 | + let handles = unsafe { maybe_uninit_slice_assume_init_ref(buffer) }; |
| 709 | + Ok(handles) |
| 710 | + } |
| 711 | + Status::BUFFER_TOO_SMALL => Err(Error::new(status, Some(num_handles))), |
| 712 | + _ => Err(Error::new(status, None)), |
| 713 | + } |
| 714 | +} |
| 715 | + |
670 | 716 | /// Returns an array of handles that support the requested protocol in a
|
671 | 717 | /// pool-allocated buffer.
|
672 | 718 | ///
|
@@ -698,6 +744,47 @@ pub fn locate_handle_buffer(search_ty: SearchType) -> Result<HandleBuffer> {
|
698 | 744 | })
|
699 | 745 | }
|
700 | 746 |
|
| 747 | +/// Returns all the handles implementing a certain protocol. |
| 748 | +/// |
| 749 | +/// # Errors |
| 750 | +/// |
| 751 | +/// * [`Status::NOT_FOUND`]: no matching handles. |
| 752 | +#[cfg(feature = "alloc")] |
| 753 | +pub fn find_handles<P: ProtocolPointer + ?Sized>() -> Result<Vec<Handle>> { |
| 754 | + // Search by protocol. |
| 755 | + let search_type = SearchType::from_proto::<P>(); |
| 756 | + |
| 757 | + // Determine how much we need to allocate. |
| 758 | + let num_handles = match locate_handle(search_type, &mut []) { |
| 759 | + Err(err) => { |
| 760 | + if err.status() == Status::BUFFER_TOO_SMALL { |
| 761 | + err.data().expect("error data is missing") |
| 762 | + } else { |
| 763 | + return Err(err.to_err_without_payload()); |
| 764 | + } |
| 765 | + } |
| 766 | + // This should never happen: if no handles match the search then a |
| 767 | + // `NOT_FOUND` error should be returned. |
| 768 | + Ok(_) => panic!("locate_handle should not return success with empty buffer"), |
| 769 | + }; |
| 770 | + |
| 771 | + // Allocate a large enough buffer without pointless initialization. |
| 772 | + let mut handles = Vec::with_capacity(num_handles); |
| 773 | + |
| 774 | + // Perform the search. |
| 775 | + let num_handles = locate_handle(search_type, handles.spare_capacity_mut()) |
| 776 | + .discard_errdata()? |
| 777 | + .len(); |
| 778 | + |
| 779 | + // Mark the returned number of elements as initialized. |
| 780 | + unsafe { |
| 781 | + handles.set_len(num_handles); |
| 782 | + } |
| 783 | + |
| 784 | + // Emit output, with warnings |
| 785 | + Ok(handles) |
| 786 | +} |
| 787 | + |
701 | 788 | /// Find an arbitrary handle that supports a particular [`Protocol`]. Returns
|
702 | 789 | /// [`NOT_FOUND`] if no handles support the protocol.
|
703 | 790 | ///
|
|
0 commit comments