mirror of https://github.com/rust-lang/rust.git
uefi: Add process
Signed-off-by: Ayush Singh <ayushdevel1325@gmail.com>
This commit is contained in:
parent
3d68afc9e8
commit
a8d7121e4a
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue