Skip to content

Commit 77283ae

Browse files
committed
Use compiler generated entry point for UEFI
Generate Entry function (`efi_main`) in compiler (similar to how C main is generated for other targets). This function passes `[image_handle, system_table]` as argv to Rust lang_start. Then initialize the global variables from `sys::init` Signed-off-by: Ayush Singh <[email protected]>
1 parent 4f7ff72 commit 77283ae

File tree

8 files changed

+42
-29
lines changed

8 files changed

+42
-29
lines changed

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
432432
) -> Bx::Function {
433433
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
434434
// depending on whether the target needs `argc` and `argv` to be passed in.
435-
let llfty = if cx.sess().target.main_needs_argc_argv {
435+
436+
let llfty = if cx.sess().target.os.contains("uefi") {
437+
cx.type_func(&[cx.type_i8p(), cx.type_i8p()], cx.type_isize())
438+
} else if cx.sess().target.main_needs_argc_argv {
436439
cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
437440
} else {
438441
cx.type_func(&[], cx.type_int())
@@ -499,8 +502,12 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
499502
};
500503

501504
let result = bx.call(start_ty, None, start_fn, &args, None);
502-
let cast = bx.intcast(result, cx.type_int(), true);
503-
bx.ret(cast);
505+
if cx.sess().target.os.contains("uefi") {
506+
bx.ret(result);
507+
} else {
508+
let cast = bx.intcast(result, cx.type_int(), true);
509+
bx.ret(cast);
510+
}
504511

505512
llfn
506513
}
@@ -511,7 +518,17 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
511518
cx: &'a Bx::CodegenCx,
512519
bx: &mut Bx,
513520
) -> (Bx::Value, Bx::Value) {
514-
if cx.sess().target.main_needs_argc_argv {
521+
if cx.sess().target.os.contains("uefi") {
522+
let param_handle = bx.get_param(0);
523+
let param_system_table = bx.get_param(1);
524+
let arg_argc = bx.const_int(cx.type_isize(), 2);
525+
let arg_argv = bx.array_alloca(cx.type_i8p(), bx.const_int(cx.type_int(), 2), Align::ONE);
526+
bx.store(param_handle, arg_argv, Align::ONE);
527+
let arg_argv_el1 =
528+
bx.gep(cx.type_ptr_to(cx.type_i8()), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
529+
bx.store(param_system_table, arg_argv_el1, Align::ONE);
530+
(arg_argc, arg_argv)
531+
} else if cx.sess().target.main_needs_argc_argv {
515532
// Params from native `main()` used as args for rust start function
516533
let param_argc = bx.get_param(0);
517534
let param_argv = bx.get_param(1);

compiler/rustc_target/src/spec/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,12 @@ pub struct TargetOptions {
16481648
/// `argc` and `argv` values.
16491649
pub main_needs_argc_argv: bool,
16501650

1651+
// The name of entry function.
1652+
pub entry_name: StaticCow<str>,
1653+
1654+
// The ABI of entry function.
1655+
pub entry_abi: Conv,
1656+
16511657
/// Flag indicating whether #[thread_local] is available for this target.
16521658
pub has_thread_local: bool,
16531659
/// This is mainly for easy compatibility with emscripten.

compiler/rustc_target/src/spec/uefi_msvc_base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub fn opts() -> TargetOptions {
4646
stack_probes: StackProbeType::Call,
4747
singlethread: true,
4848
linker: Some("rust-lld".into()),
49+
entry_name: "efi_main".into(),
4950
..base
5051
}
5152
}

compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
66
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
77

8-
use crate::spec::Target;
8+
use crate::{abi::call::Conv, spec::Target};
99

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

1516
// We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
1617
// enable these CPU features explicitly before their first use, otherwise their instructions

library/std/src/sys/uefi/mod.rs

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ pub mod memchr {
4848
pub use core::slice::memchr::{memchr, memrchr};
4949
}
5050

51-
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
51+
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
52+
assert_eq!(argc, 2);
53+
let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() };
54+
let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() };
55+
unsafe { crate::os::uefi::env::init_globals(image_handle, system_table) };
56+
}
5257

5358
// SAFETY: must be called only once during runtime cleanup.
5459
// NOTE: this is not guaranteed to run, for example when the program aborts.
@@ -133,26 +138,3 @@ unsafe fn get_random() -> Option<u64> {
133138
}
134139
None
135140
}
136-
137-
// FIXME: Do not generate this in case of `no_main`
138-
#[no_mangle]
139-
pub unsafe extern "efiapi" fn efi_main(
140-
handle: r_efi::efi::Handle,
141-
st: *mut r_efi::efi::SystemTable,
142-
) -> r_efi::efi::Status {
143-
extern "C" {
144-
fn main(argc: isize, argv: *const *const u8) -> isize;
145-
}
146-
147-
let (system_table, image_handle) = match (NonNull::new(st), NonNull::new(handle)) {
148-
(Some(x), Some(y)) => (x, y),
149-
_ => return r_efi::efi::Status::ABORTED,
150-
};
151-
unsafe { uefi::env::init_globals(image_handle, system_table.cast()) };
152-
153-
let res = unsafe { main(0, crate::ptr::null()) };
154-
match usize::try_from(res) {
155-
Ok(x) => r_efi::efi::Status::from_usize(x),
156-
Err(_) => r_efi::efi::Status::ABORTED,
157-
}
158-
}

src/test/ui/format-no-std.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// run-pass
22
// ignore-emscripten no no_std executables
3+
// ignore-uefi allocation and other std functionality is intialized in `sys::init`. This test
4+
// causes CPU Exception.
35

46
#![feature(lang_items, start)]
57
#![no_std]

src/test/ui/runtime/native-print-no-runtime.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// run-pass
2+
// ignore-uefi allocation and other std functionality is intialized in `sys::init`. This test
3+
// causes CPU Exception.
24

35
#![feature(start)]
46

src/test/ui/runtime/running-with-no-runtime.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// run-pass
22
// ignore-emscripten spawning processes is not supported
33
// ignore-sgx no processes
4+
// ignore-uefi allocation and other std functionality is intialized in `sys::init`. This test
5+
// causes CPU Exception.
46
// revisions: mir thir
57
// [thir]compile-flags: -Zthir-unsafeck
68

0 commit comments

Comments
 (0)