Skip to content

Commit 6b25708

Browse files
committed
test: add load_image integration test
1 parent a4136a0 commit 6b25708

File tree

2 files changed

+80
-12
lines changed

2 files changed

+80
-12
lines changed

uefi-test-runner/src/boot/mod.rs

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1+
use alloc::string::ToString;
12
use uefi::proto::console::text::Output;
2-
use uefi::table::boot::{BootServices, SearchType};
3+
use uefi::proto::device_path::media::FilePath;
4+
use uefi::proto::device_path::{DevicePath, LoadedImageDevicePath};
5+
use uefi::table::boot::{BootServices, LoadImageSource, SearchType};
36
use uefi::table::{Boot, SystemTable};
4-
use uefi::Identify;
7+
use uefi::{CString16, Identify};
8+
9+
mod memory;
10+
mod misc;
511

612
pub fn test(st: &SystemTable<Boot>) {
713
let bt = st.boot_services();
814
info!("Testing boot services");
915
memory::test(bt);
1016
misc::test(st);
1117
test_locate_handle_buffer(bt);
18+
test_load_image(bt);
1219
}
1320

14-
mod memory;
15-
mod misc;
16-
1721
fn test_locate_handle_buffer(bt: &BootServices) {
1822
info!("Testing the `locate_handle_buffer` function");
1923

@@ -36,3 +40,67 @@ fn test_locate_handle_buffer(bt: &BootServices) {
3640
);
3741
}
3842
}
43+
44+
/// This test loads the "self image" again into memory using the `load_image`
45+
/// boot service function. The image is not started but just loaded into memory.
46+
///
47+
/// It transitively tests the protocol [`LoadedImageDevicePath`] which is
48+
/// required as helper.
49+
fn test_load_image(bt: &BootServices) {
50+
/// The path of the loaded image executing this integration test.
51+
const LOADED_IMAGE_PATH: &str = r"\EFI\BOOT\TEST_RUNNER.EFI";
52+
53+
info!("Testing the `load_image` function");
54+
55+
let image_device_path_protocol = bt
56+
.open_protocol_exclusive::<LoadedImageDevicePath>(bt.image_handle())
57+
.expect("should open LoadedImage protocol");
58+
59+
// Note: This is the full device path. The LoadedImage protocol would only
60+
// provide us with the file-path portion of the device path.
61+
let image_device_path: &DevicePath = &image_device_path_protocol;
62+
63+
// Get the file-path portion of the device path which is typically behind
64+
// device path node (0x4, 0x4). The string is in upper case.
65+
66+
let image_device_path_file_path = image_device_path
67+
.node_iter()
68+
.find_map(|node| {
69+
let node: &FilePath = node.try_into().ok()?;
70+
let path = node.path_name().to_cstring16().ok()?;
71+
Some(path.to_string().to_uppercase())
72+
})
73+
.expect("should have file-path portion in device path");
74+
75+
assert_eq!(image_device_path_file_path.as_str(), LOADED_IMAGE_PATH);
76+
77+
// Variant A: FromBuffer
78+
{
79+
let mut fs = bt
80+
.get_image_file_system(bt.image_handle())
81+
.expect("should open file system");
82+
let path = CString16::try_from(image_device_path_file_path.as_str()).unwrap();
83+
let image_data = fs.read(&*path).expect("should read file content");
84+
let load_source = LoadImageSource::FromBuffer {
85+
buffer: image_data.as_slice(),
86+
file_path: None,
87+
};
88+
let _ = bt
89+
.load_image(bt.image_handle(), load_source)
90+
.expect("should load image");
91+
92+
log::debug!("load_image with FromBuffer strategy works");
93+
}
94+
// Variant B: FromFilePath
95+
{
96+
let load_source = LoadImageSource::FromFilePath {
97+
file_path: image_device_path,
98+
from_boot_manager: false,
99+
};
100+
let _ = bt
101+
.load_image(bt.image_handle(), load_source)
102+
.expect("should load image");
103+
104+
log::debug!("load_image with FromFilePath strategy works");
105+
}
106+
}

uefi/src/data_types/strs.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,8 @@ impl CStr16 {
211211
Self::from_u16_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1))
212212
}
213213

214-
/// Creates a C string wrapper from a u16 slice
215-
///
216-
/// Since not every u16 value is a valid UCS-2 code point, this function
217-
/// must do a bit more validity checking than CStr::from_bytes_with_nul
214+
/// Creates a `&CStr16` from a u16 slice, if the slice contains exactly
215+
/// one terminating null-byte and all chars are valid UCS-2 chars.
218216
pub fn from_u16_with_nul(codes: &[u16]) -> Result<&Self, FromSliceWithNulError> {
219217
for (pos, &code) in codes.iter().enumerate() {
220218
match code.try_into() {
@@ -234,7 +232,7 @@ impl CStr16 {
234232
Err(FromSliceWithNulError::NotNulTerminated)
235233
}
236234

237-
/// Unsafely creates a C string wrapper from a u16 slice.
235+
/// Unsafely creates a `&CStr16` from a u16 slice.
238236
///
239237
/// # Safety
240238
///
@@ -287,11 +285,13 @@ impl CStr16 {
287285
Self::from_u16_with_nul(&buf[..index + 1]).map_err(|err| match err {
288286
FromSliceWithNulError::InvalidChar(p) => FromStrWithBufError::InvalidChar(p),
289287
FromSliceWithNulError::InteriorNul(p) => FromStrWithBufError::InteriorNul(p),
290-
FromSliceWithNulError::NotNulTerminated => unreachable!(),
288+
FromSliceWithNulError::NotNulTerminated => {
289+
unreachable!()
290+
}
291291
})
292292
}
293293

294-
/// Create a [`CStr16`] from an [`UnalignedSlice`] using an aligned
294+
/// Create a `&CStr16` from an [`UnalignedSlice`] using an aligned
295295
/// buffer for storage. The lifetime of the output is tied to `buf`,
296296
/// not `src`.
297297
pub fn from_unaligned_slice<'buf>(

0 commit comments

Comments
 (0)