summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2007-07-16 17:58:38 +0200
committerMichael Brown2007-07-16 17:58:38 +0200
commit048bbeeebcfce2eac0a21a8eaf44a6810d685032 (patch)
treed1d55fed52f9ece7f2fc510a81725e7137ff0104
parentSplit the objcopy stage out of final image preparation to a separate (diff)
downloadipxe-048bbeeebcfce2eac0a21a8eaf44a6810d685032.tar.gz
ipxe-048bbeeebcfce2eac0a21a8eaf44a6810d685032.tar.xz
ipxe-048bbeeebcfce2eac0a21a8eaf44a6810d685032.zip
Compressed ROM images now work.
-rw-r--r--src/Makefile1
-rw-r--r--src/Makefile.housekeeping26
-rw-r--r--src/arch/i386/prefix/libprefix.S9
-rw-r--r--src/arch/i386/prefix/nonrv2b.S18
-rw-r--r--src/arch/i386/prefix/romprefix.S16
-rw-r--r--src/arch/i386/prefix/unnrv2b.S29
-rw-r--r--src/arch/i386/scripts/i386.lds25
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/zbin.c325
9 files changed, 439 insertions, 11 deletions
diff --git a/src/Makefile b/src/Makefile
index 4f50456a..d3280702 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index 12041ce6..ff52de1d 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -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.
diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S
index d1554513..0966dcbd 100644
--- a/src/arch/i386/prefix/libprefix.S
+++ b/src/arch/i386/prefix/libprefix.S
@@ -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
diff --git a/src/arch/i386/prefix/nonrv2b.S b/src/arch/i386/prefix/nonrv2b.S
new file mode 100644
index 00000000..d40396b3
--- /dev/null
+++ b/src/arch/i386/prefix/nonrv2b.S
@@ -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
diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S
index f68c14e0..3e6cd2d0 100644
--- a/src/arch/i386/prefix/romprefix.S
+++ b/src/arch/i386/prefix/romprefix.S
@@ -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
diff --git a/src/arch/i386/prefix/unnrv2b.S b/src/arch/i386/prefix/unnrv2b.S
index 4e3090e2..1cf570d0 100644
--- a/src/arch/i386/prefix/unnrv2b.S
+++ b/src/arch/i386/prefix/unnrv2b.S
@@ -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
diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds
index 7b7b95da..8ff7c45a 100644
--- a/src/arch/i386/scripts/i386.lds
+++ b/src/arch/i386/scripts/i386.lds
@@ -165,6 +165,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;
/*
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 9550102a..98adc2df 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -1,3 +1,4 @@
nrv2b
+zbin
hijack
prototester
diff --git a/src/util/zbin.c b/src/util/zbin.c
new file mode 100644
index 00000000..f47fa36b
--- /dev/null
+++ b/src/util/zbin.c
@@ -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;
+}