Skip to content

Commit

Permalink
Merge pull request #1392 from rust-osdev/bishop-var-exists
Browse files Browse the repository at this point in the history
uefi: Add uefi::runtime::variable_exists
  • Loading branch information
phip1611 authored Sep 8, 2024
2 parents 9090f9e + 4e513f0 commit 302d82c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
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

0 comments on commit 302d82c

Please sign in to comment.