]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[zbin] Change fixup semantics to support ROMs over 128k uncompressed
authorJoshua Oreman <oremanj@rwcr.net>
Mon, 10 Aug 2009 05:12:21 +0000 (22:12 -0700)
committerMichael Brown <mcb30@etherboot.org>
Tue, 11 Aug 2009 11:59:26 +0000 (12:59 +0100)
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>
src/arch/i386/prefix/dskprefix.S
src/arch/i386/prefix/hdprefix.S
src/arch/i386/prefix/lkrnprefix.S
src/arch/i386/prefix/nbiprefix.S
src/arch/i386/prefix/romprefix.S
src/arch/i386/scripts/i386.lds
src/util/zbin.c

index 2716a16becb86aa7aa32418ef8bfa3521f0604c5..60d351f72dd577fcf41f466d3618f62a23a7f58a 100644 (file)
@@ -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
index a06f10c361c1f0cdabdf901e77fd393c57ed2ab8..057675671f229042cab4496a93e21bfec2d85ad5 100644 (file)
@@ -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
index 02249f7a23b9ee48175406b181c82a73f434de42..101d0388ea8511cdf290f8982a0e5be9778e9b1b 100644 (file)
@@ -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
index 4fb4acb13f8de0de91401f3dac798e273f6c61e6..607d80fb3c95e9517db9ac8ebfbac66b18543026 100644 (file)
@@ -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
index 4b9d5447d3dba4ab2c4ad2a5100915395b63880f..cb474e812840d5323b96f043b4a794f4669f38f7 100644 (file)
@@ -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
@@ -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
@@ -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
index 8a0c6733df0469ddf9669923f799d46057422c82..52f8eb4bcddc037b27f439b19cfc70909bee983d 100644 (file)
@@ -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 );
 }
index 1513289e395dd7e0a03ed07c39f842b4c3d82109..2adc35c9719e4161d3158b2ea51d3258deaa1a24 100644 (file)
@@ -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,