Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Use gptprio to select boot target #13

Closed
wants to merge 9 commits into from
Closed
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ authors = [ "[email protected]" ]
[lib]
name = "picker"
crate-type = ["dylib"]
path = "src/picker.rs"

[dependencies]
uefi = { git = "https://github.com/csssuf/rust-uefi" }
rlibc = "1.0"
bitfield = "0.12.0"
4 changes: 3 additions & 1 deletion src/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ use core::ptr;

use uefi::*;

// When gptprio is implemented, boot_data may change to another type. For now it's just a path.
#[derive(Clone, Copy)]
pub struct BootOption {
pub display: &'static str,
pub boot_data: &'static str,
pub default: bool,
pub guid: Guid,
}

fn str_to_device_path(image: &str) -> Result<&protocol::DevicePathProtocol, Status> {
Expand Down
14 changes: 13 additions & 1 deletion src/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ where
loop {
write("Option 1: ");
write(option_a.display);
if option_a.default {
write(" (default)");
}
write("\r\n");

write("Option 2: ");
write(option_b.display);
if option_b.default {
write(" (default)");
}
write("\r\n");

write("Enter boot choice: ");
Expand All @@ -50,7 +56,13 @@ where
},
Ok(None) => {
write("Taking default.\r\n");
return Ok(None);
if option_a.default {
return Ok(Some(option_a));
} else if option_b.default {
return Ok(Some(option_b));
} else {
return Ok(None);
}
}
Err(e) => {
write("Error reading: ");
Expand Down
91 changes: 78 additions & 13 deletions src/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
#![no_std]
#![feature(lang_items)]

#[macro_use]
extern crate bitfield;
extern crate rlibc;
extern crate uefi;

use uefi::*;
use uefi::{Guid, Handle, SimpleTextOutput, Status};
use uefi::util::parent_device_path;

pub mod boot;
pub mod menu;
Expand All @@ -27,28 +30,90 @@ pub mod uefi_entry;

use boot::BootOption;

const BOOTPATH_1: &'static str = "\\efi\\boot\\shim_a.efi";
const BOOTPATH_2: &'static str = "\\efi\\boot\\shim_b.efi";
const BOOTPATH_USR_A: &'static str = "\\EFI\\coreos\\shim_a.efi";
const BOOTPATH_USR_B: &'static str = "\\EFI\\coreos\\shim_b.efi";

const PART_UUID_USR_A: Guid = Guid(
0x7130_C94A,
0x213A,
0x4E5A,
[0x8E, 0x26, 0x6C, 0xCE, 0x96, 0x62, 0xF1, 0x32],
);
const PART_UUID_USR_B: Guid = Guid(
0xE03D_D35C,
0x7C2D,
0x4A47,
[0xB3, 0xFE, 0x27, 0xF1, 0x57, 0x80, 0xA5, 0x7C],
);

pub fn efi_main(image_handle: Handle) -> Status {
let sys_table = uefi::get_system_table();
let bs = sys_table.boot_services();
let cons = sys_table.console();

cons.write("picker v0.0.1\r\n");

let option_a = BootOption {
display: "application a",
boot_data: BOOTPATH_1,
let mut option_a = BootOption {
display: "USR-A",
boot_data: BOOTPATH_USR_A,
default: false,
guid: PART_UUID_USR_A,
};
let option_b = BootOption {
display: "application b",
boot_data: BOOTPATH_2,
let mut option_b = BootOption {
display: "USR-B",
boot_data: BOOTPATH_USR_B,
default: false,
guid: PART_UUID_USR_B,
};

match menu::boot_menu(&option_a, &option_b).and_then(|option| {
let result = option.unwrap_or(&option_a);
boot::boot(result, image_handle)
}) {
let this = uefi::protocol::get_current_image();
let partition = bs.handle_protocol::<uefi::protocol::DevicePathProtocol>(this.device_handle)
.and_then(parent_device_path)
.and_then(|parent_path| util::GptDisk::read_from(parent_path))
.map(|disk| util::gptprio::next(disk.partitions));

match partition {
Ok(Some(gptprio_partition)) => {
if option_a.guid == gptprio_partition.unique_partition_guid {
option_a.default = true;
} else if option_b.guid == gptprio_partition.unique_partition_guid {
option_b.default = true;
} else {
cons.write(
"Unknown gptprio partition chosen as next. Defaulting to USR-A.\r\n",
);
option_a.default = true;
}
}
Ok(None) => {
cons.write(
"No acceptable gptprio partitions found; defaulting to USR-A.\r\n",
);
option_a.default = true;
}
Err(e) => {
cons.write("error reading from disk: ");
cons.write(e.str());
return e;
}
}

let boot_result = menu::boot_menu(&option_a, &option_b)
.and_then(|option| {
match option {
Some(boot_choice) => Ok(boot_choice),
None => {
cons.write(
"No option selected and no default was set. Can't proceed.\r\n",
);
// FIXME(csssuf) is this the best error to use here?
Err(Status::NoMedia)
}
}
})
.and_then(|boot_option| boot::boot(boot_option, image_handle));

match boot_result {
Ok(_) => Status::Success,
Err(e) => e,
}
Expand Down
Loading