Skip to content

Commit

Permalink
Add uefi::runtime module
Browse files Browse the repository at this point in the history
The initial version here just provides functions for getting and setting the
system time. Later commits will add functions to get/set variables, handle
update capsules, etc.

Also added some tests for the new code in the test runner (note that there were
no existing tests for the time-related functions of `RuntimeServices`).
  • Loading branch information
nicholasbishop committed Jul 19, 2024
1 parent 1fa9408 commit d160ec2
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 1 deletion.
32 changes: 31 additions & 1 deletion uefi-test-runner/src/runtime/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
mod vars;

use uefi::runtime::{self, Daylight, Time, TimeParams};
use uefi::table::runtime::RuntimeServices;

pub fn test(rt: &RuntimeServices) {
info!("Testing runtime services");
vars::test(rt);
test_time();
}

mod vars;
fn test_time() {
// Print the current time and time capabilities.
info!(
"Time with caps: {:?}",
runtime::get_time_and_caps().unwrap()
);

// Set the time.
let time = Time::new(TimeParams {
year: 2020,
month: 1,
day: 2,
hour: 3,
minute: 4,
second: 5,
nanosecond: 6,
time_zone: None,
daylight: Daylight::IN_DAYLIGHT,
})
.unwrap();
unsafe { runtime::set_time(&time).unwrap() };

// Print the new time and check that the year was successfully changed.
let now = runtime::get_time().unwrap();
info!("After setting time: {}", now);
assert_eq!(now.year(), 2020);
}
2 changes: 2 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Added
- `uefi::system` is a new module that provides freestanding functions for
accessing fields of the global system table.
- `uefi::runtime` is a new module that provides freestanding functions for
runtime services using the global system table.
- Add standard derives for `ConfigTableEntry`.
- `PcrEvent`/`PcrEventInputs` impl `Align`, `Eq`, and `PartialEq`.
- Added `PcrEvent::new_in_box` and `PcrEventInputs::new_in_box`.
Expand Down
1 change: 1 addition & 0 deletions uefi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub use uguid::guid;
mod result;
pub use result::{Error, Result, ResultExt, Status, StatusExt};

pub mod runtime;
pub mod system;
pub mod table;

Expand Down
57 changes: 57 additions & 0 deletions uefi/src/runtime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! UEFI runtime services.
//!
//! These services are available both before and after exiting boot
//! services. Note that various restrictions apply when calling runtime services
//! functions after exiting boot services; see the "Calling Convention" section
//! of the UEFI specification for details.

use crate::table::{self};
use crate::{Result, StatusExt};
use core::ptr::{self, NonNull};

pub use crate::table::runtime::{Daylight, Time, TimeCapabilities, TimeError, TimeParams};

fn runtime_services_raw_panicking() -> NonNull<uefi_raw::table::runtime::RuntimeServices> {
let st = table::system_table_raw_panicking();
// SAFETY: valid per requirements of `set_system_table`.
let st = unsafe { st.as_ref() };
NonNull::new(st.runtime_services).expect("runtime services are not active")
}

/// Query the current time and date information.
pub fn get_time() -> Result<Time> {
let rt = runtime_services_raw_panicking();
let rt = unsafe { rt.as_ref() };

let mut time = Time::invalid();
let time_ptr: *mut Time = &mut time;
unsafe { (rt.get_time)(time_ptr.cast(), ptr::null_mut()) }.to_result_with_val(|| time)
}

/// Query the current time and date information and the RTC capabilities.
pub fn get_time_and_caps() -> Result<(Time, TimeCapabilities)> {
let rt = runtime_services_raw_panicking();
let rt = unsafe { rt.as_ref() };

let mut time = Time::invalid();
let time_ptr: *mut Time = &mut time;
let mut caps = TimeCapabilities::default();
unsafe { (rt.get_time)(time_ptr.cast(), &mut caps) }.to_result_with_val(|| (time, caps))
}

/// Sets the current local time and date information
///
/// During runtime, if a PC-AT CMOS device is present in the platform, the
/// caller must synchronize access to the device before calling `set_time`.
///
/// # Safety
///
/// Undefined behavior could happen if multiple tasks try to
/// use this function at the same time without synchronisation.
pub unsafe fn set_time(time: &Time) -> Result {
let rt = runtime_services_raw_panicking();
let rt = unsafe { rt.as_ref() };

let time: *const Time = time;
(rt.set_time)(time.cast()).to_result()
}

0 comments on commit d160ec2

Please sign in to comment.