1 /* biossums.c --- written by Eike W. for the Bochs BIOS */ 2 /* adapted for the LGPL'd VGABIOS by vruppert */ 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 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 22 typedef unsigned char byte; 23 24 void check( int value, char* message ); 25 26 #define MAX_BIOS_DATA 0x10000 27 28 long chksum_bios_get_offset( byte* data, long offset ); 29 byte chksum_bios_calc_value( byte* data, long offset ); 30 byte chksum_bios_get_value( byte* data, long offset ); 31 void chksum_bios_set_value( byte* data, long offset, byte value ); 32 33 #define PMID_LEN 20 34 #define PMID_CHKSUM 19 35 36 long chksum_pmid_get_offset( byte* data, long offset ); 37 byte chksum_pmid_calc_value( byte* data, long offset ); 38 byte chksum_pmid_get_value( byte* data, long offset ); 39 void chksum_pmid_set_value( byte* data, long offset, byte value ); 40 41 #define PCIR_LEN 24 42 43 long chksum_pcir_get_offset( byte* data, long offset ); 44 45 46 byte bios_data[MAX_BIOS_DATA]; 47 long bios_len; 48 49 50 int main(int argc, char* argv[]) 51 { 52 FILE* stream; 53 long offset, tmp_offset, pcir_offset; 54 byte bios_len_byte, cur_val = 0, new_val = 0; 55 int hits, modified; 56 57 if (argc != 2) { 58 printf( "Error. Need a file-name as an argument.\n" ); 59 exit( EXIT_FAILURE ); 60 } 61 62 if ((stream = fopen(argv[1], "rb")) == NULL) { 63 printf("Error opening %s for reading.\n", argv[1]); 64 exit(EXIT_FAILURE); 65 } 66 memset(bios_data, 0, MAX_BIOS_DATA); 67 bios_len = fread(bios_data, 1, MAX_BIOS_DATA, stream); 68 if (bios_len > MAX_BIOS_DATA) { 69 printf("Error reading max. 65536 Bytes from %s.\n", argv[1]); 70 fclose(stream); 71 exit(EXIT_FAILURE); 72 } 73 fclose(stream); 74 modified = 0; 75 if (bios_len < 0x8000) { 76 bios_len = 0x8000; 77 modified = 1; 78 } else if ((bios_len & 0x1FF) != 0) { 79 bios_len = (bios_len + 0x200) & ~0x1FF; 80 modified = 1; 81 } 82 bios_len_byte = (byte)(bios_len / 512); 83 if (bios_len_byte != bios_data[2]) { 84 if (modified == 0) { 85 bios_len += 0x200; 86 } 87 bios_data[2] = (byte)(bios_len / 512); 88 modified = 1; 89 } 90 91 hits = 0; 92 offset = 0L; 93 while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) { 94 offset = tmp_offset; 95 cur_val = chksum_pmid_get_value( bios_data, offset ); 96 new_val = chksum_pmid_calc_value( bios_data, offset ); 97 printf( "\nPMID entry at: 0x%4lX\n", offset ); 98 printf( "Current checksum: 0x%02X\n", cur_val ); 99 printf( "Calculated checksum: 0x%02X ", new_val ); 100 hits++; 101 } 102 if ((hits == 1) && (cur_val != new_val)) { 103 printf("Setting checksum."); 104 chksum_pmid_set_value( bios_data, offset, new_val ); 105 if (modified == 0) { 106 bios_len += 0x200; 107 bios_data[2]++; 108 } 109 modified = 1; 110 } 111 if (hits >= 2) { 112 printf( "Multiple PMID entries! No checksum set." ); 113 } 114 if (hits) { 115 printf("\n"); 116 } 117 118 offset = 0L; 119 pcir_offset = chksum_pcir_get_offset( bios_data, offset ); 120 if (pcir_offset != -1L) { 121 if (bios_data[pcir_offset + 16] != bios_data[2]) { 122 bios_data[pcir_offset + 16] = bios_data[2]; 123 if (modified == 0) { 124 bios_len += 0x200; 125 bios_data[2]++; 126 bios_data[pcir_offset + 16]++; 127 } 128 modified = 1; 129 } 130 } 131 132 offset = 0L; 133 do { 134 offset = chksum_bios_get_offset(bios_data, offset); 135 cur_val = chksum_bios_get_value(bios_data, offset); 136 new_val = chksum_bios_calc_value(bios_data, offset); 137 if ((cur_val != new_val) && (modified == 0)) { 138 bios_len += 0x200; 139 bios_data[2]++; 140 if (pcir_offset != -1L) { 141 bios_data[pcir_offset + 16]++; 142 } 143 modified = 1; 144 } else { 145 printf("\nBios checksum at: 0x%4lX\n", offset); 146 printf("Current checksum: 0x%02X\n", cur_val); 147 printf("Calculated checksum: 0x%02X ", new_val); 148 if (cur_val != new_val) { 149 printf("Setting checksum."); 150 chksum_bios_set_value(bios_data, offset, new_val); 151 cur_val = new_val; 152 modified = 1; 153 } 154 printf( "\n" ); 155 } 156 } while (cur_val != new_val); 157 158 if (modified == 1) { 159 if ((stream = fopen( argv[1], "wb")) == NULL) { 160 printf("Error opening %s for writing.\n", argv[1]); 161 exit(EXIT_FAILURE); 162 } 163 if (fwrite(bios_data, 1, bios_len, stream) < bios_len) { 164 printf("Error writing %d KBytes to %s.\n", bios_len / 1024, argv[1]); 165 fclose(stream); 166 exit(EXIT_FAILURE); 167 } 168 fclose(stream); 169 } 170 171 return (EXIT_SUCCESS); 172 } 173 174 175 void check( int okay, char* message ) { 176 177 if( !okay ) { 178 printf( "\n\nError. %s.\n", message ); 179 exit( EXIT_FAILURE ); 180 } 181 } 182 183 184 long chksum_bios_get_offset( byte* data, long offset ) { 185 186 return (bios_len - 1); 187 } 188 189 190 byte chksum_bios_calc_value( byte* data, long offset ) { 191 192 int i; 193 byte sum; 194 195 sum = 0; 196 for( i = 0; i < offset; i++ ) { 197 sum = sum + *( data + i ); 198 } 199 sum = -sum; /* iso ensures -s + s == 0 on unsigned types */ 200 return( sum ); 201 } 202 203 204 byte chksum_bios_get_value( byte* data, long offset ) { 205 206 return( *( data + offset ) ); 207 } 208 209 210 void chksum_bios_set_value( byte* data, long offset, byte value ) { 211 212 *( data + offset ) = value; 213 } 214 215 216 byte chksum_pmid_calc_value( byte* data, long offset ) { 217 218 int i; 219 int len; 220 byte sum; 221 222 len = PMID_LEN; 223 check((offset + len) <= (bios_len - 1), "PMID entry length out of bounds" ); 224 sum = 0; 225 for( i = 0; i < len; i++ ) { 226 if( i != PMID_CHKSUM ) { 227 sum = sum + *( data + offset + i ); 228 } 229 } 230 sum = -sum; 231 return( sum ); 232 } 233 234 235 long chksum_pmid_get_offset( byte* data, long offset ) { 236 237 long result = -1L; 238 239 while ((offset + PMID_LEN) < (bios_len - 1)) { 240 offset = offset + 1; 241 if( *( data + offset + 0 ) == 'P' && \ 242 *( data + offset + 1 ) == 'M' && \ 243 *( data + offset + 2 ) == 'I' && \ 244 *( data + offset + 3 ) == 'D' ) { 245 result = offset; 246 break; 247 } 248 } 249 return( result ); 250 } 251 252 253 byte chksum_pmid_get_value( byte* data, long offset ) { 254 255 check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" ); 256 return( *( data + offset + PMID_CHKSUM ) ); 257 } 258 259 260 void chksum_pmid_set_value( byte* data, long offset, byte value ) { 261 262 check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" ); 263 *( data + offset + PMID_CHKSUM ) = value; 264 } 265 266 267 long chksum_pcir_get_offset( byte* data, long offset ) { 268 269 long result = -1L; 270 271 while ((offset + PCIR_LEN) < (bios_len - 1)) { 272 offset = offset + 1; 273 if( *( data + offset + 0 ) == 'P' && \ 274 *( data + offset + 1 ) == 'C' && \ 275 *( data + offset + 2 ) == 'I' && \ 276 *( data + offset + 3 ) == 'R' ) { 277 result = offset; 278 break; 279 } 280 } 281 return( result ); 282 } 283