Skip to content
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

Add Rust std support for x86_64-unknown-uefi #100316

Closed
wants to merge 60 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
f872477
Add UEFI module in std/sys
Ayush1325 Jun 15, 2022
2be029d
Improve Handling of Pointers
Ayush1325 Jul 2, 2022
ff55531
Add OsStringExt and OsStrExt traits
Ayush1325 Jul 3, 2022
b988418
Graceful abort
Ayush1325 Jul 4, 2022
2800931
Re-export r-efi in std::os::uefi::raw
Ayush1325 Jul 5, 2022
868e3e1
Implement args
Ayush1325 Jul 7, 2022
6769cb5
Implement SystemTime
Ayush1325 Jul 8, 2022
a14d62e
Implment fs
Ayush1325 Jul 10, 2022
289c445
Implement TCP
Ayush1325 Jul 16, 2022
645647d
Add UEFI support for running tests
Ayush1325 Jul 18, 2022
3e891b3
Implement Environment Variables
Ayush1325 Jul 20, 2022
5689d37
Implement append for files
Ayush1325 Jul 23, 2022
372f6e1
Allow Running remote-test-server for UEFI
Ayush1325 Jul 23, 2022
65849ae
Remove r_efi reexports from std
Ayush1325 Jul 25, 2022
ebc5ca2
Various fixes
Ayush1325 Jul 25, 2022
d5e78bf
Add vectored read/write for TcpStream
Ayush1325 Jul 26, 2022
368ab5a
Overhaul File I/O
Ayush1325 Jul 27, 2022
ce43ad6
Fix/Ignore tests
Ayush1325 Jul 27, 2022
72641b8
Implement more of fs
Ayush1325 Jul 29, 2022
95e8f68
Improve TCP
Ayush1325 Jul 30, 2022
aa980a6
Rebase to latest master
Ayush1325 Aug 2, 2022
3d9a83b
Add UEFI Std docs
Ayush1325 Aug 5, 2022
767650c
Refactor UCS-2 stuff
Ayush1325 Aug 6, 2022
4f32221
Improve process
Ayush1325 Aug 7, 2022
0bb8203
Add x86_64-uefi ci
Ayush1325 Aug 9, 2022
e85df7a
Add nothread and staticlink for remote-test-server
Ayush1325 Aug 9, 2022
1f52c23
Fix some tidy errors
Ayush1325 Aug 9, 2022
d84c8e3
Fixes from PR
Ayush1325 Aug 9, 2022
3bf5104
Update compiler_builtins
Ayush1325 Aug 10, 2022
176361a
Improve Envirnoment Variables
Ayush1325 Aug 11, 2022
88c615c
Implement hashmap_random_keys()
Ayush1325 Aug 11, 2022
8cd315c
Improve UEFI sys documentation
Ayush1325 Aug 13, 2022
4bc53e3
Fixes from PR
Ayush1325 Aug 13, 2022
c257c00
Initial implementation of Instant using TSC
Ayush1325 Aug 18, 2022
7262c22
Overhaul Dealing with UEFI ZSTs
Ayush1325 Aug 19, 2022
36c628f
Refactor `std::os::uefi`
Ayush1325 Aug 19, 2022
73852ec
Inline more functions
Ayush1325 Aug 19, 2022
d610cde
Implement `std::fs::File::set_times`
Ayush1325 Aug 20, 2022
3702334
Improve Environment variables
Ayush1325 Aug 22, 2022
c4320c1
Fix CI for x86_64-uefi
Ayush1325 Aug 23, 2022
944bf59
Update r-efi
Ayush1325 Aug 23, 2022
c83cbd2
Improve sys::process
Ayush1325 Aug 26, 2022
a95933b
Fix Env vars
Ayush1325 Aug 27, 2022
3df71e6
Apply fixes suggested in PR
Ayush1325 Aug 28, 2022
545899b
Improve Pipe Protocol
Ayush1325 Sep 13, 2022
945049c
Revert formatting changes to tests
Ayush1325 Sep 14, 2022
1baa38f
Rebase on master
Ayush1325 Sep 19, 2022
a9c1bb8
Implement io for UEFI
Ayush1325 Sep 19, 2022
939e11e
Improve std::uefi::env APIs
Ayush1325 Sep 19, 2022
67329ff
Fixes from PR
Ayush1325 Sep 20, 2022
2345867
Improve handling of Globals
Ayush1325 Oct 2, 2022
d343822
Improve UEFI fs
Ayush1325 Oct 2, 2022
dae6b19
Remove ignore-uefi from tests
Ayush1325 Oct 2, 2022
195633a
Improve TCP
Ayush1325 Oct 5, 2022
4f7ff72
Fixes from PR
Ayush1325 Oct 5, 2022
77283ae
Use compiler generated entry point for UEFI
Ayush1325 Oct 6, 2022
f89fceb
Fixes after rebase
Ayush1325 Oct 14, 2022
000228b
Implement UEFI argument parsing
Ayush1325 Dec 1, 2022
d48d07d
Use r-efi-alloc for allocator
Ayush1325 Dec 6, 2022
824f067
Fixes suggested in PR
Ayush1325 Dec 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2943,6 +2943,27 @@ dependencies = [
"proc-macro2",
]

[[package]]
name = "r-efi"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e7345c622833c6745e7b027a28aa95618813dc1f3c3de396206410267dce6f3"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]

[[package]]
name = "r-efi-alloc"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
dependencies = [
"compiler_builtins",
"r-efi",
"rustc-std-workspace-core",
]

[[package]]
name = "rand"
version = "0.7.3"
Expand Down Expand Up @@ -4898,6 +4919,8 @@ dependencies = [
"panic_abort",
"panic_unwind",
"profiler_builtins",
"r-efi",
"r-efi-alloc",
"rand 0.7.3",
"rustc-demangle",
"std_detect",
Expand Down
25 changes: 21 additions & 4 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
) -> 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 {

let llfty = if cx.sess().target.os.contains("uefi") {
cx.type_func(&[cx.type_i8p(), cx.type_i8p()], cx.type_isize())
} else if cx.sess().target.main_needs_argc_argv {
cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
} else {
cx.type_func(&[], cx.type_int())
Expand Down Expand Up @@ -499,8 +502,12 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
};

let result = bx.call(start_ty, 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
}
Expand All @@ -511,7 +518,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") {
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);
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)]);
bx.store(param_system_table, arg_argv_el1, Align::ONE);
(arg_argc, arg_argv)
} 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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/uefi_msvc_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub fn opts() -> TargetOptions {
stack_probes: StackProbeType::Call,
singlethread: true,
linker: Some("rust-lld".into()),
entry_name: "efi_main".into(),
..base
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.

use crate::spec::Target;
use crate::{abi::call::Conv, spec::Target};

pub fn target() -> Target {
let mut base = super::uefi_msvc_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
base.entry_abi = Conv::X86_64Win64;

// We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
// enable these CPU features explicitly before their first use, otherwise their instructions
Expand Down
1 change: 1 addition & 0 deletions library/panic_abort/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
libc::abort();
}
} else if #[cfg(any(target_os = "hermit",
target_os = "uefi",
all(target_vendor = "fortanix", target_env = "sgx")
))] {
unsafe fn abort() -> ! {
Expand Down
4 changes: 4 additions & 0 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }

[target.'cfg(target_os = "uefi")'.dependencies]
r-efi = { version = "4.1.0", features = ['rustc-dep-of-std', 'efiapi']}
r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std']}

[features]
backtrace = [
"gimli-symbolize",
Expand Down
2 changes: 1 addition & 1 deletion library/std/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ fn main() {
|| target.contains("espidf")
|| target.contains("solid")
|| target.contains("nintendo-3ds")
|| target.contains("uefi")
{
// These platforms don't have any special requirements.
} else {
Expand All @@ -42,7 +43,6 @@ fn main() {
// - nvptx64-nvidia-cuda
// - arch=avr
// - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
// - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
// - JSON targets
// - Any new targets that have not been explicitly added above.
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
)]
//
// Language features:
#![feature(abi_efiapi)]
#![feature(alloc_error_handler)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ pub mod redox;
pub mod solaris;
#[cfg(target_os = "solid_asp3")]
pub mod solid;
#[cfg(target_os = "uefi")]
pub mod uefi;
Ayush1325 marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_os = "vxworks")]
pub mod vxworks;
#[cfg(target_os = "watchos")]
Expand Down
57 changes: 57 additions & 0 deletions library/std/src/os/uefi/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! UEFI-specific extensions to the primitives in `std::env` module

use crate::ffi::c_void;
use crate::ptr::NonNull;
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::sync::Once;

static GLOBAL_SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
static GLOBAL_IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
pub(crate) static GLOBALS: Once = Once::new();
Comment on lines +8 to +10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using OnceLock here leads to cleaner code IMHO.

Suggested change
static GLOBAL_SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
static GLOBAL_IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
pub(crate) static GLOBALS: Once = Once::new();
pub(crate) static GLOBALS: OnceLock<(NonNull<c_void>, NonNull<c_void>)> = OnceLock::new();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'm not sure if using NonNull instead of AtomicPtr is correct here. It is technically possible for some other driver to change the underlying System Table and thus atomic operations seem to make more sense to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I catch your meaning here? NonNull does not mandate that the underlying data stays constant, so it should be fine to use even if that situation arises.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was referring to the AtomicPtr::load() operation since there will be multiple pointers to SystemTable floating around even in Rust code simultaneously.


/// 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.
/// 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.
///
/// This function must not be called more than once.
#[unstable(feature = "uefi_std", issue = "100499")]
pub unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
GLOBALS.call_once(|| {
GLOBAL_SYSTEM_TABLE.store(system_table.as_ptr(), Ordering::Release);
GLOBAL_IMAGE_HANDLE.store(handle.as_ptr(), Ordering::Release);
})
}

/// Get the SystemTable Pointer.
/// Note: This function panics if the System Table and Image Handle is Not initialized
#[unstable(feature = "uefi_std", issue = "100499")]
pub fn system_table() -> NonNull<c_void> {
try_system_table().unwrap()
}

/// Get the SystemHandle Pointer.
/// Note: This function panics if the System Table and Image Handle is Not initialized
#[unstable(feature = "uefi_std", issue = "100499")]
pub fn image_handle() -> NonNull<c_void> {
try_image_handle().unwrap()
}

/// 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<crate::ffi::c_void>> {
NonNull::new(GLOBAL_SYSTEM_TABLE.load(Ordering::Acquire))
}

/// Get the SystemHandle Pointer.
/// This function is mostly intended for places where panic is not an option
pub(crate) fn try_image_handle() -> Option<NonNull<crate::ffi::c_void>> {
NonNull::new(GLOBAL_IMAGE_HANDLE.load(Ordering::Acquire))
}
7 changes: 7 additions & 0 deletions library/std/src/os/uefi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! Platform-specific extensions to `std` for UEFI.

#![unstable(feature = "uefi_std", issue = "100499")]

pub mod env;
#[path = "../windows/ffi.rs"]
pub mod ffi;
3 changes: 3 additions & 0 deletions library/std/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ cfg_if::cfg_if! {
} else if #[cfg(target_family = "wasm")] {
mod wasm;
pub use self::wasm::*;
} else if #[cfg(target_os = "uefi")] {
mod uefi;
pub use self::uefi::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
Expand Down
34 changes: 34 additions & 0 deletions library/std/src/sys/uefi/alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Global Allocator for UEFI.
//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)

use crate::alloc::{handle_alloc_error, GlobalAlloc, Layout, System};

pub(crate) const POOL_ALIGNMENT: usize = 8;

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 {
let system_table = match crate::os::uefi::env::try_system_table() {
None => return crate::ptr::null_mut(),
Some(x) => x.as_ptr() as *mut _,
};

if layout.size() > 0 {
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
} else {
layout.dangling().as_ptr()
}
}

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let system_table = match crate::os::uefi::env::try_system_table() {
None => handle_alloc_error(layout),
Some(x) => x.as_ptr() as *mut _,
};
if layout.size() > 0 {
unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
}
}
}
Loading