VirtualBox

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

Last change on this file since 98416 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.3 KB
Line 
1/* $Id: biossums.c 98103 2023-01-17 14:15:46Z 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
131 g_argv0 = argv[0];
132
133 if (argc != 3)
134 return fatal("Input file name and output file name required.\n");
135
136 pIn = g_pIn = fopen(argv[1], "rb");
137 if (!pIn)
138 return fatal("Error opening '%s' for reading (%s).\n", argv[1], strerror(errno));
139
140 pOut = g_pOut = fopen(argv[2], "wb");
141 if (!pOut)
142 return fatal("Error opening '%s' for writing (%s).\n", argv[2], strerror(errno));
143 g_pszOutFile = argv[2];
144
145 /* safety precaution (aka. complete paranoia :-) */
146 memset(abBios, 0, sizeof(abBios));
147
148 cbIn = fread(abBios, 1, sizeof(abBios), pIn);
149 if (ferror(pIn))
150 return fatal("Error reading from '%s' (%s).\n", argv[1], strerror(errno));
151 g_pIn = NULL;
152 fclose(pIn);
153
154 fAdapterBios = abBios[0] == 0x55 && abBios[1] == 0xaa;
155
156 /* align size to page size */
157 if ((cbIn % 4096) != 0)
158 cbIn = (cbIn + 4095) & ~4095;
159
160 if (!fAdapterBios && cbIn != 64*1024)
161 return fatal("Size of system BIOS is not 64KB!\n");
162
163 if (fAdapterBios)
164 {
165 /* adapter BIOS */
166
167 /* set the length indicator */
168 abBios[2] = (uint8_t)(cbIn / 512);
169 }
170 else
171 {
172 /* system BIOS */
173 size_t cbChecksum;
174 uint8_t u8Checksum;
175 uint8_t *pbHeader;
176
177 /* Set the BIOS32 header checksum. */
178 switch (searchHeader(abBios, cbIn, "_32_", &pbHeader))
179 {
180 case 0:
181 return fatal("No BIOS32 header not found!\n");
182 case 2:
183 return fatal("More than one BIOS32 header found!\n");
184 case 1:
185 cbChecksum = (size_t)pbHeader[9] * 16;
186 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 10);
187 pbHeader[10] = u8Checksum;
188 break;
189 }
190
191 /* Set the PIR header checksum according to PCI IRQ Routing table
192 * specification version 1.0, Microsoft Corporation, 1996 */
193 switch (searchHeader(abBios, cbIn, "$PIR", &pbHeader))
194 {
195 case 0:
196 return fatal("No PCI IRQ routing table found!\n");
197 case 2:
198 return fatal("More than one PCI IRQ routing table found!\n");
199 case 1:
200 cbChecksum = (size_t)pbHeader[6] + (size_t)pbHeader[7] * 256;
201 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 31);
202 pbHeader[31] = u8Checksum;
203 break;
204 }
205
206 /* Set the SMBIOS header checksum according to System Management BIOS
207 * Reference Specification Version 2.5, DSP0134. */
208 switch (searchHeader(abBios, cbIn, "_SM_", &pbHeader))
209 {
210 case 0:
211 return fatal("No SMBIOS header found!\n");
212 case 2:
213 return fatal("More than one SMBIOS header found!\n");
214 case 1:
215 /* at first fix the DMI header starting at SMBIOS header offset 16 */
216 u8Checksum = calculateChecksum(pbHeader+16, 15, 5);
217 pbHeader[21] = u8Checksum;
218
219 /* now fix the checksum of the whole SMBIOS header */
220 cbChecksum = (size_t)pbHeader[5];
221 u8Checksum = calculateChecksum(pbHeader, cbChecksum, 4);
222 pbHeader[4] = u8Checksum;
223 break;
224 }
225
226 /* If there is a VPD table, adjust its checksum. */
227 switch (searchHeader(abBios, cbIn, "\xAA\x55VPD", &pbHeader))
228 {
229 case 0:
230 break; /* VPD is optional */
231 case 2:
232 return fatal("More than one VPD header found!\n");
233 case 1:
234 cbChecksum = (size_t)pbHeader[5];
235 if (cbChecksum < 0x30)
236 return fatal("VPD size too small!\n");
237 u8Checksum = calculateChecksum(pbHeader, cbChecksum, cbChecksum - 1);
238 pbHeader[cbChecksum - 1] = u8Checksum;
239 break;
240 }
241 }
242
243 /* set the BIOS checksum */
244 abBios[cbIn-1] = calculateChecksum(abBios, cbIn, cbIn - 1);
245
246 cbOut = fwrite(abBios, 1, cbIn, pOut);
247 if (ferror(pOut))
248 return fatal("Error writing to '%s' (%s).\n", g_pszOutFile, strerror(errno));
249 g_pOut = NULL;
250 if (fclose(pOut))
251 return fatal("Error closing '%s' (%s).\n", g_pszOutFile, strerror(errno));
252
253 return 0;
254}
255
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette