From 8e56b33d59593a99fdef6f73f0c1a09a012ca907 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 28 Jan 2023 23:37:54 +0530 Subject: Fixes from PR Signed-off-by: Ayush Singh --- library/std/src/sys/uefi/alloc.rs | 12 +- library/std/src/sys/uefi/common.rs | 269 ---------------------------------- library/std/src/sys/uefi/helpers.rs | 280 ++++++++++++++++++++++++++++++++++++ library/std/src/sys/uefi/mod.rs | 24 ++-- 4 files changed, 297 insertions(+), 288 deletions(-) delete mode 100644 library/std/src/sys/uefi/common.rs create mode 100644 library/std/src/sys/uefi/helpers.rs (limited to 'library/std/src/sys') diff --git a/library/std/src/sys/uefi/alloc.rs b/library/std/src/sys/uefi/alloc.rs index 6a14ee76e92..54d86d0c8a7 100644 --- a/library/std/src/sys/uefi/alloc.rs +++ b/library/std/src/sys/uefi/alloc.rs @@ -13,11 +13,8 @@ unsafe impl GlobalAlloc for System { Some(x) => x.as_ptr() as *mut _, }; - if layout.size() > 0 { - unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) } - } else { - layout.dangling().as_ptr() - } + // The caller must ensure non-0 layout + unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) } } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { @@ -25,8 +22,7 @@ unsafe impl GlobalAlloc for System { None => handle_alloc_error(layout), Some(x) => x.as_ptr() as *mut _, }; - if layout.size() > 0 { - unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) } - } + // The caller must ensure non-0 layout + unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) } } } diff --git a/library/std/src/sys/uefi/common.rs b/library/std/src/sys/uefi/common.rs deleted file mode 100644 index 6316a74d367..00000000000 --- a/library/std/src/sys/uefi/common.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Contains most of the shared UEFI specific stuff. Some of this might be moved to `std::os::uefi` -//! if needed but no point in adding extra public API when there is not Std support for UEFI in the -//! first place - -use r_efi::efi::Guid; - -use crate::io::{self, const_io_error}; -use crate::mem::MaybeUninit; -use crate::os::uefi; -use crate::ptr::NonNull; - -// Locate handles with a particular protocol GUID -/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()` -pub(crate) fn locate_handles(mut guid: Guid) -> io::Result>> { - fn inner( - guid: &mut Guid, - boot_services: NonNull, - buf_size: &mut usize, - buf: *mut r_efi::efi::Handle, - ) -> io::Result<()> { - let r = unsafe { - ((*boot_services.as_ptr()).locate_handle)( - r_efi::efi::BY_PROTOCOL, - guid, - crate::ptr::null_mut(), - buf_size, - buf, - ) - }; - - if r.is_error() { Err(status_to_io_error(r)) } else { Ok(()) } - } - - let boot_services = boot_services(); - let mut buf_len = 0usize; - - match inner(&mut guid, boot_services, &mut buf_len, crate::ptr::null_mut()) { - Ok(()) => unreachable!(), - Err(e) => match e.kind() { - io::ErrorKind::FileTooLarge => {} - _ => return Err(e), - }, - } - - // The returned buf_len is in bytes - let mut buf: Vec = - Vec::with_capacity(buf_len / crate::mem::size_of::()); - match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) { - Ok(()) => { - // SAFETY: This is safe because the call will succeed only if buf_len >= required - // length. Also, on success, the `buf_len` is updated with the size of bufferv (in - // bytes) written - unsafe { buf.set_len(buf_len / crate::mem::size_of::()) }; - Ok(buf.iter().filter_map(|x| NonNull::new(*x)).collect()) - } - Err(e) => Err(e), - } -} - -/// Open Protocol on a handle -/// Implemented using `EFI_BOOT_SERVICES.OpenProtocol()` -pub(crate) fn open_protocol( - handle: NonNull, - mut protocol_guid: Guid, -) -> io::Result> { - let boot_services = boot_services(); - let system_handle = uefi::env::image_handle(); - let mut protocol: MaybeUninit<*mut T> = MaybeUninit::uninit(); - - let r = unsafe { - ((*boot_services.as_ptr()).open_protocol)( - handle.as_ptr(), - &mut protocol_guid, - protocol.as_mut_ptr().cast(), - system_handle.as_ptr(), - crate::ptr::null_mut(), - r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL, - ) - }; - - if r.is_error() { - Err(status_to_io_error(r)) - } else { - NonNull::new(unsafe { protocol.assume_init() }) - .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) - } -} - -pub(crate) fn status_to_io_error(s: r_efi::efi::Status) -> io::Error { - use io::ErrorKind; - use r_efi::efi::Status; - - // Keep the List in Alphabetical Order - // The Messages are taken from UEFI Specification Appendix D - Status Codes - match s { - Status::ABORTED => { - const_io_error!(ErrorKind::ConnectionAborted, "The operation was aborted.") - } - Status::ACCESS_DENIED => { - const_io_error!(ErrorKind::PermissionDenied, "Access was denied.") - } - Status::ALREADY_STARTED => { - const_io_error!(ErrorKind::Other, "The protocol has already been started.") - } - Status::BAD_BUFFER_SIZE => { - const_io_error!( - ErrorKind::InvalidData, - "The buffer was not the proper size for the request." - ) - } - Status::BUFFER_TOO_SMALL => { - const_io_error!( - ErrorKind::FileTooLarge, - "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs." - ) - } - Status::COMPROMISED_DATA => { - const_io_error!( - ErrorKind::Other, - "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status." - ) - } - Status::CONNECTION_FIN => { - const_io_error!( - ErrorKind::Other, - "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance." - ) - } - Status::CONNECTION_REFUSED => { - const_io_error!( - ErrorKind::ConnectionRefused, - "The receiving or transmission operation fails because this connection is refused." - ) - } - Status::CONNECTION_RESET => { - const_io_error!( - ErrorKind::ConnectionReset, - "The connect fails because the connection is reset either by instance itself or the communication peer." - ) - } - Status::CRC_ERROR => const_io_error!(ErrorKind::Other, "A CRC error was detected."), - Status::DEVICE_ERROR => const_io_error!( - ErrorKind::Other, - "The physical device reported an error while attempting the operation." - ), - Status::END_OF_FILE => { - const_io_error!(ErrorKind::UnexpectedEof, "The end of the file was reached.") - } - Status::END_OF_MEDIA => { - const_io_error!(ErrorKind::Other, "Beginning or end of media was reached") - } - Status::HOST_UNREACHABLE => { - const_io_error!(ErrorKind::HostUnreachable, "The remote host is not reachable.") - } - Status::HTTP_ERROR => { - const_io_error!(ErrorKind::Other, "A HTTP error occurred during the network operation.") - } - Status::ICMP_ERROR => { - const_io_error!( - ErrorKind::Other, - "An ICMP error occurred during the network operation." - ) - } - Status::INCOMPATIBLE_VERSION => { - const_io_error!( - ErrorKind::Other, - "The function encountered an internal version that was incompatible with a version requested by the caller." - ) - } - Status::INVALID_LANGUAGE => { - const_io_error!(ErrorKind::InvalidData, "The language specified was invalid.") - } - Status::INVALID_PARAMETER => { - const_io_error!(ErrorKind::InvalidInput, "A parameter was incorrect.") - } - Status::IP_ADDRESS_CONFLICT => { - const_io_error!(ErrorKind::AddrInUse, "There is an address conflict address allocation") - } - Status::LOAD_ERROR => { - const_io_error!(ErrorKind::Other, "The image failed to load.") - } - Status::MEDIA_CHANGED => { - const_io_error!( - ErrorKind::Other, - "The medium in the device has changed since the last access." - ) - } - Status::NETWORK_UNREACHABLE => { - const_io_error!( - ErrorKind::NetworkUnreachable, - "The network containing the remote host is not reachable." - ) - } - Status::NO_MAPPING => { - const_io_error!(ErrorKind::Other, "A mapping to a device does not exist.") - } - Status::NO_MEDIA => { - const_io_error!( - ErrorKind::Other, - "The device does not contain any medium to perform the operation." - ) - } - Status::NO_RESPONSE => { - const_io_error!( - ErrorKind::HostUnreachable, - "The server was not found or did not respond to the request." - ) - } - Status::NOT_FOUND => const_io_error!(ErrorKind::NotFound, "The item was not found."), - Status::NOT_READY => { - const_io_error!(ErrorKind::ResourceBusy, "There is no data pending upon return.") - } - Status::NOT_STARTED => { - const_io_error!(ErrorKind::Other, "The protocol has not been started.") - } - Status::OUT_OF_RESOURCES => { - const_io_error!(ErrorKind::OutOfMemory, "A resource has run out.") - } - Status::PROTOCOL_ERROR => { - const_io_error!( - ErrorKind::Other, - "A protocol error occurred during the network operation." - ) - } - Status::PROTOCOL_UNREACHABLE => { - const_io_error!(ErrorKind::Other, "An ICMP protocol unreachable error is received.") - } - Status::SECURITY_VIOLATION => { - const_io_error!( - ErrorKind::PermissionDenied, - "The function was not performed due to a security violation." - ) - } - Status::TFTP_ERROR => { - const_io_error!(ErrorKind::Other, "A TFTP error occurred during the network operation.") - } - Status::TIMEOUT => const_io_error!(ErrorKind::TimedOut, "The timeout time expired."), - Status::UNSUPPORTED => { - const_io_error!(ErrorKind::Unsupported, "The operation is not supported.") - } - Status::VOLUME_FULL => { - const_io_error!(ErrorKind::StorageFull, "There is no more space on the file system.") - } - Status::VOLUME_CORRUPTED => { - const_io_error!( - ErrorKind::Other, - "An inconstancy was detected on the file system causing the operating to fail." - ) - } - Status::WRITE_PROTECTED => { - const_io_error!(ErrorKind::ReadOnlyFilesystem, "The device cannot be written to.") - } - _ => io::Error::new(ErrorKind::Uncategorized, format!("Status: {}", s.as_usize())), - } -} - -/// Get the BootServices Pointer. -pub(crate) fn boot_services() -> NonNull { - let system_table: NonNull = uefi::env::system_table().cast(); - let boot_services = unsafe { (*system_table.as_ptr()).boot_services }; - NonNull::new(boot_services).unwrap() -} -/// Get the BootServices Pointer. -/// This function is mostly intended for places where panic is not an option -pub(crate) fn try_boot_services() -> Option> { - let system_table: NonNull = uefi::env::try_system_table()?.cast(); - let boot_services = unsafe { (*system_table.as_ptr()).boot_services }; - NonNull::new(boot_services) -} diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs new file mode 100644 index 00000000000..e83adabaf16 --- /dev/null +++ b/library/std/src/sys/uefi/helpers.rs @@ -0,0 +1,280 @@ +//! Contains most of the shared UEFI specific stuff. Some of this might be moved to `std::os::uefi` +//! if needed but no point in adding extra public API when there is not Std support for UEFI in the +//! first place +//! +//! Some Nomenclature +//! * Protocol: +//! - Protocols serve to enable communication between separately built modules, including drivers. +//! - Every protocol has a GUID associated with it. The GUID serves as the name for the protocol. +//! - Protocols are produced and consumed. +//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles) + +use r_efi::efi::Guid; + +use crate::io::{self, const_io_error}; +use crate::mem::{size_of, MaybeUninit}; +use crate::os::uefi; +use crate::ptr::NonNull; + +/// Locate Handles with a particular Protocol GUID +/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()` +/// +/// Returns an array of [Handles](r_efi::efi::Handle) that support a specified protocol. +pub(crate) fn locate_handles(mut guid: Guid) -> io::Result>> { + fn inner( + guid: &mut Guid, + boot_services: NonNull, + buf_size: &mut usize, + buf: *mut r_efi::efi::Handle, + ) -> io::Result<()> { + let r = unsafe { + ((*boot_services.as_ptr()).locate_handle)( + r_efi::efi::BY_PROTOCOL, + guid, + crate::ptr::null_mut(), + buf_size, + buf, + ) + }; + + if r.is_error() { Err(status_to_io_error(r)) } else { Ok(()) } + } + + let boot_services = boot_services(); + let mut buf_len = 0usize; + + // This should always fail since the size of buffer is 0. This call should update the buf_len + // variable with the required buffer length + match inner(&mut guid, boot_services, &mut buf_len, crate::ptr::null_mut()) { + Ok(()) => unreachable!(), + Err(e) => match e.kind() { + io::ErrorKind::FileTooLarge => {} + _ => return Err(e), + }, + } + + // The returned buf_len is in bytes + let mut buf: Vec = + Vec::with_capacity(buf_len / size_of::()); + match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) { + Ok(()) => { + // This is safe because the call will succeed only if buf_len >= required length. + // Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written + unsafe { buf.set_len(buf_len / size_of::()) }; + Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect()) + } + Err(e) => Err(e), + } +} + +/// Open Protocol on a handle. +/// Internally just a call to `EFI_BOOT_SERVICES.OpenProtocol()`. +/// +/// Queries a handle to determine if it supports a specified protocol. If the protocol is +/// supported by the handle, it opens the protocol on behalf of the calling agent. +pub(crate) fn open_protocol( + handle: NonNull, + mut protocol_guid: Guid, +) -> io::Result> { + let boot_services = boot_services(); + let system_handle = uefi::env::image_handle(); + let mut protocol: MaybeUninit<*mut T> = MaybeUninit::uninit(); + + let r = unsafe { + ((*boot_services.as_ptr()).open_protocol)( + handle.as_ptr(), + &mut protocol_guid, + protocol.as_mut_ptr().cast(), + system_handle.as_ptr(), + crate::ptr::null_mut(), + r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL, + ) + }; + + if r.is_error() { + Err(status_to_io_error(r)) + } else { + NonNull::new(unsafe { protocol.assume_init() }) + .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) + } +} + +pub(crate) fn status_to_io_error(s: r_efi::efi::Status) -> io::Error { + use io::ErrorKind; + use r_efi::efi::Status; + + // Keep the List in Alphabetical Order + // The Messages are taken from UEFI Specification Appendix D - Status Codes + match s { + Status::ABORTED => { + const_io_error!(ErrorKind::ConnectionAborted, "The operation was aborted.") + } + Status::ACCESS_DENIED => { + const_io_error!(ErrorKind::PermissionDenied, "Access was denied.") + } + Status::ALREADY_STARTED => { + const_io_error!(ErrorKind::Other, "The protocol has already been started.") + } + Status::BAD_BUFFER_SIZE => { + const_io_error!( + ErrorKind::InvalidData, + "The buffer was not the proper size for the request." + ) + } + Status::BUFFER_TOO_SMALL => { + const_io_error!( + ErrorKind::FileTooLarge, + "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs." + ) + } + Status::COMPROMISED_DATA => { + const_io_error!( + ErrorKind::Other, + "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status." + ) + } + Status::CONNECTION_FIN => { + const_io_error!( + ErrorKind::Other, + "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance." + ) + } + Status::CONNECTION_REFUSED => { + const_io_error!( + ErrorKind::ConnectionRefused, + "The receiving or transmission operation fails because this connection is refused." + ) + } + Status::CONNECTION_RESET => { + const_io_error!( + ErrorKind::ConnectionReset, + "The connect fails because the connection is reset either by instance itself or the communication peer." + ) + } + Status::CRC_ERROR => const_io_error!(ErrorKind::Other, "A CRC error was detected."), + Status::DEVICE_ERROR => const_io_error!( + ErrorKind::Other, + "The physical device reported an error while attempting the operation." + ), + Status::END_OF_FILE => { + const_io_error!(ErrorKind::UnexpectedEof, "The end of the file was reached.") + } + Status::END_OF_MEDIA => { + const_io_error!(ErrorKind::Other, "Beginning or end of media was reached") + } + Status::HOST_UNREACHABLE => { + const_io_error!(ErrorKind::HostUnreachable, "The remote host is not reachable.") + } + Status::HTTP_ERROR => { + const_io_error!(ErrorKind::Other, "A HTTP error occurred during the network operation.") + } + Status::ICMP_ERROR => { + const_io_error!( + ErrorKind::Other, + "An ICMP error occurred during the network operation." + ) + } + Status::INCOMPATIBLE_VERSION => { + const_io_error!( + ErrorKind::Other, + "The function encountered an internal version that was incompatible with a version requested by the caller." + ) + } + Status::INVALID_LANGUAGE => { + const_io_error!(ErrorKind::InvalidData, "The language specified was invalid.") + } + Status::INVALID_PARAMETER => { + const_io_error!(ErrorKind::InvalidInput, "A parameter was incorrect.") + } + Status::IP_ADDRESS_CONFLICT => { + const_io_error!(ErrorKind::AddrInUse, "There is an address conflict address allocation") + } + Status::LOAD_ERROR => { + const_io_error!(ErrorKind::Other, "The image failed to load.") + } + Status::MEDIA_CHANGED => { + const_io_error!( + ErrorKind::Other, + "The medium in the device has changed since the last access." + ) + } + Status::NETWORK_UNREACHABLE => { + const_io_error!( + ErrorKind::NetworkUnreachable, + "The network containing the remote host is not reachable." + ) + } + Status::NO_MAPPING => { + const_io_error!(ErrorKind::Other, "A mapping to a device does not exist.") + } + Status::NO_MEDIA => { + const_io_error!( + ErrorKind::Other, + "The device does not contain any medium to perform the operation." + ) + } + Status::NO_RESPONSE => { + const_io_error!( + ErrorKind::HostUnreachable, + "The server was not found or did not respond to the request." + ) + } + Status::NOT_FOUND => const_io_error!(ErrorKind::NotFound, "The item was not found."), + Status::NOT_READY => { + const_io_error!(ErrorKind::ResourceBusy, "There is no data pending upon return.") + } + Status::NOT_STARTED => { + const_io_error!(ErrorKind::Other, "The protocol has not been started.") + } + Status::OUT_OF_RESOURCES => { + const_io_error!(ErrorKind::OutOfMemory, "A resource has run out.") + } + Status::PROTOCOL_ERROR => { + const_io_error!( + ErrorKind::Other, + "A protocol error occurred during the network operation." + ) + } + Status::PROTOCOL_UNREACHABLE => { + const_io_error!(ErrorKind::Other, "An ICMP protocol unreachable error is received.") + } + Status::SECURITY_VIOLATION => { + const_io_error!( + ErrorKind::PermissionDenied, + "The function was not performed due to a security violation." + ) + } + Status::TFTP_ERROR => { + const_io_error!(ErrorKind::Other, "A TFTP error occurred during the network operation.") + } + Status::TIMEOUT => const_io_error!(ErrorKind::TimedOut, "The timeout time expired."), + Status::UNSUPPORTED => { + const_io_error!(ErrorKind::Unsupported, "The operation is not supported.") + } + Status::VOLUME_FULL => { + const_io_error!(ErrorKind::StorageFull, "There is no more space on the file system.") + } + Status::VOLUME_CORRUPTED => { + const_io_error!( + ErrorKind::Other, + "An inconstancy was detected on the file system causing the operating to fail." + ) + } + Status::WRITE_PROTECTED => { + const_io_error!(ErrorKind::ReadOnlyFilesystem, "The device cannot be written to.") + } + _ => io::Error::new(ErrorKind::Uncategorized, format!("Status: {}", s.as_usize())), + } +} + +/// Get the BootServices Pointer. +pub(crate) fn boot_services() -> NonNull { + try_boot_services().unwrap() +} +/// Get the BootServices Pointer. +/// This function is mostly intended for places where panic is not an option +pub(crate) fn try_boot_services() -> Option> { + let system_table: NonNull = uefi::env::try_system_table()?.cast(); + let boot_services = unsafe { (*system_table.as_ptr()).boot_services }; + NonNull::new(boot_services) +} diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs index 193d4ecc16f..fed44b4f49d 100644 --- a/library/std/src/sys/uefi/mod.rs +++ b/library/std/src/sys/uefi/mod.rs @@ -47,7 +47,7 @@ pub mod thread_local_key; #[path = "../unsupported/time.rs"] pub mod time; -pub(crate) mod common; +pub(crate) mod helpers; #[cfg(test)] mod tests; @@ -60,18 +60,20 @@ pub mod memchr { pub use core::slice::memchr::{memchr, memrchr}; } -// SAFETY: must be called only once during runtime initialization. -// SAFETY: argc must be 2. -// SAFETY: argv must be &[Handle, *mut SystemTable]. -pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { +/// # SAFETY +/// - must be called only once during runtime initialization. +/// - argc must be 2. +/// - argv must be &[Handle, *mut SystemTable]. +pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { assert_eq!(argc, 2); let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() }; let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() }; unsafe { crate::os::uefi::env::init_globals(image_handle, system_table) }; } -// SAFETY: must be called only once during runtime cleanup. -// NOTE: this is not guaranteed to run, for example when the program aborts. +/// # SAFETY +/// this is not guaranteed to run, for example when the program aborts. +/// - must be called only once during runtime cleanup. pub unsafe fn cleanup() {} #[inline] @@ -89,7 +91,7 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { use r_efi::efi::Status; if let Ok(code) = usize::try_from(code) { - common::status_to_io_error(Status::from_usize(code)).kind() + helpers::status_to_io_error(Status::from_usize(code)).kind() } else { ErrorKind::Uncategorized } @@ -97,7 +99,7 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { pub fn abort_internal() -> ! { if let (Some(boot_services), Some(handle)) = - (common::try_boot_services(), uefi::env::try_image_handle()) + (helpers::try_boot_services(), uefi::env::try_image_handle()) { let _ = unsafe { ((*boot_services.as_ptr()).exit)( @@ -130,9 +132,9 @@ fn get_random() -> Option<(u64, u64)> { use r_efi::protocols::rng; let mut buf = [0u8; 16]; - let handles = common::locate_handles(rng::PROTOCOL_GUID).ok()?; + let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?; for handle in handles { - if let Ok(protocol) = common::open_protocol::(handle, rng::PROTOCOL_GUID) { + if let Ok(protocol) = helpers::open_protocol::(handle, rng::PROTOCOL_GUID) { let r = unsafe { ((*protocol.as_ptr()).get_rng)( protocol.as_ptr(), -- cgit 1.4.1-3-g733a5