1#![expect(missing_docs)]
7#![forbid(unsafe_code)]
8
9pub use uefi_specs::uefi::time::EFI_TIME;
10
11pub mod in_memory;
12
13use guid::Guid;
14#[cfg(feature = "save_restore")]
15pub use save_restore::VmmNvramStorage;
16use std::fmt::Debug;
17use thiserror::Error;
18use ucs2::Ucs2LeSlice;
19use ucs2::Ucs2LeVec;
20
21#[derive(Debug, Error)]
22pub enum NvramStorageError {
23 #[error("error deserializing nvram storage")]
24 Deserialize,
25 #[error("error loading data from Nvram storage")]
26 Load(#[source] Box<dyn std::error::Error + Send + Sync>),
27 #[error("error committing data to Nvram storage")]
28 Commit(#[source] Box<dyn std::error::Error + Send + Sync>),
29 #[error("nvram is out of space")]
30 OutOfSpace,
31 #[error("variable name too long")]
32 VariableNameTooLong,
33 #[error("variable data too long")]
34 VariableDataTooLong,
35}
36
37#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
38pub enum NextVariable {
39 InvalidKey,
40 EndOfList,
41 Exists {
42 name: Ucs2LeVec,
43 vendor: Guid,
44 attr: u32,
45 },
46}
47
48#[async_trait::async_trait]
54pub trait NvramStorage: Send + Sync {
55 async fn get_variable(
58 &mut self,
59 name: &Ucs2LeSlice,
60 vendor: Guid,
61 ) -> Result<Option<(u32, Vec<u8>, EFI_TIME)>, NvramStorageError>;
62
63 async fn set_variable(
68 &mut self,
69 name: &Ucs2LeSlice,
70 vendor: Guid,
71 attr: u32,
72 data: Vec<u8>,
73 timestamp: EFI_TIME,
74 ) -> Result<(), NvramStorageError>;
75
76 async fn append_variable(
84 &mut self,
85 name: &Ucs2LeSlice,
86 vendor: Guid,
87 data: Vec<u8>,
88 timestamp: EFI_TIME,
89 ) -> Result<bool, NvramStorageError>;
90
91 async fn remove_variable(
99 &mut self,
100 name: &Ucs2LeSlice,
101 vendor: Guid,
102 ) -> Result<bool, NvramStorageError>;
103
104 async fn next_variable(
108 &mut self,
109 name_vendor: Option<(&Ucs2LeSlice, Guid)>,
110 ) -> Result<NextVariable, NvramStorageError>;
111
112 async fn is_empty(&mut self) -> Result<bool, NvramStorageError> {
114 Ok(matches!(
115 self.next_variable(None).await?,
116 NextVariable::EndOfList
117 ))
118 }
119}
120
121#[async_trait::async_trait]
122impl NvramStorage for Box<dyn NvramStorage> {
123 async fn get_variable(
124 &mut self,
125 name: &Ucs2LeSlice,
126 vendor: Guid,
127 ) -> Result<Option<(u32, Vec<u8>, EFI_TIME)>, NvramStorageError> {
128 (**self).get_variable(name, vendor).await
129 }
130
131 async fn set_variable(
132 &mut self,
133 name: &Ucs2LeSlice,
134 vendor: Guid,
135 attr: u32,
136 data: Vec<u8>,
137 timestamp: EFI_TIME,
138 ) -> Result<(), NvramStorageError> {
139 (**self)
140 .set_variable(name, vendor, attr, data, timestamp)
141 .await
142 }
143
144 async fn append_variable(
145 &mut self,
146 name: &Ucs2LeSlice,
147 vendor: Guid,
148 data: Vec<u8>,
149 timestamp: EFI_TIME,
150 ) -> Result<bool, NvramStorageError> {
151 (**self)
152 .append_variable(name, vendor, data, timestamp)
153 .await
154 }
155
156 async fn remove_variable(
157 &mut self,
158 name: &Ucs2LeSlice,
159 vendor: Guid,
160 ) -> Result<bool, NvramStorageError> {
161 (**self).remove_variable(name, vendor).await
162 }
163
164 async fn next_variable(
165 &mut self,
166 name_vendor: Option<(&Ucs2LeSlice, Guid)>,
167 ) -> Result<NextVariable, NvramStorageError> {
168 (**self).next_variable(name_vendor).await
169 }
170}
171
172#[cfg(feature = "save_restore")]
174mod save_restore {
175 use super::*;
176 use inspect::Inspect;
177 use vmcore::save_restore::SaveRestore;
178
179 type NvramSavedState = <in_memory::InMemoryNvram as SaveRestore>::SavedState;
180
181 pub trait VmmNvramStorage:
182 NvramStorage + Inspect + SaveRestore<SavedState = NvramSavedState>
183 {
184 }
185 impl<T> VmmNvramStorage for T where
186 T: NvramStorage + Inspect + SaveRestore<SavedState = NvramSavedState>
187 {
188 }
189
190 #[async_trait::async_trait]
191 impl NvramStorage for Box<dyn VmmNvramStorage> {
192 async fn get_variable(
193 &mut self,
194 name: &Ucs2LeSlice,
195 vendor: Guid,
196 ) -> Result<Option<(u32, Vec<u8>, EFI_TIME)>, NvramStorageError> {
197 (**self).get_variable(name, vendor).await
198 }
199
200 async fn set_variable(
201 &mut self,
202 name: &Ucs2LeSlice,
203 vendor: Guid,
204 attr: u32,
205 data: Vec<u8>,
206 timestamp: EFI_TIME,
207 ) -> Result<(), NvramStorageError> {
208 (**self)
209 .set_variable(name, vendor, attr, data, timestamp)
210 .await
211 }
212
213 async fn append_variable(
214 &mut self,
215 name: &Ucs2LeSlice,
216 vendor: Guid,
217 data: Vec<u8>,
218 timestamp: EFI_TIME,
219 ) -> Result<bool, NvramStorageError> {
220 (**self)
221 .append_variable(name, vendor, data, timestamp)
222 .await
223 }
224
225 async fn remove_variable(
226 &mut self,
227 name: &Ucs2LeSlice,
228 vendor: Guid,
229 ) -> Result<bool, NvramStorageError> {
230 (**self).remove_variable(name, vendor).await
231 }
232
233 async fn next_variable(
234 &mut self,
235 name_vendor: Option<(&Ucs2LeSlice, Guid)>,
236 ) -> Result<NextVariable, NvramStorageError> {
237 (**self).next_variable(name_vendor).await
238 }
239 }
240
241 impl SaveRestore for Box<dyn VmmNvramStorage<SavedState = NvramSavedState>> {
242 type SavedState = NvramSavedState;
243
244 fn save(&mut self) -> Result<Self::SavedState, vmcore::save_restore::SaveError> {
245 (**self).save()
246 }
247
248 fn restore(
249 &mut self,
250 state: Self::SavedState,
251 ) -> Result<(), vmcore::save_restore::RestoreError> {
252 (**self).restore(state)
253 }
254 }
255}