mirror of https://github.com/ipxe/ipxe.git
[efi] Compress EFI ROM images
Use the reference implementation of the EFI compression algorithm (taken from the EDK2 codebase, with minor bugfixes to allow compilation with -Werror) to compress EFI ROM images. Inspired-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/268/head
parent
900f1f98d3
commit
b76281a885
|
@ -43,7 +43,7 @@ $(BIN)/%.drv.efi : $(BIN)/%.efidrv
|
||||||
|
|
||||||
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
|
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
|
||||||
$(QM)$(ECHO) " [FINISH] $@"
|
$(QM)$(ECHO) " [FINISH] $@"
|
||||||
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
|
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) -c $< $@
|
||||||
|
|
||||||
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
|
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
|
||||||
$(QM)$(ECHO) " [CAB] $@"
|
$(QM)$(ECHO) " [CAB] $@"
|
||||||
|
|
|
@ -1425,7 +1425,7 @@ $(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
|
||||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET64 $< -o $@
|
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET64 $< -o $@
|
||||||
CLEANUP += $(ELF2EFI64)
|
CLEANUP += $(ELF2EFI64)
|
||||||
|
|
||||||
$(EFIROM) : util/efirom.c $(MAKEDEPS)
|
$(EFIROM) : util/efirom.c util/eficompress.c $(MAKEDEPS)
|
||||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
|
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
|
||||||
CLEANUP += $(EFIROM)
|
CLEANUP += $(EFIROM)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,10 +34,17 @@
|
||||||
|
|
||||||
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
|
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
|
||||||
|
|
||||||
|
/* Round up ROM size */
|
||||||
|
#define ROM_SIZE( len ) ( ( (len) + 511 ) & ~511 )
|
||||||
|
|
||||||
|
/* Include the EDK2 compression code */
|
||||||
|
#include "eficompress.c"
|
||||||
|
|
||||||
/** Command-line options */
|
/** Command-line options */
|
||||||
struct options {
|
struct options {
|
||||||
uint16_t vendor;
|
uint16_t vendor;
|
||||||
uint16_t device;
|
uint16_t device;
|
||||||
|
int compress;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,6 +101,35 @@ static void read_pe_info ( void *pe, uint16_t *machine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to compress EFI data in-place
|
||||||
|
*
|
||||||
|
* @v data Data to be compressed
|
||||||
|
* @v max_len Length of data
|
||||||
|
* @ret len Length after attempted compression
|
||||||
|
*/
|
||||||
|
static size_t efi_compress ( void *data, size_t max_len ) {
|
||||||
|
void *tmp;
|
||||||
|
UINT32 len;
|
||||||
|
|
||||||
|
/* Allocate temporary buffer for compressed data */
|
||||||
|
tmp = xmalloc ( max_len );
|
||||||
|
|
||||||
|
/* Attempt compression */
|
||||||
|
len = max_len;
|
||||||
|
if ( ( EfiCompress ( data, max_len, tmp, &len ) == 0 ) &&
|
||||||
|
( len < max_len ) ) {
|
||||||
|
memcpy ( data, tmp, len );
|
||||||
|
} else {
|
||||||
|
len = max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free temporary buffer */
|
||||||
|
free ( tmp );
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert EFI image to ROM image
|
* Convert EFI image to ROM image
|
||||||
*
|
*
|
||||||
|
@ -109,10 +145,14 @@ static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
|
||||||
struct stat pe_stat;
|
struct stat pe_stat;
|
||||||
size_t pe_size;
|
size_t pe_size;
|
||||||
size_t rom_size;
|
size_t rom_size;
|
||||||
|
size_t compressed_size;
|
||||||
void *buf;
|
void *buf;
|
||||||
void *payload;
|
void *payload;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
uint16_t machine;
|
||||||
|
uint16_t subsystem;
|
||||||
uint8_t checksum;
|
uint8_t checksum;
|
||||||
|
int compressed;
|
||||||
|
|
||||||
/* Determine PE file size */
|
/* Determine PE file size */
|
||||||
if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
|
if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
|
||||||
|
@ -123,7 +163,7 @@ static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
|
||||||
pe_size = pe_stat.st_size;
|
pe_size = pe_stat.st_size;
|
||||||
|
|
||||||
/* Determine ROM file size */
|
/* Determine ROM file size */
|
||||||
rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
|
rom_size = ROM_SIZE ( sizeof ( *headers ) + pe_size );
|
||||||
|
|
||||||
/* Allocate ROM buffer and read in PE file */
|
/* Allocate ROM buffer and read in PE file */
|
||||||
buf = xmalloc ( rom_size );
|
buf = xmalloc ( rom_size );
|
||||||
|
@ -136,12 +176,26 @@ static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
|
||||||
exit ( 1 );
|
exit ( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse PE headers */
|
||||||
|
read_pe_info ( payload, &machine, &subsystem );
|
||||||
|
|
||||||
|
/* Compress the image, if requested */
|
||||||
|
if ( opts->compress ) {
|
||||||
|
compressed_size = efi_compress ( payload, pe_size );
|
||||||
|
rom_size = ROM_SIZE ( sizeof ( *headers ) + compressed_size );
|
||||||
|
compressed = ( compressed_size < pe_size );
|
||||||
|
} else {
|
||||||
|
compressed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Construct ROM header */
|
/* Construct ROM header */
|
||||||
headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
|
headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
|
||||||
headers->rom.InitializationSize = ( rom_size / 512 );
|
headers->rom.InitializationSize = ( rom_size / 512 );
|
||||||
headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
|
headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
|
||||||
read_pe_info ( payload, &headers->rom.EfiMachineType,
|
headers->rom.EfiSubsystem = subsystem;
|
||||||
&headers->rom.EfiSubsystem );
|
headers->rom.EfiMachineType = machine;
|
||||||
|
headers->rom.CompressionType =
|
||||||
|
( compressed ? EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED : 0 );
|
||||||
headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
|
headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
|
||||||
headers->rom.PcirOffset =
|
headers->rom.PcirOffset =
|
||||||
offsetof ( typeof ( *headers ), pci );
|
offsetof ( typeof ( *headers ), pci );
|
||||||
|
@ -194,11 +248,12 @@ static int parse_options ( const int argc, char **argv,
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{ "vendor", required_argument, NULL, 'v' },
|
{ "vendor", required_argument, NULL, 'v' },
|
||||||
{ "device", required_argument, NULL, 'd' },
|
{ "device", required_argument, NULL, 'd' },
|
||||||
|
{ "compress", 0, NULL, 'c' },
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( ( c = getopt_long ( argc, argv, "v:d:h",
|
if ( ( c = getopt_long ( argc, argv, "v:d:ch",
|
||||||
long_options,
|
long_options,
|
||||||
&option_index ) ) == -1 ) {
|
&option_index ) ) == -1 ) {
|
||||||
break;
|
break;
|
||||||
|
@ -219,6 +274,9 @@ static int parse_options ( const int argc, char **argv,
|
||||||
exit ( 2 );
|
exit ( 2 );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
opts->compress = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help ( argv[0] );
|
print_help ( argv[0] );
|
||||||
exit ( 0 );
|
exit ( 0 );
|
||||||
|
|
Loading…
Reference in New Issue