VirtualBox

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

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

Devices/PC: paranoia s/MMR3HeapFree/PDMDevHlpMMHeapFree/

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