Skip to content

Commit 92e07bb

Browse files
committed
uefi: Implementing wrappers for EFI Shell env and cur_dir functions
This commit implements wrappers for the following EFI Shell Protocol functions: set_env(), get_env(), set_cur_dir(), and get_cur_dir().
1 parent 70a63b8 commit 92e07bb

File tree

1 file changed

+130
-1
lines changed

1 file changed

+130
-1
lines changed

uefi/src/proto/shell/mod.rs

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,141 @@
22

33
//! EFI Shell Protocol v2.2
44
5-
use crate::proto::unsafe_protocol;
5+
#![cfg(feature = "alloc")]
6+
7+
use alloc::vec::Vec;
8+
use uefi_macros::unsafe_protocol;
9+
use uefi_raw::Status;
10+
11+
use core::ptr;
612

713
pub use uefi_raw::protocol::shell::ShellProtocol;
814

15+
use crate::{CStr16, Char16};
16+
917
/// Shell Protocol
1018
#[derive(Debug)]
1119
#[repr(transparent)]
1220
#[unsafe_protocol(uefi_raw::protocol::shell::ShellProtocol::GUID)]
1321
pub struct Shell(uefi_raw::protocol::shell::ShellProtocol);
22+
23+
impl Shell {
24+
/// Gets the environment variable or list of environment variables
25+
///
26+
/// # Arguments
27+
///
28+
/// * `name` - The environment variable name of which to retrieve the
29+
/// value
30+
/// If None, will return all defined shell environment
31+
/// variables
32+
///
33+
/// # Returns
34+
///
35+
/// * `Some(Vec<env_value>)` - Value of the environment variable
36+
/// * `Some(Vec<env_names>)` - Vector of environment variable names
37+
/// * `None` - Environment variable doesn't exist
38+
#[must_use]
39+
pub fn get_env<'a>(&'a self, name: Option<&CStr16>) -> Option<Vec<&'a CStr16>> {
40+
let mut env_vec = Vec::new();
41+
match name {
42+
Some(n) => {
43+
let name_ptr: *const Char16 = core::ptr::from_ref::<CStr16>(n).cast();
44+
let var_val = unsafe { (self.0.get_env)(name_ptr.cast()) };
45+
if var_val.is_null() {
46+
return None;
47+
} else {
48+
unsafe { env_vec.push(CStr16::from_ptr(var_val.cast())) };
49+
}
50+
}
51+
None => {
52+
let cur_env_ptr = unsafe { (self.0.get_env)(ptr::null()) };
53+
54+
let mut cur_start = cur_env_ptr;
55+
let mut cur_len = 0;
56+
57+
let mut i = 0;
58+
let mut null_count = 0;
59+
unsafe {
60+
while null_count <= 1 {
61+
if (*(cur_env_ptr.add(i))) == Char16::from_u16_unchecked(0).into() {
62+
if cur_len > 0 {
63+
env_vec.push(CStr16::from_char16_with_nul_unchecked(
64+
&(*ptr::slice_from_raw_parts(cur_start.cast(), cur_len + 1)),
65+
));
66+
}
67+
cur_len = 0;
68+
null_count += 1;
69+
} else {
70+
if null_count > 0 {
71+
cur_start = cur_env_ptr.add(i);
72+
}
73+
null_count = 0;
74+
cur_len += 1;
75+
}
76+
i += 1;
77+
}
78+
}
79+
}
80+
}
81+
Some(env_vec)
82+
}
83+
84+
/// Sets the environment variable
85+
///
86+
/// # Arguments
87+
///
88+
/// * `name` - The environment variable for which to set the value
89+
/// * `value` - The new value of the environment variable
90+
/// * `volatile` - Indicates whether or not the variable is volatile or
91+
/// not
92+
///
93+
/// # Returns
94+
///
95+
/// * `Status::SUCCESS` The variable was successfully set
96+
pub fn set_env(&self, name: &CStr16, value: &CStr16, volatile: bool) -> Status {
97+
let name_ptr: *const Char16 = core::ptr::from_ref::<CStr16>(name).cast();
98+
let value_ptr: *const Char16 = core::ptr::from_ref::<CStr16>(value).cast();
99+
unsafe { (self.0.set_env)(name_ptr.cast(), value_ptr.cast(), volatile) }
100+
}
101+
102+
/// Returns the current directory on the specified device
103+
///
104+
/// # Arguments
105+
///
106+
/// * `file_system_mapping` - The file system mapping for which to get
107+
/// the current directory
108+
/// # Returns
109+
///
110+
/// * `Some(cwd)` - CStr16 containing the current working directory
111+
/// * `None` - Could not retrieve current directory
112+
#[must_use]
113+
pub fn get_cur_dir<'a>(&'a self, file_system_mapping: Option<&CStr16>) -> Option<&'a CStr16> {
114+
let mapping_ptr: *const Char16 = file_system_mapping.map_or(ptr::null(), |x| (x.as_ptr()));
115+
let cur_dir = unsafe { (self.0.get_cur_dir)(mapping_ptr.cast()) };
116+
if cur_dir.is_null() {
117+
None
118+
} else {
119+
unsafe { Some(CStr16::from_ptr(cur_dir.cast())) }
120+
}
121+
}
122+
123+
/// Changes the current directory on the specified device
124+
///
125+
/// # Arguments
126+
///
127+
/// * `file_system` - Pointer to the file system's mapped name.
128+
/// * `directory` - Points to the directory on the device specified by
129+
/// `file_system`.
130+
/// # Returns
131+
///
132+
/// * `Status::SUCCESS` The directory was successfully set
133+
///
134+
/// # Errors
135+
///
136+
/// * `Status::EFI_NOT_FOUND` The directory does not exist
137+
pub fn set_cur_dir(&self, file_system: Option<&CStr16>, directory: Option<&CStr16>) -> Status {
138+
let fs_ptr: *const Char16 = file_system.map_or(ptr::null(), |x| (x.as_ptr()));
139+
let dir_ptr: *const Char16 = directory.map_or(ptr::null(), |x| (x.as_ptr()));
140+
unsafe { (self.0.set_cur_dir)(fs_ptr.cast(), dir_ptr.cast()) }
141+
}
142+
}

0 commit comments

Comments
 (0)