plex_boot/core/
bootables.rs1use crate::core::app::AppResult;
7use crate::core::app::{App, AppCtx, DisplayEntry};
8use crate::error::AppError;
9use crate::path::{DiskManager, PathReference};
10use alloc::borrow::ToOwned as _;
11use alloc::string::{String, ToString};
12use uefi::CString16;
13use uefi::boot::LoadImageSource;
14use uefi::cstr16;
15use uefi::proto::device_path::PoolDevicePath;
16use uefi::proto::loaded_image::LoadedImage;
17
18#[derive(Debug)]
19pub enum BootTarget {
21 Generic(GenericBootTarget),
23 #[cfg(feature = "iso")]
25 Iso(crate::iso::IsoBootTarget),
26}
27
28impl BootTarget {
31 fn boot(&self, handle: uefi::Handle, dm: &DiskManager) -> Result<(), AppError> {
32 match self {
33 BootTarget::Generic(target) => target.boot(handle, dm),
34 #[cfg(feature = "iso")]
35 BootTarget::Iso(target) => target.boot(handle, dm),
36 }
37 }
38}
39
40impl App for BootTarget {
41 fn run(&mut self, ctx: &mut AppCtx) -> AppResult {
42 match self.boot(ctx.handle, ctx.disk_manager) {
43 Ok(_) => AppResult::Booted,
44 Err(e) => AppResult::Error(e),
45 }
46 }
47}
48
49impl DisplayEntry for BootTarget {
50 fn display_options(&self) -> DisplayOptions {
51 match self {
52 BootTarget::Generic(target) => target.display_options(),
53 #[cfg(feature = "iso")]
54 BootTarget::Iso(target) => target.display_options(),
55 }
56 }
57}
58
59pub struct DisplayOptions {
61 pub label: String,
63}
64
65#[derive(Debug)]
70pub struct GenericBootTarget {
71 label: String,
73 executable: CString16,
76 options: CString16,
78}
79
80impl GenericBootTarget {
81 pub fn new(
83 label: impl AsRef<str>,
84 executable: impl AsRef<str>,
85 options: impl AsRef<str>,
86 ) -> Self {
87 Self {
88 label: label.as_ref().to_string(),
89 executable: CString16::try_from(executable.as_ref())
90 .unwrap_or(cstr16!("failed to parse").to_owned()),
91 options: CString16::try_from(options.as_ref())
92 .unwrap_or(cstr16!("failed to parse").to_owned()),
93 }
94 }
95
96 fn boot(&self, handle: uefi::Handle, dm: &DiskManager) -> Result<(), AppError> {
97 let pathref = PathReference::parse(self.executable.to_string().as_str())?;
98 let img_path = dm.resolve_path(&pathref)?;
99
100 log::debug!(
101 "Loading image from resolved path: {}",
102 path_to_string(&img_path)
103 );
104
105 let src = LoadImageSource::FromDevicePath {
106 device_path: &img_path,
107 boot_policy: Default::default(),
108 };
109
110 let loaded_image_handle = uefi::boot::load_image(handle, src)?;
111 let mut loaded_img =
112 uefi::boot::open_protocol_exclusive::<LoadedImage>(loaded_image_handle)?;
113
114 unsafe {
115 loaded_img.set_load_options(
116 self.options.as_ptr() as *const u8,
117 self.options.num_bytes() as u32,
118 );
119 }
120
121 Ok(uefi::boot::start_image(loaded_image_handle)?)
122 }
123
124 fn display_options(&self) -> DisplayOptions {
125 DisplayOptions {
126 label: self.label.clone(),
127 }
128 }
129}
130
131fn path_to_string(path: &PoolDevicePath) -> CString16 {
132 path.to_string(
133 uefi::proto::device_path::text::DisplayOnly(true),
134 uefi::proto::device_path::text::AllowShortcuts(true),
135 )
136 .unwrap_or(cstr16!("failed to parse.").into())
137}