virtfw_libefi/efivar/
boot.rs1extern crate alloc;
4use alloc::format;
5use alloc::string::{String, ToString};
6use alloc::vec;
7use alloc::vec::Vec;
8
9use core::fmt;
10
11use uguid::Guid;
12
13use crate::efivar::devpath::DevPath;
14
15pub const BOOT_CURRENT: &str = "BootCurrent";
17pub const BOOT_NEXT: &str = "BootNext";
18pub const BOOT_ORDER: &str = "BootOrder";
19pub const SECURE_BOOT: &str = "SecureBoot";
20
21#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
23pub struct BootIndex(pub u16);
24
25impl fmt::Display for BootIndex {
26 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27 write!(f, "{:04X}", self.0)
28 }
29}
30
31impl From<&BootIndex> for Vec<u8> {
32 fn from(value: &BootIndex) -> Vec<u8> {
33 let bytes = value.0.to_le_bytes();
34 bytes.to_vec()
35 }
36}
37
38#[derive(Debug)]
40pub struct BootOrder(pub Vec<BootIndex>);
41
42impl BootOrder {
43 pub fn new(elem: &BootIndex) -> BootOrder {
44 let v = vec![*elem];
45 BootOrder(v)
46 }
47
48 pub fn empty() -> BootOrder {
49 let v = Vec::new();
50 BootOrder(v)
51 }
52
53 pub fn len(&self) -> usize {
54 self.0.len()
55 }
56
57 pub fn is_empty(&self) -> bool {
58 self.0.is_empty()
59 }
60
61 pub fn position(&self, elem: &BootIndex) -> Option<usize> {
62 (0..self.0.len()).find(|&pos| elem == self.0.get(pos).unwrap())
63 }
64
65 pub fn insert(&self, index: usize, elem: &BootIndex) -> BootOrder {
66 let mut v = self.0.clone();
67 if self.position(elem).is_none() && index <= v.len() {
68 v.insert(index, *elem);
69 }
70 BootOrder(v)
71 }
72
73 pub fn remove(&self, index: usize) -> BootOrder {
74 let mut v = self.0.clone();
75 if index < v.len() {
76 v.remove(index);
77 }
78 BootOrder(v)
79 }
80
81 pub fn remove_elems(&self, elems: &[&BootIndex]) -> BootOrder {
82 let mut v = self.0.clone();
83 for elem in elems {
84 if let Some(index) = v.iter().position(|i| i == *elem) {
85 v.remove(index);
86 }
87 }
88 BootOrder(v)
89 }
90
91 pub fn remove_elem(&self, elem: &BootIndex) -> BootOrder {
92 let elems = vec![elem];
93 self.remove_elems(elems.as_slice())
94 }
95}
96
97impl fmt::Display for BootOrder {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 let s: Vec<String> = self.0.iter().map(|a| format!("{a}")).collect();
100 write!(f, "{}", s.join(","))
101 }
102}
103
104impl From<&BootOrder> for Vec<u8> {
105 fn from(value: &BootOrder) -> Vec<u8> {
106 value.0.iter().flat_map(Vec::from).collect()
107 }
108}
109
110pub const LOAD_OPTION_ACTIVE: u32 = 0x01;
112pub const LOAD_OPTION_FORCE_RECONNECT: u32 = 0x02;
113pub const LOAD_OPTION_HIDDEN: u32 = 0x08;
114
115pub const LOAD_OPTION_CATEGORY: u32 = 0x1f00;
116pub const LOAD_OPTION_CATEGORY_BOOT: u32 = 0x1f00;
117pub const LOAD_OPTION_CATEGORY_APP: u32 = 0x0100;
118
119#[derive(Debug)]
120pub enum BootEntryOptData {
121 None,
122 String { string: String },
123 Guid { guid: Guid },
124 Data { bytes: Vec<u8> },
125}
126
127impl fmt::Display for BootEntryOptData {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 match self {
130 BootEntryOptData::String { string } => {
131 write!(f, "\"{string}\"")
132 }
133 BootEntryOptData::Guid { guid } => {
134 write!(f, "{guid}")
135 }
136 BootEntryOptData::Data { bytes } => {
137 write!(f, "{bytes:?}")
138 }
139 BootEntryOptData::None => Ok(()),
140 }
141 }
142}
143
144#[derive(Debug)]
145pub struct BootEntry {
146 pub attributes: u32,
147 pub title: String,
148 pub devpath: DevPath,
149 pub optdata: BootEntryOptData,
150}
151
152impl BootEntry {
153 pub fn new_boot(title: &str, devpath: DevPath, optdata: Option<String>) -> BootEntry {
154 BootEntry {
155 attributes: LOAD_OPTION_ACTIVE,
156 title: title.to_string(),
157 devpath,
158 optdata: match optdata {
159 Some(s) => BootEntryOptData::String { string: s },
160 None => BootEntryOptData::None,
161 },
162 }
163 }
164
165 pub fn is_active(&self) -> bool {
166 (self.attributes & LOAD_OPTION_ACTIVE) != 0
167 }
168
169 pub fn is_hidden(&self) -> bool {
170 (self.attributes & LOAD_OPTION_HIDDEN) != 0
171 }
172
173 fn category(&self) -> u32 {
174 self.attributes & LOAD_OPTION_CATEGORY
175 }
176
177 pub fn is_boot(&self) -> bool {
178 self.category() == LOAD_OPTION_CATEGORY_BOOT
179 }
180
181 pub fn is_app(&self) -> bool {
182 self.category() == LOAD_OPTION_CATEGORY_APP
183 }
184}