Skip to content

std: sys: process: uefi: Use NULL stdin by default #139517

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

Merged
merged 3 commits into from
Apr 15, 2025
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
119 changes: 114 additions & 5 deletions library/std/src/sys/process/uefi.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use r_efi::protocols::simple_text_output;
use r_efi::protocols::{simple_text_input, simple_text_output};

use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
Expand All @@ -23,6 +23,7 @@ pub struct Command {
args: Vec<OsString>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
stdin: Option<Stdio>,
env: CommandEnv,
}

Expand All @@ -48,6 +49,7 @@ impl Command {
args: Vec::new(),
stdout: None,
stderr: None,
stdin: None,
env: Default::default(),
}
}
Expand All @@ -64,8 +66,8 @@ impl Command {
panic!("unsupported")
}

pub fn stdin(&mut self, _stdin: Stdio) {
panic!("unsupported")
pub fn stdin(&mut self, stdin: Stdio) {
self.stdin = Some(stdin);
}

pub fn stdout(&mut self, stdout: Stdio) {
Expand Down Expand Up @@ -122,6 +124,22 @@ impl Command {
}
}

fn create_stdin(
s: Stdio,
) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
match s {
Stdio::Null => unsafe {
helpers::OwnedProtocol::create(
uefi_command_internal::InputProtocol::null(),
simple_text_input::PROTOCOL_GUID,
)
}
.map(Some),
Stdio::Inherit => Ok(None),
Stdio::MakePipe => unsupported(),
}
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;

Expand Down Expand Up @@ -149,6 +167,15 @@ impl Command {
cmd.stderr_inherit()
};

// Setup Stdin
let stdin = self.stdin.unwrap_or(Stdio::Null);
let stdin = Self::create_stdin(stdin)?;
if let Some(con) = stdin {
cmd.stdin_init(con)
} else {
cmd.stdin_inherit()
};

let env = env_changes(&self.env);

// Set any new vars
Expand Down Expand Up @@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> {

#[allow(dead_code)]
mod uefi_command_internal {
use r_efi::protocols::{loaded_image, simple_text_output};
use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};

use crate::ffi::{OsStr, OsString};
use crate::io::{self, const_error};
Expand All @@ -350,6 +377,7 @@ mod uefi_command_internal {
handle: NonNull<crate::ffi::c_void>,
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
st: OwnedTable<r_efi::efi::SystemTable>,
args: Option<(*mut u16, usize)>,
}
Expand Down Expand Up @@ -384,7 +412,14 @@ mod uefi_command_internal {
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });

Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
Ok(Self {
handle: child_handle,
stdout: None,
stderr: None,
stdin: None,
st,
args: None,
})
}
}

Expand Down Expand Up @@ -445,6 +480,17 @@ mod uefi_command_internal {
}
}

fn set_stdin(
&mut self,
handle: r_efi::efi::Handle,
protocol: *mut simple_text_input::Protocol,
) {
unsafe {
(*self.st.as_mut_ptr()).console_in_handle = handle;
(*self.st.as_mut_ptr()).con_in = protocol;
}
}

pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
self.set_stdout(
protocol.handle().as_ptr(),
Expand All @@ -471,6 +517,19 @@ mod uefi_command_internal {
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
}

pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
self.set_stdin(
protocol.handle().as_ptr(),
protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
);
self.stdin = Some(protocol);
}

pub(crate) fn stdin_inherit(&mut self) {
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
}

pub fn stderr(&self) -> io::Result<Vec<u8>> {
match &self.stderr {
Some(stderr) => stderr.as_ref().utf8(),
Expand Down Expand Up @@ -722,6 +781,56 @@ mod uefi_command_internal {
}
}

#[repr(C)]
pub(crate) struct InputProtocol {
reset: simple_text_input::ProtocolReset,
read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
wait_for_key: r_efi::efi::Event,
}

impl InputProtocol {
pub(crate) fn null() -> Self {
let evt = helpers::OwnedEvent::new(
r_efi::efi::EVT_NOTIFY_WAIT,
r_efi::efi::TPL_CALLBACK,
Some(Self::empty_notify),
None,
)
.unwrap();

Self {
reset: Self::null_reset,
read_key_stroke: Self::null_read_key,
wait_for_key: evt.into_raw(),
}
}

extern "efiapi" fn null_reset(
_: *mut simple_text_input::Protocol,
_: r_efi::efi::Boolean,
) -> r_efi::efi::Status {
r_efi::efi::Status::SUCCESS
}

extern "efiapi" fn null_read_key(
_: *mut simple_text_input::Protocol,
_: *mut simple_text_input::InputKey,
) -> r_efi::efi::Status {
r_efi::efi::Status::UNSUPPORTED
}

extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
}

impl Drop for InputProtocol {
fn drop(&mut self) {
// Close wait_for_key
unsafe {
let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
}
}
}

pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
const QUOTE: u16 = 0x0022;
const SPACE: u16 = 0x0020;
Expand Down
8 changes: 6 additions & 2 deletions library/std/src/sys/stdio/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,12 @@ impl io::Write for Stderr {
// UTF-16 character should occupy 4 bytes at most in UTF-8
pub const STDIN_BUF_SIZE: usize = 4;

pub fn is_ebadf(_err: &io::Error) -> bool {
false
pub fn is_ebadf(err: &io::Error) -> bool {
if let Some(x) = err.raw_os_error() {
r_efi::efi::Status::UNSUPPORTED.as_usize() == x
} else {
false
}
}

pub fn panic_output() -> Option<impl io::Write> {
Expand Down
Loading