VirtualBox

source: vbox/trunk/src/bldprogs/biossums.c

Last change on this file was 100658, checked in by vboxsync, 10 months ago

BIOS: Reworked BIOS build to have a common core and add 286/386 specific modules (see bugref:6549).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/* $Id: biossums.c 100658 2023-07-20 07:43:52Z vboxsync $ */
2/** @file
3 * Tool for modifying a BIOS image to write the BIOS checksum.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <stdarg.h>
32#include <errno.h>
33#ifndef RT_OS_WINDOWS
34# include <unistd.h> /* unlink */
35#endif
36
37typedef unsigned char uint8_t;
38
39static uint8_t abBios[64*1024];
40static FILE *g_pIn = NULL;
41static FILE *g_pOut = NULL;
42static const char *g_pszOutFile = NULL;
43static const char *g_argv0;
44
45/**
46 * Find where the filename starts in the given path.
47 */
48static const char *name(const char *pszPath)
49{
50 const char *psz = strrchr(pszPath, '/');
51#if defined(_MSC_VER) || defined(__OS2__)
52 const char *psz2 = strrchr(pszPath, '\\');
53 if (!psz2)
54 psz2 = strrchr(pszPath, ':');
55 if (psz2 && (!psz || psz2 > psz))
56 psz = psz2;
57#endif
58 return psz ? psz + 1 : pszPath;
59}
60
61/**
62 * Report an error.
63 */
64static int fatal(const char *pszFormat, ...)
65{
66 va_list va;
67
68 fprintf(stderr, "%s: ", name(g_argv0));
69
70 va_start(va, pszFormat);
71 vfprintf(stderr, pszFormat, va);
72 va_end(va);
73
74 /* clean up */
75 if (g_pIn)
76 fclose(g_pIn);
77 if (g_pOut)
78 fclose(g_pOut);
79 if (g_pszOutFile)
80 unlink(g_pszOutFile);
81
82 return 1;
83}
84
85/**
86 * Calculate the checksum.
87 */
88static uint8_t calculateChecksum(uint8_t *pb, size_t cb, size_t iChecksum)
89{
90 uint8_t u8Sum = 0;
91 size_t i;
92
93 for (i = 0; i < cb; i++)
94 if (i != iChecksum)
95 u8Sum += pb[i];
96
97 return -u8Sum;
98}
99
100/**
101 * Find a header in the binary.
102 *
103 * @param pb Where to search for the signature
104 * @param cb Size of the search area
105 * @param pbHeader Pointer to the start of the signature
106 * @returns 0 if signature was not found, 1 if found or
107 * 2 if more than one signature was found */
108static int searchHeader(uint8_t *pb, size_t cb, const char *pszHeader, uint8_t **pbHeader)
109{
110 int fFound = 0;
111 unsigned int i;
112 size_t cbSignature = strlen(pszHeader);
113
114 for (i = 0; i < cb; i += 16)
115 if (!memcmp(pb + i, pszHeader, cbSignature))
116 {
117 if (fFound++)
118 return 2;
119 *pbHeader = pb + i;
120 }
121
122 return fFound;
123}
124
125int main(int argc, char **argv)
126{
127 FILE *pIn, *pOut;
128 size_t cbIn, cbOut;
129 int fAdapterBios = 0;
130 int fPIRQRequired = 0;
131 int fBIOS32Required = 0;
132 int fSMBIOSRequired = 0;
133
134 g_argv0 = argv[0];
135
136 while ((argc > 1) && (argv[1][0] == '-'))
137 {
138 if (!strcmp(argv[1], "-3"))
139 fBIOS32Required = 1;
140 else if (!strcmp(argv[1], "-p"))
141 fPIRQRequired = 1;
142 else if (!strcmp(argv[1], "-s"))
143 fSMBIOSRequired = 1;
144 else
145 return fatal("Invalid parameter: %s\n", argv[1]);
146
147 argc--;
148 argv++;
149 }
150
151 if (argc != 3)
152 return fatal("Input file name and output file name required.\n");
153
154 pIn = g_pIn = fopen(argv[1], "rb");
155 if (!pIn)
156 return fatal("Error opening '%s' for reading (%s).\n", argv[1], strerror(errno));
157
158 pOut = g_pOut = fopen(argv[2], "wb");
159 if (!pOut)
160 return fatal("Error opening '%s' for writing (%s).\n", argv[2], strerror(errno));
161 g_pszOutFile = argv[2];
162
163 /* safety precaution (aka. complete paranoia :-) */
164 memset(abBios, 0, sizeof(abBios));
165
166 cbIn = fread(abBios, 1, sizeof(abBios), pIn);
167 if (ferror(pIn))
168 return fatal("Error reading from '%s' (%s).\n", argv[1], strerror(errno));
169 g_pIn = NULL;
170 fclose(pIn);
171
172 fAdapterBios = abBios[0] == 0x55 && abBios[1] == 0xaa;
173
174 /* align size to page size */
175 if ((cbIn % 4096) != 0)
176 cbIn = (cbIn + 4095) & ~4095;
177
178 if (!fAdapterBios && cbIn != 64*1024)
179 return fatal("Size of system BIOS is not 64KB!\n");
180
181 if (fAdapterBios)
182 {
183 /* adapter BIOS */
184
185 /* set the length indicator */
186 abBios[2] = (uint8_t)(cbIn / 512);
187 }
188 else
189 {
190 /* system BIOS */
191 size_t cbChecksum;
192 uint8_t u8Checksum;
193 uint8_t *pbHeader;
194
195 /* Set the BIOS32 header checksum. */
196 switch (searchHeader(abBios, cbIn, "_32_", &pbHeader))
197 {
198 case 0:
199 if (fBIOS32Required)
200 return fatal("No BIOS32 header found!\n");
201 else
202 break;
203 case 2:
204 return fatal("More than one BIOS32 header found!\n");
205 case 1:
206 cbChecksum = (size_t)pbHeader[9] * 16;
207 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 10);
208 pbHeader[10] = u8Checksum;
209 break;
210 }
211
212 /* Set the PIR header checksum according to PCI IRQ Routing table
213 * specification version 1.0, Microsoft Corporation, 1996 */
214 switch (searchHeader(abBios, cbIn, "$PIR", &pbHeader))
215 {
216 case 0:
217 if (fPIRQRequired)
218 return fatal("No PCI IRQ routing table found!\n");
219 else
220 break;
221 case 2:
222 return fatal("More than one PCI IRQ routing table found!\n");
223 case 1:
224 cbChecksum = (size_t)pbHeader[6] + (size_t)pbHeader[7] * 256;
225 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 31);
226 pbHeader[31] = u8Checksum;
227 break;
228 }
229
230 /* Set the SMBIOS header checksum according to System Management BIOS
231 * Reference Specification Version 2.5, DSP0134. */
232 switch (searchHeader(abBios, cbIn, "_SM_", &pbHeader))
233 {
234 case 0:
235 if (fBIOS32Required)
236 return fatal("No SMBIOS header found!\n");
237 else
238 break;
239 case 2:
240 return fatal("More than one SMBIOS header found!\n");
241 case 1:
242 /* at first fix the DMI header starting at SMBIOS header offset 16 */
243 u8Checksum = calculateChecksum(pbHeader+16, 15, 5);
244 pbHeader[21] = u8Checksum;
245
246 /* now fix the checksum of the whole SMBIOS header */
247 cbChecksum = (size_t)pbHeader[5];
248 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 4);
249 pbHeader[4] = u8Checksum;
250 break;
251 }
252
253 /* If there is a VPD table, adjust its checksum. */
254 switch (searchHeader(abBios, cbIn, "\xAA\x55VPD", &pbHeader))
255 {
256 case 0:
257 break; /* VPD is optional */
258 case 2:
259 return fatal("More than one VPD header found!\n");
260 case 1:
261 cbChecksum = (size_t)pbHeader[5];
262 if (cbChecksum < 0x30)
263 return fatal("VPD size too small!\n");
264 u8Checksum = calculateChecksum(pbHeader, cbChecksum, cbChecksum - 1);
265 pbHeader[cbChecksum - 1] = u8Checksum;
266 break;
267 }
268 }
269
270 /* set the BIOS checksum */
271 abBios[cbIn-1] = calculateChecksum(abBios, cbIn, cbIn - 1);
272
273 cbOut = fwrite(abBios, 1, cbIn, pOut);
274 if (ferror(pOut))
275 return fatal("Error writing to '%s' (%s).\n", g_pszOutFile, strerror(errno));
276 g_pOut = NULL;
277 if (fclose(pOut))
278 return fatal("Error closing '%s' (%s).\n", g_pszOutFile, strerror(errno));
279
280 return 0;
281}
282
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use