VirtualBox

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

最後變更 在這個檔案從95387是 95387,由 vboxsync 提交於 3 年 前

ValKit/bs3kit: Workaround for the FDC thinking 180K and 160K images are single sided and making them impossible to load (BIOS returns misleading drive parameters, and even if adjusted for we end up with a garbled image seemingly because we've been 'skipping' a side). bugref:9898

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.9 KB
 
1/* $Id: VBoxBs3Linker.cpp 95387 2022-06-27 11:47:22Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 "linker".
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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: 95387 $");
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 /* Avoid output sizes that makes the FDC code think it's a single sided
319 floppy. The BIOS always report double sided floppies, and even if we
320 the bootsector adjust it's bMaxHeads value when getting a 20h error
321 we end up with a garbaged image (seems somewhere in the BIOS/FDC it is
322 still treated as a double sided floppy and we get half the data we want and
323 with gaps). */
324 uint32_t cbOutput = ftell(pOutput);
325 if ( cbOutput == 512 * 8 * 40 /* 160kB 5"1/4 */
326 || cbOutput == 512 * 9 * 40 /* 180kB 5"1/4 */)
327 {
328 static uint8_t const s_abZeroSector[512] = { 0 };
329 if (fwrite(s_abZeroSector, sizeof(uint8_t), sizeof(s_abZeroSector), pOutput) != sizeof(s_abZeroSector))
330 {
331 fprintf(stderr, "error: fwrite failed (padding)\n");
332 rcExit = 1;
333 }
334 }
335
336 /* Finally, close the output file (can fail because of buffered data). */
337 if (fclose(pOutput) != 0)
338 {
339 fprintf(stderr, "error: Error closing '%s'.\n", pszOutput);
340 rcExit = 1;
341 }
342
343 fclose(stderr);
344 return rcExit;
345}
346
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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