1 | //! UEFI services available at runtime, even after the OS boots. |
2 | |
3 | use super::{Header, Revision}; |
4 | #[cfg (feature = "alloc" )] |
5 | use crate::data_types::FromSliceWithNulError; |
6 | use crate::result::Error; |
7 | use crate::table::boot::MemoryDescriptor; |
8 | use crate::{guid, CStr16, Char16, Guid, Result, Status}; |
9 | #[cfg (feature = "alloc" )] |
10 | use alloc::{vec, vec::Vec}; |
11 | use bitflags::bitflags; |
12 | use core::fmt::{Debug, Formatter}; |
13 | #[cfg (feature = "alloc" )] |
14 | use core::mem; |
15 | use core::mem::MaybeUninit; |
16 | use core::{fmt, ptr}; |
17 | /// Contains pointers to all of the runtime services. |
18 | /// |
19 | /// This table, and the function pointers it contains are valid |
20 | /// even after the UEFI OS loader and OS have taken control of the platform. |
21 | /// |
22 | /// # Accessing `RuntimeServices` |
23 | /// |
24 | /// A reference to `RuntimeServices` can only be accessed by calling [`SystemTable::runtime_services`]. |
25 | /// |
26 | /// [`SystemTable::runtime_services`]: crate::table::SystemTable::runtime_services |
27 | #[repr (C)] |
28 | pub struct RuntimeServices { |
29 | header: Header, |
30 | get_time: |
31 | unsafe extern "efiapi" fn(time: *mut Time, capabilities: *mut TimeCapabilities) -> Status, |
32 | set_time: unsafe extern "efiapi" fn(time: &Time) -> Status, |
33 | // Skip some useless functions. |
34 | _pad: [usize; 2], |
35 | pub(crate) set_virtual_address_map: unsafe extern "efiapi" fn( |
36 | map_size: usize, |
37 | desc_size: usize, |
38 | desc_version: u32, |
39 | virtual_map: *mut MemoryDescriptor, |
40 | ) -> Status, |
41 | _pad2: usize, |
42 | get_variable: unsafe extern "efiapi" fn( |
43 | variable_name: *const Char16, |
44 | vendor_guid: *const Guid, |
45 | attributes: *mut VariableAttributes, |
46 | data_size: *mut usize, |
47 | data: *mut u8, |
48 | ) -> Status, |
49 | get_next_variable_name: unsafe extern "efiapi" fn( |
50 | variable_name_size: *mut usize, |
51 | variable_name: *mut u16, |
52 | vendor_guid: *mut Guid, |
53 | ) -> Status, |
54 | set_variable: unsafe extern "efiapi" fn( |
55 | variable_name: *const Char16, |
56 | vendor_guid: *const Guid, |
57 | attributes: VariableAttributes, |
58 | data_size: usize, |
59 | data: *const u8, |
60 | ) -> Status, |
61 | _pad3: usize, |
62 | reset: unsafe extern "efiapi" fn( |
63 | rt: ResetType, |
64 | |
65 | status: Status, |
66 | data_size: usize, |
67 | data: *const u8, |
68 | ) -> !, |
69 | |
70 | // UEFI 2.0 Capsule Services. |
71 | update_capsule: usize, |
72 | query_capsule_capabilities: usize, |
73 | |
74 | // Miscellaneous UEFI 2.0 Service. |
75 | query_variable_info: unsafe extern "efiapi" fn( |
76 | attributes: VariableAttributes, |
77 | maximum_variable_storage_size: *mut u64, |
78 | remaining_variable_storage_size: *mut u64, |
79 | maximum_variable_size: *mut u64, |
80 | ) -> Status, |
81 | } |
82 | |
83 | impl RuntimeServices { |
84 | /// Query the current time and date information |
85 | pub fn get_time(&self) -> Result<Time> { |
86 | let mut time = MaybeUninit::<Time>::uninit(); |
87 | unsafe { (self.get_time)(time.as_mut_ptr(), ptr::null_mut()) } |
88 | .into_with_val(|| unsafe { time.assume_init() }) |
89 | } |
90 | |
91 | /// Query the current time and date information and the RTC capabilities |
92 | pub fn get_time_and_caps(&self) -> Result<(Time, TimeCapabilities)> { |
93 | let mut time = MaybeUninit::<Time>::uninit(); |
94 | let mut caps = MaybeUninit::<TimeCapabilities>::uninit(); |
95 | unsafe { (self.get_time)(time.as_mut_ptr(), caps.as_mut_ptr()) } |
96 | .into_with_val(|| unsafe { (time.assume_init(), caps.assume_init()) }) |
97 | } |
98 | |
99 | /// Sets the current local time and date information |
100 | /// |
101 | /// During runtime, if a PC-AT CMOS device is present in the platform, the |
102 | /// caller must synchronize access to the device before calling `set_time`. |
103 | /// |
104 | /// # Safety |
105 | /// |
106 | /// Undefined behavior could happen if multiple tasks try to |
107 | /// use this function at the same time without synchronisation. |
108 | pub unsafe fn set_time(&mut self, time: &Time) -> Result { |
109 | (self.set_time)(time).into() |
110 | } |
111 | |
112 | /// Get the size (in bytes) of a variable. This can be used to find out how |
113 | /// big of a buffer should be passed in to `get_variable`. |
114 | pub fn get_variable_size(&self, name: &CStr16, vendor: &VariableVendor) -> Result<usize> { |
115 | let mut data_size = 0; |
116 | let status = unsafe { |
117 | (self.get_variable)( |
118 | name.as_ptr(), |
119 | &vendor.0, |
120 | ptr::null_mut(), |
121 | &mut data_size, |
122 | ptr::null_mut(), |
123 | ) |
124 | }; |
125 | |
126 | if status == Status::BUFFER_TOO_SMALL { |
127 | Status::SUCCESS.into_with_val(|| data_size) |
128 | } else { |
129 | Err(Error::from(status)) |
130 | } |
131 | } |
132 | |
133 | /// Get the contents and attributes of a variable. The size of `buf` must |
134 | /// be at least as big as the variable's size, although it can be |
135 | /// larger. If it is too small, `BUFFER_TOO_SMALL` is returned. |
136 | /// |
137 | /// On success, a tuple containing the variable's value (a slice of `buf`) |
138 | /// and the variable's attributes is returned. |
139 | pub fn get_variable<'a>( |
140 | &self, |
141 | name: &CStr16, |
142 | vendor: &VariableVendor, |
143 | buf: &'a mut [u8], |
144 | ) -> Result<(&'a [u8], VariableAttributes)> { |
145 | let mut attributes = VariableAttributes::empty(); |
146 | let mut data_size = buf.len(); |
147 | unsafe { |
148 | (self.get_variable)( |
149 | name.as_ptr(), |
150 | &vendor.0, |
151 | &mut attributes, |
152 | &mut data_size, |
153 | buf.as_mut_ptr(), |
154 | ) |
155 | .into_with_val(move || (&buf[..data_size], attributes)) |
156 | } |
157 | } |
158 | |
159 | /// Get the names and vendor GUIDs of all currently-set variables. |
160 | #[cfg (feature = "alloc" )] |
161 | pub fn variable_keys(&self) -> Result<Vec<VariableKey>> { |
162 | let mut all_variables = Vec::new(); |
163 | |
164 | // The initial value of name must start with a null character. Start |
165 | // out with a reasonable size that likely won't need to be increased. |
166 | let mut name = vec![0u16; 32]; |
167 | // The initial value of vendor is ignored. |
168 | let mut vendor = Guid::default(); |
169 | |
170 | let mut status; |
171 | loop { |
172 | let mut name_size_in_bytes = name.len() * mem::size_of::<u16>(); |
173 | status = unsafe { |
174 | (self.get_next_variable_name)( |
175 | &mut name_size_in_bytes, |
176 | name.as_mut_ptr(), |
177 | &mut vendor, |
178 | ) |
179 | }; |
180 | |
181 | match status { |
182 | Status::SUCCESS => { |
183 | // CStr16::from_u16_with_nul does not allow interior nulls, |
184 | // so make the copy exactly the right size. |
185 | let name = if let Some(nul_pos) = name.iter().position(|c| *c == 0) { |
186 | name[..=nul_pos].to_vec() |
187 | } else { |
188 | status = Status::ABORTED; |
189 | break; |
190 | }; |
191 | |
192 | all_variables.push(VariableKey { |
193 | name, |
194 | vendor: VariableVendor(vendor), |
195 | }); |
196 | } |
197 | Status::BUFFER_TOO_SMALL => { |
198 | // The name buffer passed in was too small, resize it to be |
199 | // big enough for the next variable name. |
200 | name.resize(name_size_in_bytes / 2, 0); |
201 | } |
202 | Status::NOT_FOUND => { |
203 | // This status indicates the end of the list. The final |
204 | // variable has already been received at this point, so |
205 | // no new variable should be added to the output. |
206 | status = Status::SUCCESS; |
207 | break; |
208 | } |
209 | _ => { |
210 | // For anything else, an error has occurred so break out of |
211 | // the loop and return it. |
212 | break; |
213 | } |
214 | } |
215 | } |
216 | |
217 | status.into_with_val(|| all_variables) |
218 | } |
219 | |
220 | /// Set the value of a variable. This can be used to create a new variable, |
221 | /// update an existing variable, or (when the size of `data` is zero) |
222 | /// delete a variable. |
223 | /// |
224 | /// # Warnings |
225 | /// |
226 | /// The [`Status::WARN_RESET_REQUIRED`] warning will be returned when using |
227 | /// this function to transition the Secure Boot mode to setup mode or audit |
228 | /// mode if the firmware requires a reboot for that operation. |
229 | pub fn set_variable( |
230 | &self, |
231 | name: &CStr16, |
232 | vendor: &VariableVendor, |
233 | attributes: VariableAttributes, |
234 | data: &[u8], |
235 | ) -> Result { |
236 | unsafe { |
237 | (self.set_variable)( |
238 | name.as_ptr(), |
239 | &vendor.0, |
240 | attributes, |
241 | data.len(), |
242 | data.as_ptr(), |
243 | ) |
244 | .into() |
245 | } |
246 | } |
247 | |
248 | /// Deletes a UEFI variable. |
249 | pub fn delete_variable(&self, name: &CStr16, vendor: &VariableVendor) -> Result { |
250 | self.set_variable(name, vendor, VariableAttributes::empty(), &[]) |
251 | } |
252 | |
253 | /// Get information about UEFI variable storage space for the type |
254 | /// of variable specified in `attributes`. |
255 | /// |
256 | /// This operation is only supported starting with UEFI 2.0; earlier |
257 | /// versions will fail with [`Status::UNSUPPORTED`]. |
258 | /// |
259 | /// See [`VariableStorageInfo`] for details of the information returned. |
260 | pub fn query_variable_info( |
261 | &self, |
262 | attributes: VariableAttributes, |
263 | ) -> Result<VariableStorageInfo> { |
264 | if self.header.revision < Revision::EFI_2_00 { |
265 | return Err(Status::UNSUPPORTED.into()); |
266 | } |
267 | |
268 | let mut info = VariableStorageInfo::default(); |
269 | unsafe { |
270 | (self.query_variable_info)( |
271 | attributes, |
272 | &mut info.maximum_variable_storage_size, |
273 | &mut info.remaining_variable_storage_size, |
274 | &mut info.maximum_variable_size, |
275 | ) |
276 | .into_with_val(|| info) |
277 | } |
278 | } |
279 | |
280 | /// Resets the computer. |
281 | pub fn reset(&self, rt: ResetType, status: Status, data: Option<&[u8]>) -> ! { |
282 | let (size, data) = match data { |
283 | // FIXME: The UEFI spec states that the data must start with a NUL- |
284 | // terminated string, which we should check... but it does not |
285 | // specify if that string should be Latin-1 or UCS-2! |
286 | // |
287 | // PlatformSpecific resets should also insert a GUID after the |
288 | // NUL-terminated string. |
289 | Some(data) => (data.len(), data.as_ptr()), |
290 | None => (0, ptr::null()), |
291 | }; |
292 | |
293 | unsafe { (self.reset)(rt, status, size, data) } |
294 | } |
295 | } |
296 | |
297 | impl super::Table for RuntimeServices { |
298 | const SIGNATURE: u64 = 0x5652_4553_544e_5552; |
299 | } |
300 | |
301 | impl Debug for RuntimeServices { |
302 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
303 | f&mut DebugStruct<'_, '_>.debug_struct("RuntimeServices" ) |
304 | .field("header" , &self.header) |
305 | .field("get_time" , &(self.get_time as *const u64)) |
306 | .field("set_time" , &(self.set_time as *const u64)) |
307 | .field( |
308 | "set_virtual_address_map" , |
309 | &(self.set_virtual_address_map as *const u64), |
310 | ) |
311 | .field(name:"reset" , &(self.reset as *const u64)) |
312 | .finish() |
313 | } |
314 | } |
315 | |
316 | /// Date and time representation. |
317 | #[derive (Copy, Clone)] |
318 | #[repr (C)] |
319 | pub struct Time { |
320 | year: u16, // 1900 - 9999 |
321 | month: u8, // 1 - 12 |
322 | day: u8, // 1 - 31 |
323 | hour: u8, // 0 - 23 |
324 | minute: u8, // 0 - 59 |
325 | second: u8, // 0 - 59 |
326 | _pad1: u8, |
327 | nanosecond: u32, // 0 - 999_999_999 |
328 | time_zone: i16, // -1440 to 1440, or 2047 if unspecified |
329 | daylight: Daylight, |
330 | _pad2: u8, |
331 | } |
332 | |
333 | /// Input parameters for [`Time::new`]. |
334 | #[derive (Copy, Clone)] |
335 | pub struct TimeParams { |
336 | /// Year in the range `1900..=9999`. |
337 | pub year: u16, |
338 | |
339 | /// Month in the range `1..=12`. |
340 | pub month: u8, |
341 | |
342 | /// Day in the range `1..=31`. |
343 | pub day: u8, |
344 | |
345 | /// Hour in the range `0.=23`. |
346 | pub hour: u8, |
347 | |
348 | /// Minute in the range `0..=59`. |
349 | pub minute: u8, |
350 | |
351 | /// Second in the range `0..=59`. |
352 | pub second: u8, |
353 | |
354 | /// Fraction of a second represented as nanoseconds in the range |
355 | /// `0..=999_999_999`. |
356 | pub nanosecond: u32, |
357 | |
358 | /// Offset in minutes from UTC in the range `-1440..=1440`, or |
359 | /// local time if `None`. |
360 | pub time_zone: Option<i16>, |
361 | |
362 | /// Daylight savings time information. |
363 | pub daylight: Daylight, |
364 | } |
365 | |
366 | bitflags! { |
367 | /// A bitmask containing daylight savings time information. |
368 | pub struct Daylight: u8 { |
369 | /// Time is affected by daylight savings time. |
370 | const ADJUST_DAYLIGHT = 0x01; |
371 | /// Time has been adjusted for daylight savings time. |
372 | const IN_DAYLIGHT = 0x02; |
373 | } |
374 | } |
375 | |
376 | /// Error returned by [`Time`] methods if the input is outside the valid range. |
377 | #[derive (Copy, Clone, Debug, Default, Eq, PartialEq)] |
378 | pub struct TimeError; |
379 | |
380 | impl Time { |
381 | /// Unspecified Timezone/local time. |
382 | const UNSPECIFIED_TIMEZONE: i16 = 0x07ff; |
383 | |
384 | /// Create a `Time` value. If a field is not in the valid range, |
385 | /// [`TimeError`] is returned. |
386 | pub fn new(params: TimeParams) -> core::result::Result<Self, TimeError> { |
387 | let time = Self { |
388 | year: params.year, |
389 | month: params.month, |
390 | day: params.day, |
391 | hour: params.hour, |
392 | minute: params.minute, |
393 | second: params.second, |
394 | _pad1: 0, |
395 | nanosecond: params.nanosecond, |
396 | time_zone: params.time_zone.unwrap_or(Self::UNSPECIFIED_TIMEZONE), |
397 | daylight: params.daylight, |
398 | _pad2: 0, |
399 | }; |
400 | if time.is_valid() { |
401 | Ok(time) |
402 | } else { |
403 | Err(TimeError) |
404 | } |
405 | } |
406 | |
407 | /// Create an invalid `Time` with all fields set to zero. This can |
408 | /// be used with [`FileInfo`] to indicate a field should not be |
409 | /// updated when calling [`File::set_info`]. |
410 | /// |
411 | /// [`FileInfo`]: uefi::proto::media::file::FileInfo |
412 | /// [`File::set_info`]: uefi::proto::media::file::File::set_info |
413 | #[must_use ] |
414 | pub const fn invalid() -> Self { |
415 | Self { |
416 | year: 0, |
417 | month: 0, |
418 | day: 0, |
419 | hour: 0, |
420 | minute: 0, |
421 | second: 0, |
422 | _pad1: 0, |
423 | nanosecond: 0, |
424 | time_zone: 0, |
425 | daylight: Daylight::empty(), |
426 | _pad2: 0, |
427 | } |
428 | } |
429 | |
430 | /// True if all fields are within valid ranges, false otherwise. |
431 | #[must_use ] |
432 | pub fn is_valid(&self) -> bool { |
433 | (1900..=9999).contains(&self.year) |
434 | && (1..=12).contains(&self.month) |
435 | && (1..=31).contains(&self.day) |
436 | && self.hour <= 23 |
437 | && self.minute <= 59 |
438 | && self.second <= 59 |
439 | && self.nanosecond <= 999_999_999 |
440 | && ((-1440..=1440).contains(&self.time_zone) |
441 | || self.time_zone == Self::UNSPECIFIED_TIMEZONE) |
442 | } |
443 | |
444 | /// Query the year. |
445 | #[must_use ] |
446 | pub const fn year(&self) -> u16 { |
447 | self.year |
448 | } |
449 | |
450 | /// Query the month. |
451 | #[must_use ] |
452 | pub const fn month(&self) -> u8 { |
453 | self.month |
454 | } |
455 | |
456 | /// Query the day. |
457 | #[must_use ] |
458 | pub const fn day(&self) -> u8 { |
459 | self.day |
460 | } |
461 | |
462 | /// Query the hour. |
463 | #[must_use ] |
464 | pub const fn hour(&self) -> u8 { |
465 | self.hour |
466 | } |
467 | |
468 | /// Query the minute. |
469 | #[must_use ] |
470 | pub const fn minute(&self) -> u8 { |
471 | self.minute |
472 | } |
473 | |
474 | /// Query the second. |
475 | #[must_use ] |
476 | pub const fn second(&self) -> u8 { |
477 | self.second |
478 | } |
479 | |
480 | /// Query the nanosecond. |
481 | #[must_use ] |
482 | pub const fn nanosecond(&self) -> u32 { |
483 | self.nanosecond |
484 | } |
485 | |
486 | /// Query the time offset in minutes from UTC, or None if using local time. |
487 | #[must_use ] |
488 | pub const fn time_zone(&self) -> Option<i16> { |
489 | if self.time_zone == 2047 { |
490 | None |
491 | } else { |
492 | Some(self.time_zone) |
493 | } |
494 | } |
495 | |
496 | /// Query the daylight savings time information. |
497 | #[must_use ] |
498 | pub const fn daylight(&self) -> Daylight { |
499 | self.daylight |
500 | } |
501 | } |
502 | |
503 | impl fmt::Debug for Time { |
504 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
505 | write!(f, " {:04}- {:02}- {:02} " , self.year, self.month, self.day)?; |
506 | write!( |
507 | f, |
508 | " {:02}: {:02}: {:02}. {:09}" , |
509 | self.hour, self.minute, self.second, self.nanosecond |
510 | )?; |
511 | if self.time_zone == Self::UNSPECIFIED_TIMEZONE { |
512 | write!(f, ", Timezone=local" )?; |
513 | } else { |
514 | write!(f, ", Timezone= {}" , self.time_zone)?; |
515 | } |
516 | write!(f, ", Daylight= {:?}" , self.daylight) |
517 | } |
518 | } |
519 | |
520 | impl fmt::Display for Time { |
521 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
522 | write!(f, " {:04}- {:02}- {:02} " , self.year, self.month, self.day)?; |
523 | write!( |
524 | f, |
525 | " {:02}: {:02}: {:02}. {:09}" , |
526 | self.hour, self.minute, self.second, self.nanosecond |
527 | )?; |
528 | |
529 | if self.time_zone == Self::UNSPECIFIED_TIMEZONE { |
530 | write!(f, " (local)" )?; |
531 | } else { |
532 | let offset_in_hours = self.time_zone as f32 / 60.0; |
533 | let integer_part = offset_in_hours as i16; |
534 | // We can't use "offset_in_hours.fract()" because it is part of `std`. |
535 | let fraction_part = offset_in_hours - (integer_part as f32); |
536 | // most time zones |
537 | if fraction_part == 0.0 { |
538 | write!(f, "UTC+ {offset_in_hours}" )?; |
539 | } |
540 | // time zones with 30min offset (and perhaps other special time zones) |
541 | else { |
542 | write!(f, "UTC+ {offset_in_hours:.1}" )?; |
543 | } |
544 | } |
545 | |
546 | Ok(()) |
547 | } |
548 | } |
549 | |
550 | impl PartialEq for Time { |
551 | fn eq(&self, other: &Time) -> bool { |
552 | self.year == other.year |
553 | && self.month == other.month |
554 | && self.day == other.day |
555 | && self.hour == other.hour |
556 | && self.minute == other.minute |
557 | && self.second == other.second |
558 | && self.nanosecond == other.nanosecond |
559 | && self.time_zone == other.time_zone |
560 | && self.daylight == other.daylight |
561 | } |
562 | } |
563 | |
564 | impl Eq for Time {} |
565 | |
566 | /// Real time clock capabilities |
567 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
568 | #[repr (C)] |
569 | pub struct TimeCapabilities { |
570 | /// Reporting resolution of the clock in counts per second. 1 for a normal |
571 | /// PC-AT CMOS RTC device, which reports the time with 1-second resolution. |
572 | pub resolution: u32, |
573 | |
574 | /// Timekeeping accuracy in units of 1e-6 parts per million. |
575 | pub accuracy: u32, |
576 | |
577 | /// Whether a time set operation clears the device's time below the |
578 | /// "resolution" reporting level. False for normal PC-AT CMOS RTC devices. |
579 | pub sets_to_zero: bool, |
580 | } |
581 | |
582 | bitflags! { |
583 | /// Flags describing the attributes of a variable. |
584 | pub struct VariableAttributes: u32 { |
585 | /// Variable is maintained across a power cycle. |
586 | const NON_VOLATILE = 0x01; |
587 | |
588 | /// Variable is accessible during the time that boot services are |
589 | /// accessible. |
590 | const BOOTSERVICE_ACCESS = 0x02; |
591 | |
592 | /// Variable is accessible during the time that runtime services are |
593 | /// accessible. |
594 | const RUNTIME_ACCESS = 0x04; |
595 | |
596 | /// Variable is stored in the portion of NVR allocated for error |
597 | /// records. |
598 | const HARDWARE_ERROR_RECORD = 0x08; |
599 | |
600 | /// Deprecated. |
601 | const AUTHENTICATED_WRITE_ACCESS = 0x10; |
602 | |
603 | /// Variable payload begins with an EFI_VARIABLE_AUTHENTICATION_2 |
604 | /// structure. |
605 | const TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x20; |
606 | |
607 | /// This is never set in the attributes returned by |
608 | /// `get_variable`. When passed to `set_variable`, the variable payload |
609 | /// will be appended to the current value of the variable if supported |
610 | /// by the firmware. |
611 | const APPEND_WRITE = 0x40; |
612 | |
613 | /// Variable payload begins with an EFI_VARIABLE_AUTHENTICATION_3 |
614 | /// structure. |
615 | const ENHANCED_AUTHENTICATED_ACCESS = 0x80; |
616 | } |
617 | } |
618 | |
619 | newtype_enum! { |
620 | /// Variable vendor GUID. This serves as a namespace for variables to |
621 | /// avoid naming conflicts between vendors. The UEFI specification |
622 | /// defines some special values, and vendors will define their own. |
623 | pub enum VariableVendor: Guid => { |
624 | /// Used to access global variables. |
625 | GLOBAL_VARIABLE = guid!("8be4df61-93ca-11d2-aa0d-00e098032b8c" ), |
626 | |
627 | /// Used to access EFI signature database variables. |
628 | IMAGE_SECURITY_DATABASE = guid!("d719b2cb-3d3a-4596-a3bc-dad00e67656f" ), |
629 | } |
630 | } |
631 | |
632 | /// Unique key for a variable. |
633 | #[cfg (feature = "alloc" )] |
634 | #[derive (Debug)] |
635 | pub struct VariableKey { |
636 | name: Vec<u16>, |
637 | /// Unique identifier for the vendor. |
638 | pub vendor: VariableVendor, |
639 | } |
640 | |
641 | #[cfg (feature = "alloc" )] |
642 | impl VariableKey { |
643 | /// Name of the variable. |
644 | pub fn name(&self) -> core::result::Result<&CStr16, FromSliceWithNulError> { |
645 | CStr16::from_u16_with_nul(&self.name) |
646 | } |
647 | } |
648 | |
649 | #[cfg (feature = "alloc" )] |
650 | impl fmt::Display for VariableKey { |
651 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
652 | write!(f, "VariableKey {{ name: " )?; |
653 | |
654 | match self.name() { |
655 | Ok(name) => write!(f, " \"{name}\"" )?, |
656 | Err(err) => write!(f, "Err( {err:?})" )?, |
657 | } |
658 | |
659 | write!(f, ", vendor: " )?; |
660 | |
661 | if self.vendor == VariableVendor::GLOBAL_VARIABLE { |
662 | write!(f, "GLOBAL_VARIABLE" )?; |
663 | } else { |
664 | write!(f, " {}" , self.vendor.0)?; |
665 | } |
666 | |
667 | write!(f, " }}" ) |
668 | } |
669 | } |
670 | |
671 | /// Information about UEFI variable storage space returned by |
672 | /// [`RuntimeServices::query_variable_info`]. Note that the data here is |
673 | /// limited to a specific type of variable (as specified by the |
674 | /// `attributes` argument to `query_variable_info`). |
675 | #[derive (Clone, Copy, Debug, Default, Eq, PartialEq)] |
676 | pub struct VariableStorageInfo { |
677 | /// Maximum size in bytes of the storage space available for |
678 | /// variables of the specified type. |
679 | pub maximum_variable_storage_size: u64, |
680 | |
681 | /// Remaining size in bytes of the storage space available for |
682 | /// variables of the specified type. |
683 | pub remaining_variable_storage_size: u64, |
684 | |
685 | /// Maximum size of an individual variable of the specified type. |
686 | pub maximum_variable_size: u64, |
687 | } |
688 | |
689 | /// The type of system reset. |
690 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
691 | #[repr (u32)] |
692 | pub enum ResetType { |
693 | /// Resets all the internal circuitry to its initial state. |
694 | /// |
695 | /// This is analogous to power cycling the device. |
696 | Cold = 0, |
697 | /// The processor is reset to its initial state. |
698 | Warm, |
699 | /// The components are powered off. |
700 | Shutdown, |
701 | /// A platform-specific reset type. |
702 | /// |
703 | /// The additional data must be a pointer to |
704 | /// a null-terminated string followed by an UUID. |
705 | PlatformSpecific, |
706 | // SAFETY: This enum is never exposed to the user, but only fed as input to |
707 | // the firmware. Therefore, unexpected values can never come from |
708 | // the firmware, and modeling this as a Rust enum seems safe. |
709 | } |
710 | |