-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Add Minimal Std implementation for UEFI #105861
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
Changes from all commits
48c6ae0
8e56b33
032e376
5df24d1
7a95644
40c3dac
c7e5f3c
984ecef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -420,9 +420,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |
rust_main_def_id: DefId, | ||
entry_type: EntryFnType, | ||
) -> Bx::Function { | ||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, | ||
// depending on whether the target needs `argc` and `argv` to be passed in. | ||
let llfty = if cx.sess().target.main_needs_argc_argv { | ||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or | ||
// `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 { | ||
cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int()) | ||
} else { | ||
cx.type_func(&[], cx.type_int()) | ||
|
@@ -485,8 +487,12 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |
}; | ||
|
||
let result = bx.call(start_ty, None, None, start_fn, &args, None); | ||
let cast = bx.intcast(result, cx.type_int(), true); | ||
bx.ret(cast); | ||
if cx.sess().target.os.contains("uefi") { | ||
bx.ret(result); | ||
} else { | ||
let cast = bx.intcast(result, cx.type_int(), true); | ||
bx.ret(cast); | ||
} | ||
|
||
llfn | ||
} | ||
|
@@ -497,7 +503,17 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |
cx: &'a Bx::CodegenCx, | ||
bx: &mut Bx, | ||
) -> (Bx::Value, Bx::Value) { | ||
if cx.sess().target.main_needs_argc_argv { | ||
if cx.sess().target.os.contains("uefi") { | ||
// Params for UEFI | ||
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_ptr(), 2), Align::ONE); | ||
bx.store(param_handle, arg_argv, Align::ONE); | ||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned before, you stuff random pointers into argc/argv of There is no way we can stabilize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you clarify what the concern is here, exactly? Are we worrying about conflicting with someone else trying to use argc and argv, basically? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there is an inherent conflict. But we would effectively make it impossible to use Arguments passed to the individual startup routines differ strongly across platforms. Up until now There is some discussion in the tracking issue of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe complicating the use of an unstable feature which is, as you noted, fairly "stuck", is undesirable but not unexpected. I do not believe a slightly hacky implementation on this count is sufficient reason to bar this PR, although it ought to come with an appropriately huge |
||
} else if cx.sess().target.main_needs_argc_argv { | ||
// Params from native `main()` used as args for rust start function | ||
let param_argc = bx.get_param(0); | ||
let param_argv = bx.get_param(1); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
//! UEFI-specific extensions to the primitives in `std::env` module | ||
|
||
#![unstable(feature = "uefi_std", issue = "100499")] | ||
|
||
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; | ||
use crate::{ffi::c_void, ptr::NonNull}; | ||
|
||
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. | ||
/// | ||
/// Callers are required to ensure the pointers are valid for the entire lifetime of this | ||
/// application. In particular, UEFI Boot Services must not be exited while an application with the | ||
/// standard library is loaded. | ||
/// | ||
/// # 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) | ||
} | ||
Ayush1325 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Get the SystemTable Pointer. | ||
/// If you want to use `BootServices` then please use [`boot_services`] as it performs some | ||
/// additional checks. | ||
/// | ||
/// Note: This function panics if the System Table or Image Handle is not initialized | ||
pub fn system_table() -> NonNull<c_void> { | ||
try_system_table().unwrap() | ||
} | ||
|
||
/// Get the ImageHandle Pointer. | ||
/// | ||
/// Note: This function panics if the System Table or Image Handle is not initialized | ||
pub fn image_handle() -> NonNull<c_void> { | ||
try_image_handle().unwrap() | ||
} | ||
|
||
/// 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.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()) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
/// 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>> { | ||
NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire)) | ||
} | ||
|
||
/// Get the SystemHandle Pointer. | ||
Ayush1325 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// This function is mostly intended for places where panicking is not an option | ||
pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> { | ||
NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire)) | ||
} | ||
|
||
pub(crate) fn disable_boot_services() { | ||
BOOT_SERVICES_FLAG.store(false, Ordering::Release) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//! Platform-specific extensions to `std` for UEFI. | ||
|
||
#![unstable(feature = "uefi_std", issue = "100499")] | ||
#![doc(cfg(target_os = "uefi"))] | ||
|
||
pub mod env; | ||
#[path = "../windows/ffi.rs"] | ||
pub mod ffi; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//! Global Allocator for UEFI. | ||
//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc) | ||
|
||
use crate::alloc::{GlobalAlloc, Layout, System}; | ||
|
||
const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA; | ||
|
||
#[stable(feature = "alloc_system_type", since = "1.28.0")] | ||
unsafe impl GlobalAlloc for System { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
// Return null pointer if boot services are not available | ||
if crate::os::uefi::env::boot_services().is_none() { | ||
return crate::ptr::null_mut(); | ||
} | ||
|
||
// If boot services is valid then SystemTable is not null. | ||
let system_table = crate::os::uefi::env::system_table().as_ptr().cast(); | ||
// The caller must ensure non-0 layout | ||
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) } | ||
workingjubilee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | ||
// Do nothing if boot services are not available | ||
if crate::os::uefi::env::boot_services().is_none() { | ||
return; | ||
} | ||
|
||
// If boot services is valid then SystemTable is not null. | ||
let system_table = crate::os::uefi::env::system_table().as_ptr().cast(); | ||
// The caller must ensure non-0 layout | ||
unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
pub mod os { | ||
pub const FAMILY: &str = ""; | ||
pub const OS: &str = "uefi"; | ||
pub const DLL_PREFIX: &str = ""; | ||
pub const DLL_SUFFIX: &str = ""; | ||
pub const DLL_EXTENSION: &str = ""; | ||
pub const EXE_SUFFIX: &str = ".efi"; | ||
pub const EXE_EXTENSION: &str = "efi"; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.