mirror of https://github.com/ipxe/ipxe.git
Compressed ROM images now work.
parent
37fa9a8706
commit
048bbeeebc
|
@ -90,6 +90,7 @@ MKCONFIG ?= $(PERL) ./util/mkconfig.pl
|
|||
SYMCHECK ?= $(PERL) ./util/symcheck.pl
|
||||
SORTOBJDUMP ?= $(PERL) ./util/sortobjdump.pl
|
||||
NRV2B ?= ./util/nrv2b
|
||||
ZBIN ?= ./util/zbin
|
||||
DOXYGEN ?= doxygen
|
||||
|
||||
# Location to place generated files
|
||||
|
|
|
@ -307,11 +307,23 @@ $(BIN)/%.tmp : $(BLIB) $(MAKEDEPS) $(LDSCRIPT)
|
|||
$(BIN)/%.map : $(BIN)/%.tmp
|
||||
@less $(BIN)/$*.tmp.map
|
||||
|
||||
# Extract compression information from intermediate object file
|
||||
#
|
||||
$(BIN)/%.zinfo : $(BIN)/%.tmp
|
||||
$(QM)echo " [ZINFO] $@"
|
||||
$(Q)$(OBJCOPY) -O binary -j .zinfo $< $@
|
||||
|
||||
# Build raw binary file from intermediate object file
|
||||
#
|
||||
$(BIN)/%.bin : $(BIN)/%.tmp
|
||||
$(QM)echo " [BIN] $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
$(Q)$(OBJCOPY) -O binary -R .zinfo $< $@
|
||||
|
||||
# Compress raw binary file
|
||||
#
|
||||
$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
|
||||
$(QM)echo " [ZBIN] $@"
|
||||
$(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
|
||||
|
||||
# Build bochs symbol table
|
||||
$(BIN)/%.bxs : $(BIN)/%.tmp
|
||||
|
@ -356,7 +368,7 @@ define media_template
|
|||
@$(MKDIR) -p $(dir $(2))
|
||||
@$(RM) $(2)
|
||||
@$(TOUCH) $(2)
|
||||
@echo -e '$$(BIN)/%$(1) : $$(BIN)/%$(1).bin' \
|
||||
@echo -e '$$(BIN)/%$(1) : $$(BIN)/%$(1).zbin' \
|
||||
'\n\t$$(QM)echo " [FINISH] $$@"' \
|
||||
'\n\t$$(Q)$$(CP) $$< $$@' \
|
||||
'\n\t$$(Q)$$(FINALISE_$(1))' \
|
||||
|
@ -383,13 +395,19 @@ include $(MEDIA_DEPS)
|
|||
allroms allzroms : all%s : $(foreach ROM,$(ROMS),$(BIN)/$(ROM).%)
|
||||
all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%)
|
||||
|
||||
# The compressor utility
|
||||
# The compression utilities
|
||||
#
|
||||
$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
|
||||
$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
|
||||
$(QM)echo " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
|
||||
-DBITSIZE=32 -DENDIAN=0 -o $@ $<
|
||||
CLEANUP += $(NRV2B)
|
||||
|
||||
$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
|
||||
$(QM)echo " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -O2 -o $@ $<
|
||||
CLEANUP += $(ZBIN)
|
||||
|
||||
# Auto-incrementing build serial number. Append "bs" to your list of
|
||||
# build targets to get a serial number printed at the end of the
|
||||
# build. Enable -DBUILD_SERIAL in order to see it when the code runs.
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
*/
|
||||
#define HIGHMEM_LOADPOINT ( 4 << 20 )
|
||||
|
||||
/* Image compression enabled */
|
||||
#define COMPRESS 1
|
||||
|
||||
#define CR0_PE 1
|
||||
|
||||
.arch i386
|
||||
|
@ -81,7 +84,11 @@ install_block:
|
|||
|
||||
/* Do the copy */
|
||||
cld
|
||||
rep addr32 movsb /* or "call decompress16" */
|
||||
#if COMPRESS
|
||||
call decompress16
|
||||
#else
|
||||
call nodecompress16
|
||||
#endif
|
||||
|
||||
/* Zero remaining space */
|
||||
movl %eax, %edi
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* Placeholder for decompress16 in non-compressed images */
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".prefix.lib", "ax", @progbits
|
||||
|
||||
.code16
|
||||
.globl nodecompress16
|
||||
nodecompress16:
|
||||
rep addr32 movsb
|
||||
ret
|
||||
|
||||
/* File split information for the compressor */
|
||||
.section ".zinfo", "a"
|
||||
.ascii "COPY"
|
||||
.long _prefix_load_offset
|
||||
.long _load_size
|
||||
.long _max_align
|
|
@ -14,7 +14,7 @@
|
|||
.org 0x00
|
||||
romheader:
|
||||
.word 0xAA55 /* BIOS extension signature */
|
||||
.byte _rom_size /* Size in 512-byte blocks */
|
||||
romheader_size: .byte _rom_size /* Size in 512-byte blocks */
|
||||
jmp init_vector /* Initialisation vector */
|
||||
.org 0x16
|
||||
.word undiheader
|
||||
|
@ -34,7 +34,7 @@ pciheader:
|
|||
.byte 0x02 /* Device Base Type code */
|
||||
.byte 0x00 /* Device Sub-Type code */
|
||||
.byte 0x00 /* Device Interface Type code */
|
||||
.word _rom_size /* Image length same as offset 02h */
|
||||
pciheader_size: .word _rom_size /* Image length same as offset 02h */
|
||||
.word 0x0001 /* revision level of code/data */
|
||||
.byte 0x00 /* code type */
|
||||
.byte 0x80 /* Flags (last PCI data structure) */
|
||||
|
@ -215,3 +215,15 @@ print_message:
|
|||
popw %ax
|
||||
ret
|
||||
.size print_message, . - print_message
|
||||
|
||||
|
||||
/* Data update information for the compressor */
|
||||
.section ".zinfo.fixup", "a"
|
||||
.ascii "SUBB"
|
||||
.long romheader_size
|
||||
.long 512
|
||||
.long 0
|
||||
.ascii "SUBW"
|
||||
.long pciheader_size
|
||||
.long 512
|
||||
.long 0
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.section ".prefix.lib", "ax", @progbits
|
||||
|
||||
#ifdef CODE16
|
||||
/****************************************************************************
|
||||
|
@ -54,6 +54,7 @@
|
|||
* NOTE: It would be possible to build a smaller version of the
|
||||
* decompression code for -DKEEP_IT_REAL by using
|
||||
* #define REG(x) x
|
||||
* #define MOVSB movsb
|
||||
* to use 16-bit registers where possible. This would impose limits
|
||||
* that the compressed data size must be in the range [1,65533-%si]
|
||||
* and the uncompressed data size must be in the range [1,65536-%di]
|
||||
|
@ -66,6 +67,7 @@
|
|||
*/
|
||||
|
||||
#define REG(x) e ## x
|
||||
#define MOVSB addr32 movsb
|
||||
|
||||
.code16
|
||||
.globl decompress16
|
||||
|
@ -109,11 +111,10 @@ decompress:
|
|||
cld
|
||||
xor %xBP, %xBP
|
||||
dec %xBP /* last_m_off = -1 */
|
||||
add $4, %xSI /* Skip "file length" field */
|
||||
jmp dcl1_n2b
|
||||
|
||||
decompr_literals_n2b:
|
||||
movsb
|
||||
MOVSB
|
||||
decompr_loop_n2b:
|
||||
addl %ebx, %ebx
|
||||
jnz dcl2_n2b
|
||||
|
@ -157,7 +158,7 @@ decompr_got_mlen_n2b:
|
|||
push %xSI
|
||||
lea (%xBP,%xDI), %xSI /* m_pos = dst + olen + -m_off */
|
||||
rep
|
||||
es movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */
|
||||
es MOVSB /* dst[olen++] = *m_pos++ while(m_len > 0) */
|
||||
pop %xSI
|
||||
jmp decompr_loop_n2b
|
||||
|
||||
|
@ -179,3 +180,23 @@ decompr_end_n2b:
|
|||
popl %ebx
|
||||
pop %xAX
|
||||
ret
|
||||
|
||||
|
||||
/* File split information for the compressor */
|
||||
.section ".zinfo", "a"
|
||||
.ascii "COPY"
|
||||
.long _prefix_load_offset
|
||||
.long _prefix_progbits_size
|
||||
.long _max_align
|
||||
.ascii "PACK"
|
||||
.long _text16_load_offset
|
||||
.long _text16_progbits_size
|
||||
.long _max_align
|
||||
.ascii "PACK"
|
||||
.long _data16_load_offset
|
||||
.long _data16_progbits_size
|
||||
.long _max_align
|
||||
.ascii "PACK"
|
||||
.long _textdata_load_offset
|
||||
.long _textdata_progbits_size
|
||||
.long _max_align
|
||||
|
|
|
@ -164,6 +164,24 @@ SECTIONS {
|
|||
|
||||
_end = .;
|
||||
|
||||
/*
|
||||
* Compressor information block
|
||||
*/
|
||||
|
||||
_zinfo_link_addr = 0;
|
||||
. = _zinfo_link_addr;
|
||||
_zinfo = .;
|
||||
|
||||
.zinfo : AT ( _zinfo_load_offset + __zinfo ) {
|
||||
__zinfo = .;
|
||||
_entry = .;
|
||||
*(.zinfo)
|
||||
*(.zinfo.*)
|
||||
_ezinfo_progbits = .;
|
||||
}
|
||||
|
||||
_ezinfo = .;
|
||||
|
||||
/*
|
||||
* Dispose of the comment and note sections to make the link map
|
||||
* easier to read
|
||||
|
@ -215,6 +233,13 @@ SECTIONS {
|
|||
|
||||
_load_size = . - _load_addr;
|
||||
|
||||
. -= _zinfo_link_addr;
|
||||
_zinfo_load_offset = ALIGN ( _max_align );
|
||||
_zinfo_load_addr = _zinfo_link_addr + _zinfo_load_offset;
|
||||
_zinfo_size = _ezinfo - _zinfo;
|
||||
_zinfo_progbits_size = _ezinfo_progbits - _zinfo;
|
||||
. = _zinfo_load_addr + _zinfo_progbits_size;
|
||||
|
||||
_payload_offset = _text16_load_offset;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
nrv2b
|
||||
zbin
|
||||
hijack
|
||||
prototester
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define ENCODE
|
||||
#define VERBOSE
|
||||
#include "nrv2b.c"
|
||||
FILE *infile, *outfile;
|
||||
|
||||
struct input_file {
|
||||
void *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct output_file {
|
||||
void *buf;
|
||||
size_t len;
|
||||
size_t max_len;
|
||||
};
|
||||
|
||||
struct zinfo_common {
|
||||
char type[4];
|
||||
char pad[12];
|
||||
};
|
||||
|
||||
struct zinfo_copy {
|
||||
char type[4];
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
uint32_t align;
|
||||
};
|
||||
|
||||
struct zinfo_pack {
|
||||
char type[4];
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
uint32_t align;
|
||||
};
|
||||
|
||||
struct zinfo_subtract {
|
||||
char type[4];
|
||||
uint32_t offset;
|
||||
uint32_t divisor;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
union zinfo_record {
|
||||
struct zinfo_common common;
|
||||
struct zinfo_copy copy;
|
||||
struct zinfo_pack pack;
|
||||
struct zinfo_subtract subtract;
|
||||
};
|
||||
|
||||
struct zinfo_file {
|
||||
union zinfo_record *zinfo;
|
||||
unsigned int num_entries;
|
||||
};
|
||||
|
||||
static int read_file ( const char *filename, void **buf, size_t *len ) {
|
||||
FILE *file;
|
||||
struct stat stat;
|
||||
|
||||
file = fopen ( filename, "r" );
|
||||
if ( ! file ) {
|
||||
fprintf ( stderr, "Could not open %s: %s\n", filename,
|
||||
strerror ( errno ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ( fstat ( fileno ( file ), &stat ) < 0 ) {
|
||||
fprintf ( stderr, "Could not stat %s: %s\n", filename,
|
||||
strerror ( errno ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
*len = stat.st_size;
|
||||
*buf = malloc ( *len );
|
||||
if ( ! *buf ) {
|
||||
fprintf ( stderr, "Could not malloc() %d bytes for %s: %s\n",
|
||||
*len, filename, strerror ( errno ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ( fread ( *buf, 1, *len, file ) != *len ) {
|
||||
fprintf ( stderr, "Could not read %d bytes from %s: %s\n",
|
||||
*len, filename, strerror ( errno ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
fclose ( file );
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fclose ( file );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int read_input_file ( const char *filename,
|
||||
struct input_file *input ) {
|
||||
return read_file ( filename, &input->buf, &input->len );
|
||||
}
|
||||
|
||||
static int read_zinfo_file ( const char *filename,
|
||||
struct zinfo_file *zinfo ) {
|
||||
void *buf;
|
||||
size_t len;
|
||||
|
||||
if ( read_file ( filename, &buf, &len ) < 0 )
|
||||
return -1;
|
||||
|
||||
if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
|
||||
fprintf ( stderr, ".zinfo file %s has invalid length %d\n",
|
||||
filename, len );
|
||||
return -1;
|
||||
}
|
||||
|
||||
zinfo->zinfo = buf;
|
||||
zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_output_file ( size_t max_len, struct output_file *output ) {
|
||||
output->len = 0;
|
||||
output->max_len = ( max_len );
|
||||
output->buf = malloc ( max_len );
|
||||
if ( ! output->buf ) {
|
||||
fprintf ( stderr, "Could not allocate %d bytes for output\n",
|
||||
max_len );
|
||||
return -1;
|
||||
}
|
||||
memset ( output->buf, 0xff, sizeof ( output->buf ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_zinfo_copy ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
struct zinfo_copy *copy = &zinfo->copy;
|
||||
size_t offset = copy->offset;
|
||||
size_t len = copy->len;
|
||||
unsigned int align = copy->align;
|
||||
|
||||
if ( ( offset + len ) > input->len ) {
|
||||
fprintf ( stderr, "Input buffer overrun on copy\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
|
||||
if ( ( output->len + len ) > output->max_len ) {
|
||||
fprintf ( stderr, "Output buffer overrun on copy\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy ( ( output->buf + output->len ),
|
||||
( input->buf + offset ), len );
|
||||
output->len += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_zinfo_pack ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
struct zinfo_pack *pack = &zinfo->pack;
|
||||
size_t offset = pack->offset;
|
||||
size_t len = pack->len;
|
||||
unsigned int align = pack->align;
|
||||
unsigned long packed_len;
|
||||
|
||||
if ( ( offset + len ) > input->len ) {
|
||||
fprintf ( stderr, "Input buffer overrun on pack\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
|
||||
if ( output->len > output->max_len ) {
|
||||
fprintf ( stderr, "Output buffer overrun on pack\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
|
||||
( output->buf + output->len ),
|
||||
&packed_len, 0 ) != UCL_E_OK ) {
|
||||
fprintf ( stderr, "Compression failure\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->len += packed_len;
|
||||
if ( output->len > output->max_len ) {
|
||||
fprintf ( stderr, "Output buffer overrun on pack\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_zinfo_subtract ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
struct zinfo_subtract *subtract,
|
||||
size_t datasize ) {
|
||||
size_t offset = subtract->offset;
|
||||
void *target;
|
||||
long delta;
|
||||
|
||||
if ( ( offset + datasize ) > output->len ) {
|
||||
fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
|
||||
offset );
|
||||
return -1;
|
||||
}
|
||||
|
||||
target = ( output->buf + offset );
|
||||
delta = ( ( output->len / subtract->divisor ) -
|
||||
( input->len / subtract->divisor ) );
|
||||
|
||||
switch ( datasize ) {
|
||||
case 1: {
|
||||
uint8_t *byte = target;
|
||||
*byte += delta;
|
||||
break; }
|
||||
case 2: {
|
||||
uint16_t *word = target;
|
||||
*word += delta;
|
||||
break; }
|
||||
case 4: {
|
||||
uint32_t *dword = target;
|
||||
*dword += delta;
|
||||
break; }
|
||||
default:
|
||||
fprintf ( stderr, "Unsupported subtract datasize %d\n",
|
||||
datasize );
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_zinfo_subb ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
return process_zinfo_subtract ( input, output, &zinfo->subtract, 1 );
|
||||
}
|
||||
|
||||
static int process_zinfo_subw ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
return process_zinfo_subtract ( input, output, &zinfo->subtract, 2 );
|
||||
}
|
||||
|
||||
static int process_zinfo_subl ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
return process_zinfo_subtract ( input, output, &zinfo->subtract, 4 );
|
||||
}
|
||||
|
||||
struct zinfo_processor {
|
||||
char *type;
|
||||
int ( * process ) ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo );
|
||||
};
|
||||
|
||||
static struct zinfo_processor zinfo_processors[] = {
|
||||
{ "COPY", process_zinfo_copy },
|
||||
{ "PACK", process_zinfo_pack },
|
||||
{ "SUBB", process_zinfo_subb },
|
||||
{ "SUBW", process_zinfo_subw },
|
||||
{ "SUBL", process_zinfo_subl },
|
||||
};
|
||||
|
||||
static int process_zinfo ( struct input_file *input,
|
||||
struct output_file *output,
|
||||
union zinfo_record *zinfo ) {
|
||||
struct zinfo_common *common = &zinfo->common;
|
||||
struct zinfo_processor *processor;
|
||||
char type[ sizeof ( common->type ) + 1 ] = "";
|
||||
unsigned int i;
|
||||
|
||||
strncat ( type, common->type, sizeof ( type ) - 1 );
|
||||
for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
|
||||
sizeof ( zinfo_processors[0] ) ) ; i++ ) {
|
||||
processor = &zinfo_processors[i];
|
||||
if ( strcmp ( processor->type, type ) == 0 )
|
||||
return processor->process ( input, output, zinfo );
|
||||
}
|
||||
|
||||
fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int write_output_file ( struct output_file *output ) {
|
||||
if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
|
||||
fprintf ( stderr, "Could not write %d bytes of output: %s\n",
|
||||
output->len, strerror ( errno ) );
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main ( int argc, char **argv ) {
|
||||
struct input_file input;
|
||||
struct output_file output;
|
||||
struct zinfo_file zinfo;
|
||||
unsigned int i;
|
||||
|
||||
if ( argc != 3 ) {
|
||||
fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
|
||||
"> file.zbin\n", argv[0] );
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
if ( read_input_file ( argv[1], &input ) < 0 )
|
||||
exit ( 1 );
|
||||
if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
|
||||
exit ( 1 );
|
||||
if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
|
||||
exit ( 1 );
|
||||
|
||||
for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
|
||||
if ( process_zinfo ( &input, &output,
|
||||
&zinfo.zinfo[i] ) < 0 )
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
if ( write_output_file ( &output ) < 0 )
|
||||
exit ( 1 );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue