diff options
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/.gitignore | 3 | ||||
| -rw-r--r-- | src/util/efifatbin.c | 1 | ||||
| -rw-r--r-- | src/util/efirom.c | 6 | ||||
| -rw-r--r-- | src/util/elf2efi.c | 69 | ||||
| -rwxr-xr-x | src/util/genfsimg | 13 | ||||
| -rwxr-xr-x | src/util/genkeymap.py | 1 | ||||
| -rw-r--r-- | src/util/zbin.c | 240 |
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, |
