Skip to content

Commit f114cd9

Browse files
committed
std: uefi: Add basic Env variables
- Implement environment variable functions - Using EFI Shell GUID for reading/storing variables. Signed-off-by: Ayush Singh <[email protected]>
1 parent ac77e88 commit f114cd9

File tree

1 file changed

+186
-14
lines changed
  • library/std/src/sys/pal/uefi

1 file changed

+186
-14
lines changed

library/std/src/sys/pal/uefi/os.rs

+186-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::error::Error as StdError;
66
use crate::ffi::{OsStr, OsString};
77
use crate::marker::PhantomData;
88
use crate::os::uefi;
9+
use crate::os::uefi::ffi::OsStringExt;
910
use crate::path::{self, PathBuf};
1011
use crate::ptr::NonNull;
1112
use crate::{fmt, io};
@@ -171,44 +172,70 @@ pub fn current_exe() -> io::Result<PathBuf> {
171172
helpers::device_path_to_text(protocol).map(PathBuf::from)
172173
}
173174

174-
pub struct Env(!);
175+
#[derive(Clone)]
176+
pub struct Env {
177+
last_var_name: Vec<u16>,
178+
last_var_guid: r_efi::efi::Guid,
179+
}
175180

176181
impl Env {
177182
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
178183
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
179-
let Self(inner) = self;
180-
match *inner {}
184+
self
181185
}
182186
}
183187

184188
impl Iterator for Env {
185189
type Item = (OsString, OsString);
190+
186191
fn next(&mut self) -> Option<(OsString, OsString)> {
187-
self.0
192+
let (key, guid) =
193+
uefi_vars::get_next_variable_name(&self.last_var_name, self.last_var_guid).ok()?;
194+
195+
self.last_var_name = key;
196+
self.last_var_guid = guid;
197+
198+
if self.last_var_guid == uefi_vars::SHELL_VARIABLE_GUID {
199+
let k = OsString::from_wide(&self.last_var_name[..(self.last_var_name.len() - 1)]);
200+
let v = uefi_vars::get(self.last_var_name.as_mut_slice())?;
201+
202+
Some((k, v))
203+
} else {
204+
self.next()
205+
}
188206
}
189207
}
190208

191209
impl fmt::Debug for Env {
192-
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
193-
let Self(inner) = self;
194-
match *inner {}
210+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211+
let iter: Env = self.clone();
212+
let mut list = f.debug_list();
213+
for (a, b) in iter {
214+
list.entry(&(a.to_str().unwrap(), b.to_str().unwrap()));
215+
}
216+
list.finish()
195217
}
196218
}
197219

198220
pub fn env() -> Env {
199-
panic!("not supported on this platform")
221+
Env { last_var_name: Vec::from([0]), last_var_guid: uefi_vars::SHELL_VARIABLE_GUID }
200222
}
201223

202-
pub fn getenv(_: &OsStr) -> Option<OsString> {
203-
None
224+
pub fn getenv(key: &OsStr) -> Option<OsString> {
225+
let mut key = uefi_vars::key(key)?;
226+
uefi_vars::get(key.as_mut_slice())
204227
}
205228

206-
pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
207-
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
229+
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
230+
let mut k =
231+
uefi_vars::key(k).ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid key"))?;
232+
uefi_vars::set(k.as_mut_slice(), v)
208233
}
209234

210-
pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> {
211-
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
235+
pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
236+
let mut k =
237+
uefi_vars::key(k).ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid key"))?;
238+
uefi_vars::unset(k.as_mut_slice())
212239
}
213240

214241
pub fn temp_dir() -> PathBuf {
@@ -239,3 +266,148 @@ pub fn exit(code: i32) -> ! {
239266
pub fn getpid() -> u32 {
240267
panic!("no pids on this platform")
241268
}
269+
270+
mod uefi_vars {
271+
use super::helpers;
272+
use crate::ffi::{OsStr, OsString};
273+
use crate::io;
274+
use crate::mem::size_of;
275+
use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
276+
use crate::ptr::NonNull;
277+
278+
// Using Shell Variable Guid from edk2/ShellPkg
279+
// https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Guid/ShellVariableGuid.h
280+
pub(crate) const SHELL_VARIABLE_GUID: r_efi::efi::Guid = r_efi::efi::Guid::from_fields(
281+
0x158def5a,
282+
0xf656,
283+
0x419c,
284+
0xb0,
285+
0x27,
286+
&[0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2],
287+
);
288+
289+
pub(crate) fn key(k: &OsStr) -> Option<Vec<u16>> {
290+
let key = k.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
291+
if key[..key.len() - 1].contains(&0) {
292+
return None;
293+
} else {
294+
Some(key)
295+
}
296+
}
297+
298+
pub(crate) fn get(key: &mut [u16]) -> Option<OsString> {
299+
let rt: NonNull<r_efi::efi::RuntimeServices> =
300+
helpers::runtime_services().expect("UEFI Runtime Services Missing").cast();
301+
302+
let mut len = 0usize;
303+
let mut guid = SHELL_VARIABLE_GUID;
304+
305+
let ret = unsafe {
306+
((*rt.as_ptr()).get_variable)(
307+
key.as_mut_ptr(),
308+
&mut guid,
309+
crate::ptr::null_mut(),
310+
&mut len,
311+
crate::ptr::null_mut(),
312+
)
313+
};
314+
315+
if ret != r_efi::efi::Status::BUFFER_TOO_SMALL {
316+
return None;
317+
}
318+
319+
let mut val = Vec::<u16>::with_capacity(len / size_of::<u16>());
320+
let ret = unsafe {
321+
((*rt.as_ptr()).get_variable)(
322+
key.as_mut_ptr(),
323+
&mut guid,
324+
crate::ptr::null_mut(),
325+
&mut len,
326+
val.as_mut_ptr().cast(),
327+
)
328+
};
329+
330+
if ret.is_error() {
331+
None
332+
} else {
333+
unsafe { val.set_len(len / size_of::<u16>()) };
334+
Some(OsString::from_wide(&val))
335+
}
336+
}
337+
338+
pub(crate) fn set(key: &mut [u16], val: &OsStr) -> io::Result<()> {
339+
// UEFI variable value does not need to be NULL terminated.
340+
let mut val = val.encode_wide().collect::<Vec<u16>>();
341+
let rt: NonNull<r_efi::efi::RuntimeServices> =
342+
helpers::runtime_services().expect("UEFI Runtime Services Missing").cast();
343+
let mut guid = SHELL_VARIABLE_GUID;
344+
345+
let r = unsafe {
346+
((*rt.as_ptr()).set_variable)(
347+
key.as_mut_ptr(),
348+
&mut guid,
349+
r_efi::efi::VARIABLE_BOOTSERVICE_ACCESS,
350+
val.len() * size_of::<u16>(),
351+
val.as_mut_ptr().cast(),
352+
)
353+
};
354+
355+
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
356+
}
357+
358+
pub(crate) fn unset(key: &mut [u16]) -> io::Result<()> {
359+
let rt: NonNull<r_efi::efi::RuntimeServices> =
360+
helpers::runtime_services().expect("UEFI Runtime Services Missing").cast();
361+
let mut guid = SHELL_VARIABLE_GUID;
362+
363+
let r = unsafe {
364+
((*rt.as_ptr()).set_variable)(
365+
key.as_mut_ptr(),
366+
&mut guid,
367+
r_efi::efi::VARIABLE_BOOTSERVICE_ACCESS,
368+
0,
369+
crate::ptr::null_mut(),
370+
)
371+
};
372+
373+
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
374+
}
375+
376+
pub(crate) fn get_next_variable_name(
377+
last_var_name: &[u16],
378+
last_guid: r_efi::efi::Guid,
379+
) -> io::Result<(Vec<u16>, r_efi::efi::Guid)> {
380+
let mut var_name = Vec::from(last_var_name);
381+
let mut var_size = var_name.capacity() * size_of::<u16>();
382+
let mut guid: r_efi::efi::Guid = last_guid;
383+
let rt: NonNull<r_efi::efi::RuntimeServices> =
384+
helpers::runtime_services().expect("UEFI Runtime Services Missing").cast();
385+
386+
let r = unsafe {
387+
((*rt.as_ptr()).get_next_variable_name)(&mut var_size, var_name.as_mut_ptr(), &mut guid)
388+
};
389+
390+
if !r.is_error() {
391+
unsafe { var_name.set_len(var_size / size_of::<u16>()) };
392+
return Ok((var_name, guid));
393+
}
394+
395+
if r != r_efi::efi::Status::BUFFER_TOO_SMALL {
396+
return Err(io::Error::from_raw_os_error(r.as_usize()));
397+
}
398+
399+
var_name.reserve((var_size / size_of::<u16>()) - var_name.capacity() + 1);
400+
var_size = var_name.capacity() * size_of::<u16>();
401+
402+
let r = unsafe {
403+
((*rt.as_ptr()).get_next_variable_name)(&mut var_size, var_name.as_mut_ptr(), &mut guid)
404+
};
405+
406+
if r.is_error() {
407+
Err(io::Error::from_raw_os_error(r.as_usize()))
408+
} else {
409+
unsafe { var_name.set_len(var_size / size_of::<u16>()) };
410+
Ok((var_name, guid))
411+
}
412+
}
413+
}

0 commit comments

Comments
 (0)