initial commit

This commit is contained in:
2025-10-01 16:45:04 -07:00
commit 17ca11f239
21 changed files with 610 additions and 0 deletions

61
src/chainload.rs Normal file
View File

@@ -0,0 +1,61 @@
use uefi::{
CString16,
proto::device_path::{
DevicePath, LoadedImageDevicePath, PoolDevicePath,
text::{AllowShortcuts, DevicePathFromText, DisplayOnly},
},
};
fn text_to_device_path(path: &str) -> PoolDevicePath {
let path = CString16::try_from(path).expect("unable to convert path to CString16");
let device_path_from_text = uefi::boot::open_protocol_exclusive::<DevicePathFromText>(
uefi::boot::get_handle_for_protocol::<DevicePathFromText>()
.expect("no device path from text protocol"),
)
.expect("unable to open device path from text protocol");
device_path_from_text
.convert_text_to_device_path(&path)
.expect("unable to convert text to device path")
}
pub fn chainload(path: &str) {
let sprout_image = uefi::boot::image_handle();
let image_device_path_protocol =
uefi::boot::open_protocol_exclusive::<LoadedImageDevicePath>(sprout_image)
.expect("unable to open loaded image protocol");
let image_device_path: &DevicePath = &image_device_path_protocol;
let mut full_path = image_device_path
.node_iter()
.filter_map(|item| {
let item = item
.to_string(DisplayOnly(false), AllowShortcuts(false))
.expect("unable to convert device path to string");
if item.to_string().contains("(") {
Some(item)
} else {
None
}
})
.map(|item| item.to_string())
.collect::<Vec<_>>()
.join("/");
full_path.push('/');
full_path.push_str(path);
println!("chainload: {}", full_path);
let device_path = text_to_device_path(&full_path);
let image = uefi::boot::load_image(
sprout_image,
uefi::boot::LoadImageSource::FromDevicePath {
device_path: &device_path,
boot_policy: uefi::proto::BootPolicy::ExactMatch,
},
)
.expect("failed to load image");
uefi::boot::start_image(image).expect("failed to start image");
panic!("chainloaded image exited");
}

10
src/main.rs Normal file
View File

@@ -0,0 +1,10 @@
#![feature(uefi_std)]
pub mod chainload;
pub mod setup;
const CHAINLOADER_TARGET: &str = "\\EFI\\BOOT\\KERNEL.efi";
fn main() {
setup::init();
chainload::chainload(CHAINLOADER_TARGET);
}

16
src/setup.rs Normal file
View File

@@ -0,0 +1,16 @@
use std::os::uefi as uefi_std;
pub fn init() {
let system_table = uefi_std::env::system_table();
let image_handle = uefi_std::env::image_handle();
// SAFETY: The uefi variables above come from the Rust std.
// These variables are nonnull and calling the uefi crates with these values is validated
// to be corrected by hand.
unsafe {
uefi::table::set_system_table(system_table.as_ptr().cast());
let handle = uefi::Handle::from_ptr(image_handle.as_ptr().cast())
.expect("unable to resolve image handle");
uefi::boot::set_image_handle(handle);
}
}