Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork175
Enhancement/efi shell interface#1679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Uh oh!
There was an error while loading.Please reload this page.
phip1611 left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for working on this! As a general rule of thumb: High-level wrappers should be close to the API ofstd
and not replicate "ugly" or unusual details of the low-level API. See my suggestions forget_var
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Some general guidance:
|
Thanks for the feedback! I will start with making the PR to update |
This commit implements wrappers for the following EFI Shell Protocolfunctions: set_env(), get_env(), set_cur_dir(), and get_cur_dir().
This commit includes tests for the following EFI Shell Protocol functions:get_env(), set_env(), get_cur_dir(), and set_cur_dir().
Hi all. Now that#1680 is merged, I was wondering if it would be alright to use this PR to work on the 4 ergonomic wrappers I've implemented ( If it is okay to continue to use this PR, then I plan to rebase this branch onto the current main, squash the commits, and then continue from there. |
That sounds good, start with doing that in this PR. Once the changes are in this PR it's possible I might ask for it to be split up into more than one PR for review, but we can start with the assumption that one PR is OK. |
b9a3be8
to0f30078
CompareI've rebased this branch onto the current main and updated it to disclude the |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
910e291
to42cad4a
CompareThanks for the feedback! I have updated
to represent the
instead, but I don't see this function implemented for I'll start working on unit tests next! However, for Miri I will need to take some time to read its docs since I'm not familiar. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
5661358
to6b35e5a
CompareI've updated the PR to use the |
Uh oh!
There was an error while loading.Please reload this page.
LGTM! Please squash your commits a little to smaller but sensible units, then I think we are good to go |
Uh oh!
There was an error while loading.Please reload this page.
The UEFI get_env() implementation is used for getting individual environmentvariable values and also environment variable names. This is not intuitiveso this commit splits the function into two dedicated ones: one for accessingvalues and the other for accessing names.Co-authored-by: Philipp Schuster <phip1611@gmail.com>
Co-authored-by: Philipp Schuster <phip1611@gmail.com>
c0b817e
toa21932f
CompareCommits have been squashed :) |
uefi/src/proto/shell/mod.rs Outdated
/// environment variable | ||
/// * `None` - If environment variable does not exist | ||
#[must_use] | ||
pub fn get_env(&self, name: &CStr16) -> Option<&CStr16> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
In#1679 (comment), it was suggested to use the same name asstd
:var
. I think we should do that here, for several reasons:
- Consistency in APIs is good; anyone who is familiar with
std::env
will instinctively know how to use this API - Perhttps://rust-lang.github.io/api-guidelines/naming.html#getter-names-follow-rust-convention-c-getter, Rust APIs generally should not use a
get_
prefix - It's clearer to say you are getting the variable (noun) rather than the environment (which can be a noun, but in "environment variable" it's an adjective).
uefi/src/proto/shell/mod.rs Outdated
/// | ||
/// # Returns | ||
/// | ||
/// * `Vec<env_names>` - Vector of environment variable names |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Out of date, it returnsVars
now. You can probably drop theReturns
section here though, it's redundent with the top-level description.
uefi/src/proto/shell/mod.rs Outdated
} | ||
} | ||
/// Gets the list of environment variables |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
"Gets an iterator over the names of all environment variables."
uefi/src/proto/shell/mod.rs Outdated
/// | ||
/// * `Vec<env_names>` - Vector of environment variable names | ||
#[must_use] | ||
pub fn get_envs(&self) -> Vars { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I thinkvar_names
would be a better name for this function (see comment onget_env
for details). However, even better might be to make it matchstd
and haveVars
return an iterator over both namesand values (and then the method can be named simplyvars
). Is that doable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes, sounds reasonable. High level abstractions should be close to known interfaces (such as std) and not replicate low-level details
uefi/src/proto/shell/mod.rs Outdated
/// | ||
/// * `Status::SUCCESS` - The variable was successfully set | ||
pub fn set_env(&self, name: &CStr16, value: &CStr16, volatile: bool) -> Status { | ||
let name_ptr: *const Char16 = core::ptr::from_ref::<CStr16>(name).cast(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Instead ofcore::ptr::from_ref
, you can usename.as_ptr()
(and ditto for value below).
uefi/src/proto/shell/mod.rs Outdated
/// * `None` - Could not retrieve current directory | ||
#[must_use] | ||
pub fn get_cur_dir(&self, file_system_mapping: Option<&CStr16>) -> Option<&CStr16> { | ||
let mapping_ptr: *const Char16 = file_system_mapping.map_or(ptr::null(), |x| (x.as_ptr())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
nit: parens not needed aroundx.as_ptr()
. Might be clearer to write asmap_or(ptr::null(), CStr16::as_ptr)
.
uefi/src/proto/shell/mod.rs Outdated
/// # Errors | ||
/// | ||
/// * `Status::EFI_NOT_FOUND` - The directory does not exist | ||
pub fn set_cur_dir(&self, file_system: Option<&CStr16>, directory: Option<&CStr16>) -> Status { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
set_current_dir
to matchstd
uefi/src/proto/shell/mod.rs Outdated
/// # Returns | ||
/// | ||
/// * `Status::SUCCESS` - The variable was successfully set | ||
pub fn set_env(&self, name: &CStr16, value: &CStr16, volatile: bool) -> Status { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Here and on other methods, returnResult
(https://docs.rs/uefi/latest/uefi/type.Result.html) instead of a rawStatus
. This is more convenient for users since it works with?
.
uefi/src/proto/shell/mod.rs Outdated
/// # Returns | ||
/// | ||
/// * `Status::SUCCESS` - The variable was successfully set | ||
pub fn set_env(&self, name: &CStr16, value: &CStr16, volatile: bool) -> Status { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
set_var
to matchstd
Some(CStr16::from_ptr(cur_start)) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think the implementation could be simplified, something like this:
fnnext(&mutself) ->Option<Self::Item>{let s =unsafe{CStr16::from_ptr(self.inner)};if s.is_empty(){None}else{self.inner =unsafe{self.inner.add(s.num_chars() +1)};Some(s)}}
8e808c2
to3e9bff8
CompareThank you for the feedback. I'm starting to understand the goal of abstracting the lower level implementation in ways that are useful for the user and will do my best to keep this in mind for future pull requests! I've addressed the function call names and return values. For returning As for changing |
Perfect! Thanks for your patience and valuable contributions :)
Yes, perfectly fine, and also done in other parts of the code base
Yes, that's fine. So far, we didn't have a clear guidline. IMHO, Now, IMHO, the guideline is: prevent |
In this case, would be it be okay to simply store the vector of values as one of the fields of pubstructVars<'a>{/// Char16 containing names of environment variablesnames:*constChar16,/// Vec containing values of environment variablesvalues:Vec::<Option<&'aCStr16>>,/// Current position in veccur_pos:usize,/// Placeholder to attach a lifetime to `Vars`placeholder:PhantomData<&'aCStr16>,} |
nicholasbishop commentedJul 13, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Ideally we wouldn't store a |
I see your point on storing |
Could Vars store a reference to the protocol, and call get_env in the next function to get each variable value one at a time? |
That's quite a clever approach! I've written an initial implementation and did not find any issues. I will push it shortly so we can review it. |
fd136bb
to7542291
Compare
This PR will implement the wrappers for EFI Shell Protocol functions to address#448 . This PR does branch off of the changes made in#596 so big thanks to@timrobertsdev for laying the groundwork!
Currently, I've implemented wrappers and wrote tests for
GetEnv()
,SetEnv()
,GetCurDir()
andSetCurDir()
. My plan is to first write tests for and finish implementingExecute()
,CloseFile()
,CreateFile()
,FindFiles()
,FindFilesInDir()
, andGetFileSize()
since they have already been started. Then I can implement the rest in either this PR or subsequent follow up PRs (whichever is preferable).I do have some questions about my
get_env()
implementation. UEFI'sGetEnv()
returns the value of a variable if its name is specified. However if its name is not specified, it returns all known variable names in a*const Char16
where the names are delimited by aNULL
and the end of the list is terminated by a doubleNULL
.My initial approach was to parse the
*const Char16
into aVec
in this case. I wrapped the return value in an Enum that can be unpacked into a single&CStr16
or into a vector of&CStr16
s depending on which is expected. Is this approach okay? I was concerned that if I simply returned a&CStr16
in the "name list" case that the true size of the string wouldn't be visible since the names are separated byNULL
. Also, is it okay for me to usealloc::vec::Vec
? I saw that a lot of other protocols don't use anyVec
at all so I'm not clear on if there are some restrictions for doing so.Checklist