From 44a17c6072c297e3f8af5573e74392a068b1612b Mon Sep 17 00:00:00 2001 From: James Forcier Date: Wed, 14 Jun 2017 16:42:53 -0700 Subject: [PATCH 1/2] uefi_entry: pass image_handle to application main --- src/picker.rs | 2 +- src/uefi_entry/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/picker.rs b/src/picker.rs index 4d41121..812269e 100644 --- a/src/picker.rs +++ b/src/picker.rs @@ -25,7 +25,7 @@ pub mod util; pub mod uefi_entry; -pub fn efi_main() -> Status { +pub fn efi_main(image_handle: Handle) -> Status { let cons = uefi::get_system_table().console(); cons.write("picker v0.0.1\r\n"); Status::Success diff --git a/src/uefi_entry/mod.rs b/src/uefi_entry/mod.rs index 1af958a..33a99f6 100644 --- a/src/uefi_entry/mod.rs +++ b/src/uefi_entry/mod.rs @@ -19,5 +19,5 @@ pub extern "win64" fn efi_entry(image_handle: uefi::Handle, system_table: *const uefi::SystemTable) -> isize { uefi::set_system_table(system_table).console().reset(); - ::efi_main() as isize + ::efi_main(image_handle) as isize } From f08589a7403aaecc32323064f921978580739021 Mon Sep 17 00:00:00 2001 From: James Forcier Date: Thu, 29 Jun 2017 14:49:18 -0700 Subject: [PATCH 2/2] *: implement initial boot selection logic Boots and allows user to select from two hardcoded paths residing on the same filesystem as picker itself. --- src/picker.rs | 66 ++++++++++++++++++++++++++++++++++++++++++- src/uefi_entry/mod.rs | 9 ++++++ src/util/image.rs | 49 ++++++++++++++++++++++++++++++++ src/util/mod.rs | 2 ++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/util/image.rs diff --git a/src/picker.rs b/src/picker.rs index 812269e..bc1b10a 100644 --- a/src/picker.rs +++ b/src/picker.rs @@ -25,8 +25,72 @@ pub mod util; pub mod uefi_entry; +const BOOTPATH_1: &'static str = "\\efi\\boot\\shim_a.efi"; +const BOOTPATH_2: &'static str = "\\efi\\boot\\shim_b.efi"; + pub fn efi_main(image_handle: Handle) -> Status { - let cons = uefi::get_system_table().console(); + let sys_table = uefi::get_system_table(); + let cons = sys_table.console(); + cons.write("picker v0.0.1\r\n"); + + loop { + cons.write("Option 1: "); + cons.write(BOOTPATH_1); + cons.write("\r\n"); + + cons.write("Option 2: "); + cons.write(BOOTPATH_2); + cons.write("\r\n"); + + cons.write("Option (taking default in 5 seconds...): "); + match util::read_key_timeout(5000) { + Ok(Some(key)) => { + let output: [u16; 2] = [key.unicode_char, 0]; + cons.write_raw(&output as *const u16); + cons.write("\r\n"); + + match key.unicode_char as u8 as char { + '1' => { + if let Err(e) = util::boot_image(BOOTPATH_1, image_handle) { + cons.write("Couldn't boot choice: "); + cons.write(e.str()); + cons.write("\r\n"); + return e; + } + break; + } + '2' => { + if let Err(e) = util::boot_image(BOOTPATH_2, image_handle) { + cons.write("Couldn't boot choice: "); + cons.write(e.str()); + cons.write("\r\n"); + return e; + } + break; + } + _ => { + cons.write("Unrecognized option."); + } + } + } + Ok(None) => { + cons.write("\r\nTaking default.\r\n"); + if let Err(e) = util::boot_image(BOOTPATH_1, image_handle) { + cons.write("Couldn't boot default: "); + cons.write(e.str()); + cons.write("\r\n"); + return e; + } + break; + } + Err(_) => { + cons.write("\r\nCouldn't read key."); + } + } + + cons.write("\r\n"); + } + Status::Success } diff --git a/src/uefi_entry/mod.rs b/src/uefi_entry/mod.rs index 33a99f6..9259578 100644 --- a/src/uefi_entry/mod.rs +++ b/src/uefi_entry/mod.rs @@ -14,10 +14,19 @@ extern crate uefi; +use uefi::{protocol, Status}; + #[no_mangle] pub extern "win64" fn efi_entry(image_handle: uefi::Handle, system_table: *const uefi::SystemTable) -> isize { uefi::set_system_table(system_table).console().reset(); + + let loaded_image_proto: Result<&'static protocol::LoadedImageProtocol, Status> = + protocol::set_current_image(image_handle); + if let Err(status) = loaded_image_proto { + return status as isize; + } + ::efi_main(image_handle) as isize } diff --git a/src/util/image.rs b/src/util/image.rs new file mode 100644 index 0000000..8ba8c9d --- /dev/null +++ b/src/util/image.rs @@ -0,0 +1,49 @@ +// Copyright 2017 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate uefi; + +use uefi::*; + +fn str_to_device_path(image: &str) -> Result<&protocol::DevicePathProtocol, Status> { + let bs = uefi::get_system_table().boot_services(); + bs.locate_protocol::(0 as *const CVoid) + .and_then(|from_text| from_text.text_to_device_path_node(image)) +} + +fn build_boot_path(file: &protocol::DevicePathProtocol) + -> Result<*const protocol::DevicePathProtocol, Status> { + let bs = uefi::get_system_table().boot_services(); + + bs.handle_protocol::(protocol::get_current_image().device_handle) + .and_then(|this_device_path| { + bs.locate_protocol::(0 as *const CVoid) + .and_then(|utilities| { + utilities + .append_device_node(this_device_path, file) + .map(|output| output as *const protocol::DevicePathProtocol) + }) + }) +} + +pub fn boot_image(image: &str, parent: Handle) -> Result<(), Status> { + let bs = uefi::get_system_table().boot_services(); + + str_to_device_path(image) + .and_then(build_boot_path) + .and_then(|full_path| { + bs.load_image(true, parent, full_path) + .and_then(|loaded_image| bs.start_image(loaded_image)) + }) +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 6c2378d..e26ee58 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -14,8 +14,10 @@ extern crate uefi; +mod image; mod input; +pub use self::image::*; pub use self::input::*; use core::fmt::Arguments;