VirtualBox

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

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

DevPcBios: RT_BYTE

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

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