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_elem(&self, elem: &BootIndex) -> BootOrder {
82 let mut v = self.0.clone();
83 if let Some(index) = self.position(elem) {
84 v.remove(index);
85 }
86 BootOrder(v)
87 }
88}
89
90impl fmt::Display for BootOrder {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 let s: Vec<String> = self.0.iter().map(|a| format!("{}", a)).collect();
93 write!(f, "{}", s.join(","))
94 }
95}
96
97impl From<&BootOrder> for Vec<u8> {
98 fn from(value: &BootOrder) -> Vec<u8> {
99 value.0.iter().flat_map(Vec::from).collect()
100 }
101}
102
103pub const LOAD_OPTION_ACTIVE: u32 = 0x01;
105pub const LOAD_OPTION_FORCE_RECONNECT: u32 = 0x02;
106pub const LOAD_OPTION_HIDDEN: u32 = 0x08;
107
108pub const LOAD_OPTION_CATEGORY: u32 = 0x1f00;
109pub const LOAD_OPTION_CATEGORY_BOOT: u32 = 0x1f00;
110pub const LOAD_OPTION_CATEGORY_APP: u32 = 0x0100;
111
112#[derive(Debug)]
113pub enum BootEntryOptData {
114 None,
115 String { string: String },
116 Guid { guid: Guid },
117 Data { bytes: Vec<u8> },
118}
119
120impl fmt::Display for BootEntryOptData {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 match self {
123 BootEntryOptData::String { string } => {
124 write!(f, "\"{}\"", string)
125 }
126 BootEntryOptData::Guid { guid } => {
127 write!(f, "{}", guid)
128 }
129 BootEntryOptData::Data { bytes } => {
130 write!(f, "{:?}", bytes)
131 }
132 BootEntryOptData::None => Ok(()),
133 }
134 }
135}
136
137#[derive(Debug)]
138pub struct BootEntry {
139 pub attributes: u32,
140 pub title: String,
141 pub devpath: DevPath,
142 pub optdata: BootEntryOptData,
143}
144
145impl BootEntry {
146 pub fn new_boot(title: &str, devpath: DevPath, optdata: Option<String>) -> BootEntry {
147 BootEntry {
148 attributes: LOAD_OPTION_ACTIVE,
149 title: title.to_string(),
150 devpath,
151 optdata: match optdata {
152 Some(s) => BootEntryOptData::String { string: s },
153 None => BootEntryOptData::None,
154 },
155 }
156 }
157
158 pub fn is_active(&self) -> bool {
159 (self.attributes & LOAD_OPTION_ACTIVE) != 0
160 }
161
162 pub fn is_hidden(&self) -> bool {
163 (self.attributes & LOAD_OPTION_HIDDEN) != 0
164 }
165
166 fn category(&self) -> u32 {
167 self.attributes & LOAD_OPTION_CATEGORY
168 }
169
170 pub fn is_boot(&self) -> bool {
171 self.category() == LOAD_OPTION_CATEGORY_BOOT
172 }
173
174 pub fn is_app(&self) -> bool {
175 self.category() == LOAD_OPTION_CATEGORY_APP
176 }
177}