Skip to content

Commit daf2a03

Browse files
authored
Rollup merge of #56769 - dvdhrm:uefi-target, r=alexcrichton
Add x86_64-unknown-uefi target This adds a new rustc target-configuration called 'x86_64-unknown_uefi'. Furthermore, it adds a UEFI base-configuration to be used with other targets supported by UEFI (e.g., i386, armv7hl, aarch64, itanium, ...). UEFI systems provide a very basic operating-system environment, meant to unify how systems are booted. It is tailored for simplicity and fast setup, as it is only meant to bootstrap other systems. For instance, it copies most of the ABI from Microsoft Windows, rather than inventing anything on its own. Furthermore, any complex CPU features are disabled. Only one CPU is allowed to be up, no interrupts other than the timer-interrupt are allowed, no process-separation is performed, page-tables are identity-mapped, ... Nevertheless, UEFI has an application model. Its main purpose is to allow operating-system vendors to write small UEFI applications that load their kernel and terminate the UEFI system. However, many other UEFI applications have emerged in the past, including network-boot, debug-consoles, and more. This UEFI target allows to compile rust code natively as UEFI applications. No standard library support is added, but libcore can be used out-of-the-box if a panic-handler is provided. Furthermore, liballoc works as well, if a `GlobalAlloc` handler is provided. Both have been tested with this target-configuration. Note that full libstd support is unlikely to happen. While UEFI does have standardized interfaces for networking and alike, none of these are mandatory and they are unlikely to be shipped in common consumer firmwares. Furthermore, several features like process-separation are not available (or only in very limited fashion). Those parts of libstd would have to be masked.
2 parents 65e7fe7 + 88cf2a2 commit daf2a03

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

src/librustc_target/spec/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ mod linux_musl_base;
6868
mod openbsd_base;
6969
mod netbsd_base;
7070
mod solaris_base;
71+
mod uefi_base;
7172
mod windows_base;
7273
mod windows_msvc_base;
7374
mod thumb_base;
@@ -419,6 +420,8 @@ supported_targets! {
419420
("aarch64-unknown-none", aarch64_unknown_none),
420421

421422
("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
423+
424+
("x86_64-unknown-uefi", x86_64_unknown_uefi),
422425
}
423426

424427
/// Everything `rustc` knows about how to compile for a specific target.

src/librustc_target/spec/uefi_base.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This defines a base target-configuration for native UEFI systems. The UEFI specification has
12+
// quite detailed sections on the ABI of all the supported target architectures. In almost all
13+
// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
14+
// documentation.
15+
// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
16+
// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
17+
// by the loader if the pre-chosen memory location is already in use.
18+
// UEFI forbids running code on anything but the boot-CPU. Not interrupts are allowed other than
19+
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
20+
// code runs in the same environment, no process separation is supported.
21+
22+
use spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
23+
use std::default::Default;
24+
25+
pub fn opts() -> TargetOptions {
26+
let mut pre_link_args = LinkArgs::new();
27+
28+
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), vec![
29+
// Suppress the verbose logo and authorship debugging output, which would needlessly
30+
// clog any log files.
31+
"/NOLOGO".to_string(),
32+
33+
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
34+
// non-code sections can be marked as non-executable, including stack pages.
35+
"/NXCOMPAT".to_string(),
36+
37+
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
38+
// must be freestanding.
39+
"/nodefaultlib".to_string(),
40+
41+
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
42+
// one. "efi_main" seems to be a common choice amongst other implementations and the
43+
// spec.
44+
"/entry:efi_main".to_string(),
45+
46+
// COFF images have a "Subsystem" field in their header, which defines what kind of
47+
// program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
48+
// EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
49+
// which is very likely the most common option. Individual projects can override this
50+
// with custom linker flags.
51+
// The subsystem-type only has minor effects on the application. It defines the memory
52+
// regions the application is loaded into (runtime-drivers need to be put into
53+
// reserved areas), as well as whether a return from the entry-point is treated as
54+
// exit (default for applications).
55+
"/subsystem:efi_application".to_string(),
56+
]);
57+
58+
TargetOptions {
59+
dynamic_linking: false,
60+
executables: true,
61+
disable_redzone: true,
62+
exe_suffix: ".efi".to_string(),
63+
allows_weak_linkage: false,
64+
panic_strategy: PanicStrategy::Abort,
65+
singlethread: true,
66+
emit_debug_gdb_scripts: false,
67+
68+
linker: Some("lld-link".to_string()),
69+
lld_flavor: LldFlavor::Link,
70+
pre_link_args,
71+
72+
.. Default::default()
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This defines the amd64 target for UEFI systems as described in the UEFI specification. See the
12+
// uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec)
13+
// UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a
14+
// single-CPU execution.
15+
// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
16+
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
17+
18+
use spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
19+
20+
pub fn target() -> TargetResult {
21+
let mut base = super::uefi_base::opts();
22+
base.cpu = "x86-64".to_string();
23+
base.max_atomic_width = Some(64);
24+
25+
// We disable MMX and SSE for now. UEFI does not prevent these from being used, but there have
26+
// been reports to GRUB that some firmware does not initialize the FP exception handlers
27+
// properly. Therefore, using FP coprocessors will end you up at random memory locations when
28+
// you throw FP exceptions.
29+
// To be safe, we disable them for now and force soft-float. This can be revisited when we
30+
// have more test coverage. Disabling FP served GRUB well so far, so it should be good for us
31+
// as well.
32+
base.features = "-mmx,-sse,+soft-float".to_string();
33+
34+
// UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
35+
// LLVM to expect code to reference any address in the address-space. The "large" code-model
36+
// places no locality-restrictions, so it fits well here.
37+
base.code_model = Some("large".to_string());
38+
39+
// UEFI mostly mirrors the calling-conventions used on windows. In case of x86-64 this means
40+
// small structs will be returned as int. This shouldn't matter much, since the restrictions
41+
// placed by the UEFI specifications forbid any ABI to return structures.
42+
base.abi_return_struct_as_int = true;
43+
44+
Ok(Target {
45+
llvm_target: "x86_64-unknown-windows".to_string(),
46+
target_endian: "little".to_string(),
47+
target_pointer_width: "64".to_string(),
48+
target_c_int_width: "32".to_string(),
49+
data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
50+
target_os: "uefi".to_string(),
51+
target_env: "".to_string(),
52+
target_vendor: "unknown".to_string(),
53+
arch: "x86_64".to_string(),
54+
linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
55+
56+
options: base,
57+
})
58+
}

0 commit comments

Comments
 (0)