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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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