VirtualBox

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

Last change on this file since 100444 was 100444, checked in by vboxsync, 11 months ago

Warning fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 73.1 KB
RevLine 
[2781]1/* $Id: DevPcBios.cpp 100444 2023-07-08 14:48:54Z vboxsync $ */
[1]2/** @file
[44706]3 * DevPcBios - PC BIOS Device.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[1]26 */
27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[1]32#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
[35346]33#include <VBox/vmm/pdmdev.h>
[59253]34#include <VBox/vmm/pdmstorageifs.h>
[35346]35#include <VBox/vmm/mm.h>
36#include <VBox/vmm/pgm.h>
[60422]37#include <VBox/vmm/cpum.h>
[1]38
39#include <VBox/log.h>
[29250]40#include <iprt/asm.h>
[1]41#include <iprt/assert.h>
[22823]42#include <iprt/buildconfig.h>
[1]43#include <iprt/file.h>
[29250]44#include <iprt/mem.h>
[1]45#include <iprt/string.h>
[6871]46#include <iprt/uuid.h>
[44821]47#include <iprt/cdefs.h>
[66150]48#include <VBox/bios.h>
[1]49#include <VBox/err.h>
[4670]50#include <VBox/param.h>
[1]51
[35353]52#include "VBoxDD.h"
53#include "VBoxDD2.h"
[1]54#include "DevPcBios.h"
[24706]55#include "DevFwCommon.h"
[1]56
[27461]57#define NET_BOOT_DEVS 4
[1]58
[27461]59
[11257]60/** @page pg_devbios_cmos_assign CMOS Assignments (BIOS)
61 *
[7099]62 * The BIOS uses a CMOS to store configuration data.
[11257]63 * It is currently used as follows:
[7099]64 *
[12649]65 * @verbatim
[27461]66 First CMOS bank (offsets 0x00 to 0x7f):
[38220]67 Floppy drive type:
68 0x10
69 Hard disk type (old):
70 0x12
71 Equipment byte:
72 0x14
[12649]73 Base memory:
74 0x15
75 0x16
76 Extended memory:
77 0x17
78 0x18
79 0x30
80 0x31
[38220]81 First IDE HDD:
82 0x19
83 0x1e - 0x25
84 Second IDE HDD:
85 0x1a
86 0x26 - 0x2d
87 Checksum of 0x10-0x2d:
88 0x2e
89 0x2f
[18373]90 Amount of memory above 16M and below 4GB in 64KB units:
[12649]91 0x34
92 0x35
[38220]93 Boot device (BOCHS BIOS specific):
[12649]94 0x38
95 0x3c
[38220]96 0x3d
[12649]97 PXE debug:
98 0x3f
[38220]99 First SATA HDD:
[12649]100 0x40 - 0x47
[38220]101 Second SATA HDD:
[12649]102 0x48 - 0x4f
[38220]103 Third SATA HDD:
[12649]104 0x50 - 0x57
[38220]105 Fourth SATA HDD:
[12649]106 0x58 - 0x5f
107 Number of CPUs:
108 0x60
[18373]109 RAM above 4G in 64KB units:
[17545]110 0x61 - 0x65
[38220]111 Third IDE HDD:
112 0x67 - 0x6e
113 Fourth IDE HDD:
114 0x70 - 0x77
[61054]115 APIC/x2APIC settings:
116 0x78
[27461]117
118 Second CMOS bank (offsets 0x80 to 0xff):
[30451]119 Reserved for internal use by PXE ROM:
[27461]120 0x80 - 0x81
121 First net boot device PCI bus/dev/fn:
122 0x82 - 0x83
123 Second to third net boot devices:
124 0x84 - 0x89
[50091]125 First SCSI HDD:
126 0x90 - 0x97
127 Second SCSI HDD:
128 0x98 - 0x9f
129 Third SCSI HDD:
130 0xa0 - 0xa7
131 Fourth SCSI HDD:
132 0xa8 - 0xaf
133
[12649]134@endverbatim
135 *
[12239]136 * @todo Mark which bits are compatible with which BIOSes and
137 * which are our own definitions.
[7099]138 */
139
[11257]140
[57358]141/*********************************************************************************************************************************
142* Structures and Typedefs *
143*********************************************************************************************************************************/
[1]144
145/**
146 * The boot device.
147 */
148typedef enum DEVPCBIOSBOOT
149{
150 DEVPCBIOSBOOT_NONE,
151 DEVPCBIOSBOOT_FLOPPY,
152 DEVPCBIOSBOOT_HD,
153 DEVPCBIOSBOOT_DVD,
154 DEVPCBIOSBOOT_LAN
155} DEVPCBIOSBOOT;
156
157/**
158 * PC Bios instance data structure.
159 */
160typedef struct DEVPCBIOS
161{
162 /** Pointer back to the device instance. */
163 PPDMDEVINS pDevIns;
164
165 /** Boot devices (ordered). */
166 DEVPCBIOSBOOT aenmBootDevice[4];
[84752]167 /** Bochs control string index. */
168 uint32_t iControl;
[1]169 /** Floppy device. */
170 char *pszFDDevice;
171 /** Harddisk device. */
172 char *pszHDDevice;
[7099]173 /** Sata harddisk device. */
174 char *pszSataDevice;
[50091]175 /** LUNs of the four BIOS-accessible SATA disks. */
[7099]176 uint32_t iSataHDLUN[4];
[50091]177 /** SCSI harddisk device. */
178 char *pszScsiDevice;
179 /** LUNs of the four BIOS-accessible SCSI disks. */
180 uint32_t iScsiHDLUN[4];
[1]181 /** Bios message buffer. */
182 char szMsg[256];
183 /** Bios message buffer index. */
184 uint32_t iMsg;
[6322]185 /** The system BIOS ROM data. */
186 uint8_t *pu8PcBios;
187 /** The size of the system BIOS ROM. */
[37917]188 uint32_t cbPcBios;
[6322]189 /** The name of the BIOS ROM file. */
190 char *pszPcBiosFile;
[1]191 /** The LAN boot ROM data. */
192 uint8_t *pu8LanBoot;
193 /** The name of the LAN boot ROM file. */
194 char *pszLanBootFile;
[18143]195 /** The size of the LAN boot ROM. */
196 uint64_t cbLanBoot;
[1]197 /** The DMI tables. */
[23942]198 uint8_t au8DMIPage[0x1000];
[155]199 /** The boot countdown (in seconds). */
[23942]200 uint8_t uBootDelay;
[2651]201 /** I/O-APIC enabled? */
[23942]202 uint8_t u8IOAPIC;
[61042]203 /** APIC mode to be set up by BIOS */
[61054]204 uint8_t u8APICMode;
[5170]205 /** PXE debug logging enabled? */
[23942]206 uint8_t u8PXEDebug;
[80038]207 /** Physical address of the MP table. */
208 uint32_t u32MPTableAddr;
[27461]209 /** PXE boot PCI bus/dev/fn list. */
210 uint16_t au16NetBootDev[NET_BOOT_DEVS];
[12233]211 /** Number of logical CPUs in guest */
[23942]212 uint16_t cCpus;
[67456]213 /* Physical address of PCI config space MMIO region. Currently unused. */
214 uint64_t u64McfgBase;
215 /* Length of PCI config space MMIO region. Currently unused. */
216 uint64_t cbMcfgLength;
[60404]217
218 /** Firmware registration structure. */
219 PDMFWREG FwReg;
220 /** Dummy. */
221 PCPDMFWHLPR3 pFwHlpR3;
[81920]222 /** Number of soft resets we've logged. */
223 uint32_t cLoggedSoftResets;
[60404]224 /** Whether to consult the shutdown status (CMOS[0xf]) for deciding upon soft
225 * or hard reset. */
226 bool fCheckShutdownStatusForSoftReset;
227 /** Whether to clear the shutdown status on hard reset. */
228 bool fClearShutdownStatusOnHardReset;
[66130]229 /** Current port number for Bochs shutdown (used by APM). */
230 RTIOPORT ShutdownPort;
231 /** True=use new port number for Bochs shutdown (used by APM). */
232 bool fNewShutdownPort;
[81920]233 bool afPadding[3+4];
234 /** The shudown I/O port, either at 0x040f or 0x8900 (old saved state). */
235 IOMMMIOHANDLE hIoPortShutdown;
[44706]236} DEVPCBIOS;
237/** Pointer to the BIOS device state. */
238typedef DEVPCBIOS *PDEVPCBIOS;
[1]239
240
[66130]241/*********************************************************************************************************************************
242* Defined Constants And Macros *
243*********************************************************************************************************************************/
244/** The saved state version. */
245#define PCBIOS_SSM_VERSION 0
246
247
248/*********************************************************************************************************************************
249* Global Variables *
250*********************************************************************************************************************************/
251/** Saved state DEVPCBIOS field descriptors. */
252static SSMFIELD const g_aPcBiosFields[] =
253{
254 SSMFIELD_ENTRY( DEVPCBIOS, fNewShutdownPort),
255 SSMFIELD_ENTRY_TERM()
256};
257
258
[44706]259/**
[81920]260 * @callback_method_impl{FNIOMIOPORTNEWIN, Bochs Debug.}
[44706]261 */
[81920]262static DECLCALLBACK(VBOXSTRICTRC)
263pcbiosIOPortDebugRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
[44706]264{
[81920]265 RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
[44706]266 return VERR_IOM_IOPORT_UNUSED;
267}
268
269
270/**
[81920]271 * @callback_method_impl{FNIOMIOPORTNEWOUT, Bochs Debug.}
[44706]272 */
[81920]273static DECLCALLBACK(VBOXSTRICTRC)
274pcbiosIOPortDebugWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
[44706]275{
[81591]276 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[81920]277 RT_NOREF(pvUser);
278 Assert(offPort < 4);
[62890]279
[44706]280 /*
281 * Bochs BIOS char printing.
282 */
283 if ( cb == 1
[81920]284 && ( offPort == 2
285 || offPort == 3))
[44706]286 {
287 /* The raw version. */
288 switch (u32)
289 {
290 case '\r': Log2(("pcbios: <return>\n")); break;
291 case '\n': Log2(("pcbios: <newline>\n")); break;
292 case '\t': Log2(("pcbios: <tab>\n")); break;
293 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
294 }
295
296 /* The readable, buffered version. */
[71820]297 uint32_t iMsg = pThis->iMsg;
[44706]298 if (u32 == '\n' || u32 == '\r')
299 {
[71820]300 AssertStmt(iMsg < sizeof(pThis->szMsg), iMsg = sizeof(pThis->szMsg) - 1);
301 pThis->szMsg[iMsg] = '\0';
302 if (iMsg)
[44706]303 Log(("pcbios: %s\n", pThis->szMsg));
[71820]304 iMsg = 0;
[44706]305 }
306 else
307 {
[71820]308 if (iMsg >= sizeof(pThis->szMsg) - 1)
[44706]309 {
[71820]310 pThis->szMsg[iMsg] = '\0';
[44706]311 Log(("pcbios: %s\n", pThis->szMsg));
[71820]312 iMsg = 0;
[44706]313 }
[71820]314 pThis->szMsg[iMsg] = (char)u32;
315 pThis->szMsg[++iMsg] = '\0';
[44706]316 }
[71820]317 pThis->iMsg = iMsg;
[44706]318 return VINF_SUCCESS;
319 }
320
[81920]321 /* not in use. */
322 return VINF_SUCCESS;
323}
324
325
326/**
327 * @callback_method_impl{FNIOMIOPORTNEWIN, Bochs Shutdown port.}
328 */
329static DECLCALLBACK(VBOXSTRICTRC)
330pcbiosIOPortShutdownRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
331{
332 RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
333 return VERR_IOM_IOPORT_UNUSED;
334}
335
336
337/**
338 * @callback_method_impl{FNIOMIOPORTNEWOUT, Bochs Shutdown port.}
339 */
340static DECLCALLBACK(VBOXSTRICTRC)
341pcbiosIOPortShutdownWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
342{
343 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
344 RT_NOREF(pvUser, offPort);
345 Assert(offPort == 0);
346
347 if (cb == 1)
[44706]348 {
[71820]349 static const unsigned char s_szShutdown[] = "Shutdown";
[84752]350 static const unsigned char s_szBootfail[] = "Bootfail";
351 AssertCompile(sizeof(s_szShutdown) == sizeof(s_szBootfail));
352
353 if (pThis->iControl < sizeof(s_szShutdown)) /* paranoia */
[44706]354 {
[84752]355 if (u32 == s_szShutdown[pThis->iControl])
[44706]356 {
[84752]357
358 pThis->iControl++;
359 if (pThis->iControl >= 8)
360 {
361 pThis->iControl = 0;
362 LogRel(("PcBios: APM shutdown request\n"));
363 return PDMDevHlpVMPowerOff(pDevIns);
364 }
[44706]365 }
[84752]366 else if (u32 == s_szBootfail[pThis->iControl])
367 {
368 pThis->iControl++;
369 if (pThis->iControl >= 8)
370 {
371 pThis->iControl = 0;
372 LogRel(("PcBios: Boot failure\n"));
[91566]373 int rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "VMBootFail",
374 N_("The VM failed to boot. This is possibly caused by not having an operating system installed or a misconfigured boot order. Maybe picking a guest OS install DVD will resolve the situation"));
375 AssertRC(rc);
[84752]376 }
377 }
378 else
379 pThis->iControl = 0;
[44706]380 }
381 else
[84752]382 pThis->iControl = 0;
[44706]383 }
[81920]384 /* else: not in use. */
[44706]385
386 return VINF_SUCCESS;
387}
388
389
390/**
[66130]391 * Register the Bochs shutdown port.
392 * This is used by pcbiosConstruct, pcbiosReset and pcbiosLoadExec.
393 */
394static int pcbiosRegisterShutdown(PPDMDEVINS pDevIns, PDEVPCBIOS pThis, bool fNewShutdownPort)
395{
396 if (pThis->ShutdownPort != 0)
397 {
[81920]398 int rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortShutdown);
[66130]399 AssertRC(rc);
400 }
[81920]401
[66130]402 pThis->fNewShutdownPort = fNewShutdownPort;
403 if (fNewShutdownPort)
[66150]404 pThis->ShutdownPort = VBOX_BIOS_SHUTDOWN_PORT;
[66130]405 else
[66150]406 pThis->ShutdownPort = VBOX_BIOS_OLD_SHUTDOWN_PORT;
[81920]407 return PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortShutdown, pThis->ShutdownPort);
[66130]408}
409
[66151]410
[66130]411/**
[66153]412 * @callback_method_impl{FNSSMDEVSAVEEXEC}
[66130]413 */
414static DECLCALLBACK(int) pcbiosSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
415{
[81591]416 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[81917]417 return pDevIns->pHlpR3->pfnSSMPutStruct(pSSM, pThis, g_aPcBiosFields);
[66130]418}
419
420
421/**
[66151]422 * @callback_method_impl{FNSSMDEVLOADPREP,
[66153]423 * Clears the fNewShutdownPort flag prior to loading the state so that old
424 * saved VM states keeps using the old port address (no pcbios state)}
[66130]425 */
426static DECLCALLBACK(int) pcbiosLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
427{
428 RT_NOREF(pSSM);
[81591]429 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[66151]430
[66130]431 /* Since there are legacy saved state files without any SSM data for PCBIOS
432 * this is the only way to handle them correctly. */
433 pThis->fNewShutdownPort = false;
434
435 return VINF_SUCCESS;
436}
437
[66151]438
[66130]439/**
[66151]440 * @callback_method_impl{FNSSMDEVLOADEXEC}
[66130]441 */
442static DECLCALLBACK(int) pcbiosLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
443{
[81591]444 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[66130]445
446 if (uVersion > PCBIOS_SSM_VERSION)
447 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
448 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
449
[81917]450 return pDevIns->pHlpR3->pfnSSMGetStruct(pSSM, pThis, g_aPcBiosFields);
[66130]451}
452
[66151]453
[66130]454/**
[66151]455 * @callback_method_impl{FNSSMDEVLOADDONE,
456 * Updates the shutdown port registration to match the flag loaded (or not).}
[66130]457 */
458static DECLCALLBACK(int) pcbiosLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
459{
460 RT_NOREF(pSSM);
[81591]461 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[66130]462 return pcbiosRegisterShutdown(pDevIns, pThis, pThis->fNewShutdownPort);
463}
464
465
466/**
[60404]467 * Write to CMOS memory.
468 * This is used by the init complete code.
469 */
470static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
471{
472 Assert(off < 256);
473 Assert(u32Val < 256);
474
475 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
476 AssertRC(rc);
477}
478
479
480/**
481 * Read from CMOS memory.
482 * This is used by the init complete code.
483 */
484static uint8_t pcbiosCmosRead(PPDMDEVINS pDevIns, unsigned off)
485{
486 Assert(off < 256);
487
488 uint8_t u8val;
489 int rc = PDMDevHlpCMOSRead(pDevIns, off, &u8val);
490 AssertRC(rc);
491
492 return u8val;
493}
494
495
496/**
497 * @interface_method_impl{PDMFWREG,pfnIsHardReset}
498 */
499static DECLCALLBACK(bool) pcbiosFw_IsHardReset(PPDMDEVINS pDevIns, uint32_t fFlags)
500{
[62890]501 RT_NOREF1(fFlags);
[81591]502 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[60404]503 if (pThis->fCheckShutdownStatusForSoftReset)
504 {
505 uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
506 if ( bShutdownStatus == 0x5
507 || bShutdownStatus == 0x9
508 || bShutdownStatus == 0xa)
509 {
510 const uint32_t cMaxLogged = 10;
511 if (pThis->cLoggedSoftResets < cMaxLogged)
512 {
513 RTFAR16 Far16 = { 0xfeed, 0xface };
514 PDMDevHlpPhysRead(pDevIns, 0x467, &Far16, sizeof(Far16));
515 pThis->cLoggedSoftResets++;
516 LogRel(("PcBios: Soft reset #%u - shutdown status %#x, warm reset vector (0040:0067) is %04x:%04x%s\n",
[73748]517 pThis->cLoggedSoftResets, bShutdownStatus, Far16.sel, Far16.off,
[60404]518 pThis->cLoggedSoftResets < cMaxLogged ? "." : " - won't log any more!"));
519 }
520 return false;
521 }
522 }
523 return true;
524}
525
526
527/**
528 * @interface_method_impl{PDMDEVREG,pfnReset}
529 */
530static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
531{
[81591]532 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[60404]533
534 if (pThis->fClearShutdownStatusOnHardReset)
535 {
536 uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
537 if (bShutdownStatus != 0)
538 {
539 LogRel(("PcBios: Clearing shutdown status code %02x.\n", bShutdownStatus));
540 pcbiosCmosWrite(pDevIns, 0xf, 0);
541 }
542 }
[66130]543
544 /* After reset the new BIOS code is active, use the new shutdown port. */
545 pcbiosRegisterShutdown(pDevIns, pThis, true /* fNewShutdownPort */);
[60404]546}
547
548
549/**
[44706]550 * Attempt to guess the LCHS disk geometry from the MS-DOS master boot record
551 * (partition table).
552 *
553 * @returns VBox status code.
[64369]554 * @param pMedia The media device interface of the disk.
[44706]555 * @param pLCHSGeometry Where to return the disk geometry on success
556 */
[59248]557static int biosGuessDiskLCHS(PPDMIMEDIA pMedia, PPDMMEDIAGEOMETRY pLCHSGeometry)
[6291]558{
559 uint8_t aMBR[512], *p;
560 int rc;
561 uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
[1]562
[59248]563 if (!pMedia)
[6291]564 return VERR_INVALID_PARAMETER;
[59248]565 rc = pMedia->pfnReadPcBios(pMedia, 0, aMBR, sizeof(aMBR));
[11257]566 if (RT_FAILURE(rc))
[6291]567 return rc;
568 /* Test MBR magic number. */
569 if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
570 return VERR_INVALID_PARAMETER;
571 for (uint32_t i = 0; i < 4; i++)
572 {
573 /* Figure out the start of a partition table entry. */
574 p = &aMBR[0x1be + i * 16];
575 iEndHead = p[5];
576 iEndSector = p[6] & 63;
[94080]577 if ((p[12] | p[13] | p[14] | p[15]) && iEndSector && iEndHead)
[6291]578 {
579 /* Assumption: partition terminates on a cylinder boundary. */
580 cLCHSHeads = iEndHead + 1;
581 cLCHSSectors = iEndSector;
[59248]582 cLCHSCylinders = RT_MIN(1024, pMedia->pfnGetSize(pMedia) / (512 * cLCHSHeads * cLCHSSectors));
[6291]583 if (cLCHSCylinders >= 1)
584 {
585 pLCHSGeometry->cCylinders = cLCHSCylinders;
586 pLCHSGeometry->cHeads = cLCHSHeads;
587 pLCHSGeometry->cSectors = cLCHSSectors;
588 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
589 return VINF_SUCCESS;
590 }
591 }
592 }
593 return VERR_INVALID_PARAMETER;
594}
595
596
[100443]597/* Several common PC/AT BIOS drive types. Corresponds to IBM BIOS drive tables. */
598PDMMEDIAGEOMETRY aGeomPCAT[] = {
599 /* cyls heads sectors */
600 { 0, 0, 0 }, /* Type 0 is not used */
601 { 306, 4, 17 }, /* Type 1, 10MB */
602 { 615, 4, 17 }, /* Type 2, 20MB */
603 { 615, 6, 17 }, /* Type 3, 30MB */
604 { 940, 8, 17 }, /* Type 4, 62MB */
605 { 940, 6, 17 }, /* Type 5, 47MB */
606 { 615, 4, 17 }, /* Type 6, 20MB (different WPCOMP from Type 2) */
607 { 462, 8, 17 }, /* Type 7, 30MB */
608 { 733, 5, 17 }, /* Type 8, 30MB */
609 { 900, 15, 17 }, /* Type 9, 117MB */
610
611 { 820, 3, 17 }, /* Type 10, 21MB */
612 { 855, 5, 17 }, /* Type 11, 37MB */
613 { 855, 7, 17 }, /* Type 12, 52MB */
614 { 306, 8, 17 }, /* Type 13, 21MB */
615 { 733, 7, 17 }, /* Type 14, 45MB */
616 { 0, 0, 0 }, /* Type 15 is not used */
617 { 612, 4, 17 }, /* Type 16, 21MB */
618 { 977, 5, 17 }, /* Type 17, 43MB */
619 { 977, 7, 17 }, /* Type 18, 60MB */
620 { 1024, 7, 17 }, /* Type 19, 62MB */
621
622 { 733, 5, 17 }, /* Type 20, 32MB */
623 { 733, 7, 17 }, /* Type 21, 45MB */
624 { 733, 5, 17 }, /* Type 22, 32MB */
625 { 306, 4, 17 }, /* Type 23, 10MB */
626};
627
[1]628/**
[100443]629 * Attempts to initialize CMOS data for a hard disk matching one of
630 * the PC/AT BIOS types. Only applicable to the first two drives.
631 * Returns true if drive is one of the few recognized types.
632 */
633static bool pcbiosCmosTryPCATHardDisk(PPDMDEVINS pDevIns, int drive, PCPDMMEDIAGEOMETRY pLCHSGeometry)
634{
[100444]635 unsigned type;
636 unsigned typeLow;
637 bool fCompatGeom = false;
[100443]638
639 Assert((drive == 0) || (drive == 1));
640
641 /* See if drive geometry is one of the ancient PC/AT BIOS types. */
642 for (type = 0; type < RT_ELEMENTS(aGeomPCAT); ++type) {
643 if ( (aGeomPCAT[type].cCylinders == pLCHSGeometry->cCylinders)
644 && (aGeomPCAT[type].cHeads == pLCHSGeometry->cHeads )
645 && (aGeomPCAT[type].cSectors == pLCHSGeometry->cSectors )) {
646 LogRel(("PcBios: Recognized ATA hard disk %d as PC/AT BIOS type %d\n", drive, type));
647 fCompatGeom = true;
648 break;
649 }
650 }
651
652 if (fCompatGeom) {
653 uint32_t u32;
654
655 /* For types below 15, the type is in CMOS byte 0x12.
656 * NB: The type for drive 0 is in the high nibble, drive 1
657 * is in the low nibble.
658 * For drive types above 15, CMOS byte 0x12 is set to 15
659 * and actual drive type is in byte 0x19 (drive 0) or
660 * byte 0x1a (drive 1).
661 */
662 typeLow = type < 15 ? type : 15;
663
664 /* Always update CMOS byte 0x12. */
665 u32 = pcbiosCmosRead(pDevIns, 0x12);
666 u32 &= 0x0f << (4 * drive);
667 u32 |= typeLow << (4 - 4 * drive);
668 pcbiosCmosWrite(pDevIns, 0x12, u32);
669
670 /* For higher drive types, also update CMOS byte 0x19/0x1a. */
671 if (type > 15) {
672 u32 = type;
673 pcbiosCmosWrite(pDevIns, 0x19 + drive, u32);
674 }
675 }
676
677 return fCompatGeom;
678}
679
680
681/**
[1]682 * Initializes the CMOS data for one harddisk.
683 */
[6299]684static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
[1]685{
[6299]686 Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
[100443]687 if (offType) {
688 uint32_t u32;
689 int drive;
690
691 Assert(offType == 0x1a || offType == 0x19);
692 drive = offType == 0x19 ? 0 : 1;
693
694 /* Update CMOS byte 12h. It will always be set to type 0fh for this disk. */
695 u32 = pcbiosCmosRead(pDevIns, 0x12);
696 u32 &= 0x0f << (4 * drive);
697 u32 |= 0x0f << (4 - 4 * drive);
698 pcbiosCmosWrite(pDevIns, 0x12, u32);
699
700 /* Now write the extended drive type at offset 19h or 1Ah. */
[38698]701 pcbiosCmosWrite(pDevIns, offType, 47);
[100443]702 }
[6299]703 /* Cylinders low */
704 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
705 /* Cylinders high */
706 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
707 /* Heads */
708 pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
709 /* Landing zone low */
710 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
711 /* Landing zone high */
712 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
713 /* Write precomp low */
714 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
715 /* Write precomp high */
716 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
717 /* Sectors */
718 pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
[1]719}
720
[44706]721
[7099]722/**
723 * Set logical CHS geometry for a hard disk
724 *
725 * @returns VBox status code.
726 * @param pBase Base interface for the device.
727 * @param pHardDisk The hard disk.
728 * @param pLCHSGeometry Where to store the geometry settings.
729 */
[59248]730static int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIMEDIA pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
[7099]731{
[62890]732 RT_NOREF1(pBase);
733
[7099]734 PDMMEDIAGEOMETRY LCHSGeometry;
[62890]735 int rc = pHardDisk->pfnBiosGetLCHSGeometry(pHardDisk, &LCHSGeometry);
[7099]736 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
737 || LCHSGeometry.cCylinders == 0
738 || LCHSGeometry.cHeads == 0
739 || LCHSGeometry.cHeads > 255
740 || LCHSGeometry.cSectors == 0
741 || LCHSGeometry.cSectors > 63)
742 {
743 /* No LCHS geometry, autodetect and set. */
[59248]744 rc = biosGuessDiskLCHS(pHardDisk, &LCHSGeometry);
[11257]745 if (RT_FAILURE(rc))
[7099]746 {
747 /* Try if PCHS geometry works, otherwise fall back. */
[59248]748 rc = pHardDisk->pfnBiosGetPCHSGeometry(pHardDisk, &LCHSGeometry);
[7099]749 }
[11257]750 if ( RT_FAILURE(rc)
[7099]751 || LCHSGeometry.cCylinders == 0
752 || LCHSGeometry.cCylinders > 1024
753 || LCHSGeometry.cHeads == 0
[94309]754 || LCHSGeometry.cHeads > 255
[7099]755 || LCHSGeometry.cSectors == 0
756 || LCHSGeometry.cSectors > 63)
757 {
[59248]758 uint64_t cSectors = pHardDisk->pfnGetSize(pHardDisk) / 512;
[7099]759 if (cSectors / 16 / 63 <= 1024)
760 {
761 LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
762 LCHSGeometry.cHeads = 16;
763 }
764 else if (cSectors / 32 / 63 <= 1024)
765 {
766 LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
767 LCHSGeometry.cHeads = 32;
768 }
769 else if (cSectors / 64 / 63 <= 1024)
770 {
771 LCHSGeometry.cCylinders = cSectors / 64 / 63;
772 LCHSGeometry.cHeads = 64;
773 }
774 else if (cSectors / 128 / 63 <= 1024)
775 {
776 LCHSGeometry.cCylinders = cSectors / 128 / 63;
777 LCHSGeometry.cHeads = 128;
778 }
779 else
780 {
781 LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
782 LCHSGeometry.cHeads = 255;
783 }
784 LCHSGeometry.cSectors = 63;
785
786 }
[59248]787 rc = pHardDisk->pfnBiosSetLCHSGeometry(pHardDisk, &LCHSGeometry);
[15366]788 if (rc == VERR_VD_IMAGE_READ_ONLY)
[7099]789 {
[55853]790 LogRel(("PcBios: ATA failed to update LCHS geometry, read only\n"));
[7099]791 rc = VINF_SUCCESS;
792 }
[15192]793 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
794 {
[55853]795 LogRel(("PcBios: ATA failed to update LCHS geometry, backend refused\n"));
[15192]796 rc = VINF_SUCCESS;
797 }
[7099]798 }
799
800 *pLCHSGeometry = LCHSGeometry;
801
802 return rc;
803}
804
[44706]805
[1]806/**
[50091]807 * Get logical CHS geometry for a hard disk, intended for SCSI/SAS drives
808 * with no physical geometry.
809 *
810 * @returns VBox status code.
811 * @param pHardDisk The hard disk.
812 * @param pLCHSGeometry Where to store the geometry settings.
813 */
[59248]814static int getLogicalDiskGeometry(PPDMIMEDIA pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
[50091]815{
816 PDMMEDIAGEOMETRY LCHSGeometry;
817 int rc = VINF_SUCCESS;
818
[59248]819 rc = pHardDisk->pfnBiosGetLCHSGeometry(pHardDisk, &LCHSGeometry);
[50091]820 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
821 || LCHSGeometry.cCylinders == 0
822 || LCHSGeometry.cHeads == 0
823 || LCHSGeometry.cHeads > 255
824 || LCHSGeometry.cSectors == 0
825 || LCHSGeometry.cSectors > 63)
826 {
827 /* Unlike the ATA case, if the image does not provide valid logical
828 * geometry, we leave things alone and let the BIOS decide what the
829 * logical geometry should be.
830 */
831 rc = VERR_PDM_GEOMETRY_NOT_SET;
832 }
833 else
834 *pLCHSGeometry = LCHSGeometry;
835
836 return rc;
837}
838
839
840/**
[1]841 * Get BIOS boot code from enmBootDevice in order
842 *
843 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
844 */
[11257]845static uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
[1]846{
[11257]847 switch (pThis->aenmBootDevice[iOrder])
[1]848 {
849 case DEVPCBIOSBOOT_NONE:
850 return 0;
851 case DEVPCBIOSBOOT_FLOPPY:
852 return 1;
853 case DEVPCBIOSBOOT_HD:
854 return 2;
855 case DEVPCBIOSBOOT_DVD:
856 return 3;
857 case DEVPCBIOSBOOT_LAN:
858 return 4;
859 default:
[11257]860 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
[1]861 return 0;
862 }
863}
864
865
866/**
[44706]867 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
868 *
[1]869 * This routine will write information needed by the bios to the CMOS.
870 *
871 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
872 * a description of standard and non-standard CMOS registers.
873 */
874static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
875{
[81591]876 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[1]877 uint32_t u32;
878 unsigned i;
[59248]879 PPDMIMEDIA apHDs[4] = {0};
[1]880 LogFlow(("pcbiosInitComplete:\n"));
881
[91897]882 uint64_t const cbRamSize = PDMDevHlpMMPhysGetRamSize(pDevIns);
883 uint32_t const cbBelow4GB = PDMDevHlpMMPhysGetRamSizeBelow4GB(pDevIns);
884 uint64_t const cbAbove4GB = PDMDevHlpMMPhysGetRamSizeAbove4GB(pDevIns);
[65850]885
[1]886 /*
887 * Memory sizes.
888 */
[12239]889 /* base memory. */
[65850]890 u32 = cbRamSize > 640 ? 640 : (uint32_t)cbRamSize / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
[65859]891 pcbiosCmosWrite(pDevIns, 0x15, RT_BYTE1(u32)); /* 15h - Base Memory in K, Low Byte */
892 pcbiosCmosWrite(pDevIns, 0x16, RT_BYTE2(u32)); /* 16h - Base Memory in K, High Byte */
[1]893
894 /* Extended memory, up to 65MB */
[65850]895 u32 = cbRamSize >= 65 * _1M ? 0xffff : ((uint32_t)cbRamSize - _1M) / _1K;
[65859]896 pcbiosCmosWrite(pDevIns, 0x17, RT_BYTE1(u32)); /* 17h - Extended Memory in K, Low Byte */
897 pcbiosCmosWrite(pDevIns, 0x18, RT_BYTE2(u32)); /* 18h - Extended Memory in K, High Byte */
898 pcbiosCmosWrite(pDevIns, 0x30, RT_BYTE1(u32)); /* 30h - Extended Memory in K, Low Byte */
899 pcbiosCmosWrite(pDevIns, 0x31, RT_BYTE2(u32)); /* 31h - Extended Memory in K, High Byte */
[1]900
[17542]901 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
[67585]902 and below 4GB (as it can only hold 4GB-16M). We have to chop off the
903 top 32MB or it conflict with what the ACPI tables return. (Should these
[17597]904 be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
905 with the high BIOS mapping.) */
[65850]906 if (cbRamSize > 16 * _1M)
[67585]907 u32 = (RT_MIN(cbBelow4GB, UINT32_C(0xfe000000)) - 16U * _1M) / _64K;
[1]908 else
909 u32 = 0;
[65859]910 pcbiosCmosWrite(pDevIns, 0x34, RT_BYTE1(u32));
911 pcbiosCmosWrite(pDevIns, 0x35, RT_BYTE2(u32));
[17542]912
[17545]913 /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
914 Bochs got these in a different location which we've already used for SATA,
915 it also lacks the last two. */
[65850]916 uint64_t c64KBAbove4GB = cbAbove4GB / _64K;
917 /* Make sure it doesn't hit the limits of the current BIOS code (RAM limit of ~255TB). */
918 AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
[65859]919 pcbiosCmosWrite(pDevIns, 0x61, RT_BYTE1(c64KBAbove4GB));
920 pcbiosCmosWrite(pDevIns, 0x62, RT_BYTE2(c64KBAbove4GB));
921 pcbiosCmosWrite(pDevIns, 0x63, RT_BYTE3(c64KBAbove4GB));
922 pcbiosCmosWrite(pDevIns, 0x64, RT_BYTE4(c64KBAbove4GB));
923 pcbiosCmosWrite(pDevIns, 0x65, RT_BYTE5(c64KBAbove4GB));
[1]924
925 /*
[12233]926 * Number of CPUs.
927 */
[12239]928 pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
[12233]929
930 /*
[61054]931 * APIC mode.
932 */
933 pcbiosCmosWrite(pDevIns, 0x78, pThis->u8APICMode);
934
935 /*
[1]936 * Bochs BIOS specifics - boot device.
937 * We do both new and old (ami-style) settings.
938 * See rombios.c line ~7215 (int19_function).
939 */
940
[11257]941 uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
942 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
[1]943 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
[11257]944 uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
[1]945 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
946 pcbiosCmosWrite(pDevIns, 0x38, reg38);
947 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
948
949 /*
[5170]950 * PXE debug option.
951 */
[11257]952 pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
[5170]953
954 /*
[27461]955 * Network boot device list.
956 */
[27976]957 for (i = 0; i < NET_BOOT_DEVS; ++i)
[27461]958 {
[65859]959 pcbiosCmosWrite(pDevIns, 0x82 + i * 2, RT_BYTE1(pThis->au16NetBootDev[i]));
960 pcbiosCmosWrite(pDevIns, 0x83 + i * 2, RT_BYTE2(pThis->au16NetBootDev[i]));
[27461]961 }
962
963 /*
[1]964 * Floppy drive type.
965 */
[47036]966 uint32_t cFDs = 0;
967 u32 = 0;
968 for (i = 0; i < 2; i++)
[1]969 {
970 PPDMIBASE pBase;
[91960]971 int rc = PDMDevHlpQueryLun(pDevIns, pThis->pszFDDevice, 0, i, &pBase);
[11257]972 if (RT_SUCCESS(rc))
[1]973 {
[59248]974 PPDMIMEDIA pFD = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
[47036]975 if (pFD)
976 {
977 cFDs++;
978 unsigned cShift = i == 0 ? 4 : 0;
979 switch (pFD->pfnGetType(pFD))
980 {
[59248]981 case PDMMEDIATYPE_FLOPPY_360: u32 |= 1 << cShift; break;
982 case PDMMEDIATYPE_FLOPPY_1_20: u32 |= 2 << cShift; break;
983 case PDMMEDIATYPE_FLOPPY_720: u32 |= 3 << cShift; break;
984 case PDMMEDIATYPE_FLOPPY_1_44: u32 |= 4 << cShift; break;
985 case PDMMEDIATYPE_FLOPPY_2_88: u32 |= 5 << cShift; break;
986 case PDMMEDIATYPE_FLOPPY_FAKE_15_6: u32 |= 14 << cShift; break;
987 case PDMMEDIATYPE_FLOPPY_FAKE_63_5: u32 |= 15 << cShift; break;
[47036]988 default: AssertFailed(); break;
989 }
990 }
[1]991 }
[47036]992 }
[1]993 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
994
995 /*
996 * Equipment byte.
997 */
[47036]998 if (cFDs > 0)
[59227]999 u32 = ((cFDs - 1) << 6) | 0x01; /* floppy installed, additional drives. */
[47036]1000 else
1001 u32 = 0x00; /* floppy not installed. */
[5605]1002 u32 |= RT_BIT(1); /* math coprocessor installed */
1003 u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
1004 u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
[1]1005 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
1006
1007 /*
[50091]1008 * IDE harddisks.
[1]1009 */
[11257]1010 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
[1]1011 {
1012 PPDMIBASE pBase;
[91960]1013 int rc = PDMDevHlpQueryLun(pDevIns, pThis->pszHDDevice, 0, i, &pBase);
[11257]1014 if (RT_SUCCESS(rc))
[59248]1015 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
[6291]1016 if ( apHDs[i]
[59248]1017 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
1018 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
[6291]1019 apHDs[i] = NULL;
[1]1020 if (apHDs[i])
1021 {
[6291]1022 PDMMEDIAGEOMETRY LCHSGeometry;
[25780]1023 int rc2 = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
1024 AssertRC(rc2);
[6291]1025
[6299]1026 if (i < 4)
1027 {
1028 /* Award BIOS extended drive types for first to fourth disk.
1029 * Used by the BIOS for setting the logical geometry. */
1030 int offType, offInfo;
1031 switch (i)
1032 {
1033 case 0:
1034 offType = 0x19;
1035 offInfo = 0x1e;
1036 break;
1037 case 1:
1038 offType = 0x1a;
1039 offInfo = 0x26;
1040 break;
1041 case 2:
1042 offType = 0x00;
1043 offInfo = 0x67;
1044 break;
1045 case 3:
1046 default:
1047 offType = 0x00;
1048 offInfo = 0x70;
1049 break;
1050 }
[100443]1051 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo, &LCHSGeometry);
1052 if (i < 2)
1053 pcbiosCmosTryPCATHardDisk(pDevIns, i, &LCHSGeometry);
[6299]1054 }
[55853]1055 LogRel(("PcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
[1]1056 }
1057 }
1058
[7099]1059 /*
[50091]1060 * SATA harddisks.
[7099]1061 */
[11257]1062 if (pThis->pszSataDevice)
[7099]1063 {
[50091]1064 /* Clear pointers to the block devices. */
[11257]1065 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
[10928]1066 apHDs[i] = NULL;
1067
[11257]1068 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
[7099]1069 {
1070 PPDMIBASE pBase;
[91960]1071 int rc = PDMDevHlpQueryLun(pDevIns, pThis->pszSataDevice, 0, pThis->iSataHDLUN[i], &pBase);
[11257]1072 if (RT_SUCCESS(rc))
[59248]1073 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
[7099]1074 if ( apHDs[i]
[59248]1075 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
1076 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
[7099]1077 apHDs[i] = NULL;
1078 if (apHDs[i])
1079 {
1080 PDMMEDIAGEOMETRY LCHSGeometry;
[25780]1081 rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
[7099]1082 AssertRC(rc);
1083
1084 if (i < 4)
1085 {
1086 /* Award BIOS extended drive types for first to fourth disk.
1087 * Used by the BIOS for setting the logical geometry. */
1088 int offInfo;
1089 switch (i)
1090 {
1091 case 0:
1092 offInfo = 0x40;
1093 break;
1094 case 1:
1095 offInfo = 0x48;
1096 break;
1097 case 2:
1098 offInfo = 0x50;
1099 break;
1100 case 3:
1101 default:
1102 offInfo = 0x58;
1103 break;
1104 }
1105 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
1106 &LCHSGeometry);
1107 }
[55853]1108 LogRel(("PcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
[7099]1109 }
1110 }
1111 }
1112
[50091]1113 /*
1114 * SCSI harddisks. Not handled quite the same as SATA.
1115 */
1116 if (pThis->pszScsiDevice)
1117 {
1118 /* Clear pointers to the block devices. */
1119 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
1120 apHDs[i] = NULL;
1121
1122 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
1123 {
1124 PPDMIBASE pBase;
[91960]1125 int rc = PDMDevHlpQueryLun(pDevIns, pThis->pszScsiDevice, 0, pThis->iScsiHDLUN[i], &pBase);
[50091]1126 if (RT_SUCCESS(rc))
[59248]1127 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
[50091]1128 if ( apHDs[i]
[59248]1129 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMMEDIATYPE_HARD_DISK
1130 || !apHDs[i]->pfnBiosIsVisible(apHDs[i])))
[50091]1131 apHDs[i] = NULL;
1132 if (apHDs[i])
1133 {
1134 PDMMEDIAGEOMETRY LCHSGeometry;
1135 rc = getLogicalDiskGeometry(apHDs[i], &LCHSGeometry);
1136
1137 if (i < 4 && RT_SUCCESS(rc))
1138 {
1139 /* Extended drive information (for SCSI disks).
1140 * Used by the BIOS for setting the logical geometry, but
1141 * only if the image provided valid data.
1142 */
1143 int offInfo;
1144 switch (i)
1145 {
1146 case 0:
1147 offInfo = 0x90;
1148 break;
1149 case 1:
1150 offInfo = 0x98;
1151 break;
1152 case 2:
1153 offInfo = 0xa0;
1154 break;
1155 case 3:
1156 default:
1157 offInfo = 0xa8;
1158 break;
1159 }
1160 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo, &LCHSGeometry);
[55853]1161 LogRel(("PcBios: SCSI LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
[50091]1162 }
1163 else
[55853]1164 LogRel(("PcBios: SCSI LUN#%d LCHS not provided\n", i));
[50091]1165 }
1166 }
1167 }
1168
[38220]1169 /* Calculate and store AT-style CMOS checksum. */
1170 uint16_t cksum = 0;
1171 for (i = 0x10; i < 0x2e; ++i)
1172 cksum += pcbiosCmosRead(pDevIns, i);
[65859]1173 pcbiosCmosWrite(pDevIns, 0x2e, RT_BYTE1(cksum));
1174 pcbiosCmosWrite(pDevIns, 0x2f, RT_BYTE2(cksum));
[38220]1175
[6291]1176 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
[1]1177 return VINF_SUCCESS;
1178}
1179
1180
1181/**
[45024]1182 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
[1]1183 */
[45024]1184static DECLCALLBACK(void) pcbiosMemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
[1]1185{
[62890]1186 RT_NOREF1(enmCtx);
[81591]1187 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[45024]1188 LogFlow(("pcbiosMemSetup:\n"));
[1]1189
[80038]1190 if (pThis->u8IOAPIC)
1191 FwCommonPlantMpsFloatPtr(pDevIns, pThis->u32MPTableAddr);
1192
[18143]1193 /*
1194 * Re-shadow the LAN ROM image and make it RAM/RAM.
1195 *
1196 * This is normally done by the BIOS code, but since we're currently lacking
1197 * the chipset support for this we do it here (and in the constructor).
1198 */
[93944]1199 uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
[18143]1200 RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
1201 while (cPages > 0)
1202 {
[93944]1203 uint8_t abPage[GUEST_PAGE_SIZE];
[18143]1204 int rc;
1205
1206 /* Read the (original) ROM page and write it back to the RAM page. */
[93944]1207 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, GUEST_PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
[18143]1208 AssertLogRelRC(rc);
1209
[93944]1210 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, GUEST_PAGE_SIZE);
[18143]1211 AssertLogRelRC(rc);
1212 if (RT_FAILURE(rc))
1213 memset(abPage, 0xcc, sizeof(abPage));
1214
[93944]1215 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, GUEST_PAGE_SIZE);
[18143]1216 AssertLogRelRC(rc);
1217
1218 /* Switch to the RAM/RAM mode. */
[93944]1219 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, GUEST_PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
[18143]1220 AssertLogRelRC(rc);
1221
1222 /* Advance */
[93944]1223 GCPhys += GUEST_PAGE_SIZE;
[18143]1224 cPages--;
1225 }
[1]1226}
1227
1228
1229/**
[44706]1230 * @interface_method_impl{PDMDEVREG,pfnDestruct}
[1]1231 */
1232static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
1233{
[71809]1234 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
[81591]1235 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
[1]1236 LogFlow(("pcbiosDestruct:\n"));
1237
1238 /*
1239 * Free MM heap pointers.
1240 */
[11257]1241 if (pThis->pu8PcBios)
[6322]1242 {
[65711]1243 PDMDevHlpMMHeapFree(pDevIns, pThis->pu8PcBios);
[11257]1244 pThis->pu8PcBios = NULL;
[6322]1245 }
1246
[11257]1247 if (pThis->pszPcBiosFile)
[6322]1248 {
[65711]1249 PDMDevHlpMMHeapFree(pDevIns, pThis->pszPcBiosFile);
[11257]1250 pThis->pszPcBiosFile = NULL;
[6322]1251 }
1252
[11257]1253 if (pThis->pu8LanBoot)
[1]1254 {
[65711]1255 PDMDevHlpMMHeapFree(pDevIns, pThis->pu8LanBoot);
[11257]1256 pThis->pu8LanBoot = NULL;
[1]1257 }
1258
[11257]1259 if (pThis->pszLanBootFile)
[1]1260 {
[65711]1261 PDMDevHlpMMHeapFree(pDevIns, pThis->pszLanBootFile);
[11257]1262 pThis->pszLanBootFile = NULL;
[1]1263 }
1264
[32675]1265 if (pThis->pszHDDevice)
1266 {
[65711]1267 PDMDevHlpMMHeapFree(pDevIns, pThis->pszHDDevice);
[32675]1268 pThis->pszHDDevice = NULL;
1269 }
1270
1271 if (pThis->pszFDDevice)
1272 {
[65711]1273 PDMDevHlpMMHeapFree(pDevIns, pThis->pszFDDevice);
[32675]1274 pThis->pszFDDevice = NULL;
1275 }
1276
1277 if (pThis->pszSataDevice)
1278 {
[65711]1279 PDMDevHlpMMHeapFree(pDevIns, pThis->pszSataDevice);
[32675]1280 pThis->pszSataDevice = NULL;
1281 }
1282
[50091]1283 if (pThis->pszScsiDevice)
1284 {
[65711]1285 PDMDevHlpMMHeapFree(pDevIns, pThis->pszScsiDevice);
[50091]1286 pThis->pszScsiDevice = NULL;
1287 }
1288
[1]1289 return VINF_SUCCESS;
1290}
1291
1292
1293/**
1294 * Convert config value to DEVPCBIOSBOOT.
1295 *
1296 * @returns VBox status code.
[64369]1297 * @param pDevIns Device instance data.
[26173]1298 * @param pCfg Configuration handle.
[1]1299 * @param pszParam The name of the value to read.
1300 * @param penmBoot Where to store the boot method.
1301 */
[26173]1302static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfg, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
[1]1303{
[81917]1304 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1305
1306 char szBuf[64];
1307 int rc = pHlp->pfnCFGMQueryString(pCfg, pszParam, szBuf, sizeof(szBuf));
[11257]1308 if (RT_FAILURE(rc))
[1]1309 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
[81917]1310 N_("Configuration error: Querying \"%s\" as a string failed"), pszParam);
1311
1312 if (!strcmp(szBuf, "DVD") || !strcmp(szBuf, "CDROM"))
[1]1313 *penmBoot = DEVPCBIOSBOOT_DVD;
[81917]1314 else if (!strcmp(szBuf, "IDE"))
[1]1315 *penmBoot = DEVPCBIOSBOOT_HD;
[81917]1316 else if (!strcmp(szBuf, "FLOPPY"))
[1]1317 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
[81917]1318 else if (!strcmp(szBuf, "LAN"))
[1]1319 *penmBoot = DEVPCBIOSBOOT_LAN;
[81917]1320 else if (!strcmp(szBuf, "NONE"))
[1]1321 *penmBoot = DEVPCBIOSBOOT_NONE;
[6306]1322 else
[81917]1323 rc = PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
1324 N_("Configuration error: The \"%s\" value \"%s\" is unknown"), pszParam, szBuf);
[1]1325 return rc;
1326}
1327
[81925]1328
[1]1329/**
[26160]1330 * @interface_method_impl{PDMDEVREG,pfnConstruct}
[1]1331 */
[26173]1332static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
[1]1333{
[71809]1334 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
[81917]1335 PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
1336 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1337 int rc;
1338 int cb;
[71809]1339 Assert(iInstance == 0); RT_NOREF(iInstance);
[1]1340
1341 /*
1342 * Validate configuration.
1343 */
[81917]1344 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
1345 "BootDevice0"
1346 "|BootDevice1"
1347 "|BootDevice2"
1348 "|BootDevice3"
1349 "|HardDiskDevice"
1350 "|SataHardDiskDevice"
1351 "|SataLUN1"
1352 "|SataLUN2"
1353 "|SataLUN3"
1354 "|SataLUN4"
1355 "|ScsiHardDiskDevice"
1356 "|ScsiLUN1"
1357 "|ScsiLUN2"
1358 "|ScsiLUN3"
1359 "|ScsiLUN4"
1360 "|FloppyDevice"
1361 "|DelayBoot"
1362 "|BiosRom"
1363 "|LanBootRom"
1364 "|PXEDebug"
1365 "|UUID"
1366 "|UuidLe"
1367 "|IOAPIC"
1368 "|APIC"
1369 "|NumCPUs"
1370 "|McfgBase"
1371 "|McfgLength"
1372 "|DmiBIOSFirmwareMajor"
1373 "|DmiBIOSFirmwareMinor"
1374 "|DmiBIOSReleaseDate"
1375 "|DmiBIOSReleaseMajor"
1376 "|DmiBIOSReleaseMinor"
1377 "|DmiBIOSVendor"
1378 "|DmiBIOSVersion"
1379 "|DmiSystemFamily"
1380 "|DmiSystemProduct"
1381 "|DmiSystemSerial"
1382 "|DmiSystemSKU"
1383 "|DmiSystemUuid"
1384 "|DmiSystemVendor"
1385 "|DmiSystemVersion"
1386 "|DmiBoardAssetTag"
1387 "|DmiBoardBoardType"
1388 "|DmiBoardLocInChass"
1389 "|DmiBoardProduct"
1390 "|DmiBoardSerial"
1391 "|DmiBoardVendor"
1392 "|DmiBoardVersion"
1393 "|DmiChassisAssetTag"
1394 "|DmiChassisSerial"
1395 "|DmiChassisType"
1396 "|DmiChassisVendor"
1397 "|DmiChassisVersion"
1398 "|DmiProcManufacturer"
1399 "|DmiProcVersion"
1400 "|DmiOEMVBoxVer"
1401 "|DmiOEMVBoxRev"
1402 "|DmiUseHostInfo"
1403 "|DmiExposeMemoryTable"
1404 "|DmiExposeProcInf"
1405 "|CheckShutdownStatusForSoftReset"
1406 "|ClearShutdownStatusOnHardReset"
[81918]1407 ,
1408 "NetBoot");
[1]1409 /*
1410 * Init the data.
1411 */
[81917]1412 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
[12236]1413 if (RT_FAILURE(rc))
[81917]1414 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
[12236]1415
[81917]1416 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgBase", &pThis->u64McfgBase, 0);
[34426]1417 if (RT_FAILURE(rc))
[81917]1418 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"\" as integer failed"));
1419 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgLength", &pThis->cbMcfgLength, 0);
[34426]1420 if (RT_FAILURE(rc))
[81917]1421 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"McfgLength\" as integer failed"));
[34426]1422
1423
[55853]1424 LogRel(("PcBios: [SMP] BIOS with %u CPUs\n", pThis->cCpus));
[12294]1425
[81917]1426 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
[11257]1427 if (RT_FAILURE (rc))
[81917]1428 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"IOAPIC\""));
[2651]1429
[81917]1430 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "APIC", &pThis->u8APICMode, 1);
[61042]1431 if (RT_FAILURE (rc))
[81917]1432 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"APIC\""));
[61042]1433
[1]1434 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
[11257]1435 Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
[40277]1436 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
[1]1437 {
[26173]1438 rc = pcbiosBootFromCfg(pDevIns, pCfg, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
[11257]1439 if (RT_FAILURE(rc))
[1]1440 return rc;
1441 }
1442
[81917]1443 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "HardDiskDevice", &pThis->pszHDDevice);
[11257]1444 if (RT_FAILURE(rc))
[81917]1445 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
[1]1446
[81917]1447 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "FloppyDevice", &pThis->pszFDDevice);
[11257]1448 if (RT_FAILURE(rc))
[81917]1449 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
[1]1450
[81917]1451 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "SataHardDiskDevice", &pThis->pszSataDevice);
[7099]1452 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[11257]1453 pThis->pszSataDevice = NULL;
1454 else if (RT_FAILURE(rc))
[81917]1455 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
[7099]1456
[11257]1457 if (pThis->pszSataDevice)
[7099]1458 {
[81917]1459 static const char * const s_apszSataDisks[] = { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
[11257]1460 Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
[40277]1461 for (unsigned i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
[7099]1462 {
[81917]1463 rc = pHlp->pfnCFGMQueryU32(pCfg, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
[7099]1464 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[11257]1465 pThis->iSataHDLUN[i] = i;
1466 else if (RT_FAILURE(rc))
[7099]1467 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1468 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1469 }
1470 }
[50091]1471
1472 /* Repeat the exercise for SCSI drives. */
[81917]1473 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "ScsiHardDiskDevice", &pThis->pszScsiDevice);
[50091]1474 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1475 pThis->pszScsiDevice = NULL;
1476 else if (RT_FAILURE(rc))
[81917]1477 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"ScsiHardDiskDevice\" as a string failed"));
[50091]1478
1479 if (pThis->pszScsiDevice)
1480 {
[81917]1481 static const char * const s_apszScsiDisks[] = { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
[50091]1482 Assert(RT_ELEMENTS(s_apszScsiDisks) == RT_ELEMENTS(pThis->iScsiHDLUN));
1483 for (unsigned i = 0; i < RT_ELEMENTS(pThis->iScsiHDLUN); i++)
1484 {
[81917]1485 rc = pHlp->pfnCFGMQueryU32(pCfg, s_apszScsiDisks[i], &pThis->iScsiHDLUN[i]);
[50091]1486 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1487 pThis->iScsiHDLUN[i] = i;
1488 else if (RT_FAILURE(rc))
1489 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1490 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszScsiDisks);
1491 }
1492 }
1493
[81918]1494 /* PXE debug logging option. */
1495 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "PXEDebug", &pThis->u8PXEDebug, false);
1496 if (RT_FAILURE(rc))
1497 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
[50091]1498
[81918]1499
[1]1500 /*
[81920]1501 * Register the I/O Ports.
[1]1502 */
[81920]1503 IOMIOPORTHANDLE hIoPorts;
1504 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x400 /*uPort*/, 4 /*cPorts*/, pcbiosIOPortDebugWrite, pcbiosIOPortDebugRead,
1505 "Bochs PC BIOS - Panic & Debug", NULL, &hIoPorts);
1506 AssertRCReturn(rc, rc);
1507
1508 rc = PDMDevHlpIoPortCreateIsa(pDevIns, 1 /*cPorts*/, pcbiosIOPortShutdownWrite, pcbiosIOPortShutdownRead, NULL /*pvUser*/,
1509 "Bochs PC BIOS - Shutdown", NULL /*paExtDescs*/, &pThis->hIoPortShutdown);
1510 AssertRCReturn(rc, rc);
[66130]1511 rc = pcbiosRegisterShutdown(pDevIns, pThis, true /* fNewShutdownPort */);
[81920]1512 AssertRCReturn(rc, rc);
[1]1513
[4485]1514 /*
[66130]1515 * Register SSM handlers, for remembering which shutdown port to use.
1516 */
1517 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCBIOS_SSM_VERSION, 1 /* cbGuess */, NULL,
1518 NULL, NULL, NULL,
1519 NULL, pcbiosSaveExec, NULL,
1520 pcbiosLoadPrep, pcbiosLoadExec, pcbiosLoadDone);
1521
[27461]1522 /* Clear the net boot device list. All bits set invokes old behavior,
1523 * as if no second CMOS bank was present.
1524 */
1525 memset(&pThis->au16NetBootDev, 0xff, sizeof(pThis->au16NetBootDev));
1526
[5170]1527 /*
[27461]1528 * Determine the network boot order.
1529 */
[81917]1530 PCFGMNODE pCfgNetBoot = pHlp->pfnCFGMGetChild(pCfg, "NetBoot");
[27461]1531 if (pCfgNetBoot == NULL)
1532 {
1533 /* Do nothing. */
1534 rc = VINF_SUCCESS;
1535 }
1536 else
1537 {
1538 PCFGMNODE pCfgNetBootDevice;
[33910]1539 uint8_t u8PciBus;
[27692]1540 uint8_t u8PciDev;
1541 uint8_t u8PciFn;
[27461]1542 uint16_t u16BusDevFn;
1543 char szIndex[] = "?";
1544
1545 Assert(pCfgNetBoot);
[40277]1546 for (unsigned i = 0; i < NET_BOOT_DEVS; ++i)
[27461]1547 {
1548 szIndex[0] = '0' + i;
[81917]1549 pCfgNetBootDevice = pHlp->pfnCFGMGetChild(pCfgNetBoot, szIndex);
[33910]1550
[81917]1551 rc = pHlp->pfnCFGMQueryU8(pCfgNetBootDevice, "PCIBusNo", &u8PciBus);
[33910]1552 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1553 {
1554 /* Do nothing and stop iterating. */
1555 rc = VINF_SUCCESS;
1556 break;
1557 }
1558 else if (RT_FAILURE(rc))
1559 return PDMDEV_SET_ERROR(pDevIns, rc,
1560 N_("Configuration error: Querying \"Netboot/x/PCIBusNo\" as integer failed"));
[81917]1561 rc = pHlp->pfnCFGMQueryU8(pCfgNetBootDevice, "PCIDeviceNo", &u8PciDev);
[27461]1562 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1563 {
1564 /* Do nothing and stop iterating. */
1565 rc = VINF_SUCCESS;
1566 break;
1567 }
1568 else if (RT_FAILURE(rc))
1569 return PDMDEV_SET_ERROR(pDevIns, rc,
[27692]1570 N_("Configuration error: Querying \"Netboot/x/PCIDeviceNo\" as integer failed"));
[81917]1571 rc = pHlp->pfnCFGMQueryU8(pCfgNetBootDevice, "PCIFunctionNo", &u8PciFn);
[27692]1572 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1573 {
1574 /* Do nothing and stop iterating. */
1575 rc = VINF_SUCCESS;
1576 break;
1577 }
1578 else if (RT_FAILURE(rc))
1579 return PDMDEV_SET_ERROR(pDevIns, rc,
1580 N_("Configuration error: Querying \"Netboot/x/PCIFunctionNo\" as integer failed"));
[33917]1581 u16BusDevFn = (((uint16_t)u8PciBus) << 8) | ((u8PciDev & 0x1F) << 3) | (u8PciFn & 0x7);
[27461]1582 pThis->au16NetBootDev[i] = u16BusDevFn;
1583 }
1584 }
1585
1586 /*
[6322]1587 * Get the system BIOS ROM file name.
1588 */
[81917]1589 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "BiosRom", &pThis->pszPcBiosFile);
[6322]1590 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1591 {
[11257]1592 pThis->pszPcBiosFile = NULL;
[6322]1593 rc = VINF_SUCCESS;
1594 }
[11257]1595 else if (RT_FAILURE(rc))
[6322]1596 return PDMDEV_SET_ERROR(pDevIns, rc,
1597 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
[11257]1598 else if (!*pThis->pszPcBiosFile)
[6322]1599 {
[81917]1600 PDMDevHlpMMHeapFree(pDevIns, pThis->pszPcBiosFile);
[11257]1601 pThis->pszPcBiosFile = NULL;
[6322]1602 }
1603
[60433]1604 /*
1605 * Get the CPU arch so we can load the appropriate ROMs.
1606 */
[91961]1607 CPUMMICROARCH const enmMicroarch = PDMDevHlpCpuGetGuestMicroarch(pDevIns);
[60433]1608
[11257]1609 if (pThis->pszPcBiosFile)
[6322]1610 {
[37917]1611 /*
1612 * Load the BIOS ROM.
1613 */
1614 RTFILE hFilePcBios;
1615 rc = RTFileOpen(&hFilePcBios, pThis->pszPcBiosFile,
[6322]1616 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
[11257]1617 if (RT_SUCCESS(rc))
[6322]1618 {
[37917]1619 /* Figure the size and check restrictions. */
1620 uint64_t cbPcBios;
[80585]1621 rc = RTFileQuerySize(hFilePcBios, &cbPcBios);
[11257]1622 if (RT_SUCCESS(rc))
[6322]1623 {
[37917]1624 pThis->cbPcBios = (uint32_t)cbPcBios;
1625 if ( RT_ALIGN(pThis->cbPcBios, _64K) == pThis->cbPcBios
1626 && pThis->cbPcBios == cbPcBios
1627 && pThis->cbPcBios <= 32 * _64K
1628 && pThis->cbPcBios >= _64K)
1629 {
1630 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
1631 if (pThis->pu8PcBios)
1632 {
1633 rc = RTFileRead(hFilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
1634 if (RT_FAILURE(rc))
1635 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1636 N_("Error reading the BIOS image ('%s)"), pThis->pszPcBiosFile);
1637 }
1638 else
1639 rc = PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
1640 N_("Failed to allocate %#x bytes for loading the BIOS image"),
1641 pThis->cbPcBios);
1642 }
1643 else
1644 rc = PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
1645 N_("Invalid system BIOS file size ('%s'): %#llx (%llu)"),
1646 pThis->pszPcBiosFile, cbPcBios, cbPcBios);
[6322]1647 }
[37917]1648 else
[40277]1649 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1650 N_("Failed to query the system BIOS file size ('%s')"),
[37917]1651 pThis->pszPcBiosFile);
1652 RTFileClose(hFilePcBios);
[6322]1653 }
[37917]1654 else
[40277]1655 rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1656 N_("Failed to open system BIOS file '%s'"), pThis->pszPcBiosFile);
[11257]1657 if (RT_FAILURE(rc))
[37917]1658 return rc;
1659
[55853]1660 LogRel(("PcBios: Using BIOS ROM '%s' with a size of %#x bytes\n", pThis->pszPcBiosFile, pThis->cbPcBios));
[6322]1661 }
[37917]1662 else
[6322]1663 {
1664 /*
[60422]1665 * Use one of the embedded BIOS ROM images.
[6322]1666 */
[60422]1667 uint8_t const *pbBios;
1668 uint32_t cbBios;
1669 if ( enmMicroarch == kCpumMicroarch_Intel_8086
1670 || enmMicroarch == kCpumMicroarch_Intel_80186
1671 || enmMicroarch == kCpumMicroarch_NEC_V20
1672 || enmMicroarch == kCpumMicroarch_NEC_V30)
1673 {
1674 pbBios = g_abPcBiosBinary8086;
1675 cbBios = g_cbPcBiosBinary8086;
1676 LogRel(("PcBios: Using the 8086 BIOS image!\n"));
1677 }
1678 else if (enmMicroarch == kCpumMicroarch_Intel_80286)
1679 {
1680 pbBios = g_abPcBiosBinary286;
1681 cbBios = g_cbPcBiosBinary286;
1682 LogRel(("PcBios: Using the 286 BIOS image!\n"));
1683 }
1684 else
1685 {
1686 pbBios = g_abPcBiosBinary386;
1687 cbBios = g_cbPcBiosBinary386;
1688 LogRel(("PcBios: Using the 386+ BIOS image.\n"));
1689 }
1690 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbBios);
[40277]1691 if (pThis->pu8PcBios)
1692 {
[60422]1693 pThis->cbPcBios = cbBios;
1694 memcpy(pThis->pu8PcBios, pbBios, cbBios);
[40277]1695 }
1696 else
1697 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
[60422]1698 N_("Failed to allocate %#x bytes for loading the embedded BIOS image"), cbBios);
[6873]1699 }
[43712]1700 const uint8_t *pu8PcBiosBinary = pThis->pu8PcBios;
1701 uint32_t cbPcBiosBinary = pThis->cbPcBios;
[6322]1702
1703 /*
[40277]1704 * Query the machine's UUID for SMBIOS/DMI use.
1705 */
1706 RTUUID uuid;
[81917]1707 rc = pHlp->pfnCFGMQueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
[40277]1708 if (RT_FAILURE(rc))
1709 return PDMDEV_SET_ERROR(pDevIns, rc,
1710 N_("Configuration error: Querying \"UUID\" failed"));
1711
[81557]1712 bool fUuidLe;
[81917]1713 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UuidLe", &fUuidLe, false);
[81557]1714 if (RT_FAILURE(rc))
1715 return PDMDEV_SET_ERROR(pDevIns, rc,
1716 N_("Configuration error: Querying \"UuidLe\" failed"));
1717
1718 if (!fUuidLe)
1719 {
1720 /*
1721 * UUIDs are stored little endian actually (see chapter 7.2.1 System — UUID
1722 * of the DMI/SMBIOS spec) but to not force reactivation of existing guests we have
1723 * to carry this bug along... (see also DevEFI.cpp when changing this)
1724 *
1725 * Convert the UUID to network byte order. Not entirely straightforward as
1726 * parts are MSB already...
1727 */
1728 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1729 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1730 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1731 }
1732
[40277]1733 uint16_t cbDmiTables = 0;
[81925]1734 uint16_t cDmiTables = 0;
[40277]1735 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE,
[83032]1736 &uuid, pCfg, pThis->cCpus, &cbDmiTables, &cDmiTables,
1737 false /*fUefi*/);
[40277]1738 if (RT_FAILURE(rc))
1739 return rc;
1740
[77259]1741 /* Look for _SM_/_DMI_ anchor strings within the BIOS and replace the table headers. */
[81925]1742 unsigned offAnchor = ~0U;
1743 unsigned const cbToSearch = pThis->cbPcBios - 32;
1744 for (unsigned off = 0; off <= cbToSearch; off += 16)
[40277]1745 {
[81925]1746 if ( pThis->pu8PcBios[off + 0x00] != '_'
1747 || pThis->pu8PcBios[off + 0x01] != 'S'
1748 || pThis->pu8PcBios[off + 0x02] != 'M'
1749 || pThis->pu8PcBios[off + 0x03] != '_'
1750 || pThis->pu8PcBios[off + 0x10] != '_'
1751 || pThis->pu8PcBios[off + 0x11] != 'D'
1752 || pThis->pu8PcBios[off + 0x12] != 'M'
1753 || pThis->pu8PcBios[off + 0x13] != 'I'
1754 || pThis->pu8PcBios[off + 0x14] != '_')
1755 { /* likely */ }
1756 else
[43712]1757 {
[81925]1758 offAnchor = off;
1759 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThis->pu8PcBios + off, cbDmiTables, cDmiTables);
[43712]1760 break;
1761 }
[40277]1762 }
[81925]1763 AssertLogRel(offAnchor <= cbToSearch);
[40277]1764
1765 if (pThis->u8IOAPIC)
[50320]1766 {
[80038]1767 pThis->u32MPTableAddr = VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE;
[73142]1768 FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage /* aka VBOX_DMI_TABLE_BASE */ + VBOX_DMI_TABLE_SIZE,
[40277]1769 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
[80038]1770 LogRel(("PcBios: MPS table at %08x\n", pThis->u32MPTableAddr));
[50320]1771 }
[40277]1772
1773 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1774 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1775 if (RT_FAILURE(rc))
1776 return rc;
1777
1778 /*
[1]1779 * Map the BIOS into memory.
1780 * There are two mappings:
1781 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1782 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1783 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1784 */
[6322]1785 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1786 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1787 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1788 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
[34163]1789 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb], cb,
[37917]1790 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xfffff");
[11257]1791 if (RT_FAILURE(rc))
[1]1792 return rc;
[34163]1793 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary, cbPcBiosBinary,
[37917]1794 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xffffffff");
[11257]1795 if (RT_FAILURE(rc))
[1]1796 return rc;
1797
1798 /*
1799 * Get the LAN boot ROM file name.
1800 */
[81917]1801 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "LanBootRom", &pThis->pszLanBootFile);
[1]1802 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1803 {
[11257]1804 pThis->pszLanBootFile = NULL;
[1]1805 rc = VINF_SUCCESS;
1806 }
[11257]1807 else if (RT_FAILURE(rc))
[1]1808 return PDMDEV_SET_ERROR(pDevIns, rc,
1809 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
[11257]1810 else if (!*pThis->pszLanBootFile)
[1]1811 {
[81917]1812 PDMDevHlpMMHeapFree(pDevIns, pThis->pszLanBootFile);
[11257]1813 pThis->pszLanBootFile = NULL;
[1]1814 }
1815
1816 /*
[60433]1817 * Not loading LAN ROM for old CPUs.
[1]1818 */
[60433]1819 if ( enmMicroarch != kCpumMicroarch_Intel_8086
1820 && enmMicroarch != kCpumMicroarch_Intel_80186
1821 && enmMicroarch != kCpumMicroarch_NEC_V20
1822 && enmMicroarch != kCpumMicroarch_NEC_V30
1823 && enmMicroarch != kCpumMicroarch_Intel_80286)
[1]1824 {
[60433]1825 const uint8_t *pu8LanBootBinary = NULL;
1826 uint64_t cbLanBootBinary;
[62890]1827 uint64_t cbFileLanBoot = 0;
[60433]1828
1829 /*
1830 * Open the LAN boot ROM and figure it size.
1831 * Determine the LAN boot ROM size, open specified ROM file in the process.
1832 */
1833 if (pThis->pszLanBootFile)
[1]1834 {
[60433]1835 RTFILE hFileLanBoot = NIL_RTFILE;
1836 rc = RTFileOpen(&hFileLanBoot, pThis->pszLanBootFile,
1837 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
[11257]1838 if (RT_SUCCESS(rc))
[1]1839 {
[80585]1840 rc = RTFileQuerySize(hFileLanBoot, &cbFileLanBoot);
[60433]1841 if (RT_SUCCESS(rc))
1842 {
1843 if (cbFileLanBoot <= _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff))
1844 {
1845 LogRel(("PcBios: Using LAN ROM '%s' with a size of %#x bytes\n", pThis->pszLanBootFile, cbFileLanBoot));
1846
1847 /*
1848 * Allocate buffer for the LAN boot ROM data and load it.
1849 */
1850 pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, cbFileLanBoot);
1851 if (pThis->pu8LanBoot)
1852 {
1853 rc = RTFileRead(hFileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
1854 AssertLogRelRCReturnStmt(rc, RTFileClose(hFileLanBoot), rc);
1855 }
1856 else
1857 rc = VERR_NO_MEMORY;
1858 }
1859 else
1860 rc = VERR_TOO_MUCH_DATA;
1861 }
1862 RTFileClose(hFileLanBoot);
[1]1863 }
[60433]1864 if (RT_FAILURE(rc))
1865 {
1866 /*
1867 * Play stupid and ignore failures, falling back to the built-in LAN boot ROM.
1868 */
1869 /** @todo r=bird: This should have some kind of rational. We don't usually
1870 * ignore the VM configuration. */
1871 LogRel(("PcBios: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
[81917]1872 PDMDevHlpMMHeapFree(pDevIns, pThis->pszLanBootFile);
[60433]1873 pThis->pszLanBootFile = NULL;
1874 }
[1]1875 }
[60433]1876
1877 /* If we were unable to get the data from file for whatever reason, fall
1878 * back to the built-in LAN boot ROM image.
1879 */
1880 if (pThis->pu8LanBoot == NULL)
[1]1881 {
[60433]1882#ifdef VBOX_WITH_PXE_ROM
1883 pu8LanBootBinary = g_abNetBiosBinary;
1884 cbLanBootBinary = g_cbNetBiosBinary;
1885#endif
[1]1886 }
[60433]1887 else
1888 {
1889 pu8LanBootBinary = pThis->pu8LanBoot;
1890 cbLanBootBinary = cbFileLanBoot;
1891 }
[1]1892
1893 /*
[60433]1894 * Map the Network Boot ROM into memory.
1895 *
1896 * Currently there is a fixed mapping: 0x000e2000 to 0x000effff contains
1897 * the (up to) 56 kb ROM image. The mapping size is fixed to trouble with
1898 * the saved state (in PGM).
[1]1899 */
[60433]1900 if (pu8LanBootBinary)
[1]1901 {
[60433]1902 pThis->cbLanBoot = cbLanBootBinary;
1903
1904 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4,
1905 RT_MAX(cbLanBootBinary, _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff)),
1906 pu8LanBootBinary, cbLanBootBinary,
1907 PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
1908 AssertRCReturn(rc, rc);
[1]1909 }
1910 }
[60433]1911 else if (pThis->pszLanBootFile)
1912 LogRel(("PcBios: Skipping LAN ROM '%s' due to ancient target CPU.\n", pThis->pszLanBootFile));
1913#ifdef VBOX_WITH_PXE_ROM
[1]1914 else
[60433]1915 LogRel(("PcBios: Skipping built in ROM due to ancient target CPU.\n"));
[35400]1916#endif
[1]1917
1918 /*
[60433]1919 * Configure Boot delay.
[1]1920 */
[81917]1921 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DelayBoot", &pThis->uBootDelay, 0);
[11257]1922 if (RT_FAILURE(rc))
1923 return PDMDEV_SET_ERROR(pDevIns, rc,
[155]1924 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
[11257]1925 if (pThis->uBootDelay > 15)
1926 pThis->uBootDelay = 15;
[155]1927
[60404]1928
1929 /*
1930 * Read shutdown status code config and register ourselves as the firmware device.
1931 */
1932
1933 /** @cfgm{CheckShutdownStatusForSoftReset, boolean, true}
1934 * Whether to consult the shutdown status code (CMOS register 0Fh) to
1935 * determine whether the guest intended a soft or hard reset. Currently only
1936 * shutdown status codes 05h, 09h and 0Ah are considered soft reset. */
[81917]1937 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "CheckShutdownStatusForSoftReset", &pThis->fCheckShutdownStatusForSoftReset, true);
[60404]1938 AssertLogRelRCReturn(rc, rc);
1939
1940 /** @cfgm{ClearShutdownStatusOnHardReset, boolean, true}
1941 * Whether to clear the shutdown status code (CMOS register 0Fh) on hard reset. */
[81917]1942 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ClearShutdownStatusOnHardReset", &pThis->fClearShutdownStatusOnHardReset, true);
[60404]1943 AssertLogRelRCReturn(rc, rc);
1944
1945 LogRel(("PcBios: fCheckShutdownStatusForSoftReset=%RTbool fClearShutdownStatusOnHardReset=%RTbool\n",
1946 pThis->fCheckShutdownStatusForSoftReset, pThis->fClearShutdownStatusOnHardReset));
1947
1948 static PDMFWREG const s_FwReg = { PDM_FWREG_VERSION, pcbiosFw_IsHardReset, PDM_FWREG_VERSION };
1949 rc = PDMDevHlpFirmwareRegister(pDevIns, &s_FwReg, &pThis->pFwHlpR3);
1950 AssertLogRelRCReturn(rc, rc);
1951
[31209]1952 return VINF_SUCCESS;
[1]1953}
1954
1955
1956/**
1957 * The device registration structure.
1958 */
1959const PDMDEVREG g_DevicePcBios =
1960{
[80531]1961 /* .u32Version = */ PDM_DEVREG_VERSION,
1962 /* .uReserved0 = */ 0,
1963 /* .szName = */ "pcbios",
[81925]1964 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
[80531]1965 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
1966 /* .cMaxInstances = */ 1,
1967 /* .uSharedVersion = */ 42,
1968 /* .cbInstanceShared = */ sizeof(DEVPCBIOS),
1969 /* .cbInstanceCC = */ 0,
1970 /* .cbInstanceRC = */ 0,
[80703]1971 /* .cMaxPciDevices = */ 0,
[80704]1972 /* .cMaxMsixVectors = */ 0,
[80531]1973 /* .pszDescription = */ "PC BIOS Device",
1974#if defined(IN_RING3)
1975 /* .pszRCMod = */ "",
1976 /* .pszR0Mod = */ "",
1977 /* .pfnConstruct = */ pcbiosConstruct,
1978 /* .pfnDestruct = */ pcbiosDestruct,
1979 /* .pfnRelocate = */ NULL,
1980 /* .pfnMemSetup = */ pcbiosMemSetup,
1981 /* .pfnPowerOn = */ NULL,
1982 /* .pfnReset = */ pcbiosReset,
1983 /* .pfnSuspend = */ NULL,
1984 /* .pfnResume = */ NULL,
1985 /* .pfnAttach = */ NULL,
1986 /* .pfnDetach = */ NULL,
1987 /* .pfnQueryInterface = */ NULL,
1988 /* .pfnInitComplete = */ pcbiosInitComplete,
1989 /* .pfnPowerOff = */ NULL,
1990 /* .pfnSoftReset = */ NULL,
1991 /* .pfnReserved0 = */ NULL,
1992 /* .pfnReserved1 = */ NULL,
1993 /* .pfnReserved2 = */ NULL,
1994 /* .pfnReserved3 = */ NULL,
1995 /* .pfnReserved4 = */ NULL,
1996 /* .pfnReserved5 = */ NULL,
1997 /* .pfnReserved6 = */ NULL,
1998 /* .pfnReserved7 = */ NULL,
1999#elif defined(IN_RING0)
2000 /* .pfnEarlyConstruct = */ NULL,
2001 /* .pfnConstruct = */ NULL,
2002 /* .pfnDestruct = */ NULL,
2003 /* .pfnFinalDestruct = */ NULL,
2004 /* .pfnRequest = */ NULL,
2005 /* .pfnReserved0 = */ NULL,
2006 /* .pfnReserved1 = */ NULL,
2007 /* .pfnReserved2 = */ NULL,
2008 /* .pfnReserved3 = */ NULL,
2009 /* .pfnReserved4 = */ NULL,
2010 /* .pfnReserved5 = */ NULL,
2011 /* .pfnReserved6 = */ NULL,
2012 /* .pfnReserved7 = */ NULL,
2013#elif defined(IN_RC)
2014 /* .pfnConstruct = */ NULL,
2015 /* .pfnReserved0 = */ NULL,
2016 /* .pfnReserved1 = */ NULL,
2017 /* .pfnReserved2 = */ NULL,
2018 /* .pfnReserved3 = */ NULL,
2019 /* .pfnReserved4 = */ NULL,
2020 /* .pfnReserved5 = */ NULL,
2021 /* .pfnReserved6 = */ NULL,
2022 /* .pfnReserved7 = */ NULL,
2023#else
2024# error "Not in IN_RING3, IN_RING0 or IN_RC!"
2025#endif
2026 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
[1]2027};
[44706]2028
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use