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
main(int argc,char * argv[])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
check(int okay,char * message)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
chksum_bios_get_offset(byte * data,long offset)251 long chksum_bios_get_offset( byte* data, long offset ) {
252
253 return( BIOS_OFFSET );
254 }
255
256
chksum_bios_calc_value(byte * data,long offset)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
chksum_bios_get_value(byte * data,long offset)271 byte chksum_bios_get_value( byte* data, long offset ) {
272
273 return( *( data + BIOS_OFFSET ) );
274 }
275
276
chksum_bios_set_value(byte * data,long offset,byte value)277 void chksum_bios_set_value( byte* data, long offset, byte value ) {
278
279 *( data + BIOS_OFFSET ) = value;
280 }
281
282
chksum__32__calc_value(byte * data,long offset)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
chksum__32__get_offset(byte * data,long offset)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
chksum__32__get_value(byte * data,long offset)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
chksum__32__set_value(byte * data,long offset,byte value)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
chksum__mp__calc_value(byte * data,long offset)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
chksum__mp__get_offset(byte * data,long offset)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
chksum__mp__get_value(byte * data,long offset)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
chksum__mp__set_value(byte * data,long offset,byte value)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
chksum_pcmp_calc_value(byte * data,long offset)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
chksum_pcmp_get_offset(byte * data,long offset)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
chksum_pcmp_get_value(byte * data,long offset)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
chksum_pcmp_set_value(byte * data,long offset,byte value)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
chksum__pir_calc_value(byte * data,long offset)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
chksum__pir_get_offset(byte * data,long offset)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
chksum__pir_get_value(byte * data,long offset)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
chksum__pir_set_value(byte * data,long offset,byte value)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