bootmgr_rs_core/system/
variable.rs1use alloc::vec::Vec;
6use tinyvec::TinyVec;
7use uefi::{
8 CStr16, Status, guid,
9 runtime::{self, VariableAttributes, VariableVendor},
10};
11
12use crate::{BootResult, error::BootError};
13
14const BOOTMGR_GUID: uefi::Guid = guid!("23600d08-561e-4e68-a024-1d7d6e04ee4e");
16
17trait UefiVariableStorage {
21 fn get_variable<T: UefiVariable + 'static>(
23 name: &CStr16,
24 vendor: &VariableVendor,
25 buf: &mut [u8],
26 ) -> BootResult<T>;
27
28 fn set_variable<T: UefiVariable + 'static>(
30 name: &CStr16,
31 vendor: &VariableVendor,
32 attributes: VariableAttributes,
33 num: Option<T>,
34 ) -> BootResult<()>;
35}
36
37struct RuntimeUefiVariableStorage;
39
40impl UefiVariableStorage for RuntimeUefiVariableStorage {
41 fn get_variable<T: UefiVariable>(
42 name: &CStr16,
43 vendor: &VariableVendor,
44 buf: &mut [u8],
45 ) -> BootResult<T> {
46 match runtime::get_variable(name, vendor, buf) {
47 Ok((var, _)) => Ok(T::from_bytes(var)),
48 Err(e) if e.status() == Status::NOT_FOUND => Ok(T::default()), Err(e) => Err(BootError::Uefi(e.to_err_without_payload())),
50 }
51 }
52
53 fn set_variable<T: UefiVariable>(
54 name: &CStr16,
55 vendor: &VariableVendor,
56 attributes: VariableAttributes,
57 num: Option<T>,
58 ) -> BootResult<()> {
59 let num = num.map_or_else(|| Vec::with_capacity(0), UefiVariable::to_bytes);
60 Ok(runtime::set_variable(name, vendor, attributes, &num)?)
61 }
62}
63
64pub trait UefiVariable: Sized {
70 fn to_bytes(self) -> Vec<u8>;
72
73 fn from_bytes(bytes: &[u8]) -> Self;
75
76 fn default() -> Self;
78}
79
80impl UefiVariable for usize {
81 fn to_bytes(self) -> Vec<u8> {
82 self.to_le_bytes().to_vec()
83 }
84 fn from_bytes(bytes: &[u8]) -> Self {
85 let mut array = [0; size_of::<Self>()];
86 array.copy_from_slice(bytes);
87 Self::from_le_bytes(array)
88 }
89 fn default() -> Self {
90 0
91 }
92}
93
94impl UefiVariable for u64 {
95 fn to_bytes(self) -> Vec<u8> {
96 self.to_le_bytes().to_vec()
97 }
98 fn from_bytes(bytes: &[u8]) -> Self {
99 let mut array = [0; size_of::<Self>()];
100 array.copy_from_slice(bytes);
101 Self::from_le_bytes(array)
102 }
103 fn default() -> Self {
104 0
105 }
106}
107
108impl UefiVariable for u32 {
109 fn to_bytes(self) -> Vec<u8> {
110 self.to_le_bytes().to_vec()
111 }
112 fn from_bytes(bytes: &[u8]) -> Self {
113 let mut array = [0; size_of::<Self>()];
114 array.copy_from_slice(bytes);
115 Self::from_le_bytes(array)
116 }
117 fn default() -> Self {
118 0
119 }
120}
121
122impl UefiVariable for u16 {
123 fn to_bytes(self) -> Vec<u8> {
124 self.to_le_bytes().to_vec()
125 }
126 fn from_bytes(bytes: &[u8]) -> Self {
127 let mut array = [0; size_of::<Self>()];
128 array.copy_from_slice(bytes);
129 Self::from_le_bytes(array)
130 }
131 fn default() -> Self {
132 0
133 }
134}
135
136impl UefiVariable for u8 {
137 fn to_bytes(self) -> Vec<u8> {
138 self.to_le_bytes().to_vec()
139 }
140 fn from_bytes(bytes: &[u8]) -> Self {
141 let mut array = [0; size_of::<Self>()];
142 array.copy_from_slice(bytes);
143 Self::from_le_bytes(array)
144 }
145 fn default() -> Self {
146 0
147 }
148}
149
150pub fn set_variable<T: UefiVariable + 'static>(
164 name: &CStr16,
165 vendor: Option<VariableVendor>,
166 attrs: Option<VariableAttributes>,
167 num: Option<T>,
168) -> BootResult<()> {
169 let vendor = vendor.unwrap_or(runtime::VariableVendor(BOOTMGR_GUID));
170 let attrs = attrs.map_or_else(
171 || VariableAttributes::NON_VOLATILE | VariableAttributes::BOOTSERVICE_ACCESS,
172 |x| x,
173 );
174 RuntimeUefiVariableStorage::set_variable(name, &vendor, attrs, num)
175}
176
177pub fn get_variable<T: UefiVariable + 'static>(
192 name: &CStr16,
193 vendor: Option<VariableVendor>,
194) -> BootResult<T> {
195 let mut buf: TinyVec<[_; size_of::<u64>()]> = TinyVec::with_capacity(size_of::<T>()); let vendor = vendor.unwrap_or(runtime::VariableVendor(BOOTMGR_GUID));
197 RuntimeUefiVariableStorage::get_variable(name, &vendor, &mut buf)
198}