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 x86_64-unknown-uefi target #56769

Merged
merged 1 commit into from Dec 15, 2018

Conversation

Projects
None yet
10 participants
@dvdhrm
Copy link
Contributor

dvdhrm commented Dec 13, 2018

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.

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.
@rust-highfive

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Dec 13, 2018

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @cramertj (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@cramertj

This comment has been minimized.

Copy link
Member

cramertj commented Dec 13, 2018

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 13, 2018

Thanks for this! My only hesitation would be that this defaults to link.exe for a linker, but that means this target would largely only work on Windows I think? That seems like a plausible place to start, but I imagine that we'd want to compile for this target on systems like Linux as well, right?

@IsaacWoods

This comment has been minimized.

Copy link
Contributor

IsaacWoods commented Dec 13, 2018

@alexcrichton I believe this uses lld-link as the linker if I'm not mistaken, which is available from Linux as well and is able to compile UEFI compatible PEs

@dvdhrm

This comment has been minimized.

Copy link
Contributor Author

dvdhrm commented Dec 13, 2018

Thanks for this! My only hesitation would be that this defaults to link.exe for a linker, but that means this target would largely only work on Windows I think? That seems like a plausible place to start, but I imagine that we'd want to compile for this target on systems like Linux as well, right?

Ah, no, it doesn't default to link.exe. It defaults to the link backend of lld, which on linux, defaults to lld-link, not link.exe. I tested this on my linux machine and it works fine. This is a bit confusing, because lld has 2 backends, one for ELF (called lld-ld) and one for COFF (called lld-link), named after their respective native counterparts.

Thing is, you need a COFF/PE32+ linker for UEFI targets. So if you run this on linux, it is as if you cross-compile for Windows (UEFI and windows targets are almost the same). Since lld-link is a built-in of lld, it is a perfect default linker.
An alternative to lld would be to use GNU ld. But ld has the problem that each binary only supports one target triple. So to link COFF/PE32+ binaries, you need an ld cross-toolchain for windows (usually known as mingw-for-linux), which is only partially available in most mainstream distributions.
I personally admire the LLVM-lld approach of combining all target compilers/linkers in a single binary. And since LLVM is already available for rustc, I thought lld-link as default linker sounds good.

Long story short: The lld-link link-flavor just selects the COFF backend of lld as default linker.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 13, 2018

@bors: r+

Oh wow sorry about that, I completely missed that aspect! Glad LLD can save the day again for us here :)

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 13, 2018

📌 Commit 88cf2a2 has been approved by alexcrichton

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 13, 2018

@bors: rollup

kennytm added a commit to kennytm/rust that referenced this pull request Dec 14, 2018

Rollup merge of rust-lang#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.

bors added a commit that referenced this pull request Dec 14, 2018

Auto merge of #56803 - kennytm:rollup, r=kennytm
Rollup of 36 pull requests

Successful merges:

 - #56203 (Add lint for items deprecated in future)
 - #56343 (Remove not used mod)
 - #56439 (Clearer error message for dead assign)
 - #56490 (Add checked_add method to Instant time type)
 - #56507 (polonius tweaks)
 - #56562 (Update libc version required by rustc)
 - #56600 (bootstrap: fix edition)
 - #56609 (Unconditionally emit the target-cpu LLVM attribute.)
 - #56658 (Add non-panicking `maybe_new_parser_from_file` variant)
 - #56672 (Document time of back operations of a Linked List)
 - #56677 (#[must_use] on traits in stdlib)
 - #56679 (overhaul external doc attribute diagnostics)
 - #56691 (fix install broken link)
 - #56695 (Fix irrefutable matches on integer ranges)
 - #56699 (Use a `newtype_index!` within `Symbol`.)
 - #56702 ([self-profiler] Add column for percent of total time)
 - #56708 (Remove some unnecessary feature gates)
 - #56709 (Remove unneeded extra chars to reduce search-index size)
 - #56710 (Always set the RDRAND and RDSEED features on SGX)
 - #56713 (Test capacity of ZST vector)
 - #56718 (Use libbacktrace pretty-printing)
 - #56725 (fix rust-lang/rust issue #50583)
 - #56731 (Add missing urls in ffi module docs)
 - #56738 (Fix private_no_mangle_fns message grammar)
 - #56742 (infer: remove Box from a returned Iterator)
 - #56744 (specialize: remove Boxes used by Children::insert)
 - #56746 (Add test of current behavior (infer free region within closure body))
 - #56747 (target: remove Box returned by get_targets)
 - #56749 (x86: Add the `adx` target feature to whitelist)
 - #56751 (Allow ptr::hash to accept fat pointers)
 - #56755 (Account for `impl Trait` when suggesting lifetime)
 - #56756 (Disable btree pretty-printers on older gdbs)
 - #56758 (Add short emoji status to toolstate updates)
 - #56760 (Deduplicate unsatisfied trait bounds)
 - #56769 (Add x86_64-unknown-uefi target)
 - #56789 (rustc: Add an unstable `simd_select_bitmask` intrinsic)

bors added a commit that referenced this pull request Dec 14, 2018

Auto merge of #56803 - kennytm:rollup, r=kennytm
Rollup of 36 pull requests

Successful merges:

 - #56203 (Add lint for items deprecated in future)
 - #56343 (Remove not used mod)
 - #56439 (Clearer error message for dead assign)
 - #56490 (Add checked_add method to Instant time type)
 - #56507 (polonius tweaks)
 - #56562 (Update libc version required by rustc)
 - #56600 (bootstrap: fix edition)
 - #56609 (Unconditionally emit the target-cpu LLVM attribute.)
 - #56658 (Add non-panicking `maybe_new_parser_from_file` variant)
 - #56672 (Document time of back operations of a Linked List)
 - #56677 (#[must_use] on traits in stdlib)
 - #56679 (overhaul external doc attribute diagnostics)
 - #56691 (fix install broken link)
 - #56695 (Fix irrefutable matches on integer ranges)
 - #56699 (Use a `newtype_index!` within `Symbol`.)
 - #56702 ([self-profiler] Add column for percent of total time)
 - #56708 (Remove some unnecessary feature gates)
 - #56709 (Remove unneeded extra chars to reduce search-index size)
 - #56710 (Always set the RDRAND and RDSEED features on SGX)
 - #56713 (Test capacity of ZST vector)
 - #56718 (Use libbacktrace pretty-printing)
 - #56725 (fix rust-lang/rust issue #50583)
 - #56731 (Add missing urls in ffi module docs)
 - #56738 (Fix private_no_mangle_fns message grammar)
 - #56742 (infer: remove Box from a returned Iterator)
 - #56744 (specialize: remove Boxes used by Children::insert)
 - #56746 (Add test of current behavior (infer free region within closure body))
 - #56747 (target: remove Box returned by get_targets)
 - #56749 (x86: Add the `adx` target feature to whitelist)
 - #56751 (Allow ptr::hash to accept fat pointers)
 - #56755 (Account for `impl Trait` when suggesting lifetime)
 - #56756 (Disable btree pretty-printers on older gdbs)
 - #56758 (Add short emoji status to toolstate updates)
 - #56760 (Deduplicate unsatisfied trait bounds)
 - #56769 (Add x86_64-unknown-uefi target)
 - #56789 (rustc: Add an unstable `simd_select_bitmask` intrinsic)

kennytm added a commit to kennytm/rust that referenced this pull request Dec 14, 2018

Rollup merge of rust-lang#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.

bors added a commit that referenced this pull request Dec 14, 2018

Auto merge of #56817 - kennytm:rollup, r=kennytm
Rollup of 27 pull requests (second batch)

Successful merges:

 - #53506 (Documentation for impl From for AtomicBool and other Atomic types)
 - #56203 (Add lint for items deprecated in future)
 - #56343 (Remove not used mod)
 - #56439 (Clearer error message for dead assign)
 - #56507 (polonius tweaks)
 - #56572 (Contexually dependent error message for E0424 when value is assigned to "self")
 - #56600 (bootstrap: fix edition)
 - #56672 (Document time of back operations of a Linked List)
 - #56677 (#[must_use] on traits in stdlib)
 - #56679 (overhaul external doc attribute diagnostics)
 - #56682 (Update the stdsimd submodule)
 - #56691 (fix install broken link)
 - #56710 (Always set the RDRAND and RDSEED features on SGX)
 - #56713 (Test capacity of ZST vector)
 - #56718 (Use libbacktrace pretty-printing)
 - #56725 (fix rust-lang/rust issue #50583)
 - #56731 (Add missing urls in ffi module docs)
 - #56738 (Fix private_no_mangle_fns message grammar)
 - #56746 (Add test of current behavior (infer free region within closure body))
 - #56747 (target: remove Box returned by get_targets)
 - #56751 (Allow ptr::hash to accept fat pointers)
 - #56755 (Account for `impl Trait` when suggesting lifetime)
 - #56758 (Add short emoji status to toolstate updates)
 - #56760 (Deduplicate unsatisfied trait bounds)
 - #56769 (Add x86_64-unknown-uefi target)
 - #56772 (fix issue 54153 by not testing issue-18804 on Windows nor OS X.)
 - #56808 (Fixes broken links)

Failed merges:

r? @ghost

pietroalbini added a commit to pietroalbini/rust that referenced this pull request Dec 14, 2018

Rollup merge of rust-lang#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.
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
// one. "efi_main" seems to be a common choice amongst other implementations and the
// spec.
"/entry:efi_main".to_string(),

This comment has been minimized.

@nagisa

nagisa Dec 14, 2018

Contributor

How does this work for application writers?

Are they responsible for defining an efi_main symbol? Perhaps not the best approach then, as we already have #[start] and expect function annotated with that attribute to get invoked at start-up even in #[no_std] contexts.

This comment has been minimized.

@dvdhrm

dvdhrm Dec 17, 2018

Author Contributor

Some crate in your application must provide the efi_main symbol. If we port std, we could make the #[start] logic do this. However, I don't think core should provide wrappers around the entry-point. We explicitly want a way to link applications with full control over the entry-point. With this target, you need:

pub extern fn efi_main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status

..to exist somewhere in your application.

I expect applications to pull in helper crates that wrap the UEFI API with a safe rust interface. Those crates can then provide the entry-point and retain the system-table somehow. However, note that due to ExitBootServices(), it is non-trivial to safely wrap all of the UEFI API (at least it requires some thought). By blocking ExitBootServices() and the VM-remapping, it is at least easier to imagine a safe wrapper.

We already have a public crate that simply provides the symbols from the UEFI spec as rust symbols (really just copying the definitions, not wrapper code in there) at https://github.com/r-util/r-efi
Our safe wrappers are still being worked on.

base.abi_return_struct_as_int = true;

Ok(Target {
llvm_target: "x86_64-unknown-windows".to_string(),

This comment has been minimized.

@nagisa

nagisa Dec 14, 2018

Contributor

Seems debatable to me. Are you sure this is correct (as opposed to just "x86_64"?)

This comment has been minimized.

@dvdhrm

dvdhrm Dec 17, 2018

Author Contributor

You have to trick llvm into creating COFF objects, rather than ELF objects. In theory this shouldn't matter. You should be able to use any available target compiler to get your object files, and then in the end tell your linker about the target format. However, this sadly does not work. The different object files have different capabilities, or specific annotations are only supported in one, not the other, etc. So I never succeeded in linking coff-objects into ELF-executables, or vice versa.

Preferably, I would use x86_64-unknown-coff, but that does not exit. If anyone has better suggestions, I would gladly switch over.

Selecting the windows target might cause LLVM to optimize for something that will not apply to LLVM. However, I don't think anyone can apply any assumptions on a generic target like the one I picked, because it has to be backwards-compatible to all the existing windows versions. So I believe this will be safe.

I contacted colleagues of mine here at Red Hat, maybe they have a suggestion. Sadly, it is all gcc, not LLVM ;)

This comment has been minimized.

@nagisa

nagisa Dec 17, 2018

Contributor

Makes sense then. It appears that llc has no way to specify format of the produced object file either, which most likely makes the target specification like this the best approach.

// places no locality-restrictions, so it fits well here.
base.code_model = Some("large".to_string());

// UEFI mostly mirrors the calling-conventions used on windows. In case of x86-64 this means

This comment has been minimized.

@nagisa

nagisa Dec 14, 2018

Contributor

Nit: x64 UEFI uses the exact same msabi (aka. x64) calling convention that windows uses. There is not a single difference (and therefore “mostly” is not applicable).

This comment has been minimized.

@dvdhrm

dvdhrm Dec 17, 2018

Author Contributor

Are you sure about that? UEFI explicitly disallows passing values bigger than 64bit by value (both as argument or return value; see UEFI-2.7 2.3.4.2). Isn't this allowed in msabi?

This comment has been minimized.

@nagisa

nagisa Dec 17, 2018

Contributor

UEFI explicitly disallows passing values bigger than 64bit by value (both as argument or return value; see UEFI-2.7 2.3.4.2). Isn't this allowed in msabi?

Other than XMM/floating point registers, nothing larger than 64-bit is passed by-register in x64 msabi.

This comment has been minimized.

@dvdhrm

dvdhrm Dec 17, 2018

Author Contributor

Other than XMM/floating point registers, nothing larger than 64-bit is passed by-register in x64 msabi.

Well, in registers, yes, but is that true for the stack as well? Does msabi require you to put objects bigger than 64bit in caller allocated memory and pass it by reference? Because that is how I read the UEFI spec, even for arguments passed on the stack.

The caller passes arrays and strings via a pointer to memory allocated by the
caller. The caller passes structures and unions of size 8, 16, 32, or 64 bits as if
they were integers of the same size. The caller is not allowed to pass structures
and unions of other than these sizes and must pass these unions and structures
via a pointer.

This comment has been minimized.

@nagisa

nagisa Dec 17, 2018

Contributor

Yes. Either way, this is proved by the fact that it wasn’t necessary for you to do anything special to implement UEFI’s ABI: it was already implemented!

This comment has been minimized.

@dvdhrm

dvdhrm Dec 17, 2018

Author Contributor

Right, the MSDN docs are almost identical. Thanks a lot for the link!

I certainly expecteded the ABIs to be compatible. I just wasn't sure whether the UEFI ABI is a subset (e.g., their coding-convention forbids returning anything but ints, which I expected to be rooted in a restricted ABI). I am confident using the msabi will just work, given that's what tianocore does as well.

@nagisa

This comment has been minimized.

Copy link
Contributor

nagisa commented Dec 14, 2018

Cool trick with lld though!

bors added a commit that referenced this pull request Dec 14, 2018

Auto merge of #56830 - pietroalbini:rollup, r=pietroalbini
Rollup of 25 pull requests

Successful merges:

 - #53506 (Documentation for impl From for AtomicBool and other Atomic types)
 - #56203 (Add lint for items deprecated in future)
 - #56343 (Remove not used mod)
 - #56439 (Clearer error message for dead assign)
 - #56507 (polonius tweaks)
 - #56672 (Document time of back operations of a Linked List)
 - #56677 (#[must_use] on traits in stdlib)
 - #56679 (overhaul external doc attribute diagnostics)
 - #56682 (Update the stdsimd submodule)
 - #56691 (fix install broken link)
 - #56710 (Always set the RDRAND and RDSEED features on SGX)
 - #56713 (Test capacity of ZST vector)
 - #56718 (Use libbacktrace pretty-printing)
 - #56725 (fix rust-lang/rust issue #50583)
 - #56731 (Add missing urls in ffi module docs)
 - #56738 (Fix private_no_mangle_fns message grammar)
 - #56746 (Add test of current behavior (infer free region within closure body))
 - #56747 (target: remove Box returned by get_targets)
 - #56751 (Allow ptr::hash to accept fat pointers)
 - #56755 (Account for `impl Trait` when suggesting lifetime)
 - #56758 (Add short emoji status to toolstate updates)
 - #56760 (Deduplicate unsatisfied trait bounds)
 - #56769 (Add x86_64-unknown-uefi target)
 - #56808 (Fixes broken links)
 - #56809 (Fix docs path to PermissionsExt)

Failed merges:

r? @ghost

pietroalbini added a commit to pietroalbini/rust that referenced this pull request Dec 15, 2018

Rollup merge of rust-lang#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.

bors added a commit that referenced this pull request Dec 15, 2018

Auto merge of #56840 - pietroalbini:rollup, r=pietroalbini
Rollup of 14 pull requests

Successful merges:

 - #56718 (Use libbacktrace pretty-printing)
 - #56725 (fix rust-lang/rust issue #50583)
 - #56731 (Add missing urls in ffi module docs)
 - #56738 (Fix private_no_mangle_fns message grammar)
 - #56746 (Add test of current behavior (infer free region within closure body))
 - #56747 (target: remove Box returned by get_targets)
 - #56751 (Allow ptr::hash to accept fat pointers)
 - #56755 (Account for `impl Trait` when suggesting lifetime)
 - #56758 (Add short emoji status to toolstate updates)
 - #56760 (Deduplicate unsatisfied trait bounds)
 - #56769 (Add x86_64-unknown-uefi target)
 - #56792 (Bootstrap: Add testsuite for compiletest tool)
 - #56808 (Fixes broken links)
 - #56809 (Fix docs path to PermissionsExt)

Failed merges:

r? @ghost

@bors bors merged commit 88cf2a2 into rust-lang:master Dec 15, 2018

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details

josephlr added a commit to josephlr/uefi-rs that referenced this pull request Feb 6, 2019

Use x86_64-unknown-uefi target
Rust now supports uefi as a build target: rust-lang/rust#56769

This change mainly eliminates references to the custom JSON target
file. It also requires that the entry point's name be changed to
`efi_main`.

Note that the "C" abi is now correct for EFI applications, but will
still be incorrect when uefi-rs is brought in as an external dependancy
for a different target. This means the entry point should always be
`extern "C"` while the table of function pointers should be `extern
"win64"`.

GabrielMajeri added a commit to rust-osdev/uefi-rs that referenced this pull request Feb 6, 2019

Use x86_64-unknown-uefi target
Rust now supports uefi as a build target: rust-lang/rust#56769

This change mainly eliminates references to the custom JSON target
file. It also requires that the entry point's name be changed to
`efi_main`.

Note that the "C" abi is now correct for EFI applications, but will
still be incorrect when uefi-rs is brought in as an external dependancy
for a different target. This means the entry point should always be
`extern "C"` while the table of function pointers should be `extern
"win64"`.
@kkk669

This comment has been minimized.

Copy link

kkk669 commented Feb 6, 2019

Why isn’t this using rust-lld as a linker? It is able to create an UEFI application and bundled with the default toolchain, so an external linker like lld-link is not needed.

@dvdhrm

This comment has been minimized.

Copy link
Contributor Author

dvdhrm commented Feb 6, 2019

rust-lld is only available for tier-1 platforms. It is not shipped with the others. I am not sure what the reasoning is, and whether that is still true. Furthermore, I considered the system linker to be preferable to a bundled one. I am not sure why rust-lld is bundled at all.
To be quite honest, I thought using the system linker is the expected behavior. If you have more insight on this topic, please lemme know what the recommended way here is (or, of course, feel free to open a PR).

@Rua

This comment has been minimized.

Copy link

Rua commented Feb 22, 2019

When trying to compile a project with this target, lld-link can't be found. lld-link-6.0 exists, though. I'm using Linux Mint 19.1.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Feb 25, 2019

@dvdhrm

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.

I've used those interfaces quite a bit, and they're available on many common firmware images. The filesystem interfaces are always available. And in general, almost all of what std needs should be regularly available, other than things that depend on fork or similar.

@dvdhrm

This comment has been minimized.

Copy link
Contributor Author

dvdhrm commented Feb 26, 2019

I've used those interfaces quite a bit, and they're available on many common firmware images.

I know implementations exist, and I know that people use them. Can you clarify what "many common firmware images" means? Does that include low-budget devices? Does it mean 50% of devices? 10%? Or 99.9%?

I know that we had issues with the most simple of UEFI protocols being implemented wrongly in consumer hardware (speaking of efi_simple_input_protocol and efi_graphics_output_protocol), and we had to work around peculiarities in very simple projects like gummiboot, sd-boot, efifb, etc. (see their implementations for details). So I am a bit skeptical if you claim that the more elaborate protocols like the network stack exists on many devices. I hope you are right ;)

The filesystem interfaces are always available. And in general, almost all of what std needs should be regularly available, other than things that depend on fork or similar.

Just because a protocol is available does not mean that you can use it. For instance, to safely use any of the UEFI protocols that support device hotplugging, you must register a EFI_DRIVER_BINDING_PROTOCOL instance yourself. Otherwise, there is no way that you are notified of devices being removed. For instance, UEFI Applications (unlike UEFI Drivers) usually only make use of singleton protocols (the ones that multiplex input/output of multiple devices on a single interface). While technically nobody stops you from using other protocols, they can be dropped at any point in time without you being notified, thus getting lots of stale pointers.

I still think porting std to UEFI is more complex than it initially looks. Furthermore, I think it requires a lot of background tasks to be performed, which you preferably don't want your standard library to do. Lastly, it requires global state which works against what the UEFI spec tries to build.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Feb 26, 2019

I've certainly encountered devices that don't have the EFI network protocols, I'm just saying I've run into many devices that do (various random PC hardware, both laptops and desktops). There'd be value in being able to write DXE applications using Rust, and also in writing PEI or similar code in Rust without std.

The stock Tiano core includes the network protocols, so it's more a matter of whether the device vendor shipped a working driver for network hardware.

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Mar 3, 2019

he
Update rust to version 1.33.0.
Pkgsrc changes:
 * Bump required rust version to build to 1.32.0.
 * Adapt patches to changed file locations.
 * Since we now patch some more vendor/ modules, doctor the corresponding
   .cargo-checksum.json files accordingly

Upstream changes:

Version 1.33.0 (2019-02-28)
==========================

Language
--------
- [You can now use the `cfg(target_vendor)` attribute.][57465] E.g.
  `#[cfg(target_vendor="apple")] fn main() { println!("Hello Apple!"); }`
- [Integer patterns such as in a match expression can now be exhaustive.][56362]
  E.g. You can have match statement on a `u8` that covers `0..=255` and
  you would no longer be required to have a `_ => unreachable!()` case.
- [You can now have multiple patterns in `if let` and `while let`
  expressions.][57532] You can do this with the same syntax as a `match`
  expression. E.g.
  ```rust
  enum Creature {
      Crab(String),
      Lobster(String),
      Person(String),
  }

  fn main() {
      let state = Creature::Crab("Ferris");

      if let Creature::Crab(name) | Creature::Person(name) = state {
          println!("This creature's name is: {}", name);
      }
  }
  ```
- [You can now have irrefutable `if let` and `while let` patterns.][57535]
  Using this feature will by default produce a warning as this behaviour
  can be unintuitive. E.g. `if let _ = 5 {}`
- [You can now use `let` bindings, assignments, expression statements,
  and irrefutable pattern destructuring in const functions.][57175]
- [You can now call unsafe const functions.][57067] E.g.
  ```rust
  const unsafe fn foo() -> i32 { 5 }
  const fn bar() -> i32 {
      unsafe { foo() }
  }
  ```
- [You can now specify multiple attributes in a `cfg_attr` attribute.][57332]
  E.g. `#[cfg_attr(all(), must_use, optimize)]`
- [You can now specify a specific alignment with the `#[repr(packed)]`
  attribute.][57049] E.g. `#[repr(packed(2))] struct Foo(i16, i32);` is a
  struct with an alignment of 2 bytes and a size of 6 bytes.
- [You can now import an item from a module as an `_`.][56303] This allows you
  to import a trait's impls, and not have the name in the namespace. E.g.
  ```rust
  use std::io::Read as _;

  // Allowed as there is only one `Read` in the module.
  pub trait Read {}
  ```
- [You may now use `Rc`, `Arc`, and `Pin` as method receivers][56805].

Compiler
--------
- [You can now set a linker flavor for `rustc` with the `-Clinker-flavor`
  command line argument.][56351]
- [The mininum required LLVM version has been bumped to 6.0.][56642]
- [Added support for the PowerPC64 architecture on FreeBSD.][57615]
- [The `x86_64-fortanix-unknown-sgx` target support has been upgraded to
  tier 2 support.][57130] Visit the [platform support][platform-support]
  page for information on Rust's platform support.
- [Added support for the `thumbv7neon-linux-androideabi` and
  `thumbv7neon-unknown-linux-gnueabihf` targets.][56947]
- [Added support for the `x86_64-unknown-uefi` target.][56769]

Libraries
---------
- [The methods `overflowing_{add, sub, mul, shl, shr}` are now `const`
  functions for all numeric types.][57566]
- [The methods `rotate_left`, `rotate_right`, and `wrapping_{add, sub, mul,
  shl, shr}`
  are now `const` functions for all numeric types.][57105]
- [The methods `is_positive` and `is_negative` are now `const` functions for
  all signed numeric types.][57105]
- [The `get` method for all `NonZero` types is now `const`.][57167]
- [The methods `count_ones`, `count_zeros`, `leading_zeros`, `trailing_zeros`,
  `swap_bytes`, `from_be`, `from_le`, `to_be`, `to_le` are now `const` for all
  numeric types.][57234]
- [`Ipv4Addr::new` is now a `const` function][57234]

Stabilized APIs
---------------
- [`unix::FileExt::read_exact_at`]
- [`unix::FileExt::write_all_at`]
- [`Option::transpose`]
- [`Result::transpose`]
- [`convert::identity`]
- [`pin::Pin`]
- [`marker::Unpin`]
- [`marker::PhantomPinned`]
- [`Vec::resize_with`]
- [`VecDeque::resize_with`]
- [`Duration::as_millis`]
- [`Duration::as_micros`]
- [`Duration::as_nanos`]


Cargo
-----
- [Cargo should now rebuild a crate if a file was modified during the initial
  build.][cargo/6484]

Compatibility Notes
-------------------
- The methods `str::{trim_left, trim_right, trim_left_matches,
  trim_right_matches}` are now deprecated in the standard library, and their
  usage will now produce a warning.  Please use the `str::{trim_start,
  trim_end, trim_start_matches, trim_end_matches}` methods instead.
- The `Error::cause` method has been deprecated in favor of `Error::source`
  which supports downcasting.

[55982]: rust-lang/rust#55982
[56303]: rust-lang/rust#56303
[56351]: rust-lang/rust#56351
[56362]: rust-lang/rust#56362
[56642]: rust-lang/rust#56642
[56769]: rust-lang/rust#56769
[56805]: rust-lang/rust#56805
[56947]: rust-lang/rust#56947
[57049]: rust-lang/rust#57049
[57067]: rust-lang/rust#57067
[57105]: rust-lang/rust#57105
[57130]: rust-lang/rust#57130
[57167]: rust-lang/rust#57167
[57175]: rust-lang/rust#57175
[57234]: rust-lang/rust#57234
[57332]: rust-lang/rust#57332
[57465]: rust-lang/rust#57465
[57532]: rust-lang/rust#57532
[57535]: rust-lang/rust#57535
[57566]: rust-lang/rust#57566
[57615]: rust-lang/rust#57615
[cargo/6484]: rust-lang/cargo#6484
[`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at
[`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at
[`Option::transpose`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.transpose
[`Result::transpose`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose
[`convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html
[`pin::Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html
[`marker::Unpin`]: https://doc.rust-lang.org/stable/std/marker/trait.Unpin.html
[`marker::PhantomPinned`]: https://doc.rust-lang.org/nightly/std/marker/struct.PhantomPinned.html
[`Vec::resize_with`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize_with
[`VecDeque::resize_with`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.resize_with
[`Duration::as_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_millis
[`Duration::as_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_micros
[`Duration::as_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_nanos
[platform-support]: https://forge.rust-lang.org/platform-support.html

kennytm added a commit to kennytm/rust that referenced this pull request Mar 11, 2019

Rollup merge of rust-lang#58976 - phil-opp:patch-2, r=alexcrichton
Default to integrated `rust-lld` linker for UEFI targets

The `x86_64-unknown-uefi` target was added in rust-lang#56769 with the linker defaulting to `lld-link`. This means that a system linker with that name is required for linking.

I think defaulting to `rust-lld`, which is shipped with Rust, is a better default for the following reasons:

- Most systems don't have `lld-link` installed, so it forces users to install it first.
- The naming of LLD executables is not standarized, so users often need to create an additional symlink before things work. For example, on Ubuntu `apt install lld` leads to an executable named `lld-link-6.0`.
- We already default to `rust-lld` for [many targets](https://github.com/rust-lang/rust/search?utf8=%E2%9C%93&q=rust-lld&type=), including embedded and WASM targets, so doing the same for UEFI crates seems consistent to me. (It even seems like `x86_64-unknown-uefi` is the [only target](https://github.com/rust-lang/rust/search?q=lld-link&unscoped_q=lld-link) that uses `lld-link`.)

cc @dvdhrm who added the target and @kkk669 who [proposed to use `rust-lld`](rust-lang#56769 (comment)).

Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this pull request Mar 14, 2019

Rollup merge of rust-lang#58976 - phil-opp:patch-2, r=alexcrichton
Default to integrated `rust-lld` linker for UEFI targets

The `x86_64-unknown-uefi` target was added in rust-lang#56769 with the linker defaulting to `lld-link`. This means that a system linker with that name is required for linking.

I think defaulting to `rust-lld`, which is shipped with Rust, is a better default for the following reasons:

- Most systems don't have `lld-link` installed, so it forces users to install it first.
- The naming of LLD executables is not standarized, so users often need to create an additional symlink before things work. For example, on Ubuntu `apt install lld` leads to an executable named `lld-link-6.0`.
- We already default to `rust-lld` for [many targets](https://github.com/rust-lang/rust/search?utf8=%E2%9C%93&q=rust-lld&type=), including embedded and WASM targets, so doing the same for UEFI crates seems consistent to me. (It even seems like `x86_64-unknown-uefi` is the [only target](https://github.com/rust-lang/rust/search?q=lld-link&unscoped_q=lld-link) that uses `lld-link`.)

cc @dvdhrm who added the target and @kkk669 who [proposed to use `rust-lld`](rust-lang#56769 (comment)).

kennytm added a commit to kennytm/rust that referenced this pull request Mar 15, 2019

Rollup merge of rust-lang#58976 - phil-opp:patch-2, r=alexcrichton
Default to integrated `rust-lld` linker for UEFI targets

The `x86_64-unknown-uefi` target was added in rust-lang#56769 with the linker defaulting to `lld-link`. This means that a system linker with that name is required for linking.

I think defaulting to `rust-lld`, which is shipped with Rust, is a better default for the following reasons:

- Most systems don't have `lld-link` installed, so it forces users to install it first.
- The naming of LLD executables is not standarized, so users often need to create an additional symlink before things work. For example, on Ubuntu `apt install lld` leads to an executable named `lld-link-6.0`.
- We already default to `rust-lld` for [many targets](https://github.com/rust-lang/rust/search?utf8=%E2%9C%93&q=rust-lld&type=), including embedded and WASM targets, so doing the same for UEFI crates seems consistent to me. (It even seems like `x86_64-unknown-uefi` is the [only target](https://github.com/rust-lang/rust/search?q=lld-link&unscoped_q=lld-link) that uses `lld-link`.)

cc @dvdhrm who added the target and @kkk669 who [proposed to use `rust-lld`](rust-lang#56769 (comment)).

kennytm added a commit to kennytm/rust that referenced this pull request Mar 16, 2019

Rollup merge of rust-lang#58976 - phil-opp:patch-2, r=alexcrichton
Default to integrated `rust-lld` linker for UEFI targets

The `x86_64-unknown-uefi` target was added in rust-lang#56769 with the linker defaulting to `lld-link`. This means that a system linker with that name is required for linking.

I think defaulting to `rust-lld`, which is shipped with Rust, is a better default for the following reasons:

- Most systems don't have `lld-link` installed, so it forces users to install it first.
- The naming of LLD executables is not standarized, so users often need to create an additional symlink before things work. For example, on Ubuntu `apt install lld` leads to an executable named `lld-link-6.0`.
- We already default to `rust-lld` for [many targets](https://github.com/rust-lang/rust/search?utf8=%E2%9C%93&q=rust-lld&type=), including embedded and WASM targets, so doing the same for UEFI crates seems consistent to me. (It even seems like `x86_64-unknown-uefi` is the [only target](https://github.com/rust-lang/rust/search?q=lld-link&unscoped_q=lld-link) that uses `lld-link`.)

cc @dvdhrm who added the target and @kkk669 who [proposed to use `rust-lld`](rust-lang#56769 (comment)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.