Skip to content

Commit 1c8e869

Browse files
authored
Merge pull request #1273 from nicholasbishop/bishop-free-image
Add `boot::{load_image, unload_image, start_image}`
2 parents f2ace36 + 4216052 commit 1c8e869

File tree

2 files changed

+125
-17
lines changed

2 files changed

+125
-17
lines changed

uefi-test-runner/src/bin/shell_launcher.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ extern crate alloc;
1313

1414
use alloc::vec::Vec;
1515
use log::info;
16-
use uefi::boot;
16+
use uefi::boot::{self, LoadImageSource};
1717
use uefi::prelude::*;
1818
use uefi::proto::device_path::build::{self, DevicePathBuilder};
1919
use uefi::proto::device_path::{DevicePath, DeviceSubType, DeviceType, LoadedImageDevicePath};
2020
use uefi::proto::loaded_image::LoadedImage;
21-
use uefi::table::boot::LoadImageSource;
2221

2322
/// Get the device path of the shell app. This is the same as the
2423
/// currently-loaded image's device path, but with the file path part changed.
@@ -43,23 +42,21 @@ fn get_shell_app_device_path(storage: &mut Vec<u8>) -> &DevicePath {
4342
}
4443

4544
#[entry]
46-
fn efi_main(image: Handle, st: SystemTable<Boot>) -> Status {
45+
fn efi_main() -> Status {
4746
uefi::helpers::init().unwrap();
48-
let boot_services = st.boot_services();
4947

5048
let mut storage = Vec::new();
5149
let shell_image_path = get_shell_app_device_path(&mut storage);
5250

5351
// Load the shell app.
54-
let shell_image_handle = boot_services
55-
.load_image(
56-
image,
57-
LoadImageSource::FromDevicePath {
58-
device_path: shell_image_path,
59-
from_boot_manager: false,
60-
},
61-
)
62-
.expect("failed to load shell app");
52+
let shell_image_handle = boot::load_image(
53+
boot::image_handle(),
54+
LoadImageSource::FromDevicePath {
55+
device_path: shell_image_path,
56+
from_boot_manager: false,
57+
},
58+
)
59+
.expect("failed to load shell app");
6360

6461
// Set the command line passed to the shell app so that it will run the
6562
// test-runner app. This automatically turns off the five-second delay.
@@ -74,9 +71,7 @@ fn efi_main(image: Handle, st: SystemTable<Boot>) -> Status {
7471
}
7572

7673
info!("launching the shell app");
77-
boot_services
78-
.start_image(shell_image_handle)
79-
.expect("failed to launch the shell app");
74+
boot::start_image(shell_image_handle).expect("failed to launch the shell app");
8075

8176
Status::SUCCESS
8277
}

uefi/src/boot.rs

+114-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@ use core::slice;
1111
use core::sync::atomic::{AtomicPtr, Ordering};
1212
use uefi::{table, Handle, Result, Status, StatusExt};
1313

14-
pub use uefi::table::boot::{AllocateType, OpenProtocolAttributes, OpenProtocolParams, SearchType};
14+
#[cfg(doc)]
15+
use {
16+
crate::proto::device_path::LoadedImageDevicePath, crate::proto::loaded_image::LoadedImage,
17+
crate::proto::media::fs::SimpleFileSystem,
18+
};
19+
20+
pub use uefi::table::boot::{
21+
AllocateType, LoadImageSource, OpenProtocolAttributes, OpenProtocolParams, SearchType,
22+
};
1523
pub use uefi_raw::table::boot::MemoryType;
1624

1725
/// Global image handle. This is only set by [`set_image_handle`], and it is
@@ -242,6 +250,111 @@ pub fn open_protocol_exclusive<P: ProtocolPointer + ?Sized>(
242250
}
243251
}
244252

253+
/// Loads a UEFI image into memory and return a [`Handle`] to the image.
254+
///
255+
/// There are two ways to load the image: by copying raw image data
256+
/// from a source buffer, or by loading the image via the
257+
/// [`SimpleFileSystem`] protocol. See [`LoadImageSource`] for more
258+
/// details of the `source` parameter.
259+
///
260+
/// The `parent_image_handle` is used to initialize the
261+
/// `parent_handle` field of the [`LoadedImage`] protocol for the
262+
/// image.
263+
///
264+
/// If the image is successfully loaded, a [`Handle`] supporting the
265+
/// [`LoadedImage`] and [`LoadedImageDevicePath`] protocols is returned. The
266+
/// image can be started with [`start_image`] and unloaded with
267+
/// [`unload_image`].
268+
///
269+
/// # Errors
270+
///
271+
/// * [`Status::INVALID_PARAMETER`]: `source` contains an invalid value.
272+
/// * [`Status::UNSUPPORTED`]: the image type is not supported.
273+
/// * [`Status::OUT_OF_RESOURCES`]: insufficient resources to load the image.
274+
/// * [`Status::LOAD_ERROR`]: the image is invalid.
275+
/// * [`Status::DEVICE_ERROR`]: failed to load image due to a read error.
276+
/// * [`Status::ACCESS_DENIED`]: failed to load image due to a security policy.
277+
/// * [`Status::SECURITY_VIOLATION`]: a security policy specifies that the image
278+
/// should not be started.
279+
pub fn load_image(parent_image_handle: Handle, source: LoadImageSource) -> Result<Handle> {
280+
let bt = boot_services_raw_panicking();
281+
let bt = unsafe { bt.as_ref() };
282+
283+
let boot_policy;
284+
let device_path;
285+
let source_buffer;
286+
let source_size;
287+
match source {
288+
LoadImageSource::FromBuffer { buffer, file_path } => {
289+
// Boot policy is ignored when loading from source buffer.
290+
boot_policy = 0;
291+
292+
device_path = file_path.map(|p| p.as_ffi_ptr()).unwrap_or(ptr::null());
293+
source_buffer = buffer.as_ptr();
294+
source_size = buffer.len();
295+
}
296+
LoadImageSource::FromDevicePath {
297+
device_path: file_path,
298+
from_boot_manager,
299+
} => {
300+
boot_policy = u8::from(from_boot_manager);
301+
device_path = file_path.as_ffi_ptr();
302+
source_buffer = ptr::null();
303+
source_size = 0;
304+
}
305+
};
306+
307+
let mut image_handle = ptr::null_mut();
308+
unsafe {
309+
(bt.load_image)(
310+
boot_policy,
311+
parent_image_handle.as_ptr(),
312+
device_path.cast(),
313+
source_buffer,
314+
source_size,
315+
&mut image_handle,
316+
)
317+
.to_result_with_val(
318+
// OK to unwrap: image handle is non-null for Status::SUCCESS.
319+
|| Handle::from_ptr(image_handle).unwrap(),
320+
)
321+
}
322+
}
323+
324+
/// Unloads a UEFI image.
325+
///
326+
/// # Errors
327+
///
328+
/// * [`Status::UNSUPPORTED`]: the image has been started, and does not support unload.
329+
/// * [`Status::INVALID_PARAMETER`]: `image_handle` is not valid.
330+
pub fn unload_image(image_handle: Handle) -> Result {
331+
let bt = boot_services_raw_panicking();
332+
let bt = unsafe { bt.as_ref() };
333+
334+
unsafe { (bt.unload_image)(image_handle.as_ptr()) }.to_result()
335+
}
336+
337+
/// Transfers control to a loaded image's entry point.
338+
///
339+
/// # Errors
340+
///
341+
/// * [`Status::INVALID_PARAMETER`]: `image_handle` is not valid, or the image
342+
/// has already been initialized with `start_image`.
343+
/// * [`Status::SECURITY_VIOLATION`]: a security policy specifies that the image
344+
/// should not be started.
345+
pub fn start_image(image_handle: Handle) -> Result {
346+
let bt = boot_services_raw_panicking();
347+
let bt = unsafe { bt.as_ref() };
348+
349+
// TODO: implement returning exit data to the caller.
350+
let mut exit_data_size: usize = 0;
351+
let mut exit_data: *mut u16 = ptr::null_mut();
352+
353+
unsafe {
354+
(bt.start_image)(image_handle.as_ptr(), &mut exit_data_size, &mut exit_data).to_result()
355+
}
356+
}
357+
245358
/// A buffer returned by [`locate_handle_buffer`] that contains an array of
246359
/// [`Handle`]s that support the requested protocol.
247360
#[derive(Debug, Eq, PartialEq)]

0 commit comments

Comments
 (0)