Skip to content

Commit

Permalink
Merge pull request #772 from FrameworkComputer/shell-params
Browse files Browse the repository at this point in the history
Add ShellParams protocol
  • Loading branch information
nicholasbishop authored Sep 11, 2023
2 parents f845933 + 2c9185b commit eb33785
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 1 deletion.
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
// 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,
)
}
}
}

0 comments on commit eb33785

Please sign in to comment.