Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions uefi-test-runner/src/runtime/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,13 @@ fn test_variables(rt: &RuntimeServices) {

/// Test the variable functions in `uefi::runtime`.
fn test_variables_freestanding() {
assert!(!runtime::variable_exists(NAME, VENDOR).unwrap());

// Create the test variable.
runtime::set_variable(NAME, VENDOR, ATTRS, VALUE).expect("failed to set variable");

assert!(runtime::variable_exists(NAME, VENDOR).unwrap());

// Test `get_variable` with too small of a buffer.
let mut buf = [0u8; 0];
assert_eq!(
Expand Down Expand Up @@ -106,6 +110,7 @@ fn test_variables_freestanding() {

// Delete the variable and verify it can no longer be read.
runtime::delete_variable(NAME, VENDOR).expect("failed to delete variable");
assert!(!runtime::variable_exists(NAME, VENDOR).unwrap());
assert_eq!(
runtime::get_variable(NAME, VENDOR, &mut buf)
.unwrap_err()
Expand Down
1 change: 1 addition & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ how to integrate the `uefi` crate into them.
- Added `Handle::new`.
- Added the `uefi::boot`, `uefi::runtime`, and `uefi::system` modules to the
prelude.
- Added `runtime::variable_exists`.

## Changed
- The `BootServices`, `RuntimeServices`, and `SystemTable` structs have been
Expand Down
41 changes: 41 additions & 0 deletions uefi/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,47 @@ pub unsafe fn set_time(time: &Time) -> Result {
(rt.set_time)(time.cast()).to_result()
}

/// Checks if a variable exists.
///
/// Returns `Ok(true)` if the variable exists, `Ok(false)` if the variable does
/// not exist, or `Err` if the existence of the variable could not be determined.
///
/// # Errors
///
/// * [`Status::DEVICE_ERROR`]: variable could not be read due to a hardware error.
/// * [`Status::SECURITY_VIOLATION`]: variable could not be read due to an
/// authentication error.
/// * [`Status::UNSUPPORTED`]: this platform does not support variable storage
/// after exiting boot services.
pub fn variable_exists(name: &CStr16, vendor: &VariableVendor) -> Result<bool> {
let rt = runtime_services_raw_panicking();
let rt = unsafe { rt.as_ref() };

let attributes = ptr::null_mut();
let data = ptr::null_mut();
let mut data_size = 0;

let status = unsafe {
(rt.get_variable)(
name.as_ptr().cast(),
&vendor.0,
attributes,
&mut data_size,
data,
)
};

match status {
// If the variable exists, the status will be BUFFER_TOO_SMALL because
// data_size is 0. Empty variables do not exist, because setting a
// variable with empty data deletes the variable. In other words, the
// status will never be SUCCESS.
Status::BUFFER_TOO_SMALL => Ok(true),
Status::NOT_FOUND => Ok(false),
_ => Err(Error::from(status)),
}
}

/// Gets the contents and attributes of a variable. The size of `buf` must be at
/// least as big as the variable's size, although it can be larger.
///
Expand Down