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