Several new relocations types have been added in LoongArch ABI version
2.10. In particular:
- R_LARCH_B16 (18-bit PC-relative jump)
- R_LARCH_B21 (23-bit PC-relative jump)
- R_LARCH_PCREL20_S2 (22-bit PC-relative offset)
Also relocation relaxations have been introduced. Recent GCC (13.2)
and binutils 2.41+ use these types of relocations, which confuses
elf2efi tool. As a result, iPXE EFI images for LoongArch fail to
build with the following error:
Unrecognised relocation type 103
Fix by ignoring R_LARCH_B{16,21} and R_LARCH_PCREL20_S2 (as with other
PC-relative relocations), and by ignoring relaxations (R_LARCH_RELAX).
Relocation relaxations are basically optimizations: ignoring them
results in a correct binary (although it might be suboptimal).
This mirrors iPXE commit ee6185d ("[efi] Ignore new LoongArch
PC-relative relocations and relaxations").
Modified-by: Michael Brown <mbrown@fensystems.co.uk>
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Add definitions for relocation types that may be missing on older
versions of the host system's elf.h.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The result of multiplying a uint16_t by another uint16_t will be a
signed int. Comparing this against a size_t will perform an unwanted
sign extension.
Fix by explicitly casting e_phnum to an unsigned int, thereby matching
the data type used for the loop index variable (and avoiding the
unwanted sign extension).
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Newer versions of the GNU assembler (observed with binutils 2.41) will
complain about the ".arch i386" in files assembled with "as --64",
with the message "Error: 64bit mode not supported on 'i386'".
Fix by moving ".arch i386" below ".code32", so that the assembler is
no longer expecting 64-bit instructions to be used by the time that
the ".arch i386" directive is encountered.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
There may be multiple instances of EFI_GRAPHICS_OUTPUT_PROTOCOL
(e.g. if multiple display adapters are present). We currently block
the first attempt to open EFI_GRAPHICS_OUTPUT_PROTOCOL in order to
force text mode output as described in commit b1ca1a4 ("[efi] Block
first attempt to open EFI_GRAPHICS_OUTPUT_PROTOCOL"). When multiple
protocol instances are present, we need to block the first attempt to
open each instance in order to achieve the desired behaviour.
Fix by attempting to install a dummy protocol on the same handle, and
blocking the intercepted attempt to open the protocol only if this
installation succeeds. Since a protocol may be installed only once
per handle, this allows us to block only the first attempt to open
each protocol instance.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Add support for building with the clang compiler as an alternative to
gcc. Building with clang still requires the use of GNU binutils, due
to the assorted bits of assembler and linker trickery required to
produce a hybrid 32-bit/64-bit binary.
For x86_64, clang will access the __stack_chk_guard symbol via the
global offset table, using an R_X86_64_GOTPCRELX relocation. The
linker relaxes this to an R_X86_64_32S relocation, which is not
supportable since the final PE executable may be relocated anywhere
within the 64-bit address space. We cannot instruct the linker to
create a position-independent executable, since it will then complain
about impossible relocations in the 16-bit sections. Instead, we
inhibit link-time relaxations so that the linked executable still
contains the R_X86_64_GOTPCRELX relocation, which elf2efi can then
ignore since it is PC-relative.
The address-significance table emitted by clang is not understood by
the GNU assembler, so add -fno-addrsig if applicable.
Add explicit register size modifiers for the ARM64 byte-swapping
inline assembly, since these seem to be required by clang.
Add -Wno-unused-command-line-argument to the global CFLAGS when using
clang, since otherwise many compiler invocations will fail (including
the compiler invocations used to determine the appropriate compiler
flags to be used).
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Attempt to respect external tool choices via variables such as $(CC),
$(AS), $(LD), $(AR), etc.
Cross-compiling versions of gcc are typically installed as
e.g. aarch64-linux-gnu-gcc rather than aarch64-linux-gnu-cc, and so a
naive expansion of $(CROSS_arm64)$(CC) would not produce the correct
binary name in the common case that $(CC) is set to "cc". Work around
this quirk by redefining $(CC) as "gcc" if the detected compiler
claims to be gcc (i.e. defines the __GNUC__ macro).
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Avoid the need to always specify at least one cross-compilation prefix
by attempting to pick appropriate prefixes based on the detected CPU
architecture of the default compiler.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
All relevant versions of "ar" are capable of generating the index,
without requiring a separate invocation of "ranlib".
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Unlike the older efireloc, the elf2efi tool does not require a
separate invocation of objcopy to create the PE binary.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Define and use build tools, fixed build flags, and conditionally
tested build flags for each supported CPU architecture.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The clang compiler does not (and apparently will not ever) allow for
variable-length arrays within structs.
Work around this limitation by using a fixed-length array to hold the
PDB filename in the debug section.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The bochs/QEMU debug port at I/O port 0xe9 exists only for x86, and
there is no direct equivalent for other CPU architectures.
Omit the I/O port write instruction on other CPU architectures.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The bochs/QEMU debug console (a single register located at I/O port
0xe9) is a beautifully simple mechanism that allows a guest to write
characters to a host-side log using a single CPU instruction that will
work under almost all circumstances (even with corrupt page tables or
halfway through a CPU mode transition). It is unfortunately available
only for x86 guests.
With the standard builds of the EDK2 OVMF firmware, any EFI console
output will be echoed to the first detected serial port. This allows
the wimboot output to be captured there (along with any output from
OVMF, iPXE, etc).
Add a serial log to each test VM and check both logs for the required
log messages. Do not display the serial port log via "tail -f" since
this log tends to be very noisy and to include graphical control
characters that clear or overwrite the screen.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Many test cases do not include any explicit log message checks, and
can therefore pass even if the log output mechanism is non-functional.
Add an unconditional log message check for the wimboot startup banner,
to ensure that all tests require a working log output mechanism in
order to pass.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
We do not require a fast implementation of memset(). Replace the
current x86-specific implementation with a generic implementation to
simplify the process of supporting other CPU architectures.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
We currently attempt to provide real-mode call wrappers for any
architecture that is not x86_64. Invert this logic to provide
real-mode call wrappers only for the i386 architecture.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Section virtual addresses must be aligned to page boundaries in order
to support page-level protection mechanisms. Section file offsets and
lengths do not need to be aligned to page boundaries.
Remove the padding of the bzImage prefix to reduce the size of the
overall binary. Retain the padding within other sections, since the
hybrid BIOS/UEFI binary layout requires that the remainder of the file
(after the bzImage prefix) may be loaded into memory as a single
contiguous blob with no runtime relocation.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Import elf2efi.c from the iPXE repository and use it to perform the
conversion from ELF to PE format.
This removes the build dependency on libbfd, and opens up the
possibility of using cross-compiled ELF objects.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The IntelFrameworkPkg and EdkCompatibilityPkg directories have been
removed from the EDK2 codebase. Remove these directories from the
EDK2 header import script.
This mirrors iPXE commit 9003795 ("[efi] Remove deleted directories
from EDK2 header import script").
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
This mirrors the combination of two iPXE commits: 91944c6 ("[efi]
Allow for whitespace before #include in imported EDK2 header files")
and c3dd316 ("[efi] Fix dependency list construction in EDK2 header
import script").
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
We cannot rely on the EDK2 ProcessorBind.h headers when compiling a
binary for execution on the build host itself (e.g. efireloc), since
the host's CPU architecture may not even be supported by EDK2.
Fix by skipping ProcessorBind.h when building a host binary, and
defining the bare minimum required to allow other EDK2 headers to
compile cleanly.
This mirrors iPXE commit a99e435 ("[efi] Do not rely on
ProcessorBind.h when building host binaries").
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The ELF entry point is currently ignored since the entry point is
specified in the explicitly constructed PE headers.
Prepare for the removal of the explicitly constructed PE headers by
defining the entry point within the linker script, so that an
independent symbol reference continues to exist.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Newer versions of the linker treat the absence of a .note.GNU-stack
section as implying an executable stack, and will print a warning that
this is deprecated behaviour.
Silence the warning by adding a .note.GNU-stack section to each
assembly file.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Indicate that the binary is compatible with W^X protections by setting
the NXCOMPAT bit in the DllCharacteristics field of the PE header.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Allow PE section attributes to be used to inform page-level protection
mechanisms such as W^X by aligning all sections to a page boundary.
Aligning the payload to a page boundary causes it to no longer
immediately follow the bzImage setup code. Allow for this padding
when locating the start of the loaded-high payload to be copied to the
runtime address.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The standard hybrid 32-bit BIOS and 64-bit UEFI binary is very close
to overflowing into the BIOS forbidden region at address 0x30000.
There is no problem with 64-bit UEFI code being placed within the
forbidden region, since this code can never be executed in a BIOS
environment anyway.
Reorder the .text section to place 32-bit code first, and relax the
check in the linker script to allow 64-bit code to overflow into the
forbidden region.
In the hybrid 32-bit BIOS and 32-bit UEFI binary, there is no 64-bit
code that can be allowed to overflow into the forbidden region.
However, in this build the overall code size is substantially smaller
anyway, since there is no requirement to include both 32-bit and
64-bit versions of each function.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The .payload section currently contains all of the runtime executable
code, read-only data, and writable data. It is therefore marked as
both writable and executable. This is no longer permitted in binaries
signed for UEFI Secure Boot.
Fix by splitting the .payload section into separate .text and .data
sections.
The split is necessarily non-trivial, since the hybrid BIOS/UEFI
binary layout imposes the additional requirement that the 16-bit BIOS
executable code, initialised-data, and uninitialised-data sections are
all placed within the first 64kB of the RVA address space. To
accommodate this, we currently place .bss16 first within the address
space, with .text16, .rodata16, and .data16 following immediately
afterwards at the start of the .payload section.
In the new split layout, we place the .text section after the .data
section, and place .text16, .rodata16, and .data16 at the start of the
.data section. The .data section does therefore contain executable
code. However, this is 16-bit BIOS code that can never be executed
under UEFI anyway, and may therefore be treated as opaque (and unused)
data from the perspective of a UEFI PE binary.
We do not further split .data into read-only and writable portions,
since there is no space to insert an extra PE section header before
the fixed-offset bzImage header.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The .bss16 section is relevant only for the BIOS runtime, and does not
contain any symbols that are referenced by UEFI code.
Omit .bss16 from the PE section list, to create space within the PE
headers for splitting .payload into separate writable and executable
sections.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Newer versions of QEMU (observed with QEMU 7.2.1 on Fedora 38) seem
not to be able to handle the "-set netdev.hostnet0.bootfile=..."
command-line option that we use to specify the per-test boot URL. The
error message observed is:
qemu-system-x86_64: ...: there is no netdev "hostnet0" defined
Adding debug prints to a test build of QEMU shows that at the point
that the "-set" option is handled, the list of netdevs is empty. This
appears therefore to be a bug in the order of processing command-line
options. The precise root cause has not been identified, since QEMU's
command-line parsing logic is fairly arcane and relies heavily on
autogenerated code fragments.
Work around the problem by creating a wrapper script that strips the
"-set netdev.hostnet0.bootfile=..." option and instead injects the
bootfile as part of the "-netdev" option found earlier in the same
command line.
(In an ideal world, libvirt would provide a clean way to specify the
bootfile or other options for a "user" network interface, but such a
mechanism does not seem to exist at present.)
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The output from "pesign -h" has varied in format over time. The most
recent variation (in pesign 116 and later) swaps the order of the
filename and hash value, to provide consistency with the output order
from other checksumming tools such as sha256sum.
Use a regular expression to extract only the portion of the output
looking like a checksum value, thereby accommodating any version of
pesign released to date.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Place the PE debug directory (used only to hold the binary name for
debug messages) at a fixed offset that does not depend on the length
of the bzImage setup code.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
When building a hybrid 32-bit BIOS and 64-bit UEFI binary, the
relocation records for the 32-bit portions are redundant since nothing
will ever apply them. (The BIOS portion is already linked to its
runtime address, and is loaded as a Linux bzImage rather than a PE
executable.)
Omit these redundant relocation records from the final binary.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
The sign-extending R_X86_64_32S relocation types do not map to a
four-byte PE relocation record, since the latter does not perform sign
extension.
We do not currently require these relocation types, since wimboot code
is not built with -mcmodel=kernel and so does not use addresses within
the negative 2GB of address space.
Remove the spurious and unused processing for this relocation type.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
There appears to be no reason for padding each relocation block to a
multiple of 16 bytes. Remove this padding, leaving each relocation
block padded only to a multiple of 4 bytes as required by the PE
specification.
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>