Skip to content

Commit 3fe59c8

Browse files
committed
uefi: Add LoadFile and LoadFile2
1 parent 7b862ac commit 3fe59c8

File tree

4 files changed

+164
-0
lines changed

4 files changed

+164
-0
lines changed

shell.nix

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pkgs.mkShell {
1919

2020
# Rust toolchain
2121
rustToolchain
22+
rustup
2223

2324
# Other
2425
yamlfmt

uefi/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
the implementations `MemoryMapRef`, `MemoryMapRefMut`, and `MemoryMapOwned`.
1616
This comes with some changes. Read below. We recommend to directly use the
1717
implementations instead of the traits.
18+
- Added `LoadFile` and `LoadFile2` which abstracts over the `LOAD_FILE` and
19+
`LOAD_FILE2` protocols.
1820

1921
## Changed
2022
- **Breaking:** `uefi::helpers::init` no longer takes an argument.

uefi/src/proto/media/load_file.rs

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! LoadFile and LoadFile2 protocols.
2+
3+
use crate::proto::unsafe_protocol;
4+
#[cfg(all(feature = "alloc", feature = "unstable"))]
5+
use alloc::alloc::Global;
6+
use uefi_raw::protocol::media::{LoadFile2Protocol, LoadFileProtocol};
7+
#[cfg(feature = "alloc")]
8+
use {
9+
crate::{mem::make_boxed, proto::device_path::DevicePath, Result, StatusExt},
10+
alloc::boxed::Box,
11+
};
12+
13+
/// Load File Protocol.
14+
///
15+
/// Used to obtain files, that are primarily boot options, from arbitrary
16+
/// devices.
17+
///
18+
/// # UEFI Spec Description
19+
/// The EFI_LOAD_FILE_PROTOCOL is a simple protocol used to obtain files from
20+
/// arbitrary devices.
21+
///
22+
/// When the firmware is attempting to load a file, it first attempts to use the
23+
/// device’s Simple File System protocol to read the file. If the file system
24+
/// protocol is found, the firmware implements the policy of interpreting the
25+
/// File Path value of the file being loaded. If the device does not support the
26+
/// file system protocol, the firmware then attempts to read the file via the
27+
/// EFI_LOAD_FILE_PROTOCOL and the LoadFile() function. In this case the
28+
/// LoadFile() function implements the policy of interpreting the File Path
29+
/// value.
30+
#[derive(Debug)]
31+
#[repr(transparent)]
32+
#[unsafe_protocol(LoadFileProtocol::GUID)]
33+
pub struct LoadFile(LoadFileProtocol);
34+
35+
impl LoadFile {
36+
/// Causes the driver to load a specified file.
37+
///
38+
/// # Parameters
39+
/// - `file_path` The device specific path of the file to load.
40+
/// - `boot_policy` If TRUE, indicates that the request originates from the
41+
/// boot manager, and that the boot manager is attempting to load FilePath
42+
/// as a boot selection. If FALSE, then FilePath must match an exact file
43+
/// to be loaded.
44+
///
45+
/// # Errors
46+
/// - `uefi::status::EFI_SUCCESS` The file was loaded.
47+
/// - `uefi::status::EFI_UNSUPPORTED` The device does not support the
48+
/// provided BootPolicy.
49+
/// - `uefi::status::EFI_INVALID_PARAMETER` FilePath is not a valid device
50+
/// path, or BufferSize is NULL.
51+
/// - `uefi::status::EFI_NO_MEDIA` No medium was present to load the file.
52+
/// - `uefi::status::EFI_DEVICE_ERROR` The file was not loaded due to a
53+
/// device error.
54+
/// - `uefi::status::EFI_NO_RESPONSE` The remote system did not respond.
55+
/// - `uefi::status::EFI_NOT_FOUND` The file was not found.
56+
/// - `uefi::status::EFI_ABORTED` The file load process was manually
57+
/// cancelled.
58+
/// - `uefi::status::EFI_BUFFER_TOO_SMALL` The BufferSize is too small to
59+
/// read the current directory entry. BufferSize has been updated with the
60+
/// size needed to complete the request.
61+
/// - `uefi::status::EFI_WARN_FILE_SYSTEM` The resulting Buffer contains
62+
/// UEFI-compliant file system.
63+
#[cfg(feature = "alloc")]
64+
#[allow(clippy::extra_unused_lifetimes)] // false positive, it is used
65+
pub fn load_file<'a>(
66+
&mut self,
67+
file_path: &DevicePath,
68+
boot_policy: bool,
69+
) -> Result<Box<[u8]>> {
70+
let this = core::ptr::addr_of_mut!(*self).cast();
71+
72+
let fetch_data_fn = |buf: &'a mut [u8]| {
73+
let mut size = buf.len();
74+
let status = unsafe {
75+
(self.0.load_file)(
76+
this,
77+
file_path.as_ffi_ptr().cast(),
78+
boot_policy,
79+
&mut size,
80+
buf.as_mut_ptr().cast(),
81+
)
82+
};
83+
status.to_result_with_err(|_| Some(size)).map(|_| buf)
84+
};
85+
86+
#[cfg(not(feature = "unstable"))]
87+
let file: Box<[u8]> = make_boxed::<[u8], _>(fetch_data_fn)?;
88+
89+
#[cfg(feature = "unstable")]
90+
let file = make_boxed::<[u8], _, _>(fetch_data_fn, Global)?;
91+
92+
Ok(file)
93+
}
94+
}
95+
96+
/// Load File2 Protocol.
97+
///
98+
/// The Load File2 protocol is used to obtain files from arbitrary devices that
99+
/// are not boot options.
100+
///
101+
/// # UEFI Spec Description
102+
///
103+
/// The EFI_LOAD_FILE2_PROTOCOL is a simple protocol used to obtain files from
104+
/// arbitrary devices that are not boot options. It is used by LoadImage() when
105+
/// its BootOption parameter is FALSE and the FilePath does not have an instance
106+
/// of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.
107+
#[derive(Debug)]
108+
#[repr(transparent)]
109+
#[unsafe_protocol(LoadFile2Protocol::GUID)]
110+
pub struct LoadFile2(LoadFile2Protocol);
111+
112+
impl LoadFile2 {
113+
/// Causes the driver to load a specified file.
114+
///
115+
/// # Parameters
116+
/// - `file_path` The device specific path of the file to load.
117+
///
118+
/// # Errors
119+
/// - `uefi::status::EFI_SUCCESS` The file was loaded.
120+
/// - `uefi::status::EFI_UNSUPPORTED` BootPolicy is TRUE.
121+
/// - `uefi::status::EFI_INVALID_PARAMETER` FilePath is not a valid device
122+
/// path, or BufferSize is NULL.
123+
/// - `uefi::status::EFI_NO_MEDIA` No medium was present to load the file.
124+
/// - `uefi::status::EFI_DEVICE_ERROR` The file was not loaded due to a
125+
/// device error.
126+
/// - `uefi::status::EFI_NO_RESPONSE` The remote system did not respond.
127+
/// - `uefi::status::EFI_NOT_FOUND` The file was not found.
128+
/// - `uefi::status::EFI_ABORTED` The file load process was manually
129+
/// cancelled.
130+
/// - `uefi::status::EFI_BUFFER_TOO_SMALL` The BufferSize is too small to
131+
/// read the current directory entry. BufferSize has been updated with the
132+
/// size needed to complete the request.
133+
#[cfg(feature = "alloc")]
134+
#[allow(clippy::extra_unused_lifetimes)] // false positive, it is used
135+
pub fn load_file<'a>(&mut self, file_path: &DevicePath) -> Result<Box<[u8]>> {
136+
let this = core::ptr::addr_of_mut!(*self).cast();
137+
138+
let fetch_data_fn = |buf: &'a mut [u8]| {
139+
let mut size = buf.len();
140+
let status = unsafe {
141+
(self.0.load_file)(
142+
this,
143+
file_path.as_ffi_ptr().cast(),
144+
false, /* always false - see spec */
145+
&mut size,
146+
buf.as_mut_ptr().cast(),
147+
)
148+
};
149+
status.to_result_with_err(|_| Some(size)).map(|_| buf)
150+
};
151+
152+
#[cfg(not(feature = "unstable"))]
153+
let file: Box<[u8]> = make_boxed::<[u8], _>(fetch_data_fn)?;
154+
155+
#[cfg(feature = "unstable")]
156+
let file = make_boxed::<[u8], _, _>(fetch_data_fn, Global)?;
157+
158+
Ok(file)
159+
}
160+
}

uefi/src/proto/media/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ pub mod file;
99
pub mod block;
1010
pub mod disk;
1111
pub mod fs;
12+
pub mod load_file;
1213
pub mod partition;

0 commit comments

Comments
 (0)