Skip to content

Commit 05cfcb5

Browse files
authored
Rollup merge of #58420 - dvdhrm:target-uefi-comments, r=nagisa
target/uefi: clarify documentation This clarifies why FP-units are disabled on UEFI targets, as well as why we must opt into the NXCOMPAT feature. I did find some time to investigate why GRUB and friends disable FP on UEFI. The specification explicitly allows using MMX/SSE/AVX, but as it turns out it does not mandate enabling the instruction sets explicitly. Hence, any use of these instructions will trigger CPU exceptions, unless an application explicitly enables them (which is not an option, as these are global flags that better be controlled by the kernel/firmware). Furthermore, UEFI systems are allowed to mark any non-code page as non-executable. Hence, we must make sure to never place code on the stack or heap. So we better pass /NXCOMPAT to the linker for it to complain if it ever places code in non-code pages. Lastly, this fixes some typos in related comments. r? @alexcrichton
2 parents 0178f31 + 15e4bd3 commit 05cfcb5

File tree

2 files changed

+17
-12
lines changed

2 files changed

+17
-12
lines changed

src/librustc_target/spec/uefi_base.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
66
// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
77
// by the loader if the pre-chosen memory location is already in use.
8-
// UEFI forbids running code on anything but the boot-CPU. Not interrupts are allowed other than
8+
// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
99
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
1010
// code runs in the same environment, no process separation is supported.
1111

@@ -21,7 +21,10 @@ pub fn opts() -> TargetOptions {
2121
"/NOLOGO".to_string(),
2222

2323
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
24-
// non-code sections can be marked as non-executable, including stack pages.
24+
// non-code sections can be marked as non-executable, including stack pages. In fact,
25+
// firmware might enforce this, so we better let the linker know about this, so it
26+
// will fail if the compiler ever tries placing code on the stack (e.g., trampoline
27+
// constructs and alike).
2528
"/NXCOMPAT".to_string(),
2629

2730
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets

src/librustc_target/spec/x86_64_unknown_uefi.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,25 @@ pub fn target() -> TargetResult {
1212
base.cpu = "x86-64".to_string();
1313
base.max_atomic_width = Some(64);
1414

15-
// We disable MMX and SSE for now. UEFI does not prevent these from being used, but there have
16-
// been reports to GRUB that some firmware does not initialize the FP exception handlers
17-
// properly. Therefore, using FP coprocessors will end you up at random memory locations when
18-
// you throw FP exceptions.
19-
// To be safe, we disable them for now and force soft-float. This can be revisited when we
20-
// have more test coverage. Disabling FP served GRUB well so far, so it should be good for us
21-
// as well.
15+
// We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
16+
// enable these CPU features explicitly before their first use, otherwise their instructions
17+
// will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE
18+
// instruction sets, so this must be done by the firmware. However, existing firmware is known
19+
// to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
20+
// why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
21+
// far.
22+
// If you initialize FP units yourself, you can override these flags with custom linker
23+
// arguments, thus giving you access to full MMX/SSE acceleration.
2224
base.features = "-mmx,-sse,+soft-float".to_string();
2325

2426
// UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
2527
// LLVM to expect code to reference any address in the address-space. The "large" code-model
2628
// places no locality-restrictions, so it fits well here.
2729
base.code_model = Some("large".to_string());
2830

29-
// UEFI mostly mirrors the calling-conventions used on windows. In case of x86-64 this means
30-
// small structs will be returned as int. This shouldn't matter much, since the restrictions
31-
// placed by the UEFI specifications forbid any ABI to return structures.
31+
// UEFI mirrors the calling-conventions used on windows. In case of x86-64 this means small
32+
// structs will be returned as int. This shouldn't matter much, since the restrictions placed
33+
// by the UEFI specifications forbid any ABI to return structures.
3234
base.abi_return_struct_as_int = true;
3335

3436
Ok(Target {

0 commit comments

Comments
 (0)