|
| 1 | +use alloc::boxed::Box; |
1 | 2 | use alloc::string::{String, ToString}; |
2 | 3 | use alloc::vec::Vec; |
3 | 4 |
|
4 | 5 | use uefi::proto::device_path::DevicePath; |
5 | 6 | use uefi::runtime::{VariableAttributes, VariableVendor}; |
6 | | -use uefi::CString16; |
| 7 | +use uefi::{CStr16, CString16}; |
7 | 8 |
|
8 | | -use super::UefiOS; |
| 9 | +use crate::os::error::{Error, Result}; |
9 | 10 |
|
10 | | -pub struct BootOptions { |
11 | | - pub(super) os: UefiOS, |
| 11 | +#[derive(Debug)] |
| 12 | +pub struct Variable { |
| 13 | + name: CString16, |
| 14 | + vendor: VariableVendor, |
12 | 15 | } |
13 | 16 |
|
| 17 | +impl Variable { |
| 18 | + pub fn new(name: &str, vendor: VariableVendor) -> Self { |
| 19 | + // name.len() should be enough, but... |
| 20 | + let mut name_buf = vec![0u16; name.len() * 2 + 16]; |
| 21 | + let name = CStr16::from_str_with_buf(name, &mut name_buf).unwrap(); |
| 22 | + Self { |
| 23 | + name: name.into(), |
| 24 | + vendor, |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + pub fn get(&self) -> Result<(Box<[u8]>, VariableAttributes)> { |
| 29 | + uefi::runtime::get_variable_boxed(&self.name, &self.vendor) |
| 30 | + .map_err(|e| Error(format!("Error getting variable: {e:?}"))) |
| 31 | + } |
| 32 | + |
| 33 | + pub fn set(&self, data: &[u8], attrs: VariableAttributes) -> Result<()> { |
| 34 | + uefi::runtime::set_variable(&self.name, &self.vendor, attrs, data) |
| 35 | + .map_err(|e| Error(format!("Error setting variable: {e:?}"))) |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +pub struct BootOptions; |
| 40 | + |
14 | 41 | impl BootOptions { |
15 | | - pub fn current(&self) -> u16 { |
16 | | - let cur = self |
17 | | - .os |
18 | | - .get_variable("BootCurrent", &VariableVendor::GLOBAL_VARIABLE) |
| 42 | + pub fn current() -> u16 { |
| 43 | + let cur = Variable::new("BootCurrent", VariableVendor::GLOBAL_VARIABLE) |
| 44 | + .get() |
19 | 45 | .unwrap() |
20 | 46 | .0; |
21 | | - u16::from_le_bytes(cur.try_into().unwrap()) |
| 47 | + u16::from_le_bytes((*cur).try_into().unwrap()) |
22 | 48 | } |
23 | 49 |
|
24 | | - pub fn order(&self) -> Vec<u16> { |
25 | | - self.os |
26 | | - .get_variable("BootOrder", &VariableVendor::GLOBAL_VARIABLE) |
| 50 | + pub fn order() -> Vec<u16> { |
| 51 | + Variable::new("BootOrder", VariableVendor::GLOBAL_VARIABLE) |
| 52 | + .get() |
27 | 53 | .unwrap() |
28 | 54 | .0 |
29 | 55 | .chunks(2) |
30 | 56 | .map(|x| u16::from_le_bytes(x.try_into().unwrap())) |
31 | 57 | .collect() |
32 | 58 | } |
33 | 59 |
|
34 | | - pub fn set_order(&self, order: &[u16]) { |
| 60 | + pub fn set_order(order: &[u16]) { |
35 | 61 | let order: Vec<_> = order |
36 | 62 | .iter() |
37 | 63 | .flat_map(|x| x.to_le_bytes().into_iter()) |
38 | 64 | .collect(); |
39 | | - self.os |
40 | | - .set_variable( |
41 | | - "BootOrder", |
42 | | - &VariableVendor::GLOBAL_VARIABLE, |
| 65 | + Variable::new("BootOrder", VariableVendor::GLOBAL_VARIABLE) |
| 66 | + .set( |
| 67 | + &order[..], |
43 | 68 | VariableAttributes::NON_VOLATILE |
44 | 69 | | VariableAttributes::BOOTSERVICE_ACCESS |
45 | 70 | | VariableAttributes::RUNTIME_ACCESS, |
46 | | - &order[..], |
47 | 71 | ) |
48 | 72 | .unwrap() |
49 | 73 | } |
50 | 74 |
|
51 | | - pub fn set_next(&self, next: u16) { |
52 | | - self.os |
53 | | - .set_variable( |
54 | | - "BootNext", |
55 | | - &VariableVendor::GLOBAL_VARIABLE, |
| 75 | + pub fn set_next(next: u16) { |
| 76 | + Variable::new("BootNext", VariableVendor::GLOBAL_VARIABLE) |
| 77 | + .set( |
| 78 | + &next.to_le_bytes(), |
56 | 79 | VariableAttributes::NON_VOLATILE |
57 | 80 | | VariableAttributes::BOOTSERVICE_ACCESS |
58 | 81 | | VariableAttributes::RUNTIME_ACCESS, |
59 | | - &next.to_le_bytes(), |
60 | 82 | ) |
61 | 83 | .unwrap(); |
62 | 84 | } |
63 | 85 |
|
64 | | - pub fn reboot_target(&self) -> Option<u16> { |
65 | | - let order = self.order(); |
| 86 | + pub fn reboot_target() -> Option<u16> { |
| 87 | + let order = Self::order(); |
66 | 88 | let num_skip = order |
67 | 89 | .iter() |
68 | 90 | .cloned() |
69 | | - .position(|x| x == self.current()) |
| 91 | + .position(|x| x == Self::current()) |
70 | 92 | .map(|x| x + 1) |
71 | 93 | .unwrap_or(0); |
72 | 94 | order.iter().cloned().skip(num_skip).find(|x| *x < 0x2000) |
73 | 95 | } |
74 | 96 |
|
75 | | - pub fn get(&self, id: u16) -> Vec<u8> { |
76 | | - self.os |
77 | | - .get_variable(&format!("Boot{id:04X}"), &VariableVendor::GLOBAL_VARIABLE) |
| 97 | + pub fn get(id: u16) -> Box<[u8]> { |
| 98 | + Variable::new(&format!("Boot{id:04X}"), VariableVendor::GLOBAL_VARIABLE) |
| 99 | + .get() |
78 | 100 | .unwrap() |
79 | 101 | .0 |
80 | 102 | } |
81 | 103 |
|
82 | | - pub fn set(&self, id: u16, data: &[u8]) { |
83 | | - self.os |
84 | | - .set_variable( |
85 | | - &format!("Boot{id:04X}"), |
86 | | - &VariableVendor::GLOBAL_VARIABLE, |
| 104 | + pub fn set(id: u16, data: &[u8]) { |
| 105 | + Variable::new(&format!("Boot{id:04X}"), VariableVendor::GLOBAL_VARIABLE) |
| 106 | + .set( |
| 107 | + data, |
87 | 108 | VariableAttributes::NON_VOLATILE |
88 | 109 | | VariableAttributes::BOOTSERVICE_ACCESS |
89 | 110 | | VariableAttributes::RUNTIME_ACCESS, |
90 | | - data, |
91 | 111 | ) |
92 | 112 | .unwrap(); |
93 | 113 | } |
94 | 114 |
|
95 | 115 | /// Boot entry *must* be valid (TODO). |
96 | 116 | /// Returns boot option description and device path of the option. |
97 | | - pub fn boot_entry_info<'a>(&self, entry: &'a [u8]) -> (String, &'a DevicePath) { |
| 117 | + pub fn boot_entry_info(entry: &[u8]) -> (String, &DevicePath) { |
98 | 118 | let skip_attropt = &entry[6..]; |
99 | 119 | let end_of_description = skip_attropt |
100 | 120 | .chunks(2) |
|
0 commit comments