about summary refs log tree commit diff
path: root/library/std/src/sys/process/uefi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/process/uefi.rs')
-rw-r--r--library/std/src/sys/process/uefi.rs119
1 files changed, 114 insertions, 5 deletions
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index b46418ae9bb..5f922292d05 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -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;
@@ -23,6 +23,7 @@ pub struct Command {
     args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    stdin: Option<Stdio>,
     env: CommandEnv,
 }
 
@@ -48,6 +49,7 @@ impl Command {
             args: Vec::new(),
             stdout: None,
             stderr: None,
+            stdin: None,
             env: Default::default(),
         }
     }
@@ -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) {
@@ -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)?;
 
@@ -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
@@ -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};
@@ -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)>,
     }
@@ -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,
+                })
             }
         }
 
@@ -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(),
@@ -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(),
@@ -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;