VirtualBox

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

Last change on this file since 60404 was 60404, checked in by vboxsync, 8 years ago

VMM,Devices,Main: Implemented soft/warm reset for shutdown status codes 05h, 09h and 0Ah.

This is a shot at adjusting our VM reset handling to handle the ancient way of
getting a 286 out of protected mode and back to real mode. Our exiting reset
code (XXXR3Reset, PDMDEVREG::pfnReset, and so on) is doing a cold reset of the
system and then some additional device & memory initialization that the firmware
is usually responsible for doing. When the guest triggers a reset via the
keyboard controller, system control port A, CPU triple fault, and possibly ACPI,
only the CPU is supposed to be reset. The BIOS would then decide whether memory
and devices needed resetting as well, or if the resetter justed wanted to get out
protected mode and resume executing some real mode code pointed to by 467h.

  • New states SOFT_RESETTING and SOFT_RESETTING_LS. The latter returns to RUNNING_LS, not SUSPENDED_LS like for hard reset.
  • Added a firmware interface so the VMM/PDM can ask it whether we're supposed to do a hard reset or a soft(/warm) one.
  • Implemented firmware interface for the PC BIOS (but not EFI). It indicates soft(/warm) reset when CMOS[0xf] is 5, 9 or 10.
  • Moved the CMOS[0xf] resetting from the RTC device to the PC BIOS since it's firmware thing, not RTC.
  • Added a flag parameter to PDMDevHlpVMReset for specifying the source of the reset operation. One class of sources (GIM) will always trigger hard resets, whereas the others will check with the firmware first.
  • Added PDMR3GetResetInfo for query the flags passed to PDMDevHlpVMReset and for asking the firmware whether it's a hard or soft reset. The latter, however, is only done if only CPU 0 is active. Systems with more than one CPU in a state other than EMSTATE_WAIT_SIPI status will always be hard reset.
  • Added internal VMR3ResetFF and VMR3ResetTripleFault APIs for handling the VM_FF_RESET and VINF_EM_TRIPLE_FAULT conditions.
  • Added PMDR3ResetSoft and had it call pfnSoftReset (which is now defined).

Warning! Major PDM_DEVHLPR3_VERSION change, minor PDM_DEVREG_VERSION change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 58.7 KB
Line 
1/* $Id: DevPcBios.cpp 60404 2016-04-09 23:45:55Z vboxsync $ */
2/** @file
3 * DevPcBios - PC BIOS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pdmstorageifs.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/pgm.h>
27
28#include <VBox/log.h>
29#include <iprt/asm.h>
30#include <iprt/assert.h>
31#include <iprt/buildconfig.h>
32#include <iprt/file.h>
33#include <iprt/mem.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <iprt/cdefs.h>
37#include <VBox/err.h>
38#include <VBox/param.h>
39
40#include "VBoxDD.h"
41#include "VBoxDD2.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 Floppy drive type:
56 0x10
57 Hard disk type (old):
58 0x12
59 Equipment byte:
60 0x14
61 Base memory:
62 0x15
63 0x16
64 Extended memory:
65 0x17
66 0x18
67 0x30
68 0x31
69 First IDE HDD:
70 0x19
71 0x1e - 0x25
72 Second IDE HDD:
73 0x1a
74 0x26 - 0x2d
75 Checksum of 0x10-0x2d:
76 0x2e
77 0x2f
78 Amount of memory above 16M and below 4GB in 64KB units:
79 0x34
80 0x35
81 Boot device (BOCHS BIOS specific):
82 0x38
83 0x3c
84 0x3d
85 PXE debug:
86 0x3f
87 First SATA HDD:
88 0x40 - 0x47
89 Second SATA HDD:
90 0x48 - 0x4f
91 Third SATA HDD:
92 0x50 - 0x57
93 Fourth SATA HDD:
94 0x58 - 0x5f
95 Number of CPUs:
96 0x60
97 RAM above 4G in 64KB units:
98 0x61 - 0x65
99 Third IDE HDD:
100 0x67 - 0x6e
101 Fourth IDE HDD:
102 0x70 - 0x77
103
104 Second CMOS bank (offsets 0x80 to 0xff):
105 Reserved for internal use by PXE ROM:
106 0x80 - 0x81
107 First net boot device PCI bus/dev/fn:
108 0x82 - 0x83
109 Second to third net boot devices:
110 0x84 - 0x89
111 First SCSI HDD:
112 0x90 - 0x97
113 Second SCSI HDD:
114 0x98 - 0x9f
115 Third SCSI HDD:
116 0xa0 - 0xa7
117 Fourth SCSI HDD:
118 0xa8 - 0xaf
119
120@endverbatim
121 *
122 * @todo Mark which bits are compatible with which BIOSes and
123 * which are our own definitions.
124 */
125
126
127/*********************************************************************************************************************************
128* Structures and Typedefs *
129*********************************************************************************************************************************/
130
131/**
132 * The boot device.
133 */
134typedef enum DEVPCBIOSBOOT
135{
136 DEVPCBIOSBOOT_NONE,
137 DEVPCBIOSBOOT_FLOPPY,
138 DEVPCBIOSBOOT_HD,
139 DEVPCBIOSBOOT_DVD,
140 DEVPCBIOSBOOT_LAN
141} DEVPCBIOSBOOT;
142
143/**
144 * PC Bios instance data structure.
145 */
146typedef struct DEVPCBIOS
147{
148 /** Pointer back to the device instance. */
149 PPDMDEVINS pDevIns;
150
151 /** Boot devices (ordered). */
152 DEVPCBIOSBOOT aenmBootDevice[4];
153 /** RAM size (in bytes). */
154 uint64_t cbRam;
155 /** RAM hole size (in bytes). */
156 uint32_t cbRamHole;
157 /** Bochs shutdown index. */
158 uint32_t iShutdown;
159 /** Floppy device. */
160 char *pszFDDevice;
161 /** Harddisk device. */
162 char *pszHDDevice;
163 /** Sata harddisk device. */
164 char *pszSataDevice;
165 /** LUNs of the four BIOS-accessible SATA disks. */
166 uint32_t iSataHDLUN[4];
167 /** SCSI harddisk device. */
168 char *pszScsiDevice;
169 /** LUNs of the four BIOS-accessible SCSI disks. */
170 uint32_t iScsiHDLUN[4];
171 /** Bios message buffer. */
172 char szMsg[256];
173 /** Bios message buffer index. */
174 uint32_t iMsg;
175 /** The system BIOS ROM data. */
176 uint8_t *pu8PcBios;
177 /** The size of the system BIOS ROM. */
178 uint32_t cbPcBios;
179 /** The name of the BIOS ROM file. */
180 char *pszPcBiosFile;
181 /** The LAN boot ROM data. */
182 uint8_t *pu8LanBoot;
183 /** The name of the LAN boot ROM file. */
184 char *pszLanBootFile;
185 /** The size of the LAN boot ROM. */
186 uint64_t cbLanBoot;
187 /** The DMI tables. */
188 uint8_t au8DMIPage[0x1000];
189 /** The boot countdown (in seconds). */
190 uint8_t uBootDelay;
191 /** I/O-APIC enabled? */
192 uint8_t u8IOAPIC;
193 /** PXE debug logging enabled? */
194 uint8_t u8PXEDebug;
195 /** PXE boot PCI bus/dev/fn list. */
196 uint16_t au16NetBootDev[NET_BOOT_DEVS];
197 /** Number of logical CPUs in guest */
198 uint16_t cCpus;
199 uint32_t u32McfgBase;
200 uint32_t cbMcfgLength;
201
202 /** Firmware registration structure. */
203 PDMFWREG FwReg;
204 /** Dummy. */
205 PCPDMFWHLPR3 pFwHlpR3;
206 /** Whether to consult the shutdown status (CMOS[0xf]) for deciding upon soft
207 * or hard reset. */
208 bool fCheckShutdownStatusForSoftReset;
209 /** Whether to clear the shutdown status on hard reset. */
210 bool fClearShutdownStatusOnHardReset;
211 /** Number of soft resets we've logged. */
212 uint32_t cLoggedSoftResets;
213} DEVPCBIOS;
214/** Pointer to the BIOS device state. */
215typedef DEVPCBIOS *PDEVPCBIOS;
216
217
218/**
219 * @callback_method_impl{FNIOMIOPORTIN, Boch Debug and Shutdown ports.}
220 */
221static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
222{
223 return VERR_IOM_IOPORT_UNUSED;
224}
225
226
227/**
228 * @callback_method_impl{FNIOMIOPORTOUT, Boch Debug and Shutdown ports.}
229 */
230static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
231{
232 /*
233 * Bochs BIOS char printing.
234 */
235 if ( cb == 1
236 && ( Port == 0x402
237 || Port == 0x403))
238 {
239 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
240 /* The raw version. */
241 switch (u32)
242 {
243 case '\r': Log2(("pcbios: <return>\n")); break;
244 case '\n': Log2(("pcbios: <newline>\n")); break;
245 case '\t': Log2(("pcbios: <tab>\n")); break;
246 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
247 }
248
249 /* The readable, buffered version. */
250 if (u32 == '\n' || u32 == '\r')
251 {
252 pThis->szMsg[pThis->iMsg] = '\0';
253 if (pThis->iMsg)
254 Log(("pcbios: %s\n", pThis->szMsg));
255 pThis->iMsg = 0;
256 }
257 else
258 {
259 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
260 {
261 pThis->szMsg[pThis->iMsg] = '\0';
262 Log(("pcbios: %s\n", pThis->szMsg));
263 pThis->iMsg = 0;
264 }
265 pThis->szMsg[pThis->iMsg] = (char )u32;
266 pThis->szMsg[++pThis->iMsg] = '\0';
267 }
268 return VINF_SUCCESS;
269 }
270
271 /*
272 * Bochs BIOS shutdown request.
273 */
274 if (cb == 1 && Port == 0x8900)
275 {
276 static const unsigned char szShutdown[] = "Shutdown";
277 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
278 if (u32 == szShutdown[pThis->iShutdown])
279 {
280 pThis->iShutdown++;
281 if (pThis->iShutdown == 8)
282 {
283 pThis->iShutdown = 0;
284 LogRel(("PcBios: 8900h shutdown request\n"));
285 return PDMDevHlpVMPowerOff(pDevIns);
286 }
287 }
288 else
289 pThis->iShutdown = 0;
290 return VINF_SUCCESS;
291 }
292
293 /* not in use. */
294 return VINF_SUCCESS;
295}
296
297
298/**
299 * Write to CMOS memory.
300 * This is used by the init complete code.
301 */
302static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
303{
304 Assert(off < 256);
305 Assert(u32Val < 256);
306
307 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
308 AssertRC(rc);
309}
310
311
312/**
313 * Read from CMOS memory.
314 * This is used by the init complete code.
315 */
316static uint8_t pcbiosCmosRead(PPDMDEVINS pDevIns, unsigned off)
317{
318 Assert(off < 256);
319
320 uint8_t u8val;
321 int rc = PDMDevHlpCMOSRead(pDevIns, off, &u8val);
322 AssertRC(rc);
323
324 return u8val;
325}
326
327
328/**
329 * @interface_method_impl{PDMFWREG,pfnIsHardReset}
330 */
331static DECLCALLBACK(bool) pcbiosFw_IsHardReset(PPDMDEVINS pDevIns, uint32_t fFlags)
332{
333 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
334 if (pThis->fCheckShutdownStatusForSoftReset)
335 {
336 uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
337 if ( bShutdownStatus == 0x5
338 || bShutdownStatus == 0x9
339 || bShutdownStatus == 0xa)
340 {
341 const uint32_t cMaxLogged = 10;
342 if (pThis->cLoggedSoftResets < cMaxLogged)
343 {
344 RTFAR16 Far16 = { 0xfeed, 0xface };
345 PDMDevHlpPhysRead(pDevIns, 0x467, &Far16, sizeof(Far16));
346 pThis->cLoggedSoftResets++;
347 LogRel(("PcBios: Soft reset #%u - shutdown status %#x, warm reset vector (0040:0067) is %04x:%04x%s\n",
348 pThis->cLoggedSoftResets, bShutdownStatus, Far16.sel, Far16.sel,
349 pThis->cLoggedSoftResets < cMaxLogged ? "." : " - won't log any more!"));
350 }
351 return false;
352 }
353 }
354 return true;
355}
356
357
358/**
359 * @interface_method_impl{PDMDEVREG,pfnReset}
360 */
361static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
362{
363 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
364
365 if (pThis->fClearShutdownStatusOnHardReset)
366 {
367 uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
368 if (bShutdownStatus != 0)
369 {
370 LogRel(("PcBios: Clearing shutdown status code %02x.\n", bShutdownStatus));
371 pcbiosCmosWrite(pDevIns, 0xf, 0);
372 }
373 }
374}
375
376
377/**
378 * Attempt to guess the LCHS disk geometry from the MS-DOS master boot record
379 * (partition table).
380 *
381 * @returns VBox status code.
382 * @param pBlock The block device interface of the disk.
383 * @param pLCHSGeometry Where to return the disk geometry on success
384 */
385static int biosGuessDiskLCHS(PPDMIMEDIA pMedia, PPDMMEDIAGEOMETRY pLCHSGeometry)
386{
387 uint8_t aMBR[512], *p;
388 int rc;
389 uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
390
391 if (!pMedia)
392 return VERR_INVALID_PARAMETER;
393 rc = pMedia->pfnReadPcBios(pMedia, 0, aMBR, sizeof(aMBR));
394 if (RT_FAILURE(rc))
395 return rc;
396 /* Test MBR magic number. */
397 if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
398 return VERR_INVALID_PARAMETER;
399 for (uint32_t i = 0; i < 4; i++)
400 {
401 /* Figure out the start of a partition table entry. */
402 p = &aMBR[0x1be + i * 16];
403 iEndHead = p[5];
404 iEndSector = p[6] & 63;
405 if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
406 {
407 /* Assumption: partition terminates on a cylinder boundary. */
408 cLCHSHeads = iEndHead + 1;
409 cLCHSSectors = iEndSector;
410 cLCHSCylinders = RT_MIN(1024, pMedia->pfnGetSize(pMedia) / (512 * cLCHSHeads * cLCHSSectors));
411 if (cLCHSCylinders >= 1)
412 {
413 pLCHSGeometry->cCylinders = cLCHSCylinders;
414 pLCHSGeometry->cHeads = cLCHSHeads;
415 pLCHSGeometry->cSectors = cLCHSSectors;
416 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
417 return VINF_SUCCESS;
418 }
419 }
420 }
421 return VERR_INVALID_PARAMETER;
422}
423
424
425/**
426 * Initializes the CMOS data for one harddisk.
427 */
428static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
429{
430 Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
431 if (offType)
432 pcbiosCmosWrite(pDevIns, offType, 47);
433 /* Cylinders low */
434 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
435 /* Cylinders high */
436 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
437 /* Heads */
438 pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
439 /* Landing zone low */
440 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
441 /* Landing zone high */
442 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
443 /* Write precomp low */
444 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
445 /* Write precomp high */
446 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
447 /* Sectors */
448 pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
449}
450
451
452/**
453 * Set logical CHS geometry for a hard disk
454 *
455 * @returns VBox status code.
456 * @param pBase Base interface for the device.
457 * @param pHardDisk The hard disk.
458 * @param pLCHSGeometry Where to store the geometry settings.
459 */
460static int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIMEDIA pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
461{
462 PDMMEDIAGEOMETRY LCHSGeometry;
463 int rc = VINF_SUCCESS;
464
465 rc = pHardDisk->pfnBiosGetLCHSGeometry(pHardDisk, &LCHSGeometry);
466 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
467 || LCHSGeometry.cCylinders == 0
468 || LCHSGeometry.cHeads == 0
469 || LCHSGeometry.cHeads > 255
470 || LCHSGeometry.cSectors == 0
471 || LCHSGeometry.cSectors > 63)
472 {
473 /* No LCHS geometry, autodetect and set. */
474 rc = biosGuessDiskLCHS(pHardDisk, &LCHSGeometry);
475 if (RT_FAILURE(rc))
476 {
477 /* Try if PCHS geometry works, otherwise fall back. */
478 rc = pHardDisk->pfnBiosGetPCHSGeometry(pHardDisk, &LCHSGeometry);
479 }
480 if ( RT_FAILURE(rc)
481 || LCHSGeometry.cCylinders == 0
482 || LCHSGeometry.cCylinders > 1024
483 || LCHSGeometry.cHeads == 0
484 || LCHSGeometry.cHeads > 16
485 || LCHSGeometry.cSectors == 0
486 || LCHSGeometry.cSectors > 63)
487 {
488 uint64_t cSectors = pHardDisk->pfnGetSize(pHardDisk) / 512;
489 if (cSectors / 16 / 63 <= 1024)
490 {
491 LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
492 LCHSGeometry.cHeads = 16;
493 }
494 else if (cSectors / 32 / 63 <= 1024)
495 {
496 LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
497 LCHSGeometry.cHeads = 32;
498 }
499 else if (cSectors / 64 / 63 <= 1024)
500 {
501 LCHSGeometry.cCylinders = cSectors / 64 / 63;
502 LCHSGeometry.cHeads = 64;
503 }
504 else if (cSectors / 128 / 63 <= 1024)
505 {
506 LCHSGeometry.cCylinders = cSectors / 128 / 63;
507 LCHSGeometry.cHeads = 128;
508 }
509 else
510 {
511 LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
512 LCHSGeometry.cHeads = 255;
513 }
514 LCHSGeometry.cSectors = 63;
515
516 }
517 rc = pHardDisk->pfnBiosSetLCHSGeometry(pHardDisk, &LCHSGeometry);
518 if (rc == VERR_VD_IMAGE_READ_ONLY)
519 {
520 LogRel(("PcBios: ATA failed to update LCHS geometry, read only\n"));
521 rc = VINF_SUCCESS;
522 }
523 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
524 {
525 LogRel(("PcBios: ATA failed to update LCHS geometry, backend refused\n"));
526 rc = VINF_SUCCESS;
527 }
528 }
529
530 *pLCHSGeometry = LCHSGeometry;
531
532 return rc;
533}
534
535
536/**
537 * Get logical CHS geometry for a hard disk, intended for SCSI/SAS drives
538 * with no physical geometry.
539 *
540 * @returns VBox status code.
541 * @param pHardDisk The hard disk.
542 * @param pLCHSGeometry Where to store the geometry settings.
543 */
544static int getLogicalDiskGeometry(PPDMIMEDIA pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
545{
546 PDMMEDIAGEOMETRY LCHSGeometry;
547 int rc = VINF_SUCCESS;
548
549 rc = pHardDisk->pfnBiosGetLCHSGeometry(pHardDisk, &LCHSGeometry);
550 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
551 || LCHSGeometry.cCylinders == 0
552 || LCHSGeometry.cHeads == 0
553 || LCHSGeometry.cHeads > 255
554 || LCHSGeometry.cSectors == 0
555 || LCHSGeometry.cSectors > 63)
556 {
557 /* Unlike the ATA case, if the image does not provide valid logical
558 * geometry, we leave things alone and let the BIOS decide what the
559 * logical geometry should be.
560 */
561 rc = VERR_PDM_GEOMETRY_NOT_SET;
562 }
563 else
564 *pLCHSGeometry = LCHSGeometry;
565
566 return rc;
567}
568
569
570/**
571 * Get BIOS boot code from enmBootDevice in order
572 *
573 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
574 */
575static uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
576{
577 switch (pThis->aenmBootDevice[iOrder])
578 {
579 case DEVPCBIOSBOOT_NONE:
580 return 0;
581 case DEVPCBIOSBOOT_FLOPPY:
582 return 1;
583 case DEVPCBIOSBOOT_HD:
584 return 2;
585 case DEVPCBIOSBOOT_DVD:
586 return 3;
587 case DEVPCBIOSBOOT_LAN:
588 return 4;
589 default:
590 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
591 return 0;
592 }
593}
594
595
596/**
597 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
598 *
599 * This routine will write information needed by the bios to the CMOS.
600 *
601 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
602 * a description of standard and non-standard CMOS registers.
603 */
604static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
605{
606 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
607 uint32_t u32;
608 unsigned i;
609 PUVM pUVM = PDMDevHlpGetUVM(pDevIns); AssertRelease(pUVM);
610 PPDMIMEDIA apHDs[4] = {0};
611 LogFlow(("pcbiosInitComplete:\n"));
612
613 /*
614 * Memory sizes.
615 */
616 /* base memory. */
617 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 */
618 pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
619 pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
620
621 /* Extended memory, up to 65MB */
622 u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
623 pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
624 pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
625 pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
626 pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
627
628 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
629 and below 4GB (as it can only hold 4GB+16M). We have to chop off the
630 top 2MB or it conflict with what the ACPI tables return. (Should these
631 be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
632 with the high BIOS mapping.) */
633 uint64_t const offRamHole = _4G - pThis->cbRamHole;
634 if (pThis->cbRam > 16 * _1M)
635 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
636 else
637 u32 = 0;
638 pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
639 pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
640
641 /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
642 Bochs got these in a different location which we've already used for SATA,
643 it also lacks the last two. */
644 uint64_t c64KBAbove4GB;
645 if (pThis->cbRam <= offRamHole)
646 c64KBAbove4GB = 0;
647 else
648 {
649 c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
650 /* Make sure it doesn't hit the limits of the current BIOS code. */
651 AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
652 }
653 pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
654 pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
655 pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
656 pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
657 pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
658
659 /*
660 * Number of CPUs.
661 */
662 pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
663
664 /*
665 * Bochs BIOS specifics - boot device.
666 * We do both new and old (ami-style) settings.
667 * See rombios.c line ~7215 (int19_function).
668 */
669
670 uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
671 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
672 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
673 uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
674 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
675 pcbiosCmosWrite(pDevIns, 0x38, reg38);
676 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
677
678 /*
679 * PXE debug option.
680 */
681 pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
682
683 /*
684 * Network boot device list.
685 */
686 for (i = 0; i < NET_BOOT_DEVS; ++i)
687 {
688 pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
689 pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
690 }
691
692 /*
693 * Floppy drive type.
694 */
695 uint32_t cFDs = 0;
696 u32 = 0;
697 for (i = 0; i < 2; i++)
698 {
699 PPDMIBASE pBase;
700 int rc = PDMR3QueryLun(pUVM, pThis->pszFDDevice, 0, i, &pBase);
701 if (RT_SUCCESS(rc))
702 {
703 PPDMIMEDIA pFD = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
704 if (pFD)
705 {
706 cFDs++;
707 unsigned cShift = i == 0 ? 4 : 0;
708 switch (pFD->pfnGetType(pFD))
709 {
710 case PDMMEDIATYPE_FLOPPY_360: u32 |= 1 << cShift; break;
711 case PDMMEDIATYPE_FLOPPY_1_20: u32 |= 2 << cShift; break;
712 case PDMMEDIATYPE_FLOPPY_720: u32 |= 3 << cShift; break;
713 case PDMMEDIATYPE_FLOPPY_1_44: u32 |= 4 << cShift; break;
714 case PDMMEDIATYPE_FLOPPY_2_88: u32 |= 5 << cShift; break;
715 case PDMMEDIATYPE_FLOPPY_FAKE_15_6: u32 |= 14 << cShift; break;
716 case PDMMEDIATYPE_FLOPPY_FAKE_63_5: u32 |= 15 << cShift; break;
717 default: AssertFailed(); break;
718 }
719 }
720 }
721 }
722 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
723
724 /*
725 * Equipment byte.
726 */
727 if (cFDs > 0)
728 u32 = ((cFDs - 1) << 6) | 0x01; /* floppy installed, additional drives. */
729 else
730 u32 = 0x00; /* floppy not installed. */
731 u32 |= RT_BIT(1); /* math coprocessor installed */
732 u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
733 u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
734 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
735
736 /*
737 * IDE harddisks.
738 */
739 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
740 {
741 PPDMIBASE pBase;
742 int rc = PDMR3QueryLun(pUVM, pThis->pszHDDevice, 0, i, &pBase);
743 if (RT_SUCCESS(rc))
744 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
745 if ( apHDs[i]
746 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
747 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
748 apHDs[i] = NULL;
749 if (apHDs[i])
750 {
751 PDMMEDIAGEOMETRY LCHSGeometry;
752 int rc2 = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
753 AssertRC(rc2);
754
755 if (i < 4)
756 {
757 /* Award BIOS extended drive types for first to fourth disk.
758 * Used by the BIOS for setting the logical geometry. */
759 int offType, offInfo;
760 switch (i)
761 {
762 case 0:
763 offType = 0x19;
764 offInfo = 0x1e;
765 break;
766 case 1:
767 offType = 0x1a;
768 offInfo = 0x26;
769 break;
770 case 2:
771 offType = 0x00;
772 offInfo = 0x67;
773 break;
774 case 3:
775 default:
776 offType = 0x00;
777 offInfo = 0x70;
778 break;
779 }
780 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
781 &LCHSGeometry);
782 }
783 LogRel(("PcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
784 }
785 }
786
787 /* 0Fh means extended and points to 19h, 1Ah */
788 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
789 pcbiosCmosWrite(pDevIns, 0x12, u32);
790
791 /*
792 * SATA harddisks.
793 */
794 if (pThis->pszSataDevice)
795 {
796 /* Clear pointers to the block devices. */
797 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
798 apHDs[i] = NULL;
799
800 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
801 {
802 PPDMIBASE pBase;
803 int rc = PDMR3QueryLun(pUVM, pThis->pszSataDevice, 0, pThis->iSataHDLUN[i], &pBase);
804 if (RT_SUCCESS(rc))
805 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
806 if ( apHDs[i]
807 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
808 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
809 apHDs[i] = NULL;
810 if (apHDs[i])
811 {
812 PDMMEDIAGEOMETRY LCHSGeometry;
813 rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
814 AssertRC(rc);
815
816 if (i < 4)
817 {
818 /* Award BIOS extended drive types for first to fourth disk.
819 * Used by the BIOS for setting the logical geometry. */
820 int offInfo;
821 switch (i)
822 {
823 case 0:
824 offInfo = 0x40;
825 break;
826 case 1:
827 offInfo = 0x48;
828 break;
829 case 2:
830 offInfo = 0x50;
831 break;
832 case 3:
833 default:
834 offInfo = 0x58;
835 break;
836 }
837 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
838 &LCHSGeometry);
839 }
840 LogRel(("PcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
841 }
842 }
843 }
844
845 /*
846 * SCSI harddisks. Not handled quite the same as SATA.
847 */
848 if (pThis->pszScsiDevice)
849 {
850 /* Clear pointers to the block devices. */
851 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
852 apHDs[i] = NULL;
853
854 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
855 {
856 PPDMIBASE pBase;
857 int rc = PDMR3QueryLun(pUVM, pThis->pszScsiDevice, 0, pThis->iScsiHDLUN[i], &pBase);
858 if (RT_SUCCESS(rc))
859 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
860 if ( apHDs[i]
861 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
862 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
863 apHDs[i] = NULL;
864 if (apHDs[i])
865 {
866 PDMMEDIAGEOMETRY LCHSGeometry;
867 rc = getLogicalDiskGeometry(apHDs[i], &LCHSGeometry);
868
869 if (i < 4 && RT_SUCCESS(rc))
870 {
871 /* Extended drive information (for SCSI disks).
872 * Used by the BIOS for setting the logical geometry, but
873 * only if the image provided valid data.
874 */
875 int offInfo;
876 switch (i)
877 {
878 case 0:
879 offInfo = 0x90;
880 break;
881 case 1:
882 offInfo = 0x98;
883 break;
884 case 2:
885 offInfo = 0xa0;
886 break;
887 case 3:
888 default:
889 offInfo = 0xa8;
890 break;
891 }
892 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo, &LCHSGeometry);
893 LogRel(("PcBios: SCSI LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
894 }
895 else
896 LogRel(("PcBios: SCSI LUN#%d LCHS not provided\n", i));
897 }
898 }
899 }
900
901 /* Calculate and store AT-style CMOS checksum. */
902 uint16_t cksum = 0;
903 for (i = 0x10; i < 0x2e; ++i)
904 cksum += pcbiosCmosRead(pDevIns, i);
905 pcbiosCmosWrite(pDevIns, 0x2e, cksum >> 8);
906 pcbiosCmosWrite(pDevIns, 0x2f, cksum & 0xff);
907
908 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
909 return VINF_SUCCESS;
910}
911
912
913/**
914 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
915 */
916static DECLCALLBACK(void) pcbiosMemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
917{
918 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
919 LogFlow(("pcbiosMemSetup:\n"));
920
921 if (pThis->u8IOAPIC)
922 FwCommonPlantMpsFloatPtr(pDevIns);
923
924 /*
925 * Re-shadow the LAN ROM image and make it RAM/RAM.
926 *
927 * This is normally done by the BIOS code, but since we're currently lacking
928 * the chipset support for this we do it here (and in the constructor).
929 */
930 uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, PAGE_SIZE) >> PAGE_SHIFT;
931 RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
932 while (cPages > 0)
933 {
934 uint8_t abPage[PAGE_SIZE];
935 int rc;
936
937 /* Read the (original) ROM page and write it back to the RAM page. */
938 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
939 AssertLogRelRC(rc);
940
941 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
942 AssertLogRelRC(rc);
943 if (RT_FAILURE(rc))
944 memset(abPage, 0xcc, sizeof(abPage));
945
946 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
947 AssertLogRelRC(rc);
948
949 /* Switch to the RAM/RAM mode. */
950 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
951 AssertLogRelRC(rc);
952
953 /* Advance */
954 GCPhys += PAGE_SIZE;
955 cPages--;
956 }
957}
958
959
960/**
961 * @interface_method_impl{PDMDEVREG,pfnDestruct}
962 */
963static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
964{
965 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
966 LogFlow(("pcbiosDestruct:\n"));
967 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
968
969 /*
970 * Free MM heap pointers.
971 */
972 if (pThis->pu8PcBios)
973 {
974 MMR3HeapFree(pThis->pu8PcBios);
975 pThis->pu8PcBios = NULL;
976 }
977
978 if (pThis->pszPcBiosFile)
979 {
980 MMR3HeapFree(pThis->pszPcBiosFile);
981 pThis->pszPcBiosFile = NULL;
982 }
983
984 if (pThis->pu8LanBoot)
985 {
986 MMR3HeapFree(pThis->pu8LanBoot);
987 pThis->pu8LanBoot = NULL;
988 }
989
990 if (pThis->pszLanBootFile)
991 {
992 MMR3HeapFree(pThis->pszLanBootFile);
993 pThis->pszLanBootFile = NULL;
994 }
995
996 if (pThis->pszHDDevice)
997 {
998 MMR3HeapFree(pThis->pszHDDevice);
999 pThis->pszHDDevice = NULL;
1000 }
1001
1002 if (pThis->pszFDDevice)
1003 {
1004 MMR3HeapFree(pThis->pszFDDevice);
1005 pThis->pszFDDevice = NULL;
1006 }
1007
1008 if (pThis->pszSataDevice)
1009 {
1010 MMR3HeapFree(pThis->pszSataDevice);
1011 pThis->pszSataDevice = NULL;
1012 }
1013
1014 if (pThis->pszScsiDevice)
1015 {
1016 MMR3HeapFree(pThis->pszScsiDevice);
1017 pThis->pszScsiDevice = NULL;
1018 }
1019
1020 return VINF_SUCCESS;
1021}
1022
1023
1024/**
1025 * Convert config value to DEVPCBIOSBOOT.
1026 *
1027 * @returns VBox status code.
1028 * @param pCfg Configuration handle.
1029 * @param pszParam The name of the value to read.
1030 * @param penmBoot Where to store the boot method.
1031 */
1032static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfg, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
1033{
1034 char *psz;
1035 int rc = CFGMR3QueryStringAlloc(pCfg, pszParam, &psz);
1036 if (RT_FAILURE(rc))
1037 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1038 N_("Configuration error: Querying \"%s\" as a string failed"),
1039 pszParam);
1040 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
1041 *penmBoot = DEVPCBIOSBOOT_DVD;
1042 else if (!strcmp(psz, "IDE"))
1043 *penmBoot = DEVPCBIOSBOOT_HD;
1044 else if (!strcmp(psz, "FLOPPY"))
1045 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
1046 else if (!strcmp(psz, "LAN"))
1047 *penmBoot = DEVPCBIOSBOOT_LAN;
1048 else if (!strcmp(psz, "NONE"))
1049 *penmBoot = DEVPCBIOSBOOT_NONE;
1050 else
1051 {
1052 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1053 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
1054 pszParam, psz);
1055 rc = VERR_INTERNAL_ERROR;
1056 }
1057 MMR3HeapFree(psz);
1058 return rc;
1059}
1060
1061/**
1062 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1063 */
1064static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1065{
1066 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
1067 int rc;
1068 int cb;
1069
1070 Assert(iInstance == 0);
1071 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1072
1073 /*
1074 * Validate configuration.
1075 */
1076 if (!CFGMR3AreValuesValid(pCfg,
1077 "BootDevice0\0"
1078 "BootDevice1\0"
1079 "BootDevice2\0"
1080 "BootDevice3\0"
1081 "RamSize\0"
1082 "RamHoleSize\0"
1083 "HardDiskDevice\0"
1084 "SataHardDiskDevice\0"
1085 "SataLUN1\0"
1086 "SataLUN2\0"
1087 "SataLUN3\0"
1088 "SataLUN4\0"
1089 "ScsiHardDiskDevice\0"
1090 "ScsiLUN1\0"
1091 "ScsiLUN2\0"
1092 "ScsiLUN3\0"
1093 "ScsiLUN4\0"
1094 "FloppyDevice\0"
1095 "DelayBoot\0"
1096 "BiosRom\0"
1097 "LanBootRom\0"
1098 "PXEDebug\0"
1099 "UUID\0"
1100 "IOAPIC\0"
1101 "NumCPUs\0"
1102 "McfgBase\0"
1103 "McfgLength\0"
1104 "DmiBIOSFirmwareMajor\0"
1105 "DmiBIOSFirmwareMinor\0"
1106 "DmiBIOSReleaseDate\0"
1107 "DmiBIOSReleaseMajor\0"
1108 "DmiBIOSReleaseMinor\0"
1109 "DmiBIOSVendor\0"
1110 "DmiBIOSVersion\0"
1111 "DmiSystemFamily\0"
1112 "DmiSystemProduct\0"
1113 "DmiSystemSerial\0"
1114 "DmiSystemSKU\0"
1115 "DmiSystemUuid\0"
1116 "DmiSystemVendor\0"
1117 "DmiSystemVersion\0"
1118 "DmiBoardAssetTag\0"
1119 "DmiBoardBoardType\0"
1120 "DmiBoardLocInChass\0"
1121 "DmiBoardProduct\0"
1122 "DmiBoardSerial\0"
1123 "DmiBoardVendor\0"
1124 "DmiBoardVersion\0"
1125 "DmiChassisAssetTag\0"
1126 "DmiChassisSerial\0"
1127 "DmiChassisType\0"
1128 "DmiChassisVendor\0"
1129 "DmiChassisVersion\0"
1130 "DmiProcManufacturer\0"
1131 "DmiProcVersion\0"
1132 "DmiOEMVBoxVer\0"
1133 "DmiOEMVBoxRev\0"
1134 "DmiUseHostInfo\0"
1135 "DmiExposeMemoryTable\0"
1136 "DmiExposeProcInf\0"
1137 "CheckShutdownStatusForSoftReset\0"
1138 "ClearShutdownStatusOnHardReset\0"
1139 ))
1140 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1141 N_("Invalid configuration for device pcbios device"));
1142
1143 /*
1144 * Init the data.
1145 */
1146 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
1147 if (RT_FAILURE(rc))
1148 return PDMDEV_SET_ERROR(pDevIns, rc,
1149 N_("Configuration error: Querying \"RamSize\" as integer failed"));
1150
1151 rc = CFGMR3QueryU32Def(pCfg, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
1152 if (RT_FAILURE(rc))
1153 return PDMDEV_SET_ERROR(pDevIns, rc,
1154 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
1155
1156 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
1157 if (RT_FAILURE(rc))
1158 return PDMDEV_SET_ERROR(pDevIns, rc,
1159 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
1160
1161 rc = CFGMR3QueryU32Def(pCfg, "McfgBase", &pThis->u32McfgBase, 0);
1162 if (RT_FAILURE(rc))
1163 return PDMDEV_SET_ERROR(pDevIns, rc,
1164 N_("Configuration error: Querying \"\" as integer failed"));
1165 rc = CFGMR3QueryU32Def(pCfg, "McfgLength", &pThis->cbMcfgLength, 0);
1166 if (RT_FAILURE(rc))
1167 return PDMDEV_SET_ERROR(pDevIns, rc,
1168 N_("Configuration error: Querying \"McfgLength\" as integer failed"));
1169
1170
1171 LogRel(("PcBios: [SMP] BIOS with %u CPUs\n", pThis->cCpus));
1172
1173 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
1174 if (RT_FAILURE (rc))
1175 return PDMDEV_SET_ERROR(pDevIns, rc,
1176 N_("Configuration error: Failed to read \"IOAPIC\""));
1177
1178 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
1179 Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
1180 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
1181 {
1182 rc = pcbiosBootFromCfg(pDevIns, pCfg, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
1183 if (RT_FAILURE(rc))
1184 return rc;
1185 }
1186
1187 rc = CFGMR3QueryStringAlloc(pCfg, "HardDiskDevice", &pThis->pszHDDevice);
1188 if (RT_FAILURE(rc))
1189 return PDMDEV_SET_ERROR(pDevIns, rc,
1190 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1191
1192 rc = CFGMR3QueryStringAlloc(pCfg, "FloppyDevice", &pThis->pszFDDevice);
1193 if (RT_FAILURE(rc))
1194 return PDMDEV_SET_ERROR(pDevIns, rc,
1195 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1196
1197 rc = CFGMR3QueryStringAlloc(pCfg, "SataHardDiskDevice", &pThis->pszSataDevice);
1198 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1199 pThis->pszSataDevice = NULL;
1200 else if (RT_FAILURE(rc))
1201 return PDMDEV_SET_ERROR(pDevIns, rc,
1202 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1203
1204 if (pThis->pszSataDevice)
1205 {
1206 static const char * const s_apszSataDisks[] =
1207 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
1208 Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
1209 for (unsigned i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
1210 {
1211 rc = CFGMR3QueryU32(pCfg, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
1212 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1213 pThis->iSataHDLUN[i] = i;
1214 else if (RT_FAILURE(rc))
1215 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1216 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1217 }
1218 }
1219
1220 /* Repeat the exercise for SCSI drives. */
1221 rc = CFGMR3QueryStringAlloc(pCfg, "ScsiHardDiskDevice", &pThis->pszScsiDevice);
1222 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1223 pThis->pszScsiDevice = NULL;
1224 else if (RT_FAILURE(rc))
1225 return PDMDEV_SET_ERROR(pDevIns, rc,
1226 N_("Configuration error: Querying \"ScsiHardDiskDevice\" as a string failed"));
1227
1228 if (pThis->pszScsiDevice)
1229 {
1230 static const char * const s_apszScsiDisks[] =
1231 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
1232 Assert(RT_ELEMENTS(s_apszScsiDisks) == RT_ELEMENTS(pThis->iScsiHDLUN));
1233 for (unsigned i = 0; i < RT_ELEMENTS(pThis->iScsiHDLUN); i++)
1234 {
1235 rc = CFGMR3QueryU32(pCfg, s_apszScsiDisks[i], &pThis->iScsiHDLUN[i]);
1236 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1237 pThis->iScsiHDLUN[i] = i;
1238 else if (RT_FAILURE(rc))
1239 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1240 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszScsiDisks);
1241 }
1242 }
1243
1244
1245 /*
1246 * Register I/O Ports and PC BIOS.
1247 */
1248 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1249 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1250 if (RT_FAILURE(rc))
1251 return rc;
1252 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1253 NULL, NULL, "Bochs PC BIOS - Shutdown");
1254 if (RT_FAILURE(rc))
1255 return rc;
1256
1257 /*
1258 * Read the PXE debug logging option.
1259 */
1260 rc = CFGMR3QueryU8Def(pCfg, "PXEDebug", &pThis->u8PXEDebug, false);
1261 if (RT_FAILURE(rc))
1262 return PDMDEV_SET_ERROR(pDevIns, rc,
1263 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1264
1265 /* Clear the net boot device list. All bits set invokes old behavior,
1266 * as if no second CMOS bank was present.
1267 */
1268 memset(&pThis->au16NetBootDev, 0xff, sizeof(pThis->au16NetBootDev));
1269
1270 /*
1271 * Determine the network boot order.
1272 */
1273 PCFGMNODE pCfgNetBoot = CFGMR3GetChild(pCfg, "NetBoot");
1274 if (pCfgNetBoot == NULL)
1275 {
1276 /* Do nothing. */
1277 rc = VINF_SUCCESS;
1278 }
1279 else
1280 {
1281 PCFGMNODE pCfgNetBootDevice;
1282 uint8_t u8PciBus;
1283 uint8_t u8PciDev;
1284 uint8_t u8PciFn;
1285 uint16_t u16BusDevFn;
1286 char szIndex[] = "?";
1287
1288 Assert(pCfgNetBoot);
1289 for (unsigned i = 0; i < NET_BOOT_DEVS; ++i)
1290 {
1291 szIndex[0] = '0' + i;
1292 pCfgNetBootDevice = CFGMR3GetChild(pCfgNetBoot, szIndex);
1293
1294 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIBusNo", &u8PciBus);
1295 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1296 {
1297 /* Do nothing and stop iterating. */
1298 rc = VINF_SUCCESS;
1299 break;
1300 }
1301 else if (RT_FAILURE(rc))
1302 return PDMDEV_SET_ERROR(pDevIns, rc,
1303 N_("Configuration error: Querying \"Netboot/x/PCIBusNo\" as integer failed"));
1304 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIDeviceNo", &u8PciDev);
1305 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1306 {
1307 /* Do nothing and stop iterating. */
1308 rc = VINF_SUCCESS;
1309 break;
1310 }
1311 else if (RT_FAILURE(rc))
1312 return PDMDEV_SET_ERROR(pDevIns, rc,
1313 N_("Configuration error: Querying \"Netboot/x/PCIDeviceNo\" as integer failed"));
1314 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIFunctionNo", &u8PciFn);
1315 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1316 {
1317 /* Do nothing and stop iterating. */
1318 rc = VINF_SUCCESS;
1319 break;
1320 }
1321 else if (RT_FAILURE(rc))
1322 return PDMDEV_SET_ERROR(pDevIns, rc,
1323 N_("Configuration error: Querying \"Netboot/x/PCIFunctionNo\" as integer failed"));
1324 u16BusDevFn = (((uint16_t)u8PciBus) << 8) | ((u8PciDev & 0x1F) << 3) | (u8PciFn & 0x7);
1325 pThis->au16NetBootDev[i] = u16BusDevFn;
1326 }
1327 }
1328
1329 /*
1330 * Get the system BIOS ROM file name.
1331 */
1332 rc = CFGMR3QueryStringAlloc(pCfg, "BiosRom", &pThis->pszPcBiosFile);
1333 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1334 {
1335 pThis->pszPcBiosFile = NULL;
1336 rc = VINF_SUCCESS;
1337 }
1338 else if (RT_FAILURE(rc))
1339 return PDMDEV_SET_ERROR(pDevIns, rc,
1340 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1341 else if (!*pThis->pszPcBiosFile)
1342 {
1343 MMR3HeapFree(pThis->pszPcBiosFile);
1344 pThis->pszPcBiosFile = NULL;
1345 }
1346
1347 if (pThis->pszPcBiosFile)
1348 {
1349 /*
1350 * Load the BIOS ROM.
1351 */
1352 RTFILE hFilePcBios;
1353 rc = RTFileOpen(&hFilePcBios, pThis->pszPcBiosFile,
1354 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1355 if (RT_SUCCESS(rc))
1356 {
1357 /* Figure the size and check restrictions. */
1358 uint64_t cbPcBios;
1359 rc = RTFileGetSize(hFilePcBios, &cbPcBios);
1360 if (RT_SUCCESS(rc))
1361 {
1362 pThis->cbPcBios = (uint32_t)cbPcBios;
1363 if ( RT_ALIGN(pThis->cbPcBios, _64K) == pThis->cbPcBios
1364 && pThis->cbPcBios == cbPcBios
1365 && pThis->cbPcBios <= 32 * _64K
1366 && pThis->cbPcBios >= _64K)
1367 {
1368 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
1369 if (pThis->pu8PcBios)
1370 {
1371 rc = RTFileRead(hFilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
1372 if (RT_FAILURE(rc))
1373 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1374 N_("Error reading the BIOS image ('%s)"), pThis->pszPcBiosFile);
1375 }
1376 else
1377 rc = PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
1378 N_("Failed to allocate %#x bytes for loading the BIOS image"),
1379 pThis->cbPcBios);
1380 }
1381 else
1382 rc = PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
1383 N_("Invalid system BIOS file size ('%s'): %#llx (%llu)"),
1384 pThis->pszPcBiosFile, cbPcBios, cbPcBios);
1385 }
1386 else
1387 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1388 N_("Failed to query the system BIOS file size ('%s')"),
1389 pThis->pszPcBiosFile);
1390 RTFileClose(hFilePcBios);
1391 }
1392 else
1393 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1394 N_("Failed to open system BIOS file '%s'"), pThis->pszPcBiosFile);
1395 if (RT_FAILURE(rc))
1396 return rc;
1397
1398 LogRel(("PcBios: Using BIOS ROM '%s' with a size of %#x bytes\n", pThis->pszPcBiosFile, pThis->cbPcBios));
1399 }
1400 else
1401 {
1402 /*
1403 * Use the embedded BIOS ROM image.
1404 */
1405 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, g_cbPcBiosBinary);
1406 if (pThis->pu8PcBios)
1407 {
1408 pThis->cbPcBios = g_cbPcBiosBinary;
1409 memcpy(pThis->pu8PcBios, g_abPcBiosBinary, pThis->cbPcBios);
1410 }
1411 else
1412 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
1413 N_("Failed to allocate %#x bytes for loading the embedded BIOS image"),
1414 g_cbPcBiosBinary);
1415 }
1416 const uint8_t *pu8PcBiosBinary = pThis->pu8PcBios;
1417 uint32_t cbPcBiosBinary = pThis->cbPcBios;
1418
1419 /*
1420 * Query the machine's UUID for SMBIOS/DMI use.
1421 */
1422 RTUUID uuid;
1423 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1424 if (RT_FAILURE(rc))
1425 return PDMDEV_SET_ERROR(pDevIns, rc,
1426 N_("Configuration error: Querying \"UUID\" failed"));
1427
1428 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1429 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1430 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1431 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1432 uint16_t cbDmiTables = 0;
1433 uint16_t cNumDmiTables = 0;
1434 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE,
1435 &uuid, pCfg, pThis->cCpus, &cbDmiTables, &cNumDmiTables);
1436 if (RT_FAILURE(rc))
1437 return rc;
1438
1439 for (unsigned i = 0; i < pThis->cbPcBios; i += 16)
1440 {
1441 /* If the DMI table is located at the expected place, patch the DMI table length and the checksum. */
1442 if ( pThis->pu8PcBios[i + 0x00] == '_'
1443 && pThis->pu8PcBios[i + 0x01] == 'D'
1444 && pThis->pu8PcBios[i + 0x02] == 'M'
1445 && pThis->pu8PcBios[i + 0x03] == 'I'
1446 && pThis->pu8PcBios[i + 0x04] == '_'
1447 && *(uint16_t*)&pThis->pu8PcBios[i + 0x06] == 0)
1448 {
1449 *(uint16_t*)&pThis->pu8PcBios[i + 0x06] = RT_H2LE_U16(cbDmiTables);
1450 *(uint16_t*)&pThis->pu8PcBios[i + 0x0C] = RT_H2LE_U16(cNumDmiTables);
1451 uint8_t u8Sum = 0;
1452 for (unsigned j = 0; j < pThis->cbPcBios; j++)
1453 if (j != i + 0x05)
1454 u8Sum += pThis->pu8PcBios[j];
1455 pThis->pu8PcBios[i + 0x05] = -u8Sum;
1456 break;
1457 }
1458 }
1459
1460 if (pThis->u8IOAPIC)
1461 {
1462 FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1463 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1464 LogRel(("PcBios: MPS table at %08x\n", VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE));
1465 }
1466
1467 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1468 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1469 if (RT_FAILURE(rc))
1470 return rc;
1471
1472 /*
1473 * Map the BIOS into memory.
1474 * There are two mappings:
1475 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1476 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1477 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1478 */
1479 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1480 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1481 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1482 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1483 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb], cb,
1484 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xfffff");
1485 if (RT_FAILURE(rc))
1486 return rc;
1487 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary, cbPcBiosBinary,
1488 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xffffffff");
1489 if (RT_FAILURE(rc))
1490 return rc;
1491
1492 /*
1493 * Get the LAN boot ROM file name.
1494 */
1495 rc = CFGMR3QueryStringAlloc(pCfg, "LanBootRom", &pThis->pszLanBootFile);
1496 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1497 {
1498 pThis->pszLanBootFile = NULL;
1499 rc = VINF_SUCCESS;
1500 }
1501 else if (RT_FAILURE(rc))
1502 return PDMDEV_SET_ERROR(pDevIns, rc,
1503 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1504 else if (!*pThis->pszLanBootFile)
1505 {
1506 MMR3HeapFree(pThis->pszLanBootFile);
1507 pThis->pszLanBootFile = NULL;
1508 }
1509
1510 uint64_t cbFileLanBoot;
1511 const uint8_t *pu8LanBootBinary = NULL;
1512 uint64_t cbLanBootBinary;
1513
1514 /*
1515 * Determine the LAN boot ROM size, open specified ROM file in the process.
1516 */
1517 RTFILE FileLanBoot = NIL_RTFILE;
1518 if (pThis->pszLanBootFile)
1519 {
1520 rc = RTFileOpen(&FileLanBoot, pThis->pszLanBootFile,
1521 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1522 if (RT_SUCCESS(rc))
1523 {
1524 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1525 if (RT_SUCCESS(rc))
1526 {
1527 if (cbFileLanBoot > _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff))
1528 rc = VERR_TOO_MUCH_DATA;
1529 }
1530 }
1531 if (RT_FAILURE(rc))
1532 {
1533 /*
1534 * Ignore failure and fall back to the built-in LAN boot ROM.
1535 */
1536 LogRel(("PcBios: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
1537 RTFileClose(FileLanBoot);
1538 FileLanBoot = NIL_RTFILE;
1539 MMR3HeapFree(pThis->pszLanBootFile);
1540 pThis->pszLanBootFile = NULL;
1541 }
1542 }
1543
1544 /*
1545 * Get the LAN boot ROM data.
1546 */
1547 if (pThis->pszLanBootFile)
1548 {
1549 LogRel(("PcBios: Using LAN ROM '%s' with a size of %#x bytes\n", pThis->pszLanBootFile, cbFileLanBoot));
1550 /*
1551 * Allocate buffer for the LAN boot ROM data.
1552 */
1553 pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, cbFileLanBoot);
1554 if (pThis->pu8LanBoot)
1555 {
1556 rc = RTFileRead(FileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
1557 if (RT_FAILURE(rc))
1558 {
1559 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", cbFileLanBoot, rc));
1560 MMR3HeapFree(pThis->pu8LanBoot);
1561 pThis->pu8LanBoot = NULL;
1562 }
1563 rc = VINF_SUCCESS;
1564 }
1565 else
1566 rc = VERR_NO_MEMORY;
1567 }
1568 else
1569 pThis->pu8LanBoot = NULL;
1570
1571 /* cleanup */
1572 if (FileLanBoot != NIL_RTFILE)
1573 RTFileClose(FileLanBoot);
1574
1575 /* If we were unable to get the data from file for whatever reason, fall
1576 * back to the built-in LAN boot ROM image.
1577 */
1578 if (pThis->pu8LanBoot == NULL)
1579 {
1580#ifdef VBOX_WITH_PXE_ROM
1581 pu8LanBootBinary = g_abNetBiosBinary;
1582 cbLanBootBinary = g_cbNetBiosBinary;
1583#endif
1584 }
1585 else
1586 {
1587 pu8LanBootBinary = pThis->pu8LanBoot;
1588 cbLanBootBinary = cbFileLanBoot;
1589 }
1590
1591 /*
1592 * Map the Network Boot ROM into memory.
1593 *
1594 * Currently there is a fixed mapping: 0x000e2000 to 0x000effff contains
1595 * the (up to) 56 kb ROM image. The mapping size is fixed to trouble with
1596 * the saved state (in PGM).
1597 */
1598 if (pu8LanBootBinary)
1599 {
1600 pThis->cbLanBoot = cbLanBootBinary;
1601
1602 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4,
1603 RT_MAX(cbLanBootBinary, _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff)),
1604 pu8LanBootBinary, cbLanBootBinary,
1605 PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
1606 AssertRCReturn(rc, rc);
1607 }
1608
1609 rc = CFGMR3QueryU8Def(pCfg, "DelayBoot", &pThis->uBootDelay, 0);
1610 if (RT_FAILURE(rc))
1611 return PDMDEV_SET_ERROR(pDevIns, rc,
1612 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1613 if (pThis->uBootDelay > 15)
1614 pThis->uBootDelay = 15;
1615
1616
1617 /*
1618 * Read shutdown status code config and register ourselves as the firmware device.
1619 */
1620
1621 /** @cfgm{CheckShutdownStatusForSoftReset, boolean, true}
1622 * Whether to consult the shutdown status code (CMOS register 0Fh) to
1623 * determine whether the guest intended a soft or hard reset. Currently only
1624 * shutdown status codes 05h, 09h and 0Ah are considered soft reset. */
1625 rc = CFGMR3QueryBoolDef(pCfg, "CheckShutdownStatusForSoftReset", &pThis->fCheckShutdownStatusForSoftReset, true);
1626 AssertLogRelRCReturn(rc, rc);
1627
1628 /** @cfgm{ClearShutdownStatusOnHardReset, boolean, true}
1629 * Whether to clear the shutdown status code (CMOS register 0Fh) on hard reset. */
1630 rc = CFGMR3QueryBoolDef(pCfg, "ClearShutdownStatusOnHardReset", &pThis->fClearShutdownStatusOnHardReset, true);
1631 AssertLogRelRCReturn(rc, rc);
1632
1633 LogRel(("PcBios: fCheckShutdownStatusForSoftReset=%RTbool fClearShutdownStatusOnHardReset=%RTbool\n",
1634 pThis->fCheckShutdownStatusForSoftReset, pThis->fClearShutdownStatusOnHardReset));
1635
1636 static PDMFWREG const s_FwReg = { PDM_FWREG_VERSION, pcbiosFw_IsHardReset, PDM_FWREG_VERSION };
1637 rc = PDMDevHlpFirmwareRegister(pDevIns, &s_FwReg, &pThis->pFwHlpR3);
1638 AssertLogRelRCReturn(rc, rc);
1639
1640 return VINF_SUCCESS;
1641}
1642
1643
1644/**
1645 * The device registration structure.
1646 */
1647const PDMDEVREG g_DevicePcBios =
1648{
1649 /* u32Version */
1650 PDM_DEVREG_VERSION,
1651 /* szName */
1652 "pcbios",
1653 /* szRCMod */
1654 "",
1655 /* szR0Mod */
1656 "",
1657 /* pszDescription */
1658 "PC BIOS Device",
1659 /* fFlags */
1660 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1661 /* fClass */
1662 PDM_DEVREG_CLASS_ARCH_BIOS,
1663 /* cMaxInstances */
1664 1,
1665 /* cbInstance */
1666 sizeof(DEVPCBIOS),
1667 /* pfnConstruct */
1668 pcbiosConstruct,
1669 /* pfnDestruct */
1670 pcbiosDestruct,
1671 /* pfnRelocate */
1672 NULL,
1673 /* pfnMemSetup */
1674 pcbiosMemSetup,
1675 /* pfnPowerOn */
1676 NULL,
1677 /* pfnReset */
1678 pcbiosReset,
1679 /* pfnSuspend */
1680 NULL,
1681 /* pfnResume */
1682 NULL,
1683 /* pfnAttach */
1684 NULL,
1685 /* pfnDetach */
1686 NULL,
1687 /* pfnQueryInterface. */
1688 NULL,
1689 /* pfnInitComplete. */
1690 pcbiosInitComplete,
1691 /* pfnPowerOff */
1692 NULL,
1693 /* pfnSoftReset */
1694 NULL,
1695 /* u32VersionEnd */
1696 PDM_DEVREG_VERSION
1697};
1698
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use