summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorJoshua Oreman2009-08-10 07:12:21 +0200
committerMichael Brown2009-08-11 13:59:26 +0200
commitd5d68b2e310b8bf0caa6b8529f1ce7adbb92e771 (patch)
tree520a11c84f5542fbc26fb8ad0b0464432f951305 /src/util
parent[doc] Update doxygen.cfg to match version running on rom.etherboot.org (diff)
downloadipxe-d5d68b2e310b8bf0caa6b8529f1ce7adbb92e771.tar.gz
ipxe-d5d68b2e310b8bf0caa6b8529f1ce7adbb92e771.tar.xz
ipxe-d5d68b2e310b8bf0caa6b8529f1ce7adbb92e771.zip
[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>
Diffstat (limited to 'src/util')
-rw-r--r--src/util/zbin.c126
1 files changed, 76 insertions, 50 deletions
diff --git a/src/util/zbin.c b/src/util/zbin.c
index 1513289e..2adc35c9 100644
--- a/src/util/zbin.c
+++ b/src/util/zbin.c
@@ -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;
@@ -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 {
@@ -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 ),
@@ -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;
@@ -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 {
@@ -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,