VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevPcBios.cpp@ 27692

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

Pass boot NIC PCI dev/fn separately to DevPcBios. Easier to understand and modify.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 47.6 KB
 
1/* $Id: DevPcBios.cpp 27692 2010-03-25 10:32:25Z vboxsync $ */
2/** @file
3 * PC BIOS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
26#include <VBox/pdmdev.h>
27#include <VBox/mm.h>
28#include <VBox/pgm.h>
29
30#include <VBox/log.h>
31#include <iprt/assert.h>
32#include <iprt/alloc.h>
33#include <iprt/buildconfig.h>
34#include <iprt/file.h>
35#include <iprt/string.h>
36#include <iprt/uuid.h>
37#include <VBox/err.h>
38#include <VBox/param.h>
39
40#include "../Builtins.h"
41#include "../Builtins2.h"
42#include "DevPcBios.h"
43#include "DevFwCommon.h"
44
45#define NET_BOOT_DEVS 4
46
47
48/** @page pg_devbios_cmos_assign CMOS Assignments (BIOS)
49 *
50 * The BIOS uses a CMOS to store configuration data.
51 * It is currently used as follows:
52 *
53 * @verbatim
54 First CMOS bank (offsets 0x00 to 0x7f):
55 Base memory:
56 0x15
57 0x16
58 Extended memory:
59 0x17
60 0x18
61 0x30
62 0x31
63 Amount of memory above 16M and below 4GB in 64KB units:
64 0x34
65 0x35
66 Boot device (BOCHS bios specific):
67 0x3d
68 0x38
69 0x3c
70 PXE debug:
71 0x3f
72 Floppy drive type:
73 0x10
74 Equipment byte:
75 0x14
76 First HDD:
77 0x19
78 0x1e - 0x25
79 Second HDD:
80 0x1a
81 0x26 - 0x2d
82 Third HDD:
83 0x67 - 0x6e
84 Fourth HDD:
85 0x70 - 0x77
86 Extended:
87 0x12
88 First Sata HDD:
89 0x40 - 0x47
90 Second Sata HDD:
91 0x48 - 0x4f
92 Third Sata HDD:
93 0x50 - 0x57
94 Fourth Sata HDD:
95 0x58 - 0x5f
96 Number of CPUs:
97 0x60
98 RAM above 4G in 64KB units:
99 0x61 - 0x65
100
101 Second CMOS bank (offsets 0x80 to 0xff):
102 Reserved for future use:
103 0x80 - 0x81
104 First net boot device PCI bus/dev/fn:
105 0x82 - 0x83
106 Second to third net boot devices:
107 0x84 - 0x89
108@endverbatim
109 *
110 * @todo Mark which bits are compatible with which BIOSes and
111 * which are our own definitions.
112 */
113
114
115/*******************************************************************************
116* Structures and Typedefs *
117*******************************************************************************/
118
119/**
120 * The boot device.
121 */
122typedef enum DEVPCBIOSBOOT
123{
124 DEVPCBIOSBOOT_NONE,
125 DEVPCBIOSBOOT_FLOPPY,
126 DEVPCBIOSBOOT_HD,
127 DEVPCBIOSBOOT_DVD,
128 DEVPCBIOSBOOT_LAN
129} DEVPCBIOSBOOT;
130
131/**
132 * PC Bios instance data structure.
133 */
134typedef struct DEVPCBIOS
135{
136 /** Pointer back to the device instance. */
137 PPDMDEVINS pDevIns;
138
139 /** Boot devices (ordered). */
140 DEVPCBIOSBOOT aenmBootDevice[4];
141 /** RAM size (in bytes). */
142 uint64_t cbRam;
143 /** RAM hole size (in bytes). */
144 uint32_t cbRamHole;
145 /** Bochs shutdown index. */
146 uint32_t iShutdown;
147 /** Floppy device. */
148 char *pszFDDevice;
149 /** Harddisk device. */
150 char *pszHDDevice;
151 /** Sata harddisk device. */
152 char *pszSataDevice;
153 /** LUN of the four harddisks which are emulated as IDE. */
154 uint32_t iSataHDLUN[4];
155 /** Bios message buffer. */
156 char szMsg[256];
157 /** Bios message buffer index. */
158 uint32_t iMsg;
159 /** The system BIOS ROM data. */
160 uint8_t *pu8PcBios;
161 /** The size of the system BIOS ROM. */
162 uint64_t cbPcBios;
163 /** The name of the BIOS ROM file. */
164 char *pszPcBiosFile;
165 /** The LAN boot ROM data. */
166 uint8_t *pu8LanBoot;
167 /** The name of the LAN boot ROM file. */
168 char *pszLanBootFile;
169 /** The size of the LAN boot ROM. */
170 uint64_t cbLanBoot;
171 /** The DMI tables. */
172 uint8_t au8DMIPage[0x1000];
173 /** The boot countdown (in seconds). */
174 uint8_t uBootDelay;
175 /** I/O-APIC enabled? */
176 uint8_t u8IOAPIC;
177 /** PXE debug logging enabled? */
178 uint8_t u8PXEDebug;
179 /** PXE boot PCI bus/dev/fn list. */
180 uint16_t au16NetBootDev[NET_BOOT_DEVS];
181 /** Number of logical CPUs in guest */
182 uint16_t cCpus;
183} DEVPCBIOS, *PDEVPCBIOS;
184
185
186/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
187 * record (partition table). */
188static int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
189{
190 uint8_t aMBR[512], *p;
191 int rc;
192 uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
193
194 if (!pBlock)
195 return VERR_INVALID_PARAMETER;
196 rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
197 if (RT_FAILURE(rc))
198 return rc;
199 /* Test MBR magic number. */
200 if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
201 return VERR_INVALID_PARAMETER;
202 for (uint32_t i = 0; i < 4; i++)
203 {
204 /* Figure out the start of a partition table entry. */
205 p = &aMBR[0x1be + i * 16];
206 iEndHead = p[5];
207 iEndSector = p[6] & 63;
208 if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
209 {
210 /* Assumption: partition terminates on a cylinder boundary. */
211 cLCHSHeads = iEndHead + 1;
212 cLCHSSectors = iEndSector;
213 cLCHSCylinders = RT_MIN(1024, pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors));
214 if (cLCHSCylinders >= 1)
215 {
216 pLCHSGeometry->cCylinders = cLCHSCylinders;
217 pLCHSGeometry->cHeads = cLCHSHeads;
218 pLCHSGeometry->cSectors = cLCHSSectors;
219 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
220 return VINF_SUCCESS;
221 }
222 }
223 }
224 return VERR_INVALID_PARAMETER;
225}
226
227
228/**
229 * Write to CMOS memory.
230 * This is used by the init complete code.
231 */
232static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
233{
234 Assert(off < 256);
235 Assert(u32Val < 256);
236
237#if 1
238 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
239 AssertRC(rc);
240#else
241 PVM pVM = PDMDevHlpGetVM(pDevIns);
242 IOMIOPortWrite(pVM, 0x70, off, 1);
243 IOMIOPortWrite(pVM, 0x71, u32Val, 1);
244 IOMIOPortWrite(pVM, 0x70, 0, 1);
245#endif
246}
247
248/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
249
250/**
251 * Initializes the CMOS data for one harddisk.
252 */
253static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
254{
255 Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
256 if (offType)
257 pcbiosCmosWrite(pDevIns, offType, 48);
258 /* Cylinders low */
259 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
260 /* Cylinders high */
261 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
262 /* Heads */
263 pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
264 /* Landing zone low */
265 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
266 /* Landing zone high */
267 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
268 /* Write precomp low */
269 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
270 /* Write precomp high */
271 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
272 /* Sectors */
273 pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
274}
275
276/**
277 * Set logical CHS geometry for a hard disk
278 *
279 * @returns VBox status code.
280 * @param pBase Base interface for the device.
281 * @param pHardDisk The hard disk.
282 * @param pLCHSGeometry Where to store the geometry settings.
283 */
284static int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIBLOCKBIOS pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
285{
286 PDMMEDIAGEOMETRY LCHSGeometry;
287 int rc = VINF_SUCCESS;
288
289 rc = pHardDisk->pfnGetLCHSGeometry(pHardDisk, &LCHSGeometry);
290 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
291 || LCHSGeometry.cCylinders == 0
292 || LCHSGeometry.cHeads == 0
293 || LCHSGeometry.cHeads > 255
294 || LCHSGeometry.cSectors == 0
295 || LCHSGeometry.cSectors > 63)
296 {
297 PPDMIBLOCK pBlock;
298 pBlock = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCK);
299 /* No LCHS geometry, autodetect and set. */
300 rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
301 if (RT_FAILURE(rc))
302 {
303 /* Try if PCHS geometry works, otherwise fall back. */
304 rc = pHardDisk->pfnGetPCHSGeometry(pHardDisk, &LCHSGeometry);
305 }
306 if ( RT_FAILURE(rc)
307 || LCHSGeometry.cCylinders == 0
308 || LCHSGeometry.cCylinders > 1024
309 || LCHSGeometry.cHeads == 0
310 || LCHSGeometry.cHeads > 16
311 || LCHSGeometry.cSectors == 0
312 || LCHSGeometry.cSectors > 63)
313 {
314 uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
315 if (cSectors / 16 / 63 <= 1024)
316 {
317 LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
318 LCHSGeometry.cHeads = 16;
319 }
320 else if (cSectors / 32 / 63 <= 1024)
321 {
322 LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
323 LCHSGeometry.cHeads = 32;
324 }
325 else if (cSectors / 64 / 63 <= 1024)
326 {
327 LCHSGeometry.cCylinders = cSectors / 64 / 63;
328 LCHSGeometry.cHeads = 64;
329 }
330 else if (cSectors / 128 / 63 <= 1024)
331 {
332 LCHSGeometry.cCylinders = cSectors / 128 / 63;
333 LCHSGeometry.cHeads = 128;
334 }
335 else
336 {
337 LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
338 LCHSGeometry.cHeads = 255;
339 }
340 LCHSGeometry.cSectors = 63;
341
342 }
343 rc = pHardDisk->pfnSetLCHSGeometry(pHardDisk, &LCHSGeometry);
344 if (rc == VERR_VD_IMAGE_READ_ONLY)
345 {
346 LogRel(("DevPcBios: ATA failed to update LCHS geometry, read only\n"));
347 rc = VINF_SUCCESS;
348 }
349 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
350 {
351 LogRel(("DevPcBios: ATA failed to update LCHS geometry, backend refused\n"));
352 rc = VINF_SUCCESS;
353 }
354 }
355
356 *pLCHSGeometry = LCHSGeometry;
357
358 return rc;
359}
360
361/**
362 * Get BIOS boot code from enmBootDevice in order
363 *
364 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
365 */
366static uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
367{
368 switch (pThis->aenmBootDevice[iOrder])
369 {
370 case DEVPCBIOSBOOT_NONE:
371 return 0;
372 case DEVPCBIOSBOOT_FLOPPY:
373 return 1;
374 case DEVPCBIOSBOOT_HD:
375 return 2;
376 case DEVPCBIOSBOOT_DVD:
377 return 3;
378 case DEVPCBIOSBOOT_LAN:
379 return 4;
380 default:
381 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
382 return 0;
383 }
384}
385
386
387/**
388 * Init complete notification.
389 * This routine will write information needed by the bios to the CMOS.
390 *
391 * @returns VBOX status code.
392 * @param pDevIns The device instance.
393 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
394 * a description of standard and non-standard CMOS registers.
395 */
396static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
397{
398 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
399 uint32_t u32;
400 unsigned i;
401 PVM pVM = PDMDevHlpGetVM(pDevIns);
402 PPDMIBLOCKBIOS apHDs[4] = {0};
403 PPDMIBLOCKBIOS apFDs[2] = {0};
404 AssertRelease(pVM);
405 LogFlow(("pcbiosInitComplete:\n"));
406
407 /*
408 * Memory sizes.
409 */
410 /* base memory. */
411 u32 = pThis->cbRam > 640 ? 640 : (uint32_t)pThis->cbRam / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
412 pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
413 pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
414
415 /* Extended memory, up to 65MB */
416 u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
417 pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
418 pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
419 pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
420 pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
421
422 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
423 and below 4GB (as it can only hold 4GB+16M). We have to chop off the
424 top 2MB or it conflict with what the ACPI tables return. (Should these
425 be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
426 with the high BIOS mapping.) */
427 uint64_t const offRamHole = _4G - pThis->cbRamHole;
428 if (pThis->cbRam > 16 * _1M)
429 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
430 else
431 u32 = 0;
432 pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
433 pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
434
435 /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
436 Bochs got these in a different location which we've already used for SATA,
437 it also lacks the last two. */
438 uint64_t c64KBAbove4GB;
439 if (pThis->cbRam <= offRamHole)
440 c64KBAbove4GB = 0;
441 else
442 {
443 c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
444 /* Make sure it doesn't hit the limits of the current BIOS code. */
445 AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
446 }
447 pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
448 pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
449 pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
450 pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
451 pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
452
453 /*
454 * Number of CPUs.
455 */
456 pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
457
458 /*
459 * Bochs BIOS specifics - boot device.
460 * We do both new and old (ami-style) settings.
461 * See rombios.c line ~7215 (int19_function).
462 */
463
464 uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
465 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
466 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
467 uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
468 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
469 pcbiosCmosWrite(pDevIns, 0x38, reg38);
470 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
471
472 /*
473 * PXE debug option.
474 */
475 pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
476
477 /*
478 * Network boot device list.
479 */
480 for (i = 0; i < NET_BOOT_DEVS; ++i)
481 {
482 pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
483 pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
484 }
485
486 /*
487 * Floppy drive type.
488 */
489 for (i = 0; i < RT_ELEMENTS(apFDs); i++)
490 {
491 PPDMIBASE pBase;
492 int rc = PDMR3QueryLun(pVM, pThis->pszFDDevice, 0, i, &pBase);
493 if (RT_SUCCESS(rc))
494 apFDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
495 }
496 u32 = 0;
497 if (apFDs[0])
498 switch (apFDs[0]->pfnGetType(apFDs[0]))
499 {
500 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1 << 4; break;
501 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2 << 4; break;
502 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3 << 4; break;
503 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4 << 4; break;
504 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5 << 4; break;
505 default: AssertFailed(); break;
506 }
507 if (apFDs[1])
508 switch (apFDs[1]->pfnGetType(apFDs[1]))
509 {
510 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1; break;
511 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2; break;
512 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3; break;
513 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4; break;
514 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5; break;
515 default: AssertFailed(); break;
516 }
517 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
518
519 /*
520 * Equipment byte.
521 */
522 u32 = !!apFDs[0] + !!apFDs[1];
523 switch (u32)
524 {
525 case 1: u32 = 0x01; break; /* floppy installed, 2 drives. */
526 default:u32 = 0; break; /* floppy not installed. */
527 }
528 u32 |= RT_BIT(1); /* math coprocessor installed */
529 u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
530 u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
531 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
532
533 /*
534 * Harddisks.
535 */
536 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
537 {
538 PPDMIBASE pBase;
539 int rc = PDMR3QueryLun(pVM, pThis->pszHDDevice, 0, i, &pBase);
540 if (RT_SUCCESS(rc))
541 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
542 if ( apHDs[i]
543 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
544 || !apHDs[i]->pfnIsVisible(apHDs[i])))
545 apHDs[i] = NULL;
546 if (apHDs[i])
547 {
548 PDMMEDIAGEOMETRY LCHSGeometry;
549 int rc2 = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
550 AssertRC(rc2);
551
552 if (i < 4)
553 {
554 /* Award BIOS extended drive types for first to fourth disk.
555 * Used by the BIOS for setting the logical geometry. */
556 int offType, offInfo;
557 switch (i)
558 {
559 case 0:
560 offType = 0x19;
561 offInfo = 0x1e;
562 break;
563 case 1:
564 offType = 0x1a;
565 offInfo = 0x26;
566 break;
567 case 2:
568 offType = 0x00;
569 offInfo = 0x67;
570 break;
571 case 3:
572 default:
573 offType = 0x00;
574 offInfo = 0x70;
575 break;
576 }
577 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
578 &LCHSGeometry);
579 }
580 LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
581 }
582 }
583
584 /* 0Fh means extended and points to 19h, 1Ah */
585 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
586 pcbiosCmosWrite(pDevIns, 0x12, u32);
587
588 /*
589 * Sata Harddisks.
590 */
591 if (pThis->pszSataDevice)
592 {
593 /* Clear pointers to IDE controller. */
594 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
595 apHDs[i] = NULL;
596
597 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
598 {
599 PPDMIBASE pBase;
600 int rc = PDMR3QueryLun(pVM, pThis->pszSataDevice, 0, pThis->iSataHDLUN[i], &pBase);
601 if (RT_SUCCESS(rc))
602 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
603 if ( apHDs[i]
604 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
605 || !apHDs[i]->pfnIsVisible(apHDs[i])))
606 apHDs[i] = NULL;
607 if (apHDs[i])
608 {
609 PDMMEDIAGEOMETRY LCHSGeometry;
610 rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
611 AssertRC(rc);
612
613 if (i < 4)
614 {
615 /* Award BIOS extended drive types for first to fourth disk.
616 * Used by the BIOS for setting the logical geometry. */
617 int offInfo;
618 switch (i)
619 {
620 case 0:
621 offInfo = 0x40;
622 break;
623 case 1:
624 offInfo = 0x48;
625 break;
626 case 2:
627 offInfo = 0x50;
628 break;
629 case 3:
630 default:
631 offInfo = 0x58;
632 break;
633 }
634 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
635 &LCHSGeometry);
636 }
637 LogRel(("DevPcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
638 }
639 }
640 }
641
642 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
643 return VINF_SUCCESS;
644}
645
646
647/**
648 * Port I/O Handler for IN operations.
649 *
650 * @returns VBox status code.
651 *
652 * @param pDevIns The device instance.
653 * @param pvUser User argument - ignored.
654 * @param Port Port number used for the IN operation.
655 * @param pu32 Where to store the result.
656 * @param cb Number of bytes read.
657 */
658static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
659{
660 NOREF(pDevIns);
661 NOREF(pvUser);
662 NOREF(Port);
663 NOREF(pu32);
664 NOREF(cb);
665 return VERR_IOM_IOPORT_UNUSED;
666}
667
668
669/**
670 * Port I/O Handler for OUT operations.
671 *
672 * @returns VBox status code.
673 *
674 * @param pDevIns The device instance.
675 * @param pvUser User argument - ignored.
676 * @param Port Port number used for the IN operation.
677 * @param u32 The value to output.
678 * @param cb The value size in bytes.
679 */
680static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
681{
682 /*
683 * Bochs BIOS Panic
684 */
685 if ( cb == 2
686 && ( Port == 0x400
687 || Port == 0x401))
688 {
689 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
690 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
691 return VERR_INTERNAL_ERROR;
692 }
693
694 /*
695 * Bochs BIOS char printing.
696 */
697 if ( cb == 1
698 && ( Port == 0x402
699 || Port == 0x403))
700 {
701 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
702 /* The raw version. */
703 switch (u32)
704 {
705 case '\r': Log2(("pcbios: <return>\n")); break;
706 case '\n': Log2(("pcbios: <newline>\n")); break;
707 case '\t': Log2(("pcbios: <tab>\n")); break;
708 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
709 }
710
711 /* The readable, buffered version. */
712 if (u32 == '\n' || u32 == '\r')
713 {
714 pThis->szMsg[pThis->iMsg] = '\0';
715 if (pThis->iMsg)
716 Log(("pcbios: %s\n", pThis->szMsg));
717 pThis->iMsg = 0;
718 }
719 else
720 {
721 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
722 {
723 pThis->szMsg[pThis->iMsg] = '\0';
724 Log(("pcbios: %s\n", pThis->szMsg));
725 pThis->iMsg = 0;
726 }
727 pThis->szMsg[pThis->iMsg] = (char )u32;
728 pThis->szMsg[++pThis->iMsg] = '\0';
729 }
730 return VINF_SUCCESS;
731 }
732
733 /*
734 * Bochs BIOS shutdown request.
735 */
736 if (cb == 1 && Port == 0x8900)
737 {
738 static const unsigned char szShutdown[] = "Shutdown";
739 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
740 if (u32 == szShutdown[pThis->iShutdown])
741 {
742 pThis->iShutdown++;
743 if (pThis->iShutdown == 8)
744 {
745 pThis->iShutdown = 0;
746 LogRel(("8900h shutdown request.\n"));
747 return PDMDevHlpVMPowerOff(pDevIns);
748 }
749 }
750 else
751 pThis->iShutdown = 0;
752 return VINF_SUCCESS;
753 }
754
755 /* not in use. */
756 return VINF_SUCCESS;
757}
758
759/**
760 * Reset notification.
761 *
762 * @returns VBox status.
763 * @param pDevIns The device instance data.
764 */
765static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
766{
767 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
768 LogFlow(("pcbiosReset:\n"));
769
770 if (pThis->u8IOAPIC)
771 FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
772 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
773
774 /*
775 * Re-shadow the LAN ROM image and make it RAM/RAM.
776 *
777 * This is normally done by the BIOS code, but since we're currently lacking
778 * the chipset support for this we do it here (and in the constructor).
779 */
780 uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, PAGE_SIZE) >> PAGE_SHIFT;
781 RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
782 while (cPages > 0)
783 {
784 uint8_t abPage[PAGE_SIZE];
785 int rc;
786
787 /* Read the (original) ROM page and write it back to the RAM page. */
788 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
789 AssertLogRelRC(rc);
790
791 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
792 AssertLogRelRC(rc);
793 if (RT_FAILURE(rc))
794 memset(abPage, 0xcc, sizeof(abPage));
795
796 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
797 AssertLogRelRC(rc);
798
799 /* Switch to the RAM/RAM mode. */
800 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
801 AssertLogRelRC(rc);
802
803 /* Advance */
804 GCPhys += PAGE_SIZE;
805 cPages--;
806 }
807}
808
809
810/**
811 * Destruct a device instance.
812 *
813 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
814 * resources can be freed correctly.
815 *
816 * @param pDevIns The device instance data.
817 */
818static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
819{
820 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
821 LogFlow(("pcbiosDestruct:\n"));
822 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
823
824 /*
825 * Free MM heap pointers.
826 */
827 if (pThis->pu8PcBios)
828 {
829 MMR3HeapFree(pThis->pu8PcBios);
830 pThis->pu8PcBios = NULL;
831 }
832
833 if (pThis->pszPcBiosFile)
834 {
835 MMR3HeapFree(pThis->pszPcBiosFile);
836 pThis->pszPcBiosFile = NULL;
837 }
838
839 if (pThis->pu8LanBoot)
840 {
841 MMR3HeapFree(pThis->pu8LanBoot);
842 pThis->pu8LanBoot = NULL;
843 }
844
845 if (pThis->pszLanBootFile)
846 {
847 MMR3HeapFree(pThis->pszLanBootFile);
848 pThis->pszLanBootFile = NULL;
849 }
850
851 return VINF_SUCCESS;
852}
853
854
855/**
856 * Convert config value to DEVPCBIOSBOOT.
857 *
858 * @returns VBox status code.
859 * @param pCfg Configuration handle.
860 * @param pszParam The name of the value to read.
861 * @param penmBoot Where to store the boot method.
862 */
863static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfg, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
864{
865 char *psz;
866 int rc = CFGMR3QueryStringAlloc(pCfg, pszParam, &psz);
867 if (RT_FAILURE(rc))
868 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
869 N_("Configuration error: Querying \"%s\" as a string failed"),
870 pszParam);
871 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
872 *penmBoot = DEVPCBIOSBOOT_DVD;
873 else if (!strcmp(psz, "IDE"))
874 *penmBoot = DEVPCBIOSBOOT_HD;
875 else if (!strcmp(psz, "FLOPPY"))
876 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
877 else if (!strcmp(psz, "LAN"))
878 *penmBoot = DEVPCBIOSBOOT_LAN;
879 else if (!strcmp(psz, "NONE"))
880 *penmBoot = DEVPCBIOSBOOT_NONE;
881 else
882 {
883 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
884 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
885 pszParam, psz);
886 rc = VERR_INTERNAL_ERROR;
887 }
888 MMR3HeapFree(psz);
889 return rc;
890}
891
892/**
893 * @interface_method_impl{PDMDEVREG,pfnConstruct}
894 */
895static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
896{
897 unsigned i;
898 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
899 int rc;
900 int cb;
901
902 Assert(iInstance == 0);
903 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
904
905 /*
906 * Validate configuration.
907 */
908 if (!CFGMR3AreValuesValid(pCfg,
909 "BootDevice0\0"
910 "BootDevice1\0"
911 "BootDevice2\0"
912 "BootDevice3\0"
913 "RamSize\0"
914 "RamHoleSize\0"
915 "HardDiskDevice\0"
916 "SataHardDiskDevice\0"
917 "SataPrimaryMasterLUN\0"
918 "SataPrimarySlaveLUN\0"
919 "SataSecondaryMasterLUN\0"
920 "SataSecondarySlaveLUN\0"
921 "FloppyDevice\0"
922 "DelayBoot\0"
923 "BiosRom\0"
924 "LanBootRom\0"
925 "PXEDebug\0"
926 "UUID\0"
927 "IOAPIC\0"
928 "NumCPUs\0"
929 "DmiBIOSVendor\0"
930 "DmiBIOSVersion\0"
931 "DmiBIOSReleaseDate\0"
932 "DmiBIOSReleaseMajor\0"
933 "DmiBIOSReleaseMinor\0"
934 "DmiBIOSFirmwareMajor\0"
935 "DmiBIOSFirmwareMinor\0"
936 "DmiSystemFamily\0"
937 "DmiSystemProduct\0"
938 "DmiSystemSerial\0"
939 "DmiSystemUuid\0"
940 "DmiSystemVendor\0"
941 "DmiSystemVersion\0"
942 "DmiChassisVendor\0"
943 "DmiChassisVersion\0"
944 "DmiChassisSerial\0"
945 "DmiChassisAssetTag\0"
946#ifdef VBOX_WITH_DMI_OEMSTRINGS
947 "DmiOEMVBoxVer\0"
948 "DmiOEMVBoxRev\0"
949#endif
950 "DmiUseHostInfo\0"
951 ))
952 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
953 N_("Invalid configuration for device pcbios device"));
954
955 /*
956 * Init the data.
957 */
958 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
959 if (RT_FAILURE(rc))
960 return PDMDEV_SET_ERROR(pDevIns, rc,
961 N_("Configuration error: Querying \"RamSize\" as integer failed"));
962
963 rc = CFGMR3QueryU32Def(pCfg, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
964 if (RT_FAILURE(rc))
965 return PDMDEV_SET_ERROR(pDevIns, rc,
966 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
967
968 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
969 if (RT_FAILURE(rc))
970 return PDMDEV_SET_ERROR(pDevIns, rc,
971 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
972
973 LogRel(("[SMP] BIOS with %u CPUs\n", pThis->cCpus));
974
975 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
976 if (RT_FAILURE (rc))
977 return PDMDEV_SET_ERROR(pDevIns, rc,
978 N_("Configuration error: Failed to read \"IOAPIC\""));
979
980 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
981 Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
982 for (i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
983 {
984 rc = pcbiosBootFromCfg(pDevIns, pCfg, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
985 if (RT_FAILURE(rc))
986 return rc;
987 }
988
989 rc = CFGMR3QueryStringAlloc(pCfg, "HardDiskDevice", &pThis->pszHDDevice);
990 if (RT_FAILURE(rc))
991 return PDMDEV_SET_ERROR(pDevIns, rc,
992 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
993
994 rc = CFGMR3QueryStringAlloc(pCfg, "FloppyDevice", &pThis->pszFDDevice);
995 if (RT_FAILURE(rc))
996 return PDMDEV_SET_ERROR(pDevIns, rc,
997 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
998
999 rc = CFGMR3QueryStringAlloc(pCfg, "SataHardDiskDevice", &pThis->pszSataDevice);
1000 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1001 pThis->pszSataDevice = NULL;
1002 else if (RT_FAILURE(rc))
1003 return PDMDEV_SET_ERROR(pDevIns, rc,
1004 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1005
1006 if (pThis->pszSataDevice)
1007 {
1008 static const char * const s_apszSataDisks[] =
1009 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1010 Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
1011 for (i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
1012 {
1013 rc = CFGMR3QueryU32(pCfg, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
1014 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1015 pThis->iSataHDLUN[i] = i;
1016 else if (RT_FAILURE(rc))
1017 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1018 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1019 }
1020 }
1021 /*
1022 * Register I/O Ports and PC BIOS.
1023 */
1024 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1025 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1026 if (RT_FAILURE(rc))
1027 return rc;
1028 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1029 NULL, NULL, "Bochs PC BIOS - Shutdown");
1030 if (RT_FAILURE(rc))
1031 return rc;
1032
1033 /*
1034 * Query the machine's UUID for SMBIOS/DMI use.
1035 */
1036 RTUUID uuid;
1037 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1038 if (RT_FAILURE(rc))
1039 return PDMDEV_SET_ERROR(pDevIns, rc,
1040 N_("Configuration error: Querying \"UUID\" failed"));
1041
1042
1043 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1044 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1045 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1046 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1047 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage,
1048 VBOX_DMI_TABLE_SIZE, &uuid, pCfg, /*fPutSmbiosHeaders=*/false);
1049 if (RT_FAILURE(rc))
1050 return rc;
1051 if (pThis->u8IOAPIC)
1052 FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1053 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1054
1055 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage,
1056 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1057 if (RT_FAILURE(rc))
1058 return rc;
1059
1060 /*
1061 * Read the PXE debug logging option.
1062 */
1063 rc = CFGMR3QueryU8Def(pCfg, "PXEDebug", &pThis->u8PXEDebug, false);
1064 if (RT_FAILURE(rc))
1065 return PDMDEV_SET_ERROR(pDevIns, rc,
1066 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1067
1068 /* Clear the net boot device list. All bits set invokes old behavior,
1069 * as if no second CMOS bank was present.
1070 */
1071 memset(&pThis->au16NetBootDev, 0xff, sizeof(pThis->au16NetBootDev));
1072
1073 /*
1074 * Determine the network boot order.
1075 */
1076 PCFGMNODE pCfgNetBoot = CFGMR3GetChild(pCfg, "NetBoot");
1077 if (pCfgNetBoot == NULL)
1078 {
1079 /* Do nothing. */
1080 rc = VINF_SUCCESS;
1081 }
1082 else
1083 {
1084 PCFGMNODE pCfgNetBootDevice;
1085 uint8_t u8PciDev;
1086 uint8_t u8PciFn;
1087 uint16_t u16BusDevFn;
1088 char szIndex[] = "?";
1089
1090 Assert(pCfgNetBoot);
1091 for (i = 0; i < NET_BOOT_DEVS; ++i)
1092 {
1093 szIndex[0] = '0' + i;
1094 pCfgNetBootDevice = CFGMR3GetChild(pCfgNetBoot, szIndex);
1095 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIDeviceNo", &u8PciDev);
1096 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1097 {
1098 /* Do nothing and stop iterating. */
1099 rc = VINF_SUCCESS;
1100 break;
1101 }
1102 else if (RT_FAILURE(rc))
1103 return PDMDEV_SET_ERROR(pDevIns, rc,
1104 N_("Configuration error: Querying \"Netboot/x/PCIDeviceNo\" as integer failed"));
1105 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIFunctionNo", &u8PciFn);
1106 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1107 {
1108 /* Do nothing and stop iterating. */
1109 rc = VINF_SUCCESS;
1110 break;
1111 }
1112 else if (RT_FAILURE(rc))
1113 return PDMDEV_SET_ERROR(pDevIns, rc,
1114 N_("Configuration error: Querying \"Netboot/x/PCIFunctionNo\" as integer failed"));
1115 u16BusDevFn = ((u8PciDev & 0x1F) << 3) | (u8PciFn & 0x7);
1116 pThis->au16NetBootDev[i] = u16BusDevFn;
1117 }
1118 }
1119
1120 /*
1121 * Get the system BIOS ROM file name.
1122 */
1123 rc = CFGMR3QueryStringAlloc(pCfg, "BiosRom", &pThis->pszPcBiosFile);
1124 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1125 {
1126 pThis->pszPcBiosFile = NULL;
1127 rc = VINF_SUCCESS;
1128 }
1129 else if (RT_FAILURE(rc))
1130 return PDMDEV_SET_ERROR(pDevIns, rc,
1131 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1132 else if (!*pThis->pszPcBiosFile)
1133 {
1134 MMR3HeapFree(pThis->pszPcBiosFile);
1135 pThis->pszPcBiosFile = NULL;
1136 }
1137
1138 const uint8_t *pu8PcBiosBinary = NULL;
1139 uint64_t cbPcBiosBinary;
1140 /*
1141 * Determine the system BIOS ROM size, open specified ROM file in the process.
1142 */
1143 RTFILE FilePcBios = NIL_RTFILE;
1144 if (pThis->pszPcBiosFile)
1145 {
1146 rc = RTFileOpen(&FilePcBios, pThis->pszPcBiosFile,
1147 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1148 if (RT_SUCCESS(rc))
1149 {
1150 rc = RTFileGetSize(FilePcBios, &pThis->cbPcBios);
1151 if (RT_SUCCESS(rc))
1152 {
1153 /* The following checks should be in sync the AssertReleaseMsg's below. */
1154 if ( RT_ALIGN(pThis->cbPcBios, _64K) != pThis->cbPcBios
1155 || pThis->cbPcBios > 32 * _64K
1156 || pThis->cbPcBios < _64K)
1157 rc = VERR_TOO_MUCH_DATA;
1158 }
1159 }
1160 if (RT_FAILURE(rc))
1161 {
1162 /*
1163 * In case of failure simply fall back to the built-in BIOS ROM.
1164 */
1165 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Rrc!\n", pThis->pszPcBiosFile, rc));
1166 RTFileClose(FilePcBios);
1167 FilePcBios = NIL_RTFILE;
1168 MMR3HeapFree(pThis->pszPcBiosFile);
1169 pThis->pszPcBiosFile = NULL;
1170 }
1171 }
1172
1173 /*
1174 * Attempt to get the system BIOS ROM data from file.
1175 */
1176 if (pThis->pszPcBiosFile)
1177 {
1178 /*
1179 * Allocate buffer for the system BIOS ROM data.
1180 */
1181 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
1182 if (pThis->pu8PcBios)
1183 {
1184 rc = RTFileRead(FilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
1185 if (RT_FAILURE(rc))
1186 {
1187 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbPcBios, rc));
1188 MMR3HeapFree(pThis->pu8PcBios);
1189 pThis->pu8PcBios = NULL;
1190 }
1191 rc = VINF_SUCCESS;
1192 }
1193 else
1194 rc = VERR_NO_MEMORY;
1195 }
1196 else
1197 pThis->pu8PcBios = NULL;
1198
1199 /* cleanup */
1200 if (FilePcBios != NIL_RTFILE)
1201 RTFileClose(FilePcBios);
1202
1203 /* If we were unable to get the data from file for whatever reason, fall
1204 back to the built-in ROM image. */
1205 uint32_t fFlags = 0;
1206 if (pThis->pu8PcBios == NULL)
1207 {
1208 pu8PcBiosBinary = g_abPcBiosBinary;
1209 cbPcBiosBinary = g_cbPcBiosBinary;
1210 fFlags = PGMPHYS_ROM_FLAGS_PERMANENT_BINARY;
1211 }
1212 else
1213 {
1214 pu8PcBiosBinary = pThis->pu8PcBios;
1215 cbPcBiosBinary = pThis->cbPcBios;
1216 }
1217
1218 /*
1219 * Map the BIOS into memory.
1220 * There are two mappings:
1221 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1222 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1223 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1224 */
1225 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1226 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1227 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1228 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1229 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1230 fFlags, "PC BIOS - 0xfffff");
1231 if (RT_FAILURE(rc))
1232 return rc;
1233 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1234 fFlags, "PC BIOS - 0xffffffff");
1235 if (RT_FAILURE(rc))
1236 return rc;
1237
1238#ifdef VBOX_WITH_VMI
1239 /*
1240 * Map the VMI BIOS into memory.
1241 */
1242 AssertReleaseMsg(g_cbVmiBiosBinary == _4K, ("cbVmiBiosBinary=%#x\n", g_cbVmiBiosBinary));
1243 rc = PDMDevHlpROMRegister(pDevIns, VBOX_VMI_BIOS_BASE, g_cbVmiBiosBinary, g_abVmiBiosBinary,
1244 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "VMI BIOS");
1245 if (RT_FAILURE(rc))
1246 return rc;
1247#endif /* VBOX_WITH_VMI */
1248
1249 /*
1250 * Call reset to set values and stuff.
1251 */
1252 pcbiosReset(pDevIns);
1253
1254 /*
1255 * Get the LAN boot ROM file name.
1256 */
1257 rc = CFGMR3QueryStringAlloc(pCfg, "LanBootRom", &pThis->pszLanBootFile);
1258 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1259 {
1260 pThis->pszLanBootFile = NULL;
1261 rc = VINF_SUCCESS;
1262 }
1263 else if (RT_FAILURE(rc))
1264 return PDMDEV_SET_ERROR(pDevIns, rc,
1265 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1266 else if (!*pThis->pszLanBootFile)
1267 {
1268 MMR3HeapFree(pThis->pszLanBootFile);
1269 pThis->pszLanBootFile = NULL;
1270 }
1271
1272 uint64_t cbFileLanBoot;
1273 const uint8_t *pu8LanBootBinary = NULL;
1274 uint64_t cbLanBootBinary;
1275
1276 /*
1277 * Determine the LAN boot ROM size, open specified ROM file in the process.
1278 */
1279 RTFILE FileLanBoot = NIL_RTFILE;
1280 if (pThis->pszLanBootFile)
1281 {
1282 rc = RTFileOpen(&FileLanBoot, pThis->pszLanBootFile,
1283 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1284 if (RT_SUCCESS(rc))
1285 {
1286 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1287 if (RT_SUCCESS(rc))
1288 {
1289 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1290 || cbFileLanBoot > _64K)
1291 rc = VERR_TOO_MUCH_DATA;
1292 }
1293 }
1294 if (RT_FAILURE(rc))
1295 {
1296 /*
1297 * Ignore failure and fall back to the built-in LAN boot ROM.
1298 */
1299 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
1300 RTFileClose(FileLanBoot);
1301 FileLanBoot = NIL_RTFILE;
1302 MMR3HeapFree(pThis->pszLanBootFile);
1303 pThis->pszLanBootFile = NULL;
1304 }
1305 }
1306
1307 /*
1308 * Get the LAN boot ROM data.
1309 */
1310 if (pThis->pszLanBootFile)
1311 {
1312 /*
1313 * Allocate buffer for the LAN boot ROM data.
1314 */
1315 pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1316 if (pThis->pu8LanBoot)
1317 {
1318 rc = RTFileRead(FileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
1319 if (RT_FAILURE(rc))
1320 {
1321 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", cbFileLanBoot, rc));
1322 MMR3HeapFree(pThis->pu8LanBoot);
1323 pThis->pu8LanBoot = NULL;
1324 }
1325 rc = VINF_SUCCESS;
1326 }
1327 else
1328 rc = VERR_NO_MEMORY;
1329 }
1330 else
1331 pThis->pu8LanBoot = NULL;
1332
1333 /* cleanup */
1334 if (FileLanBoot != NIL_RTFILE)
1335 RTFileClose(FileLanBoot);
1336
1337 /* If we were unable to get the data from file for whatever reason, fall
1338 * back to the built-in LAN boot ROM image.
1339 */
1340 if (pThis->pu8LanBoot == NULL)
1341 {
1342 pu8LanBootBinary = g_abNetBiosBinary;
1343 cbLanBootBinary = g_cbNetBiosBinary;
1344 }
1345 else
1346 {
1347 pu8LanBootBinary = pThis->pu8LanBoot;
1348 cbLanBootBinary = cbFileLanBoot;
1349 }
1350
1351 /*
1352 * Map the Network Boot ROM into memory.
1353 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1354 * the (up to) 32 kb ROM image.
1355 */
1356 if (pu8LanBootBinary)
1357 {
1358 pThis->cbLanBoot = cbLanBootBinary;
1359
1360 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1361 PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
1362 if (RT_SUCCESS(rc))
1363 {
1364 rc = PDMDevHlpROMProtectShadow(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, PGMROMPROT_READ_RAM_WRITE_RAM);
1365 AssertRCReturn(rc, rc);
1366 rc = PDMDevHlpPhysWrite(pDevIns, VBOX_LANBOOT_SEG << 4, pu8LanBootBinary, cbLanBootBinary);
1367 AssertRCReturn(rc, rc);
1368 }
1369 }
1370
1371 rc = CFGMR3QueryU8Def(pCfg, "DelayBoot", &pThis->uBootDelay, 0);
1372 if (RT_FAILURE(rc))
1373 return PDMDEV_SET_ERROR(pDevIns, rc,
1374 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1375 if (pThis->uBootDelay > 15)
1376 pThis->uBootDelay = 15;
1377
1378 return rc;
1379}
1380
1381
1382/**
1383 * The device registration structure.
1384 */
1385const PDMDEVREG g_DevicePcBios =
1386{
1387 /* u32Version */
1388 PDM_DEVREG_VERSION,
1389 /* szName */
1390 "pcbios",
1391 /* szRCMod */
1392 "",
1393 /* szR0Mod */
1394 "",
1395 /* pszDescription */
1396 "PC BIOS Device",
1397 /* fFlags */
1398 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1399 /* fClass */
1400 PDM_DEVREG_CLASS_ARCH_BIOS,
1401 /* cMaxInstances */
1402 1,
1403 /* cbInstance */
1404 sizeof(DEVPCBIOS),
1405 /* pfnConstruct */
1406 pcbiosConstruct,
1407 /* pfnDestruct */
1408 pcbiosDestruct,
1409 /* pfnRelocate */
1410 NULL,
1411 /* pfnIOCtl */
1412 NULL,
1413 /* pfnPowerOn */
1414 NULL,
1415 /* pfnReset */
1416 pcbiosReset,
1417 /* pfnSuspend */
1418 NULL,
1419 /* pfnResume */
1420 NULL,
1421 /* pfnAttach */
1422 NULL,
1423 /* pfnDetach */
1424 NULL,
1425 /* pfnQueryInterface. */
1426 NULL,
1427 /* pfnInitComplete. */
1428 pcbiosInitComplete,
1429 /* pfnPowerOff */
1430 NULL,
1431 /* pfnSoftReset */
1432 NULL,
1433 /* u32VersionEnd */
1434 PDM_DEVREG_VERSION
1435};
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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