summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorSimon Rettberg2026-01-28 12:53:53 +0100
committerSimon Rettberg2026-01-28 12:53:53 +0100
commit8e82785c584dc13e20f9229decb95bd17bbe9cd1 (patch)
treea8b359e59196be5b2e3862bed189107f4bc9975f /src/util
parentMerge branch 'master' into openslx (diff)
parent[prefix] Make unlzma.S compatible with 386 class CPUs (diff)
downloadipxe-openslx.tar.gz
ipxe-openslx.tar.xz
ipxe-openslx.zip
Merge branch 'master' into openslxopenslx
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore3
-rw-r--r--src/util/efifatbin.c1
-rw-r--r--src/util/efirom.c6
-rw-r--r--src/util/elf2efi.c69
-rwxr-xr-xsrc/util/genfsimg13
-rwxr-xr-xsrc/util/genkeymap.py1
-rw-r--r--src/util/zbin.c240
7 files changed, 331 insertions, 2 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index b4cb13601..fe68ee753 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -1,5 +1,6 @@
nrv2b
-zbin
+zbin32
+zbin64
hijack
prototester
elf2efi32
diff --git a/src/util/efifatbin.c b/src/util/efifatbin.c
index 918e7a3c4..e50f9a9ab 100644
--- a/src/util/efifatbin.c
+++ b/src/util/efifatbin.c
@@ -18,6 +18,7 @@
*/
#define FILE_LICENCE(...) extern void __file_licence ( void )
+#define FILE_SECBOOT(...) extern void __file_secboot ( void )
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
diff --git a/src/util/efirom.c b/src/util/efirom.c
index b0334bdb1..af912b87b 100644
--- a/src/util/efirom.c
+++ b/src/util/efirom.c
@@ -18,6 +18,7 @@
*/
#define FILE_LICENCE(...) extern void __file_licence ( void )
+#define FILE_SECBOOT(...) extern void __file_secboot ( void )
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
@@ -34,6 +35,9 @@
#include <ipxe/efi/IndustryStandard/PeImage.h>
#include <ipxe/efi/IndustryStandard/Pci22.h>
+/* Provide constants spuriously deleted from EDK2 headers */
+#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01c2
+
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
/* Round up ROM size */
@@ -91,11 +95,13 @@ static void read_pe_info ( void *pe, uint16_t *machine,
switch ( *machine ) {
case EFI_IMAGE_MACHINE_IA32:
case EFI_IMAGE_MACHINE_ARMTHUMB_MIXED:
+ case EFI_IMAGE_MACHINE_RISCV32:
*subsystem = nt->nt32.OptionalHeader.Subsystem;
break;
case EFI_IMAGE_MACHINE_X64:
case EFI_IMAGE_MACHINE_AARCH64:
case EFI_IMAGE_MACHINE_LOONGARCH64:
+ case EFI_IMAGE_MACHINE_RISCV64:
*subsystem = nt->nt64.OptionalHeader.Subsystem;
break;
default:
diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c
index 4af587d87..9fd7c27ea 100644
--- a/src/util/elf2efi.c
+++ b/src/util/elf2efi.c
@@ -18,6 +18,7 @@
*/
#define FILE_LICENCE(...) extern void __file_licence ( void )
+#define FILE_SECBOOT(...) extern void __file_secboot ( void )
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
@@ -38,6 +39,9 @@
#include <ipxe/efi/Uefi.h>
#include <ipxe/efi/IndustryStandard/PeImage.h>
+/* Provide constants spuriously deleted from EDK2 headers */
+#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01c2
+
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
#undef ELF_R_TYPE
@@ -83,6 +87,9 @@
#ifndef EM_AARCH64
#define EM_AARCH64 183
#endif
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
@@ -167,6 +174,45 @@
#ifndef R_LARCH_PCREL20_S2
#define R_LARCH_PCREL20_S2 103
#endif
+#ifndef R_RISCV_NONE
+#define R_RISCV_NONE 0
+#endif
+#ifndef R_RISCV_32
+#define R_RISCV_32 1
+#endif
+#ifndef R_RISCV_64
+#define R_RISCV_64 2
+#endif
+#ifndef R_RISCV_BRANCH
+#define R_RISCV_BRANCH 16
+#endif
+#ifndef R_RISCV_JAL
+#define R_RISCV_JAL 17
+#endif
+#ifndef R_RISCV_PCREL_HI20
+#define R_RISCV_PCREL_HI20 23
+#endif
+#ifndef R_RISCV_PCREL_LO12_I
+#define R_RISCV_PCREL_LO12_I 24
+#endif
+#ifndef R_RISCV_PCREL_LO12_S
+#define R_RISCV_PCREL_LO12_S 25
+#endif
+#ifndef R_RISCV_ADD32
+#define R_RISCV_ADD32 35
+#endif
+#ifndef R_RISCV_SUB32
+#define R_RISCV_SUB32 39
+#endif
+#ifndef R_RISCV_RVC_BRANCH
+#define R_RISCV_RVC_BRANCH 44
+#endif
+#ifndef R_RISCV_RVC_JUMP
+#define R_RISCV_RVC_JUMP 45
+#endif
+#ifndef R_RISCV_RELAX
+#define R_RISCV_RELAX 51
+#endif
#ifndef R_X86_64_GOTPCRELX
#define R_X86_64_GOTPCRELX 41
#endif
@@ -596,6 +642,11 @@ static void set_machine ( struct elf_file *elf, struct pe_header *pe_header ) {
case EM_LOONGARCH:
machine = EFI_IMAGE_MACHINE_LOONGARCH64;
break;
+ case EM_RISCV:
+ machine = ( ( ELFCLASS == ELFCLASS64 ) ?
+ EFI_IMAGE_MACHINE_RISCV64 :
+ EFI_IMAGE_MACHINE_RISCV32 );
+ break;
default:
eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
exit ( 1 );
@@ -828,16 +879,19 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
case ELF_MREL ( EM_AARCH64, R_AARCH64_NONE ) :
case ELF_MREL ( EM_AARCH64, R_AARCH64_NULL ) :
case ELF_MREL ( EM_LOONGARCH, R_LARCH_NONE ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_NONE ) :
/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
break;
case ELF_MREL ( EM_386, R_386_32 ) :
case ELF_MREL ( EM_ARM, R_ARM_ABS32 ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_32 ) :
/* Generate a 4-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 4 );
break;
case ELF_MREL ( EM_X86_64, R_X86_64_64 ) :
case ELF_MREL ( EM_AARCH64, R_AARCH64_ABS64 ) :
case ELF_MREL ( EM_LOONGARCH, R_LARCH_64 ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_64 ) :
/* Generate an 8-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 8 );
break;
@@ -869,16 +923,31 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
case ELF_MREL ( EM_LOONGARCH, R_LARCH_GOT_PC_HI20 ):
case ELF_MREL ( EM_LOONGARCH, R_LARCH_GOT_PC_LO12 ):
case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCREL20_S2 ):
+ case ELF_MREL ( EM_RISCV, R_RISCV_BRANCH ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_JAL ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_PCREL_HI20 ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_PCREL_LO12_I ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_PCREL_LO12_S ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_RVC_BRANCH ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_RVC_JUMP ) :
/* Skip PC-relative relocations; all relative
* offsets remain unaltered when the object is
* loaded.
*/
break;
case ELF_MREL ( EM_LOONGARCH, R_LARCH_RELAX ):
+ case ELF_MREL ( EM_RISCV, R_RISCV_RELAX ) :
/* Relocation can be relaxed (optimized out).
* Ignore it for now.
*/
break;
+ case ELF_MREL ( EM_RISCV, R_RISCV_ADD32 ) :
+ case ELF_MREL ( EM_RISCV, R_RISCV_SUB32 ) :
+ /* Ignore label difference relocations since
+ * we do not perform any relocations that can
+ * result in altered label differences.
+ */
+ break;
case ELF_MREL ( EM_X86_64, R_X86_64_32 ) :
/* Ignore 32-bit relocations in a hybrid
* 32-bit BIOS and 64-bit UEFI binary,
diff --git a/src/util/genfsimg b/src/util/genfsimg
index a981a62d8..ac4bbadf8 100755
--- a/src/util/genfsimg
+++ b/src/util/genfsimg
@@ -78,6 +78,12 @@ efi_boot_name() {
"64aa" )
echo "BOOTAA64.EFI"
;;
+ "6450" )
+ echo "BOOTRISCV64.EFI"
+ ;;
+ "3250" )
+ echo "BOOTRISCV32.EFI"
+ ;;
* )
echo "${FILENAME}: unrecognised EFI architecture ${ARCH}" >&2
exit 1
@@ -287,6 +293,7 @@ if [ -n "${ISOIMG}" ] ; then
MKISOFS=
MKISOFS_MISSING=
MKISOFS_NOTSUP=
+ NOISOHYBRID=
for CMD in genisoimage mkisofs xorrisofs ; do
if ! "${CMD}" --version >/dev/null 2>&1 ; then
MKISOFS_MISSING="${MKISOFS_MISSING} ${CMD}"
@@ -309,11 +316,15 @@ if [ -n "${ISOIMG}" ] ; then
echo "${0}: cannot find a suitable mkisofs or equivalent" >&2
exit 1
fi
+ if [ "${MKISOFS}" = "xorrisofs" ] ; then
+ ISOARGS="${ISOARGS} -isohybrid-gpt-basdat"
+ NOISOHYBRID=1
+ fi
"${MKISOFS}" -quiet -volid "iPXE" -preparer "iPXE build system" \
-appid "iPXE - Open Source Network Boot Firmware" \
-publisher "ipxe.org" -sysid "iPXE" -o "${ISOIMG}" \
${ISOARGS} "${ISODIR}"
- if isohybrid --version >/dev/null 2>&1 ; then
+ if [ -z "${NOISOHYBRID}" ] && isohybrid --version >/dev/null 2>&1 ; then
ISOHYBRIDARGS=
if [ -n "${EFI}" ] ; then
ISOHYBRIDARGS="${ISOHYBRIDARGS} --uefi"
diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py
index b70ce5f72..f5ad1dcfe 100755
--- a/src/util/genkeymap.py
+++ b/src/util/genkeymap.py
@@ -412,6 +412,7 @@ class Keymap:
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+ FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/util/zbin.c b/src/util/zbin.c
index 3a4670b88..bbaf08f16 100644
--- a/src/util/zbin.c
+++ b/src/util/zbin.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <sys/stat.h>
#include <lzma.h>
+#include <elf.h>
#define DEBUG 0
@@ -16,6 +17,67 @@
/* LZMA preset choice. This is a policy decision */
#define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
+#undef ELF_R_TYPE
+
+#ifdef ELF32
+#define Elf_Addr Elf32_Addr
+#define Elf_Rel Elf32_Rel
+#define Elf_Rela Elf32_Rela
+#define ELF_R_TYPE ELF32_R_TYPE
+typedef uint32_t zrel_t;
+#endif
+
+#ifdef ELF64
+#define Elf_Addr Elf64_Addr
+#define Elf_Rel Elf64_Rel
+#define Elf_Rela Elf64_Rela
+#define ELF_R_TYPE ELF64_R_TYPE
+typedef uint64_t zrel_t;
+#endif
+
+/* Provide constants missing on some platforms */
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+#ifndef R_RISCV_NONE
+#define R_RISCV_NONE 0
+#endif
+#ifndef R_RISCV_RELATIVE
+#define R_RISCV_RELATIVE 3
+#endif
+
+#define ELF_MREL( mach, type ) ( (mach) | ( (type) << 16 ) )
+
+/* Compressed relocation records
+ *
+ * Based on ELF Relr (which is not yet sufficiently widely supported
+ * to be usable), and optimised slightly for iPXE. Each record is a
+ * single machine word comprising the bit pattern:
+ *
+ * NSSS...SSSSRRR...RRRRRRRRRRRRRR
+ *
+ * where:
+ *
+ * "N" is a single bit (the MSB). If N=0 then there are 19 "S" bits,
+ * otherwise there are zero "S" bits. All remaining bits are "R"
+ * bits.
+ *
+ * "SSS...SSSS" is the number of machine words to skip. (If there are
+ * no "S" bits, then the number of machine words to skip is zero.)
+ *
+ * Each "R" bit represents a potential machine word relocation. If
+ * R=1 then a relocation is to be applied.
+ *
+ * The record list is terminated by a record with N=0 and S=0.
+ */
+#define ZREL_BITS ( 8 * sizeof ( zrel_t ) )
+#define ZREL_NO_SKIP_LIMIT ( ZREL_BITS - 1 )
+#define ZREL_NO_SKIP_FLAG ( 1ULL << ZREL_NO_SKIP_LIMIT )
+#define ZREL_SKIP_BITS 19
+#define ZREL_SKIP_LIMIT ( ZREL_NO_SKIP_LIMIT - ZREL_SKIP_BITS )
+#define ZREL_SKIP( x ) ( ( ( unsigned long long ) (x) ) << ZREL_SKIP_LIMIT )
+#define ZREL_SKIP_MAX ( ( 1ULL << ZREL_SKIP_BITS ) - 1 )
+
struct input_file {
void *buf;
size_t len;
@@ -26,6 +88,7 @@ struct output_file {
size_t len;
size_t hdr_len;
size_t max_len;
+ uintptr_t base;
};
struct zinfo_common {
@@ -61,12 +124,27 @@ struct zinfo_add {
uint32_t pad;
};
+struct zinfo_base {
+ char type[4];
+ uint32_t pad;
+ uint64_t base;
+};
+
+struct zinfo_zrel {
+ char type[4];
+ uint32_t offset;
+ uint32_t len;
+ uint32_t machine;
+};
+
union zinfo_record {
struct zinfo_common common;
struct zinfo_copy copy;
struct zinfo_pack pack;
struct zinfo_payload payload;
struct zinfo_add add;
+ struct zinfo_base base;
+ struct zinfo_zrel zrel;
};
struct zinfo_file {
@@ -513,6 +591,166 @@ static int process_zinfo_appl ( struct input_file *input,
&zinfo->add, output->hdr_len, 4 );
}
+static int process_zinfo_base ( struct input_file *input
+ __attribute__ (( unused )),
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ struct zinfo_base *base = &zinfo->base;
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "BASE %#llx\n",
+ ( ( unsigned long long ) base->base ) );
+ }
+
+ output->base = base->base;
+ return 0;
+}
+
+static int process_zinfo_zrel ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ struct zinfo_zrel *zrel = &zinfo->zrel;
+ size_t start_len = output->len;
+ union {
+ const Elf_Rel *rel;
+ const Elf_Rela *rela;
+ void *raw;
+ } erel;
+ Elf_Addr *address;
+ Elf_Addr addend;
+ size_t remaining;
+ size_t stride;
+ size_t offset;
+ size_t prev;
+ zrel_t *records;
+ zrel_t *record;
+ unsigned long base;
+ unsigned long limit;
+ unsigned long delta;
+ unsigned int type;
+
+ /* Check input length */
+ if ( ( zrel->offset + zrel->len ) > input->len ) {
+ fprintf ( stderr, "Input buffer overrun on relocations\n" );
+ return -1;
+ }
+
+ /* Align output and check length */
+ output->len = align ( output->len, sizeof ( *address ) );
+ if ( output->len > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on relocations\n" );
+ return -1;
+ }
+
+ /* Calculate stride based on relocation type */
+ switch ( zrel->machine ) {
+ case EM_RISCV:
+ stride = sizeof ( *erel.rela );
+ break;
+ default:
+ fprintf ( stderr, "Unsupported machine type %d\n",
+ zrel->machine );
+ return -1;
+ }
+
+ /* Apply dynamic relocations and build compressed relocation records */
+ records = ( output->buf + output->len );
+ record = ( records - 1 );
+ base = 0;
+ limit = 0;
+ prev = 0;
+ for ( remaining = zrel->len, erel.raw = ( input->buf + zrel->offset ) ;
+ remaining >= stride ; remaining -= stride, erel.raw += stride ) {
+
+ /* Parse ELF relocation record */
+ type = ELF_R_TYPE ( erel.rel->r_info );
+ offset = ( erel.rel->r_offset - output->base );
+
+ /* Handle relocation type */
+ switch ( ELF_MREL ( zrel->machine, type ) ) {
+ case ELF_MREL ( EM_RISCV, R_RISCV_NONE ):
+ continue;
+ case ELF_MREL ( EM_RISCV, R_RISCV_RELATIVE ):
+ addend = erel.rela->r_addend;
+ break;
+ default:
+ fprintf ( stderr, "Unsupported relocation type %d\n",
+ type );
+ return -1;
+ }
+
+ /* Apply dynamic relocation */
+ if ( offset > output->len ) {
+ fprintf ( stderr, "Relocation outside output\n" );
+ return -1;
+ }
+ if ( ( offset % sizeof ( *address ) ) != 0 ) {
+ fprintf ( stderr, "Misaligned relocation\n" );
+ return -1;
+ }
+ address = ( output->buf + offset );
+ if ( stride == sizeof ( *erel.rela ) )
+ *address = addend;
+
+ /* Construct compressed relocation record */
+ if ( prev && ( offset <= prev ) ) {
+ fprintf ( stderr, "Unsorted relocation\n" );
+ return -1;
+ }
+ prev = offset;
+ delta = ( ( offset / sizeof ( *address ) ) - base );
+ while ( delta >= limit ) {
+ output->len += sizeof ( *record );
+ if ( output->len > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on "
+ "relocation\n" );
+ return -1;
+ }
+ record++;
+ base += limit;
+ delta -= limit;
+ if ( delta < ZREL_SKIP_BITS ) {
+ *record = ZREL_NO_SKIP_FLAG;
+ limit = ZREL_NO_SKIP_LIMIT;
+ } else if ( delta <= ZREL_SKIP_MAX ) {
+ *record = ZREL_SKIP ( delta );
+ base += delta;
+ delta = 0;
+ limit = ZREL_SKIP_LIMIT;
+ } else {
+ *record = ZREL_SKIP ( ZREL_SKIP_MAX );
+ base += ZREL_SKIP_MAX;
+ delta -= ZREL_SKIP_MAX;
+ limit = ZREL_SKIP_LIMIT;
+ }
+ }
+ *record |= ( 1ULL << delta );
+ }
+
+ /* Convert final record to terminator or add terminator as needed */
+ if ( ( record >= records ) &&
+ ( ( *record & ZREL_SKIP ( ZREL_SKIP_MAX ) ) == 0 ) ) {
+ *record &= ~ZREL_NO_SKIP_FLAG;
+ } else {
+ output->len += sizeof ( *record );
+ if ( output->len > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on "
+ "relocation\n" );
+ return -1;
+ }
+ record++;
+ *record = 0;
+ }
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "ZREL [%#x,%#x) to [%#zx,%#zx)\n",
+ zrel->offset, ( zrel->offset + zrel->len ),
+ start_len, output->len );
+ }
+
+ return 0;
+}
+
struct zinfo_processor {
char *type;
int ( * process ) ( struct input_file *input,
@@ -536,6 +774,8 @@ static struct zinfo_processor zinfo_processors[] = {
{ "APPB", process_zinfo_appb },
{ "APPW", process_zinfo_appw },
{ "APPL", process_zinfo_appl },
+ { "BASE", process_zinfo_base },
+ { "ZREL", process_zinfo_zrel },
};
static int process_zinfo ( struct input_file *input,