bootmgr_rs_core/boot.rs
1// SPDX-FileCopyrightText: 2025 some100 <ootinnyoo@outlook.com>
2// SPDX-License-Identifier: MIT
3
4//! Provides [`BootMgr`], a struct which abstracts most of loading a [`Config`].
5
6use alloc::vec::Vec;
7use log::error;
8use uefi::Handle;
9
10use crate::{
11 BootResult,
12 boot::{action::add_special_boot, config::BootConfig, loader::load_boot_option},
13 config::{Config, scan_configs},
14 system::drivers::load_drivers,
15};
16
17pub mod action;
18pub mod bli;
19pub mod config;
20pub mod devicetree;
21pub mod loader;
22pub mod secure_boot;
23
24/// The storage for configuration files.
25pub struct BootMgr {
26 /// The configuration of the boot manager.
27 pub boot_config: BootConfig,
28
29 /// The boot options.
30 configs: Vec<Config>,
31}
32
33impl BootMgr {
34 /// Creates a new [`BootMgr`], load drivers, then populate it with [`Config`]s.
35 ///
36 /// It will also add special boot options, like Reboot, Shutdown, and Reset to Firmware.
37 /// This will also parse the main configuration file located at `\\loader\\bootmgr-rs.conf`
38 /// for user settings.
39 ///
40 /// # Errors
41 ///
42 /// May return an `Error` if a fatal error occurred when parsing the [`BootConfig`] (such as the image handle not
43 /// supporting `SimpleFileSystem`) or when parsing the [`Config`]s.
44 pub fn new() -> BootResult<Self> {
45 let _ = bli::export_variables();
46
47 let boot_config = BootConfig::new()?;
48 if boot_config.drivers {
49 load_drivers(&boot_config.driver_path)?; // load drivers before configs from other fs are parsed
50 }
51
52 let mut configs = scan_configs()?;
53 add_special_boot(&mut configs, &boot_config);
54
55 if let Some(default) = boot_config.default {
56 let _ = bli::set_default_entry(&configs, default);
57 }
58
59 let _ = bli::set_loader_entries(&configs);
60
61 Ok(Self {
62 boot_config,
63 configs,
64 })
65 }
66
67 /// Load a boot option from a [`Config`] given the index.
68 ///
69 /// # Errors
70 ///
71 /// May return an `Error` if an error occurred while loading the boot option.
72 pub fn load(&mut self, selected: usize) -> BootResult<Handle> {
73 let config = &self.configs[selected];
74 match load_boot_option(config) {
75 Ok(handle) => {
76 let _ = bli::generate_random_seed();
77 let _ = bli::record_exit_time();
78 Ok(handle)
79 }
80 Err(e) => {
81 self.configs[selected].bad = true;
82 Err(e) // after setting as bad, finally return the error
83 }
84 }
85 }
86
87 /// Returns a reference to the inner [`Vec<Config>`].
88 #[must_use = "Has no effect if the result is unused"]
89 pub const fn list(&self) -> &Vec<Config> {
90 &self.configs
91 }
92
93 /// Returns a mutable reference to the inner [`Vec<Config>`].
94 #[must_use = "Has no effect if the result is unused"]
95 pub const fn list_mut(&mut self) -> &mut Vec<Config> {
96 &mut self.configs
97 }
98
99 /// Returns a mutable reference to an inner [`Config`].
100 pub fn get_config(&mut self, option: usize) -> &mut Config {
101 &mut self.configs[option]
102 }
103
104 /// Gets the default boot option.
105 ///
106 /// If the default boot option is not set, then 0 is returned
107 #[must_use = "Has no effect if the result is unused"]
108 pub fn get_default(&self) -> usize {
109 if let Some(default) = bli::get_default_entry(&self.configs)
110 && default < self.configs.len()
111 {
112 default
113 } else {
114 0
115 }
116 }
117
118 /// Sets the default boot option by index.
119 ///
120 /// This is stored in a UEFI variable. Due to the poor quality of how UEFI variables are stored sometimes, this
121 /// cannot be completely reliable across all firmware implementations.
122 pub fn set_default(&self, option: usize) {
123 if option < self.configs.len()
124 && let Err(e) = bli::set_default_entry(&self.configs, option)
125 {
126 error!("Failed to set LoaderEntryDefault UEFI variable: {e}");
127 }
128 }
129
130 /// Validates the inner [`Vec<Config>`] through various criteria.
131 ///
132 /// If any of the [`Config`]s are found to be invalid, then they will be
133 /// filtered.
134 pub fn validate(&mut self) {
135 self.configs.retain(Config::is_good);
136 }
137}