1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use super::NvramError;
use super::NvramResult;
use super::NvramSpecServices;
use guid::Guid;
use ucs2::Ucs2LeSlice;
use uefi_nvram_storage::InspectableNvramStorage;
use uefi_specs::uefi::common::EfiStatus;
/// Extension trait around `NvramServices` that makes it easier to use the API
/// outside the context of the UEFI device.
///
/// This trait provides various helper methods that make it easier to get/set
/// nvram variables without worrying about the nitty-gritty details of UCS-2
/// string encoding, pointer sizes/nullness, etc...
#[async_trait::async_trait]
pub trait NvramServicesExt {
/// Get a variable identified by `name` (as a Rust string) + `vendor`,
/// returning the variable's attributes and data.
#[allow(dead_code)] // Useful for debugging
async fn get_variable(
&mut self,
vendor: Guid,
name: &str,
) -> Result<(u32, Vec<u8>), (EfiStatus, Option<NvramError>)>;
/// Get a variable identified by `name` (as a UCS-2 string) + `vendor`,
/// returning the variable's attributes and data.
#[allow(dead_code)] // Useful for debugging
async fn get_variable_ucs2(
&mut self,
vendor: Guid,
name: &Ucs2LeSlice,
) -> Result<(u32, Vec<u8>), (EfiStatus, Option<NvramError>)>;
/// Set a variable identified by `name` (as a Rust string) + `vendor` with
/// the specified `attr` and `data`.
async fn set_variable(
&mut self,
vendor: Guid,
name: &str,
attr: u32,
data: Vec<u8>,
) -> Result<(), (EfiStatus, Option<NvramError>)>;
/// Set a variable identified by `name` (as a UCS-2 string) + `vendor` with
/// the specified `attr` and `data`.
async fn set_variable_ucs2(
&mut self,
vendor: Guid,
name: &Ucs2LeSlice,
attr: u32,
data: Vec<u8>,
) -> Result<(), (EfiStatus, Option<NvramError>)>;
}
#[async_trait::async_trait]
impl<S: InspectableNvramStorage> NvramServicesExt for NvramSpecServices<S> {
async fn get_variable(
&mut self,
vendor: Guid,
name: &str,
) -> Result<(u32, Vec<u8>), (EfiStatus, Option<NvramError>)> {
let name = ucs2::Ucs2LeVec::from(name);
self.get_variable_ucs2(vendor, &name).await
}
async fn get_variable_ucs2(
&mut self,
vendor: Guid,
name: &Ucs2LeSlice,
) -> Result<(u32, Vec<u8>), (EfiStatus, Option<NvramError>)> {
let mut attr = 0;
// the low level UEFI APIs includes the `in_out_data_size` parameter so
// that it can perform validation logic to ensure the user-provided
// buffer is large enough to store the variable data.
//
// this validation logic isn't relevant to the high level API, as
// consumers can simply use the returned Rust reference directly
// (without having to copy it into another buffer).
let mut in_out_data_size = u32::MAX;
let NvramResult(data, status, err) = self
.uefi_get_variable(
Some(name.as_bytes()),
vendor,
&mut attr,
&mut in_out_data_size,
false,
)
.await;
if matches!(status, EfiStatus::SUCCESS) {
Ok((attr, data.expect("data will not be None on EFI_SUCCESS")))
} else {
Err((status, err))
}
}
async fn set_variable(
&mut self,
vendor: Guid,
name: &str,
attr: u32,
data: Vec<u8>,
) -> Result<(), (EfiStatus, Option<NvramError>)> {
let name = ucs2::Ucs2LeVec::from(name);
self.set_variable_ucs2(vendor, &name, attr, data).await
}
async fn set_variable_ucs2(
&mut self,
vendor: Guid,
name: &Ucs2LeSlice,
attr: u32,
data: Vec<u8>,
) -> Result<(), (EfiStatus, Option<NvramError>)> {
let NvramResult((), status, err) = self
.uefi_set_variable(
Some(name.as_bytes()),
vendor,
attr,
data.len() as u32,
Some(data),
)
.await;
if matches!(status, EfiStatus::SUCCESS) {
Ok(())
} else {
Err((status, err))
}
}
}