mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rebase to master
- Update Example - Add thread_parking to sys::uefi - Fix unsafe in unsafe errors - Improve docs - Improve os/exit - Some asserts - Switch back to atomics Signed-off-by: Ayush Singh <ayushdevel1325@gmail.com>
This commit is contained in:
parent
40c3dacc76
commit
c7e5f3ca08
@ -421,7 +421,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
entry_type: EntryFnType,
|
||||
) -> Bx::Function {
|
||||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
|
||||
// `Status efi_main(Handle hd, SystemTable *st)` depending on the target.
|
||||
// `usize efi_main(void *handle, void *system_table)` depending on the target.
|
||||
let llfty = if cx.sess().target.os.contains("uefi") {
|
||||
cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
|
||||
} else if cx.sess().target.main_needs_argc_argv {
|
||||
@ -508,10 +508,9 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
let param_handle = bx.get_param(0);
|
||||
let param_system_table = bx.get_param(1);
|
||||
let arg_argc = bx.const_int(cx.type_isize(), 2);
|
||||
let arg_argv = bx.alloca(cx.type_array(cx.type_i8p(), 2), Align::ONE);
|
||||
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), Align::ONE);
|
||||
bx.store(param_handle, arg_argv, Align::ONE);
|
||||
let arg_argv_el1 =
|
||||
bx.gep(cx.type_ptr_to(cx.type_i8()), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
|
||||
let arg_argv_el1 = bx.gep(cx.type_ptr(), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
|
||||
bx.store(param_system_table, arg_argv_el1, Align::ONE);
|
||||
(arg_argc, arg_argv)
|
||||
} else if cx.sess().target.main_needs_argc_argv {
|
||||
@ -566,11 +565,7 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
|
||||
});
|
||||
if any_dynamic_crate {
|
||||
None
|
||||
} else {
|
||||
tcx.allocator_kind(())
|
||||
}
|
||||
if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
|
||||
}
|
||||
|
||||
pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||
|
@ -44,7 +44,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
|
||||
}
|
||||
} else if #[cfg(any(target_os = "hermit",
|
||||
all(target_vendor = "fortanix", target_env = "sgx"),
|
||||
target_os = "xous"
|
||||
target_os = "xous",
|
||||
target_os = "uefi",
|
||||
))] {
|
||||
unsafe fn abort() -> ! {
|
||||
|
@ -52,7 +52,6 @@ fn main() {
|
||||
// - mipsel-sony-psp
|
||||
// - nvptx64-nvidia-cuda
|
||||
// - arch=avr
|
||||
// - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
|
||||
// - JSON targets
|
||||
// - Any new targets that have not been explicitly added above.
|
||||
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
|
||||
|
@ -263,6 +263,7 @@
|
||||
#![cfg_attr(target_os = "xous", feature(slice_ptr_len))]
|
||||
//
|
||||
// Language features:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(allow_internal_unsafe)]
|
||||
|
@ -142,7 +142,6 @@ pub mod solid;
|
||||
#[cfg(target_os = "tvos")]
|
||||
#[path = "ios/mod.rs"]
|
||||
pub(crate) mod tvos;
|
||||
#[cfg(target_os = "uefi")]
|
||||
#[cfg(any(target_os = "uefi", doc))]
|
||||
pub mod uefi;
|
||||
#[cfg(target_os = "vita")]
|
||||
|
@ -2,23 +2,22 @@
|
||||
|
||||
#![unstable(feature = "uefi_std", issue = "100499")]
|
||||
|
||||
use crate::{cell::Cell, ffi::c_void, ptr::NonNull};
|
||||
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
||||
use crate::{ffi::c_void, ptr::NonNull};
|
||||
|
||||
// Since UEFI is single-threaded, making the global variables thread local should be safe.
|
||||
thread_local! {
|
||||
// Flag to check if BootServices are still valid.
|
||||
// Start with assuming that they are not available
|
||||
static BOOT_SERVICES_FLAG: Cell<bool> = Cell::new(false);
|
||||
// Position 0 = SystemTable
|
||||
// Position 1 = ImageHandle
|
||||
static GLOBALS: Cell<Option<(NonNull<c_void>, NonNull<c_void>)>> = Cell::new(None);
|
||||
}
|
||||
static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
|
||||
static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
|
||||
// Flag to check if BootServices are still valid.
|
||||
// Start with assuming that they are not available
|
||||
static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Initializes the global System Table and Image Handle pointers.
|
||||
///
|
||||
/// The standard library requires access to the UEFI System Table and the Application Image Handle
|
||||
/// to operate. Those are provided to UEFI Applications via their application entry point. By
|
||||
/// calling `init_globals()`, those pointers are retained by the standard library for future use.
|
||||
/// Thus this function must be called before any of the standard library services are used.
|
||||
///
|
||||
/// The pointers are never exposed to any entity outside of this application and it is guaranteed
|
||||
/// that, once the application exited, these pointers are never dereferenced again.
|
||||
///
|
||||
@ -26,9 +25,26 @@ thread_local! {
|
||||
/// application. In particular, UEFI Boot Services must not be exited while an application with the
|
||||
/// standard library is loaded.
|
||||
///
|
||||
/// This function must not be called more than once.
|
||||
pub unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
|
||||
GLOBALS.set(Some((system_table, handle)));
|
||||
/// # SAFETY
|
||||
/// Calling this function more than once will panic
|
||||
pub(crate) unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
|
||||
IMAGE_HANDLE
|
||||
.compare_exchange(
|
||||
crate::ptr::null_mut(),
|
||||
handle.as_ptr(),
|
||||
Ordering::Release,
|
||||
Ordering::Acquire,
|
||||
)
|
||||
.unwrap();
|
||||
SYSTEM_TABLE
|
||||
.compare_exchange(
|
||||
crate::ptr::null_mut(),
|
||||
system_table.as_ptr(),
|
||||
Ordering::Release,
|
||||
Ordering::Acquire,
|
||||
)
|
||||
.unwrap();
|
||||
BOOT_SERVICES_FLAG.store(true, Ordering::Release)
|
||||
}
|
||||
|
||||
/// Get the SystemTable Pointer.
|
||||
@ -50,7 +66,7 @@ pub fn image_handle() -> NonNull<c_void> {
|
||||
/// Get the BootServices Pointer.
|
||||
/// This function also checks if `ExitBootServices` has already been called.
|
||||
pub fn boot_services() -> Option<NonNull<c_void>> {
|
||||
if BOOT_SERVICES_FLAG.get() {
|
||||
if BOOT_SERVICES_FLAG.load(Ordering::Acquire) {
|
||||
let system_table: NonNull<r_efi::efi::SystemTable> = try_system_table()?.cast();
|
||||
let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
|
||||
NonNull::new(boot_services).map(|x| x.cast())
|
||||
@ -62,19 +78,15 @@ pub fn boot_services() -> Option<NonNull<c_void>> {
|
||||
/// Get the SystemTable Pointer.
|
||||
/// This function is mostly intended for places where panic is not an option
|
||||
pub(crate) fn try_system_table() -> Option<NonNull<c_void>> {
|
||||
GLOBALS.get().map(|x| x.0)
|
||||
NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
/// Get the SystemHandle Pointer.
|
||||
/// This function is mostly intended for places where panicking is not an option
|
||||
pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> {
|
||||
GLOBALS.get().map(|x| x.1)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_boot_services() {
|
||||
BOOT_SERVICES_FLAG.set(true);
|
||||
NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
pub(crate) fn disable_boot_services() {
|
||||
BOOT_SERVICES_FLAG.set(false);
|
||||
BOOT_SERVICES_FLAG.store(false, Ordering::Release)
|
||||
}
|
||||
|
@ -60,13 +60,14 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
|
||||
}
|
||||
|
||||
// The returned buf_len is in bytes
|
||||
let mut buf: Vec<r_efi::efi::Handle> =
|
||||
Vec::with_capacity(buf_len / size_of::<r_efi::efi::Handle>());
|
||||
assert_eq!(buf_len % size_of::<r_efi::efi::Handle>(), 0);
|
||||
let num_of_handles = buf_len / size_of::<r_efi::efi::Handle>();
|
||||
let mut buf: Vec<r_efi::efi::Handle> = Vec::with_capacity(num_of_handles);
|
||||
match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) {
|
||||
Ok(()) => {
|
||||
// This is safe because the call will succeed only if buf_len >= required length.
|
||||
// Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written
|
||||
unsafe { buf.set_len(buf_len / size_of::<r_efi::efi::Handle>()) };
|
||||
unsafe { buf.set_len(num_of_handles) };
|
||||
Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
@ -114,16 +115,15 @@ pub(crate) fn create_event(
|
||||
) -> io::Result<NonNull<crate::ffi::c_void>> {
|
||||
let boot_services: NonNull<efi::BootServices> =
|
||||
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
|
||||
let mut exit_boot_service_event: r_efi::efi::Event = crate::ptr::null_mut();
|
||||
let mut event: r_efi::efi::Event = crate::ptr::null_mut();
|
||||
let r = unsafe {
|
||||
let create_event = (*boot_services.as_ptr()).create_event;
|
||||
(create_event)(signal, tpl, handler, context, &mut exit_boot_service_event)
|
||||
(create_event)(signal, tpl, handler, context, &mut event)
|
||||
};
|
||||
if r.is_error() {
|
||||
Err(crate::io::Error::from_raw_os_error(r.as_usize()))
|
||||
} else {
|
||||
NonNull::new(exit_boot_service_event)
|
||||
.ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
|
||||
NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
//! [`OsStr`]: crate::ffi::OsStr
|
||||
//! [`OsString`]: crate::ffi::OsString
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
pub mod alloc;
|
||||
#[path = "../unsupported/args.rs"]
|
||||
pub mod args;
|
||||
@ -43,6 +42,8 @@ pub mod stdio;
|
||||
pub mod thread;
|
||||
#[path = "../unsupported/thread_local_key.rs"]
|
||||
pub mod thread_local_key;
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
@ -53,18 +54,17 @@ mod tests;
|
||||
|
||||
pub type RawOsError = usize;
|
||||
|
||||
use crate::cell::Cell;
|
||||
use crate::io as std_io;
|
||||
use crate::os::uefi;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
pub mod memchr {
|
||||
pub use core::slice::memchr::{memchr, memrchr};
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static EXIT_BOOT_SERVICE_EVENT: Cell<Option<NonNull<crate::ffi::c_void>>> = Cell::new(None);
|
||||
}
|
||||
static EXIT_BOOT_SERVICE_EVENT: AtomicPtr<crate::ffi::c_void> =
|
||||
AtomicPtr::new(crate::ptr::null_mut());
|
||||
|
||||
/// # SAFETY
|
||||
/// - must be called only once during runtime initialization.
|
||||
@ -75,8 +75,6 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
|
||||
let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() };
|
||||
let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() };
|
||||
unsafe { uefi::env::init_globals(image_handle, system_table) };
|
||||
// Enable boot services once GLOBALS are initialized
|
||||
uefi::env::enable_boot_services();
|
||||
|
||||
// Register exit boot services handler
|
||||
match helpers::create_event(
|
||||
@ -86,7 +84,17 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
|
||||
crate::ptr::null_mut(),
|
||||
) {
|
||||
Ok(x) => {
|
||||
EXIT_BOOT_SERVICE_EVENT.set(Some(x));
|
||||
if EXIT_BOOT_SERVICE_EVENT
|
||||
.compare_exchange(
|
||||
crate::ptr::null_mut(),
|
||||
x.as_ptr(),
|
||||
Ordering::Release,
|
||||
Ordering::Acquire,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
abort_internal();
|
||||
};
|
||||
}
|
||||
Err(_) => abort_internal(),
|
||||
}
|
||||
@ -96,7 +104,9 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
|
||||
/// this is not guaranteed to run, for example when the program aborts.
|
||||
/// - must be called only once during runtime cleanup.
|
||||
pub unsafe fn cleanup() {
|
||||
if let Some(exit_boot_service_event) = EXIT_BOOT_SERVICE_EVENT.take() {
|
||||
if let Some(exit_boot_service_event) =
|
||||
NonNull::new(EXIT_BOOT_SERVICE_EVENT.swap(crate::ptr::null_mut(), Ordering::Acquire))
|
||||
{
|
||||
let _ = unsafe { helpers::close_event(exit_boot_service_event) };
|
||||
}
|
||||
}
|
||||
@ -159,7 +169,9 @@ pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind {
|
||||
}
|
||||
|
||||
pub fn abort_internal() -> ! {
|
||||
if let Some(exit_boot_service_event) = EXIT_BOOT_SERVICE_EVENT.take() {
|
||||
if let Some(exit_boot_service_event) =
|
||||
NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire))
|
||||
{
|
||||
let _ = unsafe { helpers::close_event(exit_boot_service_event) };
|
||||
}
|
||||
|
||||
@ -226,3 +238,7 @@ fn get_random() -> Option<(u64, u64)> {
|
||||
extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) {
|
||||
uefi::env::disable_boot_services();
|
||||
}
|
||||
|
||||
pub fn is_interrupted(_code: RawOsError) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -4,15 +4,16 @@ use crate::ffi::{OsStr, OsString};
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::os::uefi;
|
||||
use crate::path::{self, PathBuf};
|
||||
use crate::ptr::NonNull;
|
||||
use r_efi::efi::Status;
|
||||
|
||||
pub fn errno() -> RawOsError {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn error_string(errno: RawOsError) -> String {
|
||||
use r_efi::efi::Status;
|
||||
|
||||
// Keep the List in Alphabetical Order
|
||||
// The Messages are taken from UEFI Specification Appendix D - Status Codes
|
||||
match r_efi::efi::Status::from_usize(errno) {
|
||||
@ -160,12 +161,7 @@ impl fmt::Display for JoinPathsError {
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for JoinPathsError {
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
"not supported on this platform yet"
|
||||
}
|
||||
}
|
||||
impl StdError for JoinPathsError {}
|
||||
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
unsupported()
|
||||
@ -173,6 +169,14 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
||||
|
||||
pub struct Env(!);
|
||||
|
||||
impl Env {
|
||||
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
|
||||
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
|
||||
let Self(inner) = self;
|
||||
match *inner {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Env {
|
||||
type Item = (OsString, OsString);
|
||||
fn next(&mut self) -> Option<(OsString, OsString)> {
|
||||
@ -180,6 +184,13 @@ impl Iterator for Env {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Env {
|
||||
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self(inner) = self;
|
||||
match *inner {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env() -> Env {
|
||||
panic!("not supported on this platform")
|
||||
}
|
||||
@ -204,7 +215,20 @@ pub fn home_dir() -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn exit(_code: i32) -> ! {
|
||||
pub fn exit(code: i32) -> ! {
|
||||
if let (Some(boot_services), Some(handle)) =
|
||||
(uefi::env::boot_services(), uefi::env::try_image_handle())
|
||||
{
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
|
||||
let _ = unsafe {
|
||||
((*boot_services.as_ptr()).exit)(
|
||||
handle.as_ptr(),
|
||||
Status::from_usize(code as usize),
|
||||
0,
|
||||
crate::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
}
|
||||
crate::intrinsics::abort()
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,9 @@ cargo +custom build --target x86_64-unknown-uefi
|
||||
```
|
||||
|
||||
```rust,ignore (platform-specific)
|
||||
use r_efi::efi;
|
||||
#![feature(uefi_std)]
|
||||
|
||||
use r_efi::{efi, protocols::simple_text_output};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
os::uefi::{env, ffi::OsStrExt}
|
||||
@ -290,7 +292,7 @@ pub fn main() {
|
||||
let r =
|
||||
unsafe {
|
||||
let con_out: *mut simple_text_output::Protocol = (*st).con_out;
|
||||
let output_string: extern "efiapi" fn(_: *mut simple_text_output::Protocol, *mut u16) = (*con_out).output_string;
|
||||
let output_string: extern "efiapi" fn(_: *mut simple_text_output::Protocol, *mut u16) -> efi::Status = (*con_out).output_string;
|
||||
output_string(con_out, s.as_ptr() as *mut efi::Char16)
|
||||
};
|
||||
assert!(!r.is_error())
|
||||
@ -298,6 +300,6 @@ pub fn main() {
|
||||
```
|
||||
|
||||
### BootServices
|
||||
The current implementation of std make `BootServices` unavailable once `ExitBootServices` is called. Refer to [Runtime Drivers](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/7_driver_entry_point/711_runtime_drivers) for more information regarding how to handle switching from using physical addresses to using virtual addresses.
|
||||
The current implementation of std makes `BootServices` unavailable once `ExitBootServices` is called. Refer to [Runtime Drivers](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/7_driver_entry_point/711_runtime_drivers) for more information regarding how to handle switching from using physical addresses to using virtual addresses.
|
||||
|
||||
Note: It should be noted that it is upto the user to drop all allocated memory before `ExitBootServices` is called.
|
||||
Note: It should be noted that it is up to the user to drop all allocated memory before `ExitBootServices` is called.
|
||||
|
Loading…
Reference in New Issue
Block a user