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
25typedef unsigned char byte;
26
27void 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
35long chksum_bios_get_offset( byte* data, long offset );
36byte chksum_bios_calc_value( byte* data, long offset );
37byte chksum_bios_get_value(  byte* data, long offset );
38void 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
46long chksum__32__get_offset( byte* data, long offset );
47byte chksum__32__calc_value( byte* data, long offset );
48byte chksum__32__get_value(  byte* data, long offset );
49void 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
57long chksum__mp__get_offset( byte* data, long offset );
58byte chksum__mp__calc_value( byte* data, long offset );
59byte chksum__mp__get_value(  byte* data, long offset );
60void 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
70long chksum_pcmp_get_offset( byte* data, long offset );
71byte chksum_pcmp_calc_value( byte* data, long offset );
72byte chksum_pcmp_get_value(  byte* data, long offset );
73void 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
81long chksum__pir_get_offset( byte *data, long offset );
82byte chksum__pir_calc_value( byte* data, long offset );
83byte chksum__pir_get_value(  byte* data, long offset );
84void chksum__pir_set_value(  byte* data, long offset, byte value );
85
86
87byte bios_data[LEN_BIOS_DATA];
88long bios_len;
89
90
91int 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
226write_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
242void check(int okay, char* message) {
243
244  if (!okay) {
245    printf("\n\nError. %s.\n", message);
246    exit(EXIT_FAILURE);
247  }
248}
249
250
251long chksum_bios_get_offset( byte* data, long offset ) {
252
253  return( BIOS_OFFSET );
254}
255
256
257byte 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
271byte chksum_bios_get_value( byte* data, long offset ) {
272
273  return( *( data + BIOS_OFFSET ) );
274}
275
276
277void chksum_bios_set_value( byte* data, long offset, byte value ) {
278
279  *( data + BIOS_OFFSET ) = value;
280}
281
282
283byte 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
303long 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
323byte 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
330void 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
337byte 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
357long 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
377byte 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
384void 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
391byte 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
417long 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
437byte 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
444void 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
451byte 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
472long 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
492byte 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
499void 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