Skip to content
This repository has been archived by the owner on Sep 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #16 from x1tan/loader-application
Browse files Browse the repository at this point in the history
Add EFI loader application to first load the hypervisor and subsequently start Windows
  • Loading branch information
memN0ps authored Apr 2, 2024
2 parents b54bc1d + 152155f commit f4d29d8
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ resolver = "2"

members = [
"driver",
"hypervisor",
"hypervisor",
"loader",
]

[profile.release]
Expand Down
2 changes: 2 additions & 0 deletions loader/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "x86_64-unknown-uefi"
10 changes: 10 additions & 0 deletions loader/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "loader"
version = "0.1.0"
edition = "2021"

[dependencies]
log = "0.4.20"

uefi = { version = "0.27.0", features = ["alloc"] }
uefi-services = { version = "0.24.0", default-features = true }
7 changes: 7 additions & 0 deletions loader/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Loader

The loader is a simple EFI application which searches the available file systems to first load the illusion hypervisor (`illusion.efi`) and then start Windows (`bootmgfw.efi`).

## Usage

Build the loader (`$ cargo build --target x86_64-unknown-uefi --profile release --package loader`) and copy the loader (`EFI/Boot/bootx64.efi`) as well as the hypervisor (`EFI/Boot/illusion.efi`) to your boot disk. The loader will automatically start the hypervisor and Windows.
99 changes: 99 additions & 0 deletions loader/src/images.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
extern crate alloc;

use {
alloc::{borrow::ToOwned, boxed::Box, vec::Vec},
uefi::{
prelude::*,
proto::{
device_path::{
build::{media::FilePath, DevicePathBuilder},
DevicePath,
},
media::{
file::{File, FileAttribute, FileMode},
fs::SimpleFileSystem,
},
},
table::boot::{HandleBuffer, SearchType},
CStr16, Identify,
},
};

const WINDOWS_BOOT_MANAGER_PATH: &CStr16 = cstr16!("\\efi\\microsoft\\boot\\bootmgfw.efi");
const HYPERVISOR_PATH: &CStr16 = cstr16!("\\efi\\boot\\illusion.efi");

/// Finds the device path for a given file path.
///
/// # Arguments
///
/// * `boot_services` - A reference to the UEFI boot services.
/// * `path` - The file path to search for, as a `CStr16`.
///
/// # Returns
///
/// If a device containing the specified file is found, this function returns an `Option` containing
/// a `DevicePath` to the file. If no such device is found, it returns `None`.
pub(crate) fn find_device_path(
boot_services: &BootServices,
path: &CStr16,
) -> Option<Box<DevicePath>> {
let handles: HandleBuffer = boot_services
.locate_handle_buffer(SearchType::ByProtocol(&SimpleFileSystem::GUID))
.ok()?;

handles.iter().find_map(|handle| {
let mut file_system = boot_services
.open_protocol_exclusive::<SimpleFileSystem>(*handle)
.ok()?;

let mut root = file_system.open_volume().ok()?;
root.open(path, FileMode::Read, FileAttribute::READ_ONLY)
.ok()?;

let device_path = boot_services
.open_protocol_exclusive::<DevicePath>(*handle)
.ok()?;

let mut storage = Vec::new();
let boot_path = device_path
.node_iter()
.fold(
DevicePathBuilder::with_vec(&mut storage),
|builder, item| builder.push(&item).unwrap(),
)
.push(&FilePath { path_name: path })
.ok()?
.finalize()
.ok()?;

Some(boot_path.to_owned())
})
}

/// Finds the device path of the Windows boot manager.
///
/// # Arguments
///
/// * `boot_services` - A reference to the UEFI boot services.
///
/// # Returns
///
/// If a device containing the Windows boot manager is found, this function returns an `Option` containing
/// a `DevicePath` to the file. If no such device is found, it returns `None`.
pub(crate) fn find_windows_boot_manager(boot_services: &BootServices) -> Option<Box<DevicePath>> {
find_device_path(boot_services, WINDOWS_BOOT_MANAGER_PATH)
}

/// Finds the device path of the Illusion hypervisor.
///
/// # Arguments
///
/// * `boot_services` - A reference to the UEFI boot services.
///
/// # Returns
///
/// If a device containing the Illusion hypervisor is found, this function returns an `Option` containing
/// a `DevicePath` to the file. If no such device is found, it returns `None`.
pub(crate) fn find_hypervisor(boot_services: &BootServices) -> Option<Box<DevicePath>> {
find_device_path(boot_services, HYPERVISOR_PATH)
}
84 changes: 84 additions & 0 deletions loader/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#![no_main]
#![no_std]

mod images;

use uefi::{prelude::*, table::boot::LoadImageSource};

#[entry]
unsafe fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
if let Err(error) = uefi_services::init(&mut system_table) {
log::error!("Failed to initialize UEFI services ({:?})", error);
return Status::ABORTED;
}

log::info!("Searching Illusion hypervisor (illusion.efi)..");

match images::find_hypervisor(system_table.boot_services()) {
Some(hypervisor_device_path) => {
log::info!("Found! Loading hypervisor into memory..");

match system_table.boot_services().load_image(
image_handle,
LoadImageSource::FromDevicePath {
device_path: &hypervisor_device_path,
from_boot_manager: false,
},
) {
Ok(handle) => {
log::info!("Loaded hypervisor into mermoy, starting..");

if let Err(error) = system_table.boot_services().start_image(handle) {
log::error!("Failed to start hypervisor ({:?})", error);
return Status::ABORTED;
}
}
Err(error) => {
log::error!("Failed to load hypervisor ({:?})", error);
return Status::ABORTED;
}
}
}
None => {
log::info!("Failed to find hypervisor image");
return Status::ABORTED;
}
};

log::info!("Searching Windows boot manager (bootmgfw.efi)..");

match images::find_windows_boot_manager(system_table.boot_services()) {
Some(bootmgr_device_path) => {
log::info!("Found! Loading boot manager into memory..");

system_table.boot_services().stall(3_000_000);

match system_table.boot_services().load_image(
image_handle,
LoadImageSource::FromDevicePath {
device_path: &bootmgr_device_path,
from_boot_manager: false,
},
) {
Ok(handle) => {
log::info!("Loaded boot manager into memory, starting..");

if let Err(error) = system_table.boot_services().start_image(handle) {
log::error!("Failed to start boot manager ({:?})", error);
return Status::ABORTED;
}
}
Err(error) => {
log::error!("Failed to load boot manager ({:?})", error);
return Status::ABORTED;
}
}
}
None => {
log::info!("Failed to find Windows boot manager image");
return Status::ABORTED;
}
}

Status::SUCCESS
}

0 comments on commit f4d29d8

Please sign in to comment.