[RFC][UEFI][Driver] Support UEFI target

Abstract

To compile UEFI applications using Clang, we currently use Windows target triple (e.g. x86_64-pc-windows-msvc). We would like to introduce a first-class UEFI environment support to compile UEFI applications where only UEFI constraints are included and not the Windows ABI or API interoperability constraints. We intend to add support for this UEFI environment incrementally beginning with the introduction of UEFI specific target triple. The immediate focus and proposed implementation will cover Driver and Tool support for UEFI. Eventually, we would like to port runtime, compiler-rt builtins, libc and libc++ libraries.

Proposed Changes

This is an informal specification for a minimum viable implementation.

  • Introduce a new LLVM Triple OSType named UEFI.
  • Add UEFI toolchain support to the Clang driver.
  • For each of the target architectures, implement a UEFI TargetInfo e.g. UEFIX86_64TargetInfo.

We make some assumptions regarding certain aspects of the UEFI compilations that are not explicitly mentioned in the UEFI specification. This is to simplify the early implementation and we expect to expand the support as and when new projects are onboarded and require changes to these assumptions:

  1. Default subsystem - efi_application (EFI_IMAGE_SUSBSYTEM_EFI_APPLICATION)
  2. Default entry point - EfiMain

The following macro defines will be part of the implementation.

  • __UEFI__
  • __PECOFF__
    • If this macro can be set for all PE-COFF targets (i.e. UEFI and Windows PE-COFF targets), it can be useful.

This effort is carried out by the Fuchsia toolchain team at Google which I am part of. We plan to compile the UEFI early bring up code used by the Zircon kernel with the new target.

Discussion

We plan to provide a simple UEFI example that can be compiled and run on QEMU using the new target for demonstration and testing purposes. We fully welcome comments, questions and suggestions from the community on this effort.

3 Likes

Having an official target seems like an improvement over the existing hacks people are using. (I’ve seen hacks much uglier than using a Windows target.)

Do you have a plan to make recipes for building a complete toolchain available?

1 Like

As UEFI supports more architectures nowadays, it should also support at least also AArch64 and RISC-V. LoongArch uses UEFI too, AFAIK: GitHub - loongson/Firmware: Firmware Of LoongArch Machines

1 Like

RISC-V cannot be supported so long as there is no full PE/COFF spec for RISC-V; there are no architecture-specific relocations defined for it. Getting those likely depends on Microsoft wanting to do a Windows port, too, so don’t expect that to happen any time soon. The workaround is generally to build an ELF and convert it to PE/COFF, whether through some objcopy-like tool emitting a PE/COFF file itself or by constructing the PE/COFF header in assembly and using objcopy -O binary. This is the downside of UEFI using a spec owned by Microsoft for its object file format.

2 Likes

I think modelling UEFI as an OS makes sense to me, we should do it.

1 Like

Thank you.

We intend to provide documentation on how to build UEFI applications with the new target with examples. The Fuchsia toolchain CMake changes can also be useful as a reference.

1 Like

What’s the latest status of this proposed UEFI target support in Clang?

@bmeng - I am continuing to chip away at it albeit slowly. The X86 64 bit support with the assumptions mentioned in the RFC is pretty close to completion. Working on X86 codegen tests at the moment.

Patches under review:
https://reviews.llvm.org/D159541
https://reviews.llvm.org/D159540

The codegen patch needs some cleaning up but the Driver patch feels complete to me. I am thinking about the next steps after these patches and will share the progress as and when I have more work done.

Thanks. I’m glad to see that we are moving forward toward the goal.

Do you plan to add Arm and RISC-V UEFI target support after x86 is done?

ARM is certainly in my plans. But RISC-V story is unclear at the moment given the lack of specification. It is something I’m willing to explore and it’s one of the future directions I’m contemplating at the moment.

As I understand, PE relocations used in runtime are architecture-independent and will also work for RISC-V.

Object file relocations are not a part of UEFI ABI and can be arbitrary, it can even be different for different compilers and change in new compiler version in incompatible way. It will work unless someone will want to use static libraries for UEFI distributed in binary only form.

Also I see RISC-V relocations mentioned in Microsoft documentation:

IMAGE_REL_BASED_RISCV_HIGH20
5
This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the high 20 bits of a 32-bit absolute address.