about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAyush Singh <ayushdevel1325@gmail.com>2024-03-27 01:07:39 +0530
committerAyush Singh <ayush@beagleboard.org>2024-07-19 17:43:37 +0530
commita8d7121e4a02764962c85e29168bebed2116b392 (patch)
treeb3d8b73ee03d25c600c1308b4280e2da63af7ce2
parent3d68afc9e821b00d59058abc9bda670b07639955 (diff)
downloadrust-a8d7121e4a02764962c85e29168bebed2116b392.tar.gz
rust-a8d7121e4a02764962c85e29168bebed2116b392.zip
uefi: Add process
Signed-off-by: Ayush Singh <ayushdevel1325@gmail.com>
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs72
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/process.rs328
3 files changed, 399 insertions, 2 deletions
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 23aa4da14a7..97dd90716bb 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -12,7 +12,7 @@
 use r_efi::efi::{self, Guid};
 use r_efi::protocols::{device_path, device_path_to_text};
 
-use crate::ffi::OsString;
+use crate::ffi::{OsString, OsStr};
 use crate::io::{self, const_io_error};
 use crate::mem::{size_of, MaybeUninit};
 use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
@@ -221,3 +221,73 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
     let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services };
     NonNull::new(runtime_services)
 }
+
+pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
+
+impl DevicePath {
+    pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
+        fn inner(
+            p: &OsStr,
+            protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
+        ) -> io::Result<DevicePath> {
+            let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
+            let path =
+                unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
+
+            NonNull::new(path).map(DevicePath).ok_or_else(|| {
+                const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")
+            })
+        }
+
+        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+            AtomicPtr::new(crate::ptr::null_mut());
+
+        if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
+            if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
+                handle,
+                r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
+            ) {
+                return inner(p, protocol);
+            }
+        }
+
+        let handles = locate_handles(r_efi::protocols::device_path_from_text::PROTOCOL_GUID)?;
+        for handle in handles {
+            if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
+                handle,
+                r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
+            ) {
+                LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
+                return inner(p, protocol);
+            }
+        }
+
+        io::Result::Err(const_io_error!(
+            io::ErrorKind::NotFound,
+            "DevicePathFromText Protocol not found"
+        ))
+    }
+}
+
+impl AsRef<r_efi::protocols::device_path::Protocol> for DevicePath {
+    fn as_ref(&self) -> &r_efi::protocols::device_path::Protocol {
+        unsafe { self.0.as_ref() }
+    }
+}
+
+impl AsMut<r_efi::protocols::device_path::Protocol> for DevicePath {
+    fn as_mut(&mut self) -> &mut r_efi::protocols::device_path::Protocol {
+        unsafe { self.0.as_mut() }
+    }
+}
+
+impl Drop for DevicePath {
+    fn drop(&mut self) {
+        if let Some(bt) = boot_services() {
+            let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
+            unsafe {
+                ((*bt.as_ptr()).free_pool)(self.0.as_ptr() as *mut crate::ffi::c_void);
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 4d50d9e8c3d..c54e9477bfc 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -25,7 +25,6 @@ pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
 pub mod process;
 pub mod stdio;
 pub mod thread;
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
new file mode 100644
index 00000000000..e85fc209c0e
--- /dev/null
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -0,0 +1,328 @@
+use crate::ffi::OsStr;
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::num::NonZero;
+use crate::num::NonZeroI32;
+use crate::path::Path;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::unsupported;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
+
+pub use crate::ffi::OsString as EnvKey;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    prog: OsString,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+// FIXME: This should be a unit struct, so we can always construct it
+// The value here should be never used, since we cannot spawn processes.
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        Command { prog: program.to_os_string() }
+    }
+
+    pub fn arg(&mut self, _arg: &OsStr) {
+        panic!("unsupported")
+    }
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
+        panic!("unsupported")
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {
+        panic!("unsupported")
+    }
+
+    pub fn stdin(&mut self, _stdin: Stdio) {
+        panic!("unsupported")
+    }
+
+    pub fn stdout(&mut self, _stdout: Stdio) {
+        panic!("unsupported")
+    }
+
+    pub fn stderr(&mut self, _stderr: Stdio) {
+        panic!("unsupported")
+    }
+
+    pub fn get_program(&self) -> &OsStr {
+        panic!("unsupported")
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        panic!("unsupported")
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        panic!("unsupported")
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        None
+    }
+
+    pub fn spawn(
+        &mut self,
+        _default: Stdio,
+        _needs_stdin: bool,
+    ) -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let cmd = uefi_command_internal::Command::load_image(&self.prog)?;
+        let stat = cmd.start_image()?;
+        Ok((ExitStatus(stat), Vec::new(), Vec::new()))
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(_file: File) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Ok(())
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[non_exhaustive]
+pub struct ExitStatus(r_efi::efi::Status);
+
+impl ExitStatus {
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        if self.0 == r_efi::efi::Status::SUCCESS { Ok(()) } else { Err(ExitStatusError(self.0)) }
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        Some(self.0.as_usize() as i32)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let err_str = super::os::error_string(self.0.as_usize());
+        write!(f, "{}", err_str)
+    }
+}
+
+impl Default for ExitStatus {
+    fn default() -> Self {
+        ExitStatus(r_efi::efi::Status::SUCCESS)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct ExitStatusError(r_efi::efi::Status);
+
+impl fmt::Debug for ExitStatusError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let err_str = super::os::error_string(self.0.as_usize());
+        write!(f, "{}", err_str)
+    }
+}
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0)
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZero<i32>> {
+        NonZeroI32::new(self.0.as_usize() as i32)
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        match code {
+            0 => Self::SUCCESS,
+            1..=255 => Self::FAILURE,
+        }
+    }
+}
+
+pub struct Process(!);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        self.0
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        self.0
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        self.0
+    }
+}
+
+pub struct CommandArgs<'a> {
+    _p: PhantomData<&'a ()>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        None
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl<'a> ExactSizeIterator for CommandArgs<'a> {}
+
+impl<'a> fmt::Debug for CommandArgs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().finish()
+    }
+}
+
+mod uefi_command_internal {
+    use super::super::helpers;
+    use crate::ffi::OsStr;
+    use crate::io::{self, const_io_error};
+    use crate::mem::MaybeUninit;
+    use crate::os::uefi::env::{boot_services, image_handle};
+    use crate::ptr::NonNull;
+
+    pub struct Command {
+        handle: NonNull<crate::ffi::c_void>,
+    }
+
+    impl Command {
+        const fn new(handle: NonNull<crate::ffi::c_void>) -> Self {
+            Self { handle }
+        }
+
+        pub fn load_image(p: &OsStr) -> io::Result<Self> {
+            let mut path = helpers::DevicePath::from_text(p)?;
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
+                .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
+                .cast();
+            let mut child_handle: MaybeUninit<r_efi::efi::Handle> = MaybeUninit::uninit();
+            let image_handle = image_handle();
+
+            let r = unsafe {
+                ((*boot_services.as_ptr()).load_image)(
+                    r_efi::efi::Boolean::FALSE,
+                    image_handle.as_ptr(),
+                    path.as_mut(),
+                    crate::ptr::null_mut(),
+                    0,
+                    child_handle.as_mut_ptr(),
+                )
+            };
+
+            if r.is_error() {
+                Err(io::Error::from_raw_os_error(r.as_usize()))
+            } else {
+                let child_handle = unsafe { child_handle.assume_init() };
+                let child_handle = NonNull::new(child_handle).unwrap();
+                Ok(Self::new(child_handle))
+            }
+        }
+
+        pub fn start_image(&self) -> io::Result<r_efi::efi::Status> {
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
+                .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
+                .cast();
+            let mut exit_data_size: MaybeUninit<usize> = MaybeUninit::uninit();
+            let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit();
+
+            let r = unsafe {
+                ((*boot_services.as_ptr()).start_image)(
+                    self.handle.as_ptr(),
+                    exit_data_size.as_mut_ptr(),
+                    exit_data.as_mut_ptr(),
+                )
+            };
+
+            // Drop exitdata
+            unsafe {
+                exit_data_size.assume_init_drop();
+                exit_data.assume_init_drop();
+            }
+
+            Ok(r)
+        }
+    }
+
+    impl Drop for Command {
+        fn drop(&mut self) {
+            if let Some(bt) = boot_services() {
+                let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
+                unsafe {
+                    ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
+                }
+            }
+        }
+    }
+}