VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp@ 77922

Last change on this file since 77922 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: VBoxBs3Linker.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 "linker".
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <iprt/types.h>
35#include <iprt/assert.h>
36
37
38/*********************************************************************************************************************************
39* Structures and Typedefs *
40*********************************************************************************************************************************/
41#pragma pack(1)
42typedef struct BS3BOOTSECTOR
43{
44 uint8_t abJmp[3];
45 char abOemId[8];
46 /** @name EBPB, DOS 4.0 style.
47 * @{ */
48 uint16_t cBytesPerSector; /**< 00bh */
49 uint8_t cSectorsPerCluster; /**< 00dh */
50 uint16_t cReservedSectors; /**< 00eh */
51 uint8_t cFATs; /**< 010h */
52 uint16_t cRootDirEntries; /**< 011h */
53 uint16_t cTotalSectors; /**< 013h */
54 uint8_t bMediaDescriptor; /**< 015h */
55 uint16_t cSectorsPerFAT; /**< 016h */
56 uint16_t cPhysSectorsPerTrack; /**< 018h */
57 uint16_t cHeads; /**< 01ah */
58 uint32_t cHiddentSectors; /**< 01ch */
59 uint32_t cLargeTotalSectors; /**< 020h - We (ab)use this to indicate the number of sectors to load. */
60 uint8_t bBootDrv; /**< 024h */
61 uint8_t bFlagsEtc; /**< 025h */
62 uint8_t bExtendedSignature; /**< 026h */
63 uint32_t dwSerialNumber; /**< 027h */
64 char abLabel[11]; /**< 02bh */
65 char abFSType[8]; /**< 036h */
66 /** @} */
67} BS3BOOTSECTOR;
68#pragma pack()
69typedef BS3BOOTSECTOR *PBS3BOOTSECTOR;
70
71AssertCompileMemberOffset(BS3BOOTSECTOR, cLargeTotalSectors, 0x20);
72AssertCompileMemberOffset(BS3BOOTSECTOR, abLabel, 0x2b);
73AssertCompileMemberOffset(BS3BOOTSECTOR, abFSType, 0x36);
74
75#define BS3_OEMID "BS3Kit\n\n"
76#define BS3_FSTYPE "RawCode\n"
77#define BS3_LABEL "VirtualBox\n"
78#define BS3_MAX_SIZE UINT32_C(491520) /* 480KB */
79
80
81int main(int argc, char **argv)
82{
83 const char *pszOutput = NULL;
84 struct BS3LNKINPUT
85 {
86 const char *pszFile;
87 FILE *pFile;
88 uint32_t cbFile;
89 } *paInputs = (struct BS3LNKINPUT *)calloc(sizeof(paInputs[0]), argc);
90 unsigned cInputs = 0;
91 uint32_t cSectors = 0;
92
93 /*
94 * Scan the arguments.
95 */
96 for (int i = 1; i < argc; i++)
97 {
98 if (argv[i][0] == '-')
99 {
100 const char *pszOpt = &argv[i][1];
101 if (*pszOpt == '-')
102 {
103 /* Convert long options to short ones. */
104 pszOpt--;
105 if (!strcmp(pszOpt, "--output"))
106 pszOpt = "o";
107 else if (!strcmp(pszOpt, "--version"))
108 pszOpt = "V";
109 else if (!strcmp(pszOpt, "--help"))
110 pszOpt = "h";
111 else
112 {
113 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
114 free(paInputs);
115 return 2;
116 }
117 }
118
119 /* Process the list of short options. */
120 while (*pszOpt)
121 {
122 switch (*pszOpt++)
123 {
124 case 'o':
125 {
126 const char *pszValue = pszOpt;
127 pszOpt = strchr(pszOpt, '\0');
128 if (*pszValue == '=')
129 pszValue++;
130 else if (!*pszValue)
131 {
132 if (i + 1 >= argc)
133 {
134 fprintf(stderr, "syntax error: The --output option expects a filename.\n");
135 free(paInputs);
136 return 12;
137 }
138 pszValue = argv[++i];
139 }
140 if (pszOutput)
141 {
142 fprintf(stderr, "Only one output file is allowed. You've specified '%s' and '%s'\n",
143 pszOutput, pszValue);
144 free(paInputs);
145 return 2;
146 }
147 pszOutput = pszValue;
148 pszOpt = "";
149 break;
150 }
151
152 case 'V':
153 printf("%s\n", "$Revision: 76553 $");
154 free(paInputs);
155 return 0;
156
157 case '?':
158 case 'h':
159 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
160 argv[0]);
161 free(paInputs);
162 return 0;
163 }
164 }
165 }
166 else
167 {
168 /*
169 * Add to input file collection.
170 */
171 paInputs[cInputs].pszFile = argv[i];
172#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
173 FILE *pFile = fopen(paInputs[cInputs].pszFile, "rb");
174#else
175 FILE *pFile = fopen(paInputs[cInputs].pszFile, "r");
176#endif
177 if (pFile)
178 {
179 if (fseek(pFile, 0, SEEK_END) == 0)
180 {
181 paInputs[cInputs].cbFile = (uint32_t)ftell(pFile);
182 if (fseek(pFile, 0, SEEK_SET) == 0)
183 {
184 if (cInputs != 0 || paInputs[cInputs].cbFile == 512)
185 {
186 cSectors += RT_ALIGN_32(paInputs[cInputs].cbFile, 512) / 512;
187 if (cSectors <= BS3_MAX_SIZE / 512)
188 {
189 if (cSectors > 0)
190 {
191 paInputs[cInputs].pFile = pFile;
192 pFile = NULL;
193 }
194 else
195 fprintf(stderr, "error: empty input file: '%s'\n", paInputs[cInputs].pszFile);
196 }
197 else
198 fprintf(stderr, "error: input is too big: %u bytes, %u sectors (max %u bytes, %u sectors)\n"
199 "info: detected loading '%s'\n",
200 cSectors * 512, cSectors, BS3_MAX_SIZE, BS3_MAX_SIZE / 512,
201 paInputs[cInputs].pszFile);
202 }
203 else
204 fprintf(stderr, "error: first input file (%s) must be exactly 512 bytes\n", paInputs[cInputs].pszFile);
205 }
206 else
207 fprintf(stderr, "error: seeking to start of '%s' failed\n", paInputs[cInputs].pszFile);
208 }
209 else
210 fprintf(stderr, "error: seeking to end of '%s' failed\n", paInputs[cInputs].pszFile);
211 }
212 else
213 fprintf(stderr, "error: Failed to open input file '%s' for reading\n", paInputs[cInputs].pszFile);
214 if (pFile)
215 {
216 free(paInputs);
217 return 1;
218 }
219 cInputs++;
220 }
221 }
222
223 if (!pszOutput)
224 {
225 fprintf(stderr, "syntax error: No output file was specified (-o or --output).\n");
226 free(paInputs);
227 return 2;
228 }
229 if (cInputs == 0)
230 {
231 fprintf(stderr, "syntax error: No input files was specified.\n");
232 free(paInputs);
233 return 2;
234 }
235
236 /*
237 * Do the job.
238 */
239 /* Open the output file. */
240#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
241 FILE *pOutput = fopen(pszOutput, "wb");
242#else
243 FILE *pOutput = fopen(pszOutput, "w");
244#endif
245 if (!pOutput)
246 {
247 fprintf(stderr, "error: Failed to open output file '%s' for writing\n", pszOutput);
248 free(paInputs);
249 return 1;
250 }
251
252 /* Copy the input files to the output file, with sector padding applied. */
253 int rcExit = 0;
254 size_t off = 0;
255 for (unsigned i = 0; i < cInputs && rcExit == 0; i++)
256 {
257 uint8_t abBuf[4096]; /* Must be multiple of 512! */
258 uint32_t cbToRead = paInputs[i].cbFile;
259 while (cbToRead > 0)
260 {
261 /* Read a block from the input file. */
262 uint32_t const cbThisRead = RT_MIN(cbToRead, sizeof(abBuf));
263 size_t cbRead = fread(abBuf, sizeof(uint8_t), cbThisRead, paInputs[i].pFile);
264 if (cbRead != cbThisRead)
265 {
266 fprintf(stderr, "error: Error reading '%s' (got %d bytes, wanted %u).\n",
267 paInputs[i].pszFile, (int)cbRead, (unsigned)cbThisRead);
268 rcExit = 1;
269 break;
270 }
271 cbToRead -= cbThisRead;
272
273 /* Padd the end of the file if necessary. */
274 if ((cbRead & 0x1ff) != 0)
275 {
276 memset(&abBuf[cbRead], 0, 4096 - cbRead);
277 cbRead = (cbRead + 0x1ff) & ~0x1ffU;
278 }
279
280 /* Patch the BPB of the first file. */
281 if (off == 0)
282 {
283 PBS3BOOTSECTOR pBs = (PBS3BOOTSECTOR)&abBuf[0];
284 if ( memcmp(pBs->abLabel, RT_STR_TUPLE(BS3_LABEL)) == 0
285 && memcmp(pBs->abFSType, RT_STR_TUPLE(BS3_FSTYPE)) == 0
286 && memcmp(pBs->abOemId, RT_STR_TUPLE(BS3_OEMID)) == 0)
287 pBs->cLargeTotalSectors = cSectors;
288 else
289 {
290 fprintf(stderr, "error: Didn't find magic strings in the first file (%s).\n", paInputs[i].pszFile);
291 rcExit = 1;
292 }
293 }
294
295 /* Write the block to the output file. */
296 if (fwrite(abBuf, sizeof(uint8_t), cbRead, pOutput) == cbRead)
297 off += cbRead;
298 else
299 {
300 fprintf(stderr, "error: fwrite failed\n");
301 rcExit = 1;
302 break;
303 }
304 }
305
306 if (ferror(paInputs[i].pFile))
307 {
308 fprintf(stderr, "error: Error reading '%s'.\n", paInputs[i].pszFile);
309 rcExit = 1;
310 }
311 }
312
313 /* Close the input files. */
314 for (unsigned i = 0; i < cInputs && rcExit == 0; i++)
315 fclose(paInputs[i].pFile);
316 free(paInputs);
317
318 /* Finally, close the output file (can fail because of buffered data). */
319 if (fclose(stderr) != 0)
320 {
321 fprintf(stderr, "error: Error closing '%s'.\n", pszOutput);
322 rcExit = 1;
323 }
324
325 fclose(pOutput);
326 return rcExit;
327}
328
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