Skip to main content

vck_loader/
chainload.rs

1// SPDX-FileCopyrightText: 2026 JC-Lab <joseph@jc-lab.net>
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Chainloading the next EFI image.
6//!
7//! Loads and starts the next OS loader (e.g. the Windows Boot Manager,
8//! `msbootmgfw.os.efi`) using `LoadImage` / `StartImage`. See docs/architecture.md boot flow
9//! step 5.
10
11use alloc::format;
12
13use uefi::boot::{image_handle, load_image, start_image, LoadImageSource};
14use uefi::proto::BootPolicy;
15use vck_common::{VckError, VckResult};
16
17use crate::provider::DevicePath;
18
19/// Loads the EFI image at `next_loader` and transfers control to it.
20///
21/// On success this normally does not return (the next loader takes over);
22/// if `StartImage` returns, the started image exited and control comes back.
23///
24/// Block IO hooks must remain installed across the chainload so the next loader
25/// reads the OS volume transparently decrypted, but the loader's own resources
26/// should otherwise be cleaned up before handing off.
27pub fn chainload_next(next_loader: &DevicePath) -> VckResult<()> {
28    let image = load_image(
29        image_handle(),
30        LoadImageSource::FromDevicePath {
31            // `next_loader` is our owned `Box<DevicePath>`; deref to the borrowed
32            // `&uefi::proto::device_path::DevicePath` the FFI source expects.
33            device_path: next_loader,
34            boot_policy: BootPolicy::ExactMatch,
35        },
36    )
37    .map_err(|e| VckError::Io(format!("LoadImage(next loader) failed: {e:?}")))?;
38
39    start_image(image)
40        .map_err(|e| VckError::Io(format!("StartImage(next loader) failed: {e:?}")))?;
41    Ok(())
42}