1//! UEFI services available at runtime, even after the OS boots.
2
3use super::{Header, Revision};
4#[cfg(feature = "alloc")]
5use crate::data_types::FromSliceWithNulError;
6use crate::result::Error;
7use crate::table::boot::MemoryDescriptor;
8use crate::{guid, CStr16, Char16, Guid, Result, Status};
9#[cfg(feature = "alloc")]
10use alloc::{vec, vec::Vec};
11use bitflags::bitflags;
12use core::fmt::{Debug, Formatter};
13#[cfg(feature = "alloc")]
14use core::mem;
15use core::mem::MaybeUninit;
16use 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)]
28pub 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
83impl 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
297impl super::Table for RuntimeServices {
298 const SIGNATURE: u64 = 0x5652_4553_544e_5552;
299}
300
301impl 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)]
319pub 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)]
335pub 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
366bitflags! {
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)]
378pub struct TimeError;
379
380impl 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
503impl 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
520impl 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
550impl 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
564impl Eq for Time {}
565
566/// Real time clock capabilities
567#[derive(Debug, Copy, Clone, Eq, PartialEq)]
568#[repr(C)]
569pub 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
582bitflags! {
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
619newtype_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)]
635pub struct VariableKey {
636 name: Vec<u16>,
637 /// Unique identifier for the vendor.
638 pub vendor: VariableVendor,
639}
640
641#[cfg(feature = "alloc")]
642impl 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")]
650impl 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)]
676pub 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)]
692pub 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