Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[zbin] Change fixup semantics to support ROMs over 128k uncompressed
The option ROM header contains a one-byte field indicating the number
of 512-byte sectors in the ROM image.  Currently it is linked to
contain the number of uncompressed sectors, with an instruction to the
compressor to correct it.  This causes link failure when the
uncompressed size of the ROM image is over 128k.

Fix by replacing the SUBx compressor fixup with an ADDx fixup that
adds the total compressed output length, scaled as requested, to an
addend stored in the field where the final length value will be
placed.  This is similar to the behavior of ELF relocations, and
ensures that an overflow error will not be generated unless the
compressed size is still too large for the field.

This also allows us to do away with the _filesz_pgh and _filesz_sect
calculations exported by the linker script.

Output tested bitwise identical to the old SUBx mechanism on hd, dsk,
lkrn, and rom prefixes, on both 32-bit and 64-bit processors.

Modified-by: Michael Brown <mcb30@etherboot.org>
Signed-off-by: Michael Brown <mcb30@etherboot.org>
  • Loading branch information
rwcr authored and Michael Brown committed Aug 11, 2009
1 parent 487347a commit d5d68b2
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 75 deletions.
4 changes: 2 additions & 2 deletions src/arch/i386/prefix/dskprefix.S
Expand Up @@ -146,9 +146,9 @@ got_sectors:
/* Jump to loaded copy */
ljmp $SYSSEG, $start_runtime

endseg: .word SYSSEG + _filesz_pgh
endseg: .word SYSSEG
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.ascii "ADDW"
.long endseg
.long 16
.long 0
Expand Down
4 changes: 2 additions & 2 deletions src/arch/i386/prefix/hdprefix.S
Expand Up @@ -65,10 +65,10 @@ max_sector:
max_head:
.byte 0
load_length:
.long _filesz_sect
.long 0

.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.ascii "ADDL"
.long load_length
.long 512
.long 0
Expand Down
4 changes: 2 additions & 2 deletions src/arch/i386/prefix/lkrnprefix.S
Expand Up @@ -94,10 +94,10 @@ setup_sects:
root_flags:
.word 0
syssize:
.long _filesz_pgh - PREFIXPGH
.long -PREFIXPGH

.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.ascii "ADDL"
.long syssize
.long 16
.long 0
Expand Down
8 changes: 4 additions & 4 deletions src/arch/i386/prefix/nbiprefix.S
Expand Up @@ -30,16 +30,16 @@ segment_header:
.byte 0
.byte 0x04 /* Last segment */
.long 0x00007e00
imglen: .long _filesz - 512
memlen: .long _filesz - 512
imglen: .long -512
memlen: .long -512
.size segment_header, . - segment_header

.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.ascii "ADDL"
.long imglen
.long 1
.long 0
.ascii "SUBL"
.ascii "ADDL"
.long memlen
.long 1
.long 0
Expand Down
12 changes: 6 additions & 6 deletions src/arch/i386/prefix/romprefix.S
Expand Up @@ -33,7 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
.org 0x00
romheader:
.word 0xAA55 /* BIOS extension signature */
romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */
romheader_size: .byte 0 /* Size in 512-byte blocks */
jmp init /* Initialisation vector */
checksum:
.byte 0
Expand All @@ -46,7 +46,7 @@ checksum:
.size romheader, . - romheader

.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBB"
.ascii "ADDB"
.long romheader_size
.long 512
.long 0
Expand All @@ -61,23 +61,23 @@ pciheader:
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
pciheader_image_length:
.word _filesz_sect /* Image length */
.word 0 /* Image length */
.word 0x0001 /* Revision level */
.byte 0x00 /* Code type */
.byte 0x80 /* Last image indicator */
pciheader_runtime_length:
.word _filesz_sect /* Maximum run-time image length */
.word 0 /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
.word 0x0000 /* DMTF CLP entry point */
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader

.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.ascii "ADDW"
.long pciheader_image_length
.long 512
.long 0
.ascii "SUBW"
.ascii "ADDW"
.long pciheader_runtime_length
.long 512
.long 0
Expand Down
9 changes: 0 additions & 9 deletions src/arch/i386/scripts/i386.lds
Expand Up @@ -197,13 +197,4 @@ SECTIONS {
_prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 );
_text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 );
_data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 );

/*
* File size in paragraphs and sectors. Note that wherever the
* _filesz variables are used, there must be a corresponding
* .zinfo.fixup section.
*
*/
_filesz_pgh = ( ( _filesz + 15 ) / 16 );
_filesz_sect = ( ( _filesz + 511 ) / 512 );
}
126 changes: 76 additions & 50 deletions src/util/zbin.c
Expand Up @@ -38,7 +38,7 @@ struct zinfo_pack {
uint32_t align;
};

struct zinfo_subtract {
struct zinfo_add {
char type[4];
uint32_t offset;
uint32_t divisor;
Expand All @@ -49,7 +49,7 @@ union zinfo_record {
struct zinfo_common common;
struct zinfo_copy copy;
struct zinfo_pack pack;
struct zinfo_subtract subtract;
struct zinfo_add add;
};

struct zinfo_file {
Expand Down Expand Up @@ -157,8 +157,9 @@ static int process_zinfo_copy ( struct input_file *input,
}

if ( DEBUG ) {
fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
output->len, ( output->len + len ) );
fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
offset, ( offset + len ), output->len,
( output->len + len ) );
}

memcpy ( ( output->buf + output->len ),
Expand Down Expand Up @@ -194,8 +195,9 @@ static int process_zinfo_pack ( struct input_file *input,
}

if ( DEBUG ) {
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
output->len, ( output->len + packed_len ) );
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
offset, ( offset + len ), output->len,
( output->len + packed_len ) );
}

output->len += packed_len;
Expand All @@ -207,78 +209,102 @@ static int process_zinfo_pack ( struct input_file *input,
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;
static int process_zinfo_add ( struct input_file *input,
struct output_file *output,
struct zinfo_add *add,
size_t datasize ) {
size_t offset = add->offset;
void *target;
signed long raw_delta;
signed long delta;
unsigned long old;
unsigned long new;
signed long addend;
unsigned long size;
signed long val;
unsigned long mask;

if ( ( offset + datasize ) > output->len ) {
fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
fprintf ( stderr, "Add at %#zx outside output buffer\n",
offset );
return -1;
}

target = ( output->buf + offset );
raw_delta = ( align ( output->len, subtract->divisor ) -
align ( input->len, subtract->divisor ) );
delta = ( raw_delta / ( ( signed long ) subtract->divisor ) );
size = ( align ( output->len, add->divisor ) / add->divisor );

switch ( datasize ) {
case 1: {
uint8_t *byte = target;
old = *byte;
*byte += delta;
new = *byte;
break; }
case 2: {
uint16_t *word = target;
old = *word;
*word += delta;
new = *word;
break; }
case 4: {
uint32_t *dword = target;
old = *dword;
*dword += delta;
new = *dword;
break; }
case 1:
addend = *( ( int8_t * ) target );
break;
case 2:
addend = *( ( int16_t * ) target );
break;
case 4:
addend = *( ( int32_t * ) target );
break;
default:
fprintf ( stderr, "Unsupported subtract datasize %d\n",
fprintf ( stderr, "Unsupported add datasize %d\n",
datasize );
return -1;
}

val = size + addend;

/* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
mask = ( ( datasize < sizeof ( mask ) ) ?
( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );

if ( val < 0 ) {
fprintf ( stderr, "Add %s%#lx+%#lx at %#zx %sflows field\n",
( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
offset, ( ( addend < 0 ) ? "under" : "over" ) );
return -1;
}

if ( val & ~mask ) {
fprintf ( stderr, "Add %s%#lx+%#lx at %#zx overflows %d-byte "
"field (%d bytes too big)\n",
( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
offset, datasize,
( ( val - mask - 1 ) * add->divisor ) );
return -1;
}

switch ( datasize ) {
case 1:
*( ( uint8_t * ) target ) = val;
break;
case 2:
*( ( uint16_t * ) target ) = val;
break;
case 4:
*( ( uint32_t * ) target ) = val;
break;
}

if ( DEBUG ) {
fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#x)-(%#lx/%#x)) = %#lx\n",
offset, ( offset + datasize ), old, output->len, subtract->divisor,
input->len, subtract->divisor, new );
fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#lx+(%#lx/%#x)) = "
"%#lx\n", offset, ( offset + datasize ),
( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
output->len, add->divisor, val );
}

return 0;
}

static int process_zinfo_subb ( struct input_file *input,
static int process_zinfo_addb ( struct input_file *input,
struct output_file *output,
union zinfo_record *zinfo ) {
return process_zinfo_subtract ( input, output, &zinfo->subtract, 1 );
return process_zinfo_add ( input, output, &zinfo->add, 1 );
}

static int process_zinfo_subw ( struct input_file *input,
static int process_zinfo_addw ( struct input_file *input,
struct output_file *output,
union zinfo_record *zinfo ) {
return process_zinfo_subtract ( input, output, &zinfo->subtract, 2 );
return process_zinfo_add ( input, output, &zinfo->add, 2 );
}

static int process_zinfo_subl ( struct input_file *input,
static int process_zinfo_addl ( struct input_file *input,
struct output_file *output,
union zinfo_record *zinfo ) {
return process_zinfo_subtract ( input, output, &zinfo->subtract, 4 );
return process_zinfo_add ( input, output, &zinfo->add, 4 );
}

struct zinfo_processor {
Expand All @@ -291,9 +317,9 @@ struct zinfo_processor {
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 },
{ "ADDB", process_zinfo_addb },
{ "ADDW", process_zinfo_addw },
{ "ADDL", process_zinfo_addl },
};

static int process_zinfo ( struct input_file *input,
Expand Down

0 comments on commit d5d68b2

Please sign in to comment.