VirtualBox

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

Last change on this file since 61042 was 61042, checked in by vboxsync, 9 years ago

Main/Machine+BIOSSettings: introduce APIC/X2APIC CPU feature settings and a BIOS setting what should be used.
Frontends/VBoxManage: corresponding changes to allow making the settings changes
Devices/BIOS+EFI: placeholder for the BIOS setting part, which isn't implemented yet

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

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