Home | History | Annotate | Download | only in bios
      1 /*
      2  * $Id$
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Lesser General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Lesser General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Lesser General Public
     15  *  License along with this library; if not, write to the Free Software
     16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
     17  */
     18 
     19 /* biossums.c  --- written by Eike W. for the Bochs BIOS */
     20 
     21 #include <stdlib.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 
     25 typedef unsigned char byte;
     26 
     27 void check( int value, char* message );
     28 
     29 #define LEN_BIOS_DATA 0x10000
     30 #define MAX_OFFSET    (LEN_BIOS_DATA - 1)
     31 
     32 
     33 #define BIOS_OFFSET 0xFFFF
     34 
     35 long chksum_bios_get_offset( byte* data, long offset );
     36 byte chksum_bios_calc_value( byte* data, long offset );
     37 byte chksum_bios_get_value(  byte* data, long offset );
     38 void chksum_bios_set_value(  byte* data, long offset, byte value );
     39 
     40 
     41 #define _32__LEN         9
     42 #define _32__CHKSUM     10
     43 
     44 #define _32__MINHDR     16
     45 
     46 long chksum__32__get_offset( byte* data, long offset );
     47 byte chksum__32__calc_value( byte* data, long offset );
     48 byte chksum__32__get_value(  byte* data, long offset );
     49 void chksum__32__set_value(  byte* data, long offset, byte value );
     50 
     51 
     52 #define _MP__LEN         8
     53 #define _MP__CHKSUM     10
     54 
     55 #define _MP__MINHDR     16
     56 
     57 long chksum__mp__get_offset( byte* data, long offset );
     58 byte chksum__mp__calc_value( byte* data, long offset );
     59 byte chksum__mp__get_value(  byte* data, long offset );
     60 void chksum__mp__set_value(  byte* data, long offset, byte value );
     61 
     62 
     63 #define PCMP_BASELEN     4
     64 #define PCMP_CHKSUM      7
     65 #define PCMP_EXT_LEN    40
     66 #define PCMP_EXT_CHKSUM 42
     67 
     68 #define PCMP_MINHDR     42
     69 
     70 long chksum_pcmp_get_offset( byte* data, long offset );
     71 byte chksum_pcmp_calc_value( byte* data, long offset );
     72 byte chksum_pcmp_get_value(  byte* data, long offset );
     73 void chksum_pcmp_set_value(  byte* data, long offset, byte value );
     74 
     75 
     76 #define _PIR_LEN         6
     77 #define _PIR_CHKSUM     31
     78 
     79 #define _PIR_MINHDR     32
     80 
     81 long chksum__pir_get_offset( byte *data, long offset );
     82 byte chksum__pir_calc_value( byte* data, long offset );
     83 byte chksum__pir_get_value(  byte* data, long offset );
     84 void chksum__pir_set_value(  byte* data, long offset, byte value );
     85 
     86 
     87 byte bios_data[LEN_BIOS_DATA];
     88 long bios_len;
     89 
     90 
     91 int main(int argc, char* argv[]) {
     92 
     93   FILE* stream;
     94   long  offset, tmp_offset;
     95   byte  cur_val = 0, new_val = 0;
     96   int   arg = 1, hits, pad = 0;
     97 
     98 
     99   if ((argc == 3) && (!strcmp(argv[1], "-pad"))) {
    100     pad = 1;
    101     arg = 2;
    102   } else if (argc != 2) {
    103     printf("Error. Need a file-name as an argument.\n");
    104     exit(EXIT_FAILURE);
    105   }
    106   memset(bios_data, 0xff, LEN_BIOS_DATA);
    107 
    108   if ((stream = fopen(argv[arg], "rb")) == NULL) {
    109     printf("Error opening %s for reading.\n", argv[arg]);
    110     exit(EXIT_FAILURE);
    111   }
    112   bios_len = fread(bios_data, 1, LEN_BIOS_DATA, stream);
    113   if ((bios_len < LEN_BIOS_DATA) && (pad == 0)) {
    114     printf("Error reading 64KBytes from %s.\n", argv[arg]);
    115     fclose(stream);
    116     exit(EXIT_FAILURE);
    117   }
    118   fclose(stream);
    119   if (pad == 1) goto write_bios;
    120 
    121   hits   = 0;
    122   offset = 0L;
    123   while( (tmp_offset = chksum__32__get_offset( bios_data, offset )) != -1L ) {
    124     offset  = tmp_offset;
    125     cur_val = chksum__32__get_value(  bios_data, offset );
    126     new_val = chksum__32__calc_value( bios_data, offset );
    127     printf( "\n\nPCI-Bios header at: 0x%4lX\n", offset  );
    128     printf( "Current checksum:     0x%02X\n",   cur_val );
    129     printf( "Calculated checksum:  0x%02X  ",   new_val );
    130     hits++;
    131   }
    132   if( hits == 1 && cur_val != new_val ) {
    133     printf( "Setting checksum." );
    134     chksum__32__set_value( bios_data, offset, new_val );
    135   }
    136   if( hits >= 2 ) {
    137     printf( "Multiple PCI headers! No checksum set." );
    138   }
    139   if( hits ) {
    140     printf( "\n" );
    141   }
    142 
    143 
    144   hits   = 0;
    145   offset = 0L;
    146   while( (tmp_offset = chksum__mp__get_offset( bios_data, offset )) != -1L ) {
    147     offset  = tmp_offset;
    148     cur_val = chksum__mp__get_value(  bios_data, offset );
    149     new_val = chksum__mp__calc_value( bios_data, offset );
    150     printf( "\n\nMP header at:       0x%4lX\n", offset  );
    151     printf( "Current checksum:     0x%02X\n",   cur_val );
    152     printf( "Calculated checksum:  0x%02X  ",   new_val );
    153     hits++;
    154   }
    155   if( hits == 1 && cur_val != new_val ) {
    156     printf( "Setting checksum." );
    157     chksum__mp__set_value( bios_data, offset, new_val );
    158   }
    159   if( hits >= 2 ) {
    160     printf( "Warning! Multiple MP headers. No checksum set." );
    161   }
    162   if( hits ) {
    163     printf( "\n" );
    164   }
    165 
    166 
    167   hits   = 0;
    168   offset = 0L;
    169   while( (tmp_offset = chksum_pcmp_get_offset( bios_data, offset )) != -1L ) {
    170     offset  = tmp_offset;
    171     cur_val = chksum_pcmp_get_value(  bios_data, offset );
    172     new_val = chksum_pcmp_calc_value( bios_data, offset );
    173     printf( "\n\nPCMP header at:     0x%4lX\n", offset  );
    174     printf( "Current checksum:     0x%02X\n",   cur_val );
    175     printf( "Calculated checksum:  0x%02X  ",   new_val );
    176     hits++;
    177   }
    178   if( hits == 1 && cur_val != new_val ) {
    179     printf( "Setting checksum." );
    180     chksum_pcmp_set_value( bios_data, offset, new_val );
    181   }
    182   if( hits >= 2 ) {
    183     printf( "Warning! Multiple PCMP headers. No checksum set." );
    184   }
    185   if( hits ) {
    186     printf( "\n" );
    187   }
    188 
    189 
    190   hits   = 0;
    191   offset = 0L;
    192   while( (tmp_offset = chksum__pir_get_offset( bios_data, offset )) != -1L ) {
    193     offset  = tmp_offset;
    194     cur_val = chksum__pir_get_value(  bios_data, offset );
    195     new_val = chksum__pir_calc_value( bios_data, offset );
    196     printf( "\n\n$PIR header at:     0x%4lX\n", offset  );
    197     printf( "Current checksum:     0x%02X\n",   cur_val );
    198     printf( "Calculated checksum:  0x%02X\n  ",  new_val );
    199     hits++;
    200   }
    201   if( hits == 1 && cur_val != new_val ) {
    202     printf( "Setting checksum." );
    203     chksum__pir_set_value( bios_data, offset, new_val );
    204   }
    205   if( hits >= 2 ) {
    206     printf( "Warning! Multiple $PIR headers. No checksum set." );
    207   }
    208   if( hits ) {
    209     printf( "\n" );
    210   }
    211 
    212 
    213   offset  = 0L;
    214   offset  = chksum_bios_get_offset( bios_data, offset );
    215   cur_val = chksum_bios_get_value(  bios_data, offset );
    216   new_val = chksum_bios_calc_value( bios_data, offset );
    217   printf( "\n\nBios checksum at:   0x%4lX\n", offset  );
    218   printf( "Current checksum:     0x%02X\n",   cur_val );
    219   printf( "Calculated checksum:  0x%02X  ",   new_val );
    220   if( cur_val != new_val ) {
    221     printf( "Setting checksum." );
    222     chksum_bios_set_value( bios_data, offset, new_val );
    223   }
    224   printf( "\n" );
    225 
    226 write_bios:
    227   if ((stream = fopen(argv[arg], "wb")) == NULL) {
    228     printf("Error opening %s for writing.\n", argv[arg]);
    229     exit(EXIT_FAILURE);
    230   }
    231   if (fwrite(bios_data, 1, LEN_BIOS_DATA, stream) < LEN_BIOS_DATA) {
    232     printf("Error writing 64KBytes to %s.\n", argv[arg]);
    233     fclose(stream);
    234     exit(EXIT_FAILURE);
    235   }
    236   fclose(stream);
    237 
    238   return(EXIT_SUCCESS);
    239 }
    240 
    241 
    242 void check(int okay, char* message) {
    243 
    244   if (!okay) {
    245     printf("\n\nError. %s.\n", message);
    246     exit(EXIT_FAILURE);
    247   }
    248 }
    249 
    250 
    251 long chksum_bios_get_offset( byte* data, long offset ) {
    252 
    253   return( BIOS_OFFSET );
    254 }
    255 
    256 
    257 byte chksum_bios_calc_value( byte* data, long offset ) {
    258 
    259   int   i;
    260   byte  sum;
    261 
    262   sum = 0;
    263   for( i = 0; i < MAX_OFFSET; i++ ) {
    264     sum = sum + *( data + i );
    265   }
    266   sum = -sum;          /* iso ensures -s + s == 0 on unsigned types */
    267   return( sum );
    268 }
    269 
    270 
    271 byte chksum_bios_get_value( byte* data, long offset ) {
    272 
    273   return( *( data + BIOS_OFFSET ) );
    274 }
    275 
    276 
    277 void chksum_bios_set_value( byte* data, long offset, byte value ) {
    278 
    279   *( data + BIOS_OFFSET ) = value;
    280 }
    281 
    282 
    283 byte chksum__32__calc_value( byte* data, long offset ) {
    284 
    285   int           i;
    286   int           len;
    287   byte sum;
    288 
    289   check( offset + _32__MINHDR <= MAX_OFFSET, "_32_ header out of bounds" );
    290   len = *( data + offset + _32__LEN ) << 4;
    291   check( offset + len <= MAX_OFFSET, "_32_ header-length out of bounds" );
    292   sum = 0;
    293   for( i = 0; i < len; i++ ) {
    294     if( i != _32__CHKSUM ) {
    295       sum = sum + *( data + offset + i );
    296     }
    297   }
    298   sum = -sum;
    299   return( sum );
    300 }
    301 
    302 
    303 long chksum__32__get_offset( byte* data, long offset ) {
    304 
    305   long result = -1L;
    306 
    307   offset = offset + 0x0F;
    308   offset = offset & ~( 0x0F );
    309   while( offset + 16 < MAX_OFFSET ) {
    310     offset = offset + 16;
    311     if( *( data + offset + 0 ) == '_' && \
    312         *( data + offset + 1 ) == '3' && \
    313         *( data + offset + 2 ) == '2' && \
    314         *( data + offset + 3 ) == '_' ) {
    315       result = offset;
    316       break;
    317     }
    318   }
    319   return( result );
    320 }
    321 
    322 
    323 byte chksum__32__get_value( byte* data, long offset ) {
    324 
    325   check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
    326   return(  *( data + offset + _32__CHKSUM ) );
    327 }
    328 
    329 
    330 void chksum__32__set_value( byte* data, long offset, byte value ) {
    331 
    332   check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
    333   *( data + offset + _32__CHKSUM ) = value;
    334 }
    335 
    336 
    337 byte chksum__mp__calc_value( byte* data, long offset ) {
    338 
    339   int   i;
    340   int   len;
    341   byte  sum;
    342 
    343   check( offset + _MP__MINHDR <= MAX_OFFSET, "_MP_ header out of bounds" );
    344   len = *( data + offset + _MP__LEN ) << 4;
    345   check( offset + len <= MAX_OFFSET, "_MP_ header-length out of bounds" );
    346   sum = 0;
    347   for( i = 0; i < len; i++ ) {
    348     if( i != _MP__CHKSUM ) {
    349       sum = sum + *( data + offset + i );
    350     }
    351   }
    352   sum = -sum;
    353   return( sum );
    354 }
    355 
    356 
    357 long chksum__mp__get_offset( byte* data, long offset ) {
    358 
    359   long result = -1L;
    360 
    361   offset = offset + 0x0F;
    362   offset = offset & ~( 0x0F );
    363   while( offset + 16 < MAX_OFFSET ) {
    364     offset = offset + 16;
    365     if( *( data + offset + 0 ) == '_' && \
    366         *( data + offset + 1 ) == 'M' && \
    367         *( data + offset + 2 ) == 'P' && \
    368         *( data + offset + 3 ) == '_' ) {
    369       result = offset;
    370       break;
    371     }
    372   }
    373   return( result );
    374 }
    375 
    376 
    377 byte chksum__mp__get_value( byte* data, long offset ) {
    378 
    379   check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
    380   return( *( data + offset + _MP__CHKSUM ) );
    381 }
    382 
    383 
    384 void chksum__mp__set_value( byte* data, long offset, byte value ) {
    385 
    386   check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
    387   *( data + offset + _MP__CHKSUM ) = value;
    388 }
    389 
    390 
    391 byte chksum_pcmp_calc_value( byte* data, long offset ) {
    392 
    393   int   i;
    394   int   len;
    395   byte  sum;
    396 
    397   check( offset + PCMP_MINHDR <= MAX_OFFSET, "PCMP header out of bounds" );
    398   len  =   *( data + offset + PCMP_BASELEN )      + \
    399          ( *( data + offset + PCMP_BASELEN + 1 ) << 8 );
    400   check( offset + len <= MAX_OFFSET, "PCMP header-length out of bounds" );
    401   if( *( data + offset + PCMP_EXT_LEN )     | \
    402       *( data + offset + PCMP_EXT_LEN + 1 ) | \
    403       *( data + offset + PCMP_EXT_CHKSUM ) ) {
    404     check( 0, "PCMP header indicates extended tables (unsupported)" );
    405   }
    406   sum = 0;
    407   for( i = 0; i < len; i++ ) {
    408     if( i != PCMP_CHKSUM ) {
    409       sum = sum + *( data + offset + i );
    410     }
    411   }
    412   sum = -sum;
    413   return( sum );
    414 }
    415 
    416 
    417 long chksum_pcmp_get_offset( byte* data, long offset ) {
    418 
    419   long result = -1L;
    420 
    421   offset = offset + 0x0F;
    422   offset = offset & ~( 0x0F );
    423   while( offset + 16 < MAX_OFFSET ) {
    424     offset = offset + 16;
    425     if( *( data + offset + 0 ) == 'P' && \
    426         *( data + offset + 1 ) == 'C' && \
    427         *( data + offset + 2 ) == 'M' && \
    428         *( data + offset + 3 ) == 'P' ) {
    429       result = offset;
    430       break;
    431     }
    432   }
    433   return( result );
    434 }
    435 
    436 
    437 byte chksum_pcmp_get_value( byte* data, long offset ) {
    438 
    439   check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
    440   return( *( data + offset + PCMP_CHKSUM ) );
    441 }
    442 
    443 
    444 void chksum_pcmp_set_value( byte* data, long offset, byte value ) {
    445 
    446   check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
    447   *( data + offset + PCMP_CHKSUM ) = value;
    448 }
    449 
    450 
    451 byte chksum__pir_calc_value( byte* data, long offset ) {
    452 
    453   int   i;
    454   int   len;
    455   byte  sum;
    456 
    457   check( offset + _PIR_MINHDR <= MAX_OFFSET, "$PIR header out of bounds" );
    458   len  =   *( data + offset + _PIR_LEN )      + \
    459          ( *( data + offset + _PIR_LEN + 1 ) << 8 );
    460   check( offset + len <= MAX_OFFSET, "$PIR header-length out of bounds" );
    461   sum = 0;
    462   for( i = 0; i < len; i++ ) {
    463     if( i != _PIR_CHKSUM ) {
    464       sum = sum + *( data + offset + i );
    465     }
    466   }
    467   sum = -sum;
    468   return( sum );
    469 }
    470 
    471 
    472 long chksum__pir_get_offset( byte* data, long offset ) {
    473 
    474   long result = -1L;
    475 
    476   offset = offset + 0x0F;
    477   offset = offset & ~( 0x0F );
    478   while( offset + 16 < MAX_OFFSET ) {
    479     offset = offset + 16;
    480     if( *( data + offset + 0 ) == '$' && \
    481         *( data + offset + 1 ) == 'P' && \
    482         *( data + offset + 2 ) == 'I' && \
    483         *( data + offset + 3 ) == 'R' ) {
    484       result = offset;
    485       break;
    486     }
    487   }
    488   return( result );
    489 }
    490 
    491 
    492 byte chksum__pir_get_value( byte* data, long offset ) {
    493 
    494   check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
    495   return(  *( data + offset + _PIR_CHKSUM ) );
    496 }
    497 
    498 
    499 void chksum__pir_set_value( byte* data, long offset, byte value ) {
    500 
    501   check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
    502   *( data + offset + _PIR_CHKSUM ) = value;
    503 }
    504 
    505