diff options
Diffstat (limited to 'qemu/roms/vgabios/biossums.c')
-rw-r--r-- | qemu/roms/vgabios/biossums.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/qemu/roms/vgabios/biossums.c b/qemu/roms/vgabios/biossums.c new file mode 100644 index 000000000..d5816f420 --- /dev/null +++ b/qemu/roms/vgabios/biossums.c @@ -0,0 +1,282 @@ +/* biossums.c --- written by Eike W. for the Bochs BIOS */ +/* adapted for the LGPL'd VGABIOS by vruppert */ + +/* This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +typedef unsigned char byte; + +void check( int value, char* message ); + +#define MAX_BIOS_DATA 0x10000 + +long chksum_bios_get_offset( byte* data, long offset ); +byte chksum_bios_calc_value( byte* data, long offset ); +byte chksum_bios_get_value( byte* data, long offset ); +void chksum_bios_set_value( byte* data, long offset, byte value ); + +#define PMID_LEN 20 +#define PMID_CHKSUM 19 + +long chksum_pmid_get_offset( byte* data, long offset ); +byte chksum_pmid_calc_value( byte* data, long offset ); +byte chksum_pmid_get_value( byte* data, long offset ); +void chksum_pmid_set_value( byte* data, long offset, byte value ); + +#define PCIR_LEN 24 + +long chksum_pcir_get_offset( byte* data, long offset ); + + +byte bios_data[MAX_BIOS_DATA]; +long bios_len; + + +int main(int argc, char* argv[]) +{ + FILE* stream; + long offset, tmp_offset, pcir_offset; + byte bios_len_byte, cur_val = 0, new_val = 0; + int hits, modified; + + if (argc != 2) { + printf( "Error. Need a file-name as an argument.\n" ); + exit( EXIT_FAILURE ); + } + + if ((stream = fopen(argv[1], "rb")) == NULL) { + printf("Error opening %s for reading.\n", argv[1]); + exit(EXIT_FAILURE); + } + memset(bios_data, 0, MAX_BIOS_DATA); + bios_len = fread(bios_data, 1, MAX_BIOS_DATA, stream); + if (bios_len > MAX_BIOS_DATA) { + printf("Error reading max. 65536 Bytes from %s.\n", argv[1]); + fclose(stream); + exit(EXIT_FAILURE); + } + fclose(stream); + modified = 0; + if (bios_len < 0x8000) { + bios_len = 0x8000; + modified = 1; + } else if ((bios_len & 0x1FF) != 0) { + bios_len = (bios_len + 0x200) & ~0x1FF; + modified = 1; + } + bios_len_byte = (byte)(bios_len / 512); + if (bios_len_byte != bios_data[2]) { + if (modified == 0) { + bios_len += 0x200; + } + bios_data[2] = (byte)(bios_len / 512); + modified = 1; + } + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum_pmid_get_value( bios_data, offset ); + new_val = chksum_pmid_calc_value( bios_data, offset ); + printf( "\nPMID entry at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + hits++; + } + if ((hits == 1) && (cur_val != new_val)) { + printf("Setting checksum."); + chksum_pmid_set_value( bios_data, offset, new_val ); + if (modified == 0) { + bios_len += 0x200; + bios_data[2]++; + } + modified = 1; + } + if (hits >= 2) { + printf( "Multiple PMID entries! No checksum set." ); + } + if (hits) { + printf("\n"); + } + + offset = 0L; + pcir_offset = chksum_pcir_get_offset( bios_data, offset ); + if (pcir_offset != -1L) { + if (bios_data[pcir_offset + 16] != bios_data[2]) { + bios_data[pcir_offset + 16] = bios_data[2]; + if (modified == 0) { + bios_len += 0x200; + bios_data[2]++; + bios_data[pcir_offset + 16]++; + } + modified = 1; + } + } + + offset = 0L; + do { + offset = chksum_bios_get_offset(bios_data, offset); + cur_val = chksum_bios_get_value(bios_data, offset); + new_val = chksum_bios_calc_value(bios_data, offset); + if ((cur_val != new_val) && (modified == 0)) { + bios_len += 0x200; + bios_data[2]++; + if (pcir_offset != -1L) { + bios_data[pcir_offset + 16]++; + } + modified = 1; + } else { + printf("\nBios checksum at: 0x%4lX\n", offset); + printf("Current checksum: 0x%02X\n", cur_val); + printf("Calculated checksum: 0x%02X ", new_val); + if (cur_val != new_val) { + printf("Setting checksum."); + chksum_bios_set_value(bios_data, offset, new_val); + cur_val = new_val; + modified = 1; + } + printf( "\n" ); + } + } while (cur_val != new_val); + + if (modified == 1) { + if ((stream = fopen( argv[1], "wb")) == NULL) { + printf("Error opening %s for writing.\n", argv[1]); + exit(EXIT_FAILURE); + } + if (fwrite(bios_data, 1, bios_len, stream) < bios_len) { + printf("Error writing %d KBytes to %s.\n", bios_len / 1024, argv[1]); + fclose(stream); + exit(EXIT_FAILURE); + } + fclose(stream); + } + + return (EXIT_SUCCESS); +} + + +void check( int okay, char* message ) { + + if( !okay ) { + printf( "\n\nError. %s.\n", message ); + exit( EXIT_FAILURE ); + } +} + + +long chksum_bios_get_offset( byte* data, long offset ) { + + return (bios_len - 1); +} + + +byte chksum_bios_calc_value( byte* data, long offset ) { + + int i; + byte sum; + + sum = 0; + for( i = 0; i < offset; i++ ) { + sum = sum + *( data + i ); + } + sum = -sum; /* iso ensures -s + s == 0 on unsigned types */ + return( sum ); +} + + +byte chksum_bios_get_value( byte* data, long offset ) { + + return( *( data + offset ) ); +} + + +void chksum_bios_set_value( byte* data, long offset, byte value ) { + + *( data + offset ) = value; +} + + +byte chksum_pmid_calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + len = PMID_LEN; + check((offset + len) <= (bios_len - 1), "PMID entry length out of bounds" ); + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != PMID_CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum_pmid_get_offset( byte* data, long offset ) { + + long result = -1L; + + while ((offset + PMID_LEN) < (bios_len - 1)) { + offset = offset + 1; + if( *( data + offset + 0 ) == 'P' && \ + *( data + offset + 1 ) == 'M' && \ + *( data + offset + 2 ) == 'I' && \ + *( data + offset + 3 ) == 'D' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum_pmid_get_value( byte* data, long offset ) { + + check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" ); + return( *( data + offset + PMID_CHKSUM ) ); +} + + +void chksum_pmid_set_value( byte* data, long offset, byte value ) { + + check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" ); + *( data + offset + PMID_CHKSUM ) = value; +} + + +long chksum_pcir_get_offset( byte* data, long offset ) { + + long result = -1L; + + while ((offset + PCIR_LEN) < (bios_len - 1)) { + offset = offset + 1; + if( *( data + offset + 0 ) == 'P' && \ + *( data + offset + 1 ) == 'C' && \ + *( data + offset + 2 ) == 'I' && \ + *( data + offset + 3 ) == 'R' ) { + result = offset; + break; + } + } + return( result ); +} |