diff --git a/uefi-raw/src/protocol/media.rs b/uefi-raw/src/protocol/media.rs new file mode 100644 index 000000000..80246fbdf --- /dev/null +++ b/uefi-raw/src/protocol/media.rs @@ -0,0 +1,25 @@ +use crate::{guid, Guid, Status}; +use crate::protocol::device_path::DevicePathProtocol; +use core::ffi::c_void; + +/// The UEFI LoadFile2 protocol. +/// +/// This protocol has a single method to load a file according to some +/// device path. +/// +/// This interface is implemented by many devices, e.g. network and filesystems. +#[derive(Debug)] +#[repr(C)] +pub struct LoadFile2 { + pub load_file: unsafe extern "efiapi" fn( + this: &mut LoadFile2, + file_path: *const DevicePathProtocol, + boot_policy: bool, + buffer_size: *mut usize, + buffer: *mut c_void, + ) -> Status, +} + +impl LoadFile2 { + pub const GUID: Guid = guid!("4006c0c1-fcb3-403e-996d-4a6c8724e06d"); +} diff --git a/uefi/src/proto/media/load_file.rs b/uefi/src/proto/media/load_file.rs new file mode 100644 index 000000000..007154a0b --- /dev/null +++ b/uefi/src/proto/media/load_file.rs @@ -0,0 +1,79 @@ +//! Load file support protocols. + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +use crate::proto::device_path::{FfiDevicePath, DevicePath}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; +use core::ffi::c_void; +use core::ptr; + +/// The UEFI LoadFile2 protocol. +/// +/// This protocol has a single method to load a file according to some +/// device path. +/// +/// This interface is implemented by many devices, e.g. network and filesystems. +#[derive(Debug)] +#[repr(transparent)] +#[unsafe_protocol(uefi_raw::protocol::media::LoadFile2::GUID)] +pub struct LoadFile2(uefi_raw::protocol::media::LoadFile2); + +impl LoadFile2 { + /// Load file addressed by provided device path + pub fn load_file(&mut self, + file_path: &DevicePath, + buffer: &mut [u8] + ) -> Result<(), usize> { + let mut buffer_size = buffer.len(); + unsafe { + (self.0.load_file)(self, + file_path, + false, + buffer_size, + buffer.as_mut_ptr() + ) + }.to_result_with( + || debug_assert_eq!(buffer_size, buffer.len()), + |_| buffer_size + ) + } + + #[cfg(feature = "alloc")] + /// Load file addressed by the provided device path. + pub fn load_file_to_vec(&mut self, + file_path: &DevicePath, + ) -> Result> { + let mut buffer_size: usize = 0; + let mut status: Status; + unsafe { + status = (self.0.load_file)(self, + file_path.as_ffi_ptr(), + false, + ptr::addr_of_mut!(buffer_size), + ptr::null_mut() + ); + } + + if status.is_error() { + return Err(status.into()); + } + + let mut buffer: Vec = Vec::with_capacity(buffer_size); + unsafe { + status = (self.0.load_file)(self, + file_path.as_ffi_ptr(), + false, + ptr::addr_of_mut!(buffer_size), + buffer.as_mut_ptr() as *mut c_void + ); + } + + if status.is_error() { + return Err(status.into()); + } + + Ok(buffer) + } +} diff --git a/uefi/src/proto/media/mod.rs b/uefi/src/proto/media/mod.rs index 6750875a6..705bfa5b9 100644 --- a/uefi/src/proto/media/mod.rs +++ b/uefi/src/proto/media/mod.rs @@ -10,3 +10,4 @@ pub mod block; pub mod disk; pub mod fs; pub mod partition; +pub mod load_file;