Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ShellParams protocol #772

Merged
merged 3 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Added `core::error::Error` implementations to all error types.
- `SystemTable::exit_boot_services` now takes one param `memory_type` to ensure
the memory type of memory map.
- Added the `ShellParams` protocol

### Removed
- `BootServices::memmove` and `BootServices::set_mem` have been removed, use
Expand Down
1 change: 1 addition & 0 deletions uefi-raw/src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ pub mod driver;
pub mod loaded_image;
pub mod memory_protection;
pub mod rng;
pub mod shell_params;
23 changes: 23 additions & 0 deletions uefi-raw/src/protocol/shell_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::{guid, Char16, Guid};
use core::ffi::c_void;

pub type ShellFileHandle = *const c_void;

#[derive(Debug)]
#[repr(C)]
pub struct ShellParametersProtocol {
/// Pointer to a list of arguments.
pub argv: *const *const Char16,
/// Number of arguments.
pub argc: usize,
/// Handle of the standard input.
pub std_in: ShellFileHandle,
/// Handle of the standard output.
pub std_out: ShellFileHandle,
/// Handle of the standard error output.
pub std_err: ShellFileHandle,
}

impl ShellParametersProtocol {
pub const GUID: Guid = guid!("752f3136-4e16-4fdc-a22a-e5f46812f4ca");
}
53 changes: 53 additions & 0 deletions uefi-test-runner/examples/shell_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// ANCHOR: all
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ANCHOR comments are just used by mdbook (see https://rust-osdev.github.io/uefi-rs/HEAD/how_to/protocols.html#walkthrough for example), so unless you are looking to add this example to the book, you can leave these out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to have a shell application example in the book.
However it would be more useful once the shell protocol is merged.

// ANCHOR: features
#![no_main]
#![no_std]
// ANCHOR_END: features

use log::error;
// ANCHOR: use
use uefi::{prelude::*, proto::shell_params::ShellParameters};
use uefi_services::println;

extern crate alloc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
// ANCHOR_END: use

// ANCHOR: entry
#[entry]
fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
// ANCHOR_END: entry
// ANCHOR: services
uefi_services::init(&mut system_table).unwrap();
let boot_services = system_table.boot_services();
// ANCHOR_END: services

// ANCHOR: params
let shell_params =
boot_services.open_protocol_exclusive::<ShellParameters>(image_handle);
let shell_params = match shell_params {
Ok(s) => s,
Err(e) => {
error!("Failed to get ShellParameters protocol");
return e.status();
}
};

// Get as Vec of String, only with alloc feature
let args: Vec<String> =
shell_params.args().map(|x| x.to_string()).collect();
println!("Args: {:?}", args);

// Or without allocating, get a slice of the pointers
println!("Num args: {}", args.len());
if shell_params.args_len() > 1 {
println!("First real arg: '{}'", args[1]);
}
// ANCHOR_END: params

// ANCHOR: return
Status::SUCCESS
}
// ANCHOR_END: return
// ANCHOR_END: all
2 changes: 1 addition & 1 deletion uefi-test-runner/src/bin/shell_launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn efi_main(image: Handle, mut st: SystemTable<Boot>) -> Status {
let mut shell_loaded_image = boot_services
.open_protocol_exclusive::<LoadedImage>(shell_image_handle)
.expect("failed to open LoadedImage protocol");
let load_options = cstr16!(r"shell.efi test_runner.efi");
let load_options = cstr16!(r"shell.efi test_runner.efi arg1 arg2");
unsafe {
shell_loaded_image.set_load_options(
load_options.as_ptr().cast(),
Expand Down
2 changes: 2 additions & 0 deletions uefi-test-runner/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
network::test(bt);
pi::test(bt);
rng::test(bt);
shell_params::test(bt);
string::test(bt);

#[cfg(any(
Expand Down Expand Up @@ -63,6 +64,7 @@ mod media;
mod network;
mod pi;
mod rng;
mod shell_params;
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
Expand Down
25 changes: 25 additions & 0 deletions uefi-test-runner/src/proto/shell_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use uefi::proto::shell_params::ShellParameters;
use uefi::table::boot::BootServices;

use alloc::string::ToString;
use alloc::vec::Vec;

pub fn test(bt: &BootServices) {
info!("Running loaded image protocol test");

let image = bt
.get_handle_for_protocol::<ShellParameters>()
.expect("No ShellParameters handles");
let shell_params = bt
.open_protocol_exclusive::<ShellParameters>(image)
.expect("Failed to open ShellParameters protocol");

assert_eq!(shell_params.args_len(), 4);
assert_eq!(
shell_params
.args()
.map(|x| x.to_string())
.collect::<Vec<_>>(),
&["shell.efi", "test_runner.efi", "arg1", "arg2"]
);
}
1 change: 1 addition & 0 deletions uefi/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub mod network;
pub mod pi;
pub mod rng;
pub mod security;
pub mod shell_params;
pub mod shim;
pub mod string;
pub mod tcg;
40 changes: 40 additions & 0 deletions uefi/src/proto/shell_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! `ShellParams` protocol

use crate::proto::unsafe_protocol;
use crate::{data_types, Char16};
use core::slice::from_raw_parts;
use uefi_raw::protocol::shell_params::ShellParametersProtocol;

use crate::CStr16;

/// The ShellParameters protocol.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(ShellParametersProtocol::GUID)]
pub struct ShellParameters(ShellParametersProtocol);

impl ShellParameters {
/// Get the number of shell parameter arguments
#[must_use]
pub fn args_len(&self) -> usize {
self.0.argc
}

/// Get an iterator of the shell parameter arguments
pub fn args(&self) -> impl Iterator<Item = &CStr16> {
self.args_slice()
.iter()
.map(|x| unsafe { CStr16::from_ptr(*x) })
}

/// Get a slice of the args, as Char16 pointers
#[must_use]
fn args_slice(&self) -> &[*const Char16] {
unsafe {
from_raw_parts(
self.0.argv.cast::<*const data_types::chars::Char16>(),
self.0.argc,
)
}
}
}