VirtualBox

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

Last change on this file since 9005 was 9005, checked in by vboxsync, 17 years ago

improved + documented mechanism for overwriting DMI information

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 57.5 KB
Line 
1/* $Id: DevPcBios.cpp 9005 2008-05-21 09:42:46Z vboxsync $ */
2/** @file
3 * PC BIOS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
26#include <VBox/pdmdev.h>
27#include <VBox/mm.h>
28
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/alloc.h>
32#include <iprt/file.h>
33#include <iprt/string.h>
34#include <iprt/uuid.h>
35#include <VBox/err.h>
36#include <VBox/param.h>
37
38#include "Builtins.h"
39#include "Builtins2.h"
40#include "DevPcBios.h"
41
42
43/*
44 * The BIOS uses a CMOS to store configuration data.
45 * It is currently used as followed:
46 *
47 * Base memory:
48 * 0x15
49 * 0x16
50 * Extended memory:
51 * 0x17
52 * 0x18
53 * 0x30
54 * 0x31
55 * Amount of memory above 16M:
56 * 0x34
57 * 0x35
58 * Boot device (BOCHS bios specific):
59 * 0x3d
60 * 0x38
61 * 0x3c
62 * PXE debug:
63 * 0x3f
64 * Floppy drive type:
65 * 0x10
66 * Equipment byte:
67 * 0x14
68 * First HDD:
69 * 0x19
70 * 0x1e - 0x25
71 * Second HDD:
72 * 0x1a
73 * 0x26 - 0x2d
74 * Third HDD:
75 * 0x67 - 0x6e
76 * Fourth HDD:
77 * 0x70 - 0x77
78 * Extended:
79 * 0x12
80 * First Sata HDD:
81 * 0x40 - 0x47
82 * Second Sata HDD:
83 * 0x48 - 0x4f
84 * Third Sata HDD:
85 * 0x50 - 0x57
86 * Fourth Sata HDD:
87 * 0x58 - 0x5f
88 */
89
90/*******************************************************************************
91* Structures and Typedefs *
92*******************************************************************************/
93
94/**
95 * The boot device.
96 */
97typedef enum DEVPCBIOSBOOT
98{
99 DEVPCBIOSBOOT_NONE,
100 DEVPCBIOSBOOT_FLOPPY,
101 DEVPCBIOSBOOT_HD,
102 DEVPCBIOSBOOT_DVD,
103 DEVPCBIOSBOOT_LAN
104} DEVPCBIOSBOOT;
105
106/**
107 * PC Bios instance data structure.
108 */
109typedef struct DEVPCBIOS
110{
111 /** Pointer back to the device instance. */
112 PPDMDEVINS pDevIns;
113
114 /** Boot devices (ordered). */
115 DEVPCBIOSBOOT aenmBootDevice[4];
116 /** Ram Size (in bytes). */
117 uint64_t cbRam;
118 /** Bochs shutdown index. */
119 uint32_t iShutdown;
120 /** Floppy device. */
121 char *pszFDDevice;
122 /** Harddisk device. */
123 char *pszHDDevice;
124 /** Sata harddisk device. */
125 char *pszSataDevice;
126 /** LUN of the four harddisks which are emulated as IDE. */
127 uint32_t iSataHDLUN[4];
128 /** Bios message buffer. */
129 char szMsg[256];
130 /** Bios message buffer index. */
131 uint32_t iMsg;
132 /** The system BIOS ROM data. */
133 uint8_t *pu8PcBios;
134 /** The size of the system BIOS ROM. */
135 uint64_t cbPcBios;
136 /** The name of the BIOS ROM file. */
137 char *pszPcBiosFile;
138 /** The LAN boot ROM data. */
139 uint8_t *pu8LanBoot;
140 /** The name of the LAN boot ROM file. */
141 char *pszLanBootFile;
142 /** The DMI tables. */
143 uint8_t au8DMIPage[0x1000];
144 /** The boot countdown (in seconds). */
145 uint8_t uBootDelay;
146 /** I/O-APIC enabled? */
147 uint8_t u8IOAPIC;
148 /** PXE debug logging enabled? */
149 uint8_t u8PXEDebug;
150} DEVPCBIOS, *PDEVPCBIOS;
151
152#pragma pack(1)
153
154/** DMI header */
155typedef struct DMIHDR
156{
157 uint8_t u8Type;
158 uint8_t u8Length;
159 uint16_t u16Handle;
160} *PDMIHDR;
161AssertCompileSize(DMIHDR, 4);
162
163/** DMI BIOS information */
164typedef struct DMIBIOSINF
165{
166 DMIHDR header;
167 uint8_t u8Vendor;
168 uint8_t u8Version;
169 uint16_t u16Start;
170 uint8_t u8Release;
171 uint8_t u8ROMSize;
172 uint64_t u64Characteristics;
173 uint8_t u8CharacteristicsByte1;
174 uint8_t u8CharacteristicsByte2;
175 uint8_t u8ReleaseMajor;
176 uint8_t u8ReleaseMinor;
177 uint8_t u8FirmwareMajor;
178 uint8_t u8FirmwareMinor;
179} *PDMIBIOSINF;
180AssertCompileSize(DMIBIOSINF, 0x18);
181
182/** DMI system information */
183typedef struct DMISYSTEMINF
184{
185 DMIHDR header;
186 uint8_t u8Manufacturer;
187 uint8_t u8ProductName;
188 uint8_t u8Version;
189 uint8_t u8SerialNumber;
190 uint8_t au8Uuid[16];
191 uint8_t u8WakeupType;
192 uint8_t u8SKUNumber;
193 uint8_t u8Family;
194} *PDMISYSTEMINF;
195AssertCompileSize(DMISYSTEMINF, 0x1b);
196
197/** MPS floating pointer structure */
198typedef struct MPSFLOATPTR
199{
200 uint8_t au8Signature[4];
201 uint32_t u32MPSAddr;
202 uint8_t u8Length;
203 uint8_t u8SpecRev;
204 uint8_t u8Checksum;
205 uint8_t au8Feature[5];
206} *PMPSFLOATPTR;
207AssertCompileSize(MPSFLOATPTR, 16);
208
209/** MPS config table header */
210typedef struct MPSCFGTBLHEADER
211{
212 uint8_t au8Signature[4];
213 uint16_t u16Length;
214 uint8_t u8SpecRev;
215 uint8_t u8Checksum;
216 uint8_t au8OemId[8];
217 uint8_t au8ProductId[12];
218 uint32_t u32OemTablePtr;
219 uint16_t u16OemTableSize;
220 uint16_t u16EntryCount;
221 uint32_t u32AddrLocalApic;
222 uint16_t u16ExtTableLength;
223 uint8_t u8ExtTableChecksxum;
224 uint8_t u8Reserved;
225} *PMPSCFGTBLHEADER;
226AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
227
228/** MPS processor entry */
229typedef struct MPSPROCENTRY
230{
231 uint8_t u8EntryType;
232 uint8_t u8LocalApicId;
233 uint8_t u8LocalApicVersion;
234 uint8_t u8CPUFlags;
235 uint32_t u32CPUSignature;
236 uint32_t u32CPUFeatureFlags;
237 uint32_t u32Reserved[2];
238} *PMPSPROCENTRY;
239AssertCompileSize(MPSPROCENTRY, 20);
240
241/** MPS bus entry */
242typedef struct MPSBUSENTRY
243{
244 uint8_t u8EntryType;
245 uint8_t u8BusId;
246 uint8_t au8BusTypeStr[6];
247} *PMPSBUSENTRY;
248AssertCompileSize(MPSBUSENTRY, 8);
249
250/** MPS I/O-APIC entry */
251typedef struct MPSIOAPICENTRY
252{
253 uint8_t u8EntryType;
254 uint8_t u8Id;
255 uint8_t u8Version;
256 uint8_t u8Flags;
257 uint32_t u32Addr;
258} *PMPSIOAPICENTRY;
259AssertCompileSize(MPSIOAPICENTRY, 8);
260
261/** MPS I/O-Interrupt entry */
262typedef struct MPSIOINTERRUPTENTRY
263{
264 uint8_t u8EntryType;
265 uint8_t u8Type;
266 uint16_t u16Flags;
267 uint8_t u8SrcBusId;
268 uint8_t u8SrcBusIrq;
269 uint8_t u8DstIOAPICId;
270 uint8_t u8DstIOAPICInt;
271} *PMPSIOIRQENTRY;
272AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
273
274#pragma pack()
275
276/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
277 * record (partition table). */
278static int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
279{
280 uint8_t aMBR[512], *p;
281 int rc;
282 uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
283
284 if (!pBlock)
285 return VERR_INVALID_PARAMETER;
286 rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
287 if (VBOX_FAILURE(rc))
288 return rc;
289 /* Test MBR magic number. */
290 if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
291 return VERR_INVALID_PARAMETER;
292 for (uint32_t i = 0; i < 4; i++)
293 {
294 /* Figure out the start of a partition table entry. */
295 p = &aMBR[0x1be + i * 16];
296 iEndHead = p[5];
297 iEndSector = p[6] & 63;
298 if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
299 {
300 /* Assumption: partition terminates on a cylinder boundary. */
301 cLCHSHeads = iEndHead + 1;
302 cLCHSSectors = iEndSector;
303 cLCHSCylinders = RT_MIN(1024, pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors));
304 if (cLCHSCylinders >= 1)
305 {
306 pLCHSGeometry->cCylinders = cLCHSCylinders;
307 pLCHSGeometry->cHeads = cLCHSHeads;
308 pLCHSGeometry->cSectors = cLCHSSectors;
309 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
310 return VINF_SUCCESS;
311 }
312 }
313 }
314 return VERR_INVALID_PARAMETER;
315}
316
317
318/**
319 * Write to CMOS memory.
320 * This is used by the init complete code.
321 */
322static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
323{
324 Assert(off < 128);
325 Assert(u32Val < 256);
326
327#if 1
328 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
329 AssertRC(rc);
330#else
331 PVM pVM = PDMDevHlpGetVM(pDevIns);
332 IOMIOPortWrite(pVM, 0x70, off, 1);
333 IOMIOPortWrite(pVM, 0x71, u32Val, 1);
334 IOMIOPortWrite(pVM, 0x70, 0, 1);
335#endif
336}
337
338/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
339
340/**
341 * Initializes the CMOS data for one harddisk.
342 */
343static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
344{
345 Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
346 if (offType)
347 pcbiosCmosWrite(pDevIns, offType, 48);
348 /* Cylinders low */
349 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
350 /* Cylinders high */
351 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
352 /* Heads */
353 pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
354 /* Landing zone low */
355 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
356 /* Landing zone high */
357 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
358 /* Write precomp low */
359 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
360 /* Write precomp high */
361 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
362 /* Sectors */
363 pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
364}
365
366/**
367 * Set logical CHS geometry for a hard disk
368 *
369 * @returns VBox status code.
370 * @param pBase Base interface for the device.
371 * @param pHardDisk The hard disk.
372 * @param pLCHSGeometry Where to store the geometry settings.
373 */
374static int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIBLOCKBIOS pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
375{
376 PDMMEDIAGEOMETRY LCHSGeometry;
377 int rc = VINF_SUCCESS;
378
379 rc = pHardDisk->pfnGetLCHSGeometry(pHardDisk, &LCHSGeometry);
380 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
381 || LCHSGeometry.cCylinders == 0
382 || LCHSGeometry.cCylinders > 1024
383 || LCHSGeometry.cHeads == 0
384 || LCHSGeometry.cHeads > 255
385 || LCHSGeometry.cSectors == 0
386 || LCHSGeometry.cSectors > 63)
387 {
388 PPDMIBLOCK pBlock;
389 pBlock = (PPDMIBLOCK)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK);
390 /* No LCHS geometry, autodetect and set. */
391 rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
392 if (VBOX_FAILURE(rc))
393 {
394 /* Try if PCHS geometry works, otherwise fall back. */
395 rc = pHardDisk->pfnGetPCHSGeometry(pHardDisk, &LCHSGeometry);
396 }
397 if ( VBOX_FAILURE(rc)
398 || LCHSGeometry.cCylinders == 0
399 || LCHSGeometry.cCylinders > 1024
400 || LCHSGeometry.cHeads == 0
401 || LCHSGeometry.cHeads > 16
402 || LCHSGeometry.cSectors == 0
403 || LCHSGeometry.cSectors > 63)
404 {
405 uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
406 if (cSectors / 16 / 63 <= 1024)
407 {
408 LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
409 LCHSGeometry.cHeads = 16;
410 }
411 else if (cSectors / 32 / 63 <= 1024)
412 {
413 LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
414 LCHSGeometry.cHeads = 32;
415 }
416 else if (cSectors / 64 / 63 <= 1024)
417 {
418 LCHSGeometry.cCylinders = cSectors / 64 / 63;
419 LCHSGeometry.cHeads = 64;
420 }
421 else if (cSectors / 128 / 63 <= 1024)
422 {
423 LCHSGeometry.cCylinders = cSectors / 128 / 63;
424 LCHSGeometry.cHeads = 128;
425 }
426 else
427 {
428 LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
429 LCHSGeometry.cHeads = 255;
430 }
431 LCHSGeometry.cSectors = 63;
432
433 }
434 rc = pHardDisk->pfnSetLCHSGeometry(pHardDisk, &LCHSGeometry);
435 if (rc == VERR_VDI_IMAGE_READ_ONLY)
436 {
437 LogRel(("DevPcBios: ATA failed to update LCHS geometry\n"));
438 rc = VINF_SUCCESS;
439 }
440 }
441
442 *pLCHSGeometry = LCHSGeometry;
443
444 return rc;
445}
446
447/**
448 * Get BIOS boot code from enmBootDevice in order
449 *
450 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
451 */
452static uint8_t getBiosBootCode(PDEVPCBIOS pData, unsigned iOrder)
453{
454 switch (pData->aenmBootDevice[iOrder])
455 {
456 case DEVPCBIOSBOOT_NONE:
457 return 0;
458 case DEVPCBIOSBOOT_FLOPPY:
459 return 1;
460 case DEVPCBIOSBOOT_HD:
461 return 2;
462 case DEVPCBIOSBOOT_DVD:
463 return 3;
464 case DEVPCBIOSBOOT_LAN:
465 return 4;
466 default:
467 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pData->aenmBootDevice[iOrder]));
468 return 0;
469 }
470}
471
472
473/**
474 * Init complete notification.
475 * This routine will write information needed by the bios to the CMOS.
476 *
477 * @returns VBOX status code.
478 * @param pDevIns The device instance.
479 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
480 * a description of standard and non-standard CMOS registers.
481 */
482static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
483{
484 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
485 uint32_t u32;
486 unsigned i;
487 PVM pVM = PDMDevHlpGetVM(pDevIns);
488 PPDMIBLOCKBIOS apHDs[4] = {0};
489 PPDMIBLOCKBIOS apFDs[2] = {0};
490 AssertRelease(pVM);
491 LogFlow(("pcbiosInitComplete:\n"));
492
493 /*
494 * Memory sizes.
495 */
496 /* base memory. */
497 u32 = pData->cbRam > 640 ? 640 : (uint32_t)pData->cbRam / _1K;
498 pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
499 pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
500
501 /* Extended memory, up to 65MB */
502 u32 = pData->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pData->cbRam - _1M) / _1K;
503 pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
504 pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
505 pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
506 pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
507
508 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB */
509 if (pData->cbRam > 16 * _1M)
510 {
511 u32 = (uint32_t)( (pData->cbRam - 16 * _1M) / _64K );
512 u32 = RT_MIN(u32, 0xffff);
513 }
514 else
515 u32 = 0;
516 pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
517 pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
518
519 /*
520 * Bochs BIOS specifics - boot device.
521 * We do both new and old (ami-style) settings.
522 * See rombios.c line ~7215 (int19_function).
523 */
524
525 uint8_t reg3d = getBiosBootCode(pData, 0) | (getBiosBootCode(pData, 1) << 4);
526 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pData, 2) << 4;
527 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
528 uint8_t reg3c = getBiosBootCode(pData, 3) | (pData->uBootDelay << 4);
529 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
530 pcbiosCmosWrite(pDevIns, 0x38, reg38);
531 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
532
533 /*
534 * PXE debug option.
535 */
536 pcbiosCmosWrite(pDevIns, 0x3f, pData->u8PXEDebug);
537
538 /*
539 * Floppy drive type.
540 */
541 for (i = 0; i < ELEMENTS(apFDs); i++)
542 {
543 PPDMIBASE pBase;
544 int rc = PDMR3QueryLun(pVM, pData->pszFDDevice, 0, i, &pBase);
545 if (VBOX_SUCCESS(rc))
546 apFDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
547 }
548 u32 = 0;
549 if (apFDs[0])
550 switch (apFDs[0]->pfnGetType(apFDs[0]))
551 {
552 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1 << 4; break;
553 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2 << 4; break;
554 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3 << 4; break;
555 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4 << 4; break;
556 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5 << 4; break;
557 default: AssertFailed(); break;
558 }
559 if (apFDs[1])
560 switch (apFDs[1]->pfnGetType(apFDs[1]))
561 {
562 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1; break;
563 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2; break;
564 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3; break;
565 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4; break;
566 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5; break;
567 default: AssertFailed(); break;
568 }
569 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
570
571 /*
572 * Equipment byte.
573 */
574 u32 = !!apFDs[0] + !!apFDs[1];
575 switch (u32)
576 {
577 case 1: u32 = 0x01; break; /* floppy installed, 2 drives. */
578 default:u32 = 0; break; /* floppy not installed. */
579 }
580 u32 |= RT_BIT(1); /* math coprocessor installed */
581 u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
582 u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
583 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
584
585 /*
586 * Harddisks.
587 */
588 for (i = 0; i < ELEMENTS(apHDs); i++)
589 {
590 PPDMIBASE pBase;
591 int rc = PDMR3QueryLun(pVM, pData->pszHDDevice, 0, i, &pBase);
592 if (VBOX_SUCCESS(rc))
593 apHDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
594 if ( apHDs[i]
595 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
596 || !apHDs[i]->pfnIsVisible(apHDs[i])))
597 apHDs[i] = NULL;
598 if (apHDs[i])
599 {
600 PDMMEDIAGEOMETRY LCHSGeometry;
601 int rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
602 AssertRC(rc);
603
604 if (i < 4)
605 {
606 /* Award BIOS extended drive types for first to fourth disk.
607 * Used by the BIOS for setting the logical geometry. */
608 int offType, offInfo;
609 switch (i)
610 {
611 case 0:
612 offType = 0x19;
613 offInfo = 0x1e;
614 break;
615 case 1:
616 offType = 0x1a;
617 offInfo = 0x26;
618 break;
619 case 2:
620 offType = 0x00;
621 offInfo = 0x67;
622 break;
623 case 3:
624 default:
625 offType = 0x00;
626 offInfo = 0x70;
627 break;
628 }
629 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
630 &LCHSGeometry);
631 }
632 LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
633 }
634 }
635
636 /* 0Fh means extended and points to 19h, 1Ah */
637 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
638 pcbiosCmosWrite(pDevIns, 0x12, u32);
639
640 /*
641 * Sata Harddisks.
642 */
643 if (pData->pszSataDevice)
644 {
645 for (i = 0; i < ELEMENTS(apHDs); i++)
646 {
647 PPDMIBASE pBase;
648 int rc = PDMR3QueryLun(pVM, pData->pszSataDevice, 0, pData->iSataHDLUN[i], &pBase);
649 if (VBOX_SUCCESS(rc))
650 apHDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
651 if ( apHDs[i]
652 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
653 || !apHDs[i]->pfnIsVisible(apHDs[i])))
654 apHDs[i] = NULL;
655 if (apHDs[i])
656 {
657 PDMMEDIAGEOMETRY LCHSGeometry;
658 int rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
659 AssertRC(rc);
660
661 if (i < 4)
662 {
663 /* Award BIOS extended drive types for first to fourth disk.
664 * Used by the BIOS for setting the logical geometry. */
665 int offInfo;
666 switch (i)
667 {
668 case 0:
669 offInfo = 0x40;
670 break;
671 case 1:
672 offInfo = 0x48;
673 break;
674 case 2:
675 offInfo = 0x50;
676 break;
677 case 3:
678 default:
679 offInfo = 0x58;
680 break;
681 }
682 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
683 &LCHSGeometry);
684 }
685 LogRel(("DevPcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
686 }
687 }
688 }
689
690 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
691 return VINF_SUCCESS;
692}
693
694
695/**
696 * Port I/O Handler for IN operations.
697 *
698 * @returns VBox status code.
699 *
700 * @param pDevIns The device instance.
701 * @param pvUser User argument - ignored.
702 * @param Port Port number used for the IN operation.
703 * @param pu32 Where to store the result.
704 * @param cb Number of bytes read.
705 */
706static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
707{
708 NOREF(pDevIns);
709 NOREF(pvUser);
710 NOREF(Port);
711 NOREF(pu32);
712 NOREF(cb);
713 return VERR_IOM_IOPORT_UNUSED;
714}
715
716
717/**
718 * Port I/O Handler for OUT operations.
719 *
720 * @returns VBox status code.
721 *
722 * @param pDevIns The device instance.
723 * @param pvUser User argument - ignored.
724 * @param Port Port number used for the IN operation.
725 * @param u32 The value to output.
726 * @param cb The value size in bytes.
727 */
728static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
729{
730 /*
731 * Bochs BIOS Panic
732 */
733 if ( cb == 2
734 && ( Port == 0x400
735 || Port == 0x401))
736 {
737 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
738 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
739 return VERR_INTERNAL_ERROR;
740 }
741
742 /*
743 * Bochs BIOS char printing.
744 */
745 if ( cb == 1
746 && ( Port == 0x402
747 || Port == 0x403))
748 {
749 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
750 /* The raw version. */
751 switch (u32)
752 {
753 case '\r': Log2(("pcbios: <return>\n")); break;
754 case '\n': Log2(("pcbios: <newline>\n")); break;
755 case '\t': Log2(("pcbios: <tab>\n")); break;
756 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
757 }
758
759 /* The readable, buffered version. */
760 if (u32 == '\n' || u32 == '\r')
761 {
762 pData->szMsg[pData->iMsg] = '\0';
763 if (pData->iMsg)
764 Log(("pcbios: %s\n", pData->szMsg));
765 pData->iMsg = 0;
766 }
767 else
768 {
769 if (pData->iMsg >= sizeof(pData->szMsg)-1)
770 {
771 pData->szMsg[pData->iMsg] = '\0';
772 Log(("pcbios: %s\n", pData->szMsg));
773 pData->iMsg = 0;
774 }
775 pData->szMsg[pData->iMsg] = (char )u32;
776 pData->szMsg[++pData->iMsg] = '\0';
777 }
778 return VINF_SUCCESS;
779 }
780
781 /*
782 * Bochs BIOS shutdown request.
783 */
784 if (cb == 1 && Port == 0x8900)
785 {
786 static const unsigned char szShutdown[] = "Shutdown";
787 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
788 if (u32 == szShutdown[pData->iShutdown])
789 {
790 pData->iShutdown++;
791 if (pData->iShutdown == 8)
792 {
793 pData->iShutdown = 0;
794 LogRel(("8900h shutdown request.\n"));
795 return PDMDevHlpVMPowerOff(pDevIns);
796 }
797 }
798 else
799 pData->iShutdown = 0;
800 return VINF_SUCCESS;
801 }
802
803 /* not in use. */
804 return VINF_SUCCESS;
805}
806
807
808/**
809 * Construct the DMI table.
810 *
811 * @returns VBox status code.
812 * @param pDevIns The device instance.
813 * @param pTable Where to create the DMI table.
814 * @param cbMax The max size of the DMI table.
815 * @param pUuid Pointer to the UUID to use if the DmiUuid
816 * configuration string isn't present.
817 * @param pCfgHandle The handle to our config node.
818 */
819static int pcbiosPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PRTUUID pUuid, PCFGMNODE pCfgHandle)
820{
821 char *pszStr = (char *)pTable;
822 int iStrNr;
823 int rc;
824 char *pszDmiBIOSVendor, *pszDmiBIOSVersion, *pszDmiBIOSReleaseDate;
825 int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor, iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
826 char *pszDmiSystemVendor, *pszDmiSystemProduct, *pszDmiSystemVersion, *pszDmiSystemSerial, *pszDmiSystemUuid, *pszDmiSystemFamily;
827
828#define STRCPY(p, s) \
829 do { \
830 size_t _len = strlen(s) + 1; \
831 size_t _max = (size_t)(pszStr + _len - (char *)pTable) + 1; /* +1 for strtab terminator */ \
832 if (_max > cbMax) \
833 return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
834 N_("One of the DMI strings is too long. Check all bios/Dmi* configuration entries. At least %zu bytes are needed but there is no space for more than %d bytes"), _max, cbMax); \
835 memcpy(p, s, _len); \
836 p += _len; \
837 } while (0)
838#define READCFGSTR(name, variable, default_value) \
839 do { \
840 rc = CFGMR3QueryStringAlloc(pCfgHandle, name, & variable); \
841 if (rc == VERR_CFGM_VALUE_NOT_FOUND) \
842 variable = MMR3HeapStrDup(PDMDevHlpGetVM(pDevIns), MM_TAG_CFGM, default_value); \
843 else if (VBOX_FAILURE(rc)) \
844 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
845 N_("Configuration error: Querying \"" name "\" as a string failed")); \
846 } while (0)
847#define READCFGINT(name, variable, default_value) \
848 do { \
849 rc = CFGMR3QueryS32(pCfgHandle, name, & variable); \
850 if (rc == VERR_CFGM_VALUE_NOT_FOUND) \
851 variable = default_value; \
852 else if (VBOX_FAILURE(rc)) \
853 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
854 N_("Configuration error: Querying \"" name "\" as a Int failed")); \
855 } while (0)
856
857
858 READCFGSTR("DmiBIOSVendor", pszDmiBIOSVendor, "innotek GmbH");
859 READCFGSTR("DmiBIOSVersion", pszDmiBIOSVersion, "VirtualBox");
860 READCFGSTR("DmiBIOSReleaseDate", pszDmiBIOSReleaseDate, "12/01/2006");
861 READCFGINT("DmiBIOSReleaseMajor", iDmiBIOSReleaseMajor, 0);
862 READCFGINT("DmiBIOSReleaseMinor", iDmiBIOSReleaseMinor, 0);
863 READCFGINT("DmiBIOSFirmwareMajor", iDmiBIOSFirmwareMajor, 0);
864 READCFGINT("DmiBIOSFirmwareMinor", iDmiBIOSFirmwareMinor, 0);
865 READCFGSTR("DmiSystemVendor", pszDmiSystemVendor, "innotek GmbH");
866 READCFGSTR("DmiSystemProduct", pszDmiSystemProduct, "VirtualBox");
867 READCFGSTR("DmiSystemVersion", pszDmiSystemVersion, "1.2");
868 READCFGSTR("DmiSystemSerial", pszDmiSystemSerial, "0");
869 rc = CFGMR3QueryStringAlloc(pCfgHandle, "DmiSystemUuid", &pszDmiSystemUuid);
870 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
871 pszDmiSystemUuid = NULL;
872 else if (VBOX_FAILURE(rc))
873 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
874 N_("Configuration error: Querying \"DmiUuid\" as a string failed"));
875 READCFGSTR("DmiSystemFamily", pszDmiSystemFamily, "Virtual Machine");
876
877 /* DMI BIOS information */
878 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
879
880 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
881 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
882
883 /* don't set these fields by default for legacy compatibility */
884 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
885 {
886 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
887 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
888 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
889 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
890 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
891 {
892 pszStr = (char *)(pBIOSInf + 1);
893 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
894 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
895 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
896 }
897 }
898
899 iStrNr = 1;
900 pBIOSInf->header.u8Type = 0; /* BIOS Information */
901 pBIOSInf->header.u16Handle = 0x0000;
902 pBIOSInf->u8Vendor = iStrNr++;
903 STRCPY(pszStr, pszDmiBIOSVendor);
904 pBIOSInf->u8Version = iStrNr++;
905 STRCPY(pszStr, pszDmiBIOSVersion);
906 pBIOSInf->u16Start = 0xE000;
907 pBIOSInf->u8Release = iStrNr++;
908 STRCPY(pszStr, pszDmiBIOSReleaseDate);
909 pBIOSInf->u8ROMSize = 1; /* 128K */
910 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
911 | RT_BIT(7) /* PCI is supported */
912 | RT_BIT(15) /* Boot from CD is supported */
913 | RT_BIT(16) /* Selectable Boot is supported */
914 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
915 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
916 /* any more?? */
917 ;
918 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
919 /* any more?? */
920 ;
921 pBIOSInf->u8CharacteristicsByte2 = 0
922 /* any more?? */
923 ;
924 *pszStr++ = '\0';
925
926 /* DMI system information */
927 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
928 pszStr = (char *)(pSystemInf + 1);
929 iStrNr = 1;
930 pSystemInf->header.u8Type = 1; /* System Information */
931 pSystemInf->header.u8Length = sizeof(*pSystemInf);
932 pSystemInf->header.u16Handle = 0x0001;
933 pSystemInf->u8Manufacturer = iStrNr++;
934 STRCPY(pszStr, pszDmiSystemVendor);
935 pSystemInf->u8ProductName = iStrNr++;
936 STRCPY(pszStr, pszDmiSystemProduct);
937 pSystemInf->u8Version = iStrNr++;
938 STRCPY(pszStr, pszDmiSystemVersion);
939 pSystemInf->u8SerialNumber = iStrNr++;
940 STRCPY(pszStr, pszDmiSystemSerial);
941
942 RTUUID uuid;
943 if (pszDmiSystemUuid)
944 {
945 int rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
946 if (VBOX_FAILURE(rc))
947 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
948 N_("Invalid UUID for DMI tables specified"));
949 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
950 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
951 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
952 pUuid = &uuid;
953 }
954 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
955
956 pSystemInf->u8WakeupType = 6; /* Power Switch */
957 pSystemInf->u8SKUNumber = 0;
958 pSystemInf->u8Family = iStrNr++;
959 STRCPY(pszStr, pszDmiSystemFamily);
960 *pszStr++ = '\0';
961
962 /* If more fields are added here, fix the size check in STRCPY */
963
964#undef STRCPY
965#undef READCFG
966
967 MMR3HeapFree(pszDmiBIOSVendor);
968 MMR3HeapFree(pszDmiBIOSVersion);
969 MMR3HeapFree(pszDmiBIOSReleaseDate);
970 MMR3HeapFree(pszDmiSystemVendor);
971 MMR3HeapFree(pszDmiSystemProduct);
972 MMR3HeapFree(pszDmiSystemVersion);
973 MMR3HeapFree(pszDmiSystemSerial);
974 MMR3HeapFree(pszDmiSystemUuid);
975 MMR3HeapFree(pszDmiSystemFamily);
976
977 return VINF_SUCCESS;
978}
979AssertCompile(VBOX_DMI_TABLE_ENTR == 2);
980
981
982/**
983 * Calculate a simple checksum for the MPS table.
984 *
985 * @param data data
986 * @param len size of data
987 */
988static uint8_t pcbiosChecksum(const uint8_t * const au8Data, uint32_t u32Length)
989{
990 uint8_t u8Sum = 0;
991 for (size_t i = 0; i < u32Length; ++i)
992 u8Sum += au8Data[i];
993 return -u8Sum;
994}
995
996
997/**
998 * Construct the MPS table. Only applicable if IOAPIC is active!
999 *
1000 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
1001 * ``1.3 Scope
1002 * ...
1003 * The hardware required to implement the MP specification is kept to a
1004 * minimum, as follows:
1005 * * One or more processors that are Intel architecture instruction set
1006 * compatible, such as the CPUs in the Intel486 or Pentium processor
1007 * family.
1008 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
1009 * Interrupt Controller or the integrated APIC, such as that on the
1010 * Intel Pentium 735\90 and 815\100 processors, together with a discrete
1011 * I/O APIC unit.''
1012 * and later:
1013 * ``4.3.3 I/O APIC Entries
1014 * The configuration table contains one or more entries for I/O APICs.
1015 * ...
1016 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
1017 * operating system should not attempt to access
1018 * this I/O APIC.
1019 * At least one I/O APIC must be enabled.''
1020 *
1021 * @param pDevIns The device instance data.
1022 * @param addr physical address in guest memory.
1023 */
1024static void pcbiosPlantMPStable(PPDMDEVINS pDevIns, uint8_t *pTable)
1025{
1026 /* configuration table */
1027 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
1028 memcpy(pCfgTab->au8Signature, "PCMP", 4);
1029 pCfgTab->u8SpecRev = 4; /* 1.4 */
1030 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
1031 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
1032 pCfgTab->u32OemTablePtr = 0;
1033 pCfgTab->u16OemTableSize = 0;
1034 pCfgTab->u16EntryCount = 1 /* Processor */
1035 + 1 /* ISA Bus */
1036 + 1 /* I/O-APIC */
1037 + 16 /* Interrupts */;
1038 pCfgTab->u32AddrLocalApic = 0xfee00000;
1039 pCfgTab->u16ExtTableLength = 0;
1040 pCfgTab->u8ExtTableChecksxum = 0;
1041 pCfgTab->u8Reserved = 0;
1042
1043 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
1044 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
1045 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
1046 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1047 if (u32Eax >= 1)
1048 {
1049 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1050 u32CPUSignature = u32Eax & 0xfff;
1051 /* Local APIC will be enabled later so override it here. Since we provide
1052 * an MP table we have an IOAPIC and therefore a Local APIC. */
1053 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
1054 }
1055
1056 /* one processor so far */
1057 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
1058 pProcEntry->u8EntryType = 0; /* processor entry */
1059 pProcEntry->u8LocalApicId = 0;
1060 pProcEntry->u8LocalApicVersion = 0x11;
1061 pProcEntry->u8CPUFlags = 2 /* bootstrap processor */ | 1 /* enabled */;
1062 pProcEntry->u32CPUSignature = u32CPUSignature;
1063 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
1064 pProcEntry->u32Reserved[0] =
1065 pProcEntry->u32Reserved[1] = 0;
1066
1067 /* ISA bus */
1068 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1);
1069 pBusEntry->u8EntryType = 1; /* bus entry */
1070 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
1071 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
1072
1073 /* PCI bus? */
1074
1075 /* I/O-APIC.
1076 * MP spec: "The configuration table contains one or more entries for I/O APICs.
1077 * ... At least one I/O APIC must be enabled." */
1078 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
1079 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
1080 pIOAPICEntry->u8Id = 1; /* this ID is referenced by the interrupt entries */
1081 pIOAPICEntry->u8Version = 0x11;
1082 pIOAPICEntry->u8Flags = 1 /* enable */;
1083 pIOAPICEntry->u32Addr = 0xfec00000;
1084
1085 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
1086 for (int i = 0; i < 16; i++, pIrqEntry++)
1087 {
1088 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
1089 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
1090 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
1091 trigger mode = conforms to bus */
1092 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
1093 pIrqEntry->u8SrcBusIrq = i;
1094 pIrqEntry->u8DstIOAPICId = 1;
1095 pIrqEntry->u8DstIOAPICInt = i;
1096 }
1097
1098 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
1099 pCfgTab->u8Checksum = pcbiosChecksum(pTable, pCfgTab->u16Length);
1100
1101 AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100,
1102 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
1103 pCfgTab->u16Length, 0x1000-0x100));
1104
1105 MPSFLOATPTR floatPtr;
1106 floatPtr.au8Signature[0] = '_';
1107 floatPtr.au8Signature[1] = 'M';
1108 floatPtr.au8Signature[2] = 'P';
1109 floatPtr.au8Signature[3] = '_';
1110 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
1111 floatPtr.u8Length = 1; /* structure size in paragraphs */
1112 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
1113 floatPtr.u8Checksum = 0;
1114 floatPtr.au8Feature[0] = 0;
1115 floatPtr.au8Feature[1] = 0;
1116 floatPtr.au8Feature[2] = 0;
1117 floatPtr.au8Feature[3] = 0;
1118 floatPtr.au8Feature[4] = 0;
1119 floatPtr.u8Checksum = pcbiosChecksum((uint8_t*)&floatPtr, 16);
1120 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
1121}
1122
1123
1124/**
1125 * Reset notification.
1126 *
1127 * @returns VBox status.
1128 * @param pDevIns The device instance data.
1129 */
1130static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
1131{
1132 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1133 LogFlow(("pcbiosReset:\n"));
1134
1135 if (pData->u8IOAPIC)
1136 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + 0x100);
1137}
1138
1139
1140/**
1141 * Destruct a device instance.
1142 *
1143 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1144 * resources can be freed correctly.
1145 *
1146 * @param pDevIns The device instance data.
1147 */
1148static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
1149{
1150 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1151 LogFlow(("pcbiosDestruct:\n"));
1152
1153 /*
1154 * Free MM heap pointers.
1155 */
1156 if (pData->pu8PcBios)
1157 {
1158 MMR3HeapFree(pData->pu8PcBios);
1159 pData->pu8PcBios = NULL;
1160 }
1161
1162 if (pData->pszPcBiosFile)
1163 {
1164 MMR3HeapFree(pData->pszPcBiosFile);
1165 pData->pszPcBiosFile = NULL;
1166 }
1167
1168 if (pData->pu8LanBoot)
1169 {
1170 MMR3HeapFree(pData->pu8LanBoot);
1171 pData->pu8LanBoot = NULL;
1172 }
1173
1174 if (pData->pszLanBootFile)
1175 {
1176 MMR3HeapFree(pData->pszLanBootFile);
1177 pData->pszLanBootFile = NULL;
1178 }
1179
1180 return VINF_SUCCESS;
1181}
1182
1183
1184/**
1185 * Convert config value to DEVPCBIOSBOOT.
1186 *
1187 * @returns VBox status code.
1188 * @param pCfgHandle Configuration handle.
1189 * @param pszParam The name of the value to read.
1190 * @param penmBoot Where to store the boot method.
1191 */
1192static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
1193{
1194 char *psz;
1195 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
1196 if (VBOX_FAILURE(rc))
1197 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1198 N_("Configuration error: Querying \"%s\" as a string failed"),
1199 pszParam);
1200 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
1201 *penmBoot = DEVPCBIOSBOOT_DVD;
1202 else if (!strcmp(psz, "IDE"))
1203 *penmBoot = DEVPCBIOSBOOT_HD;
1204 else if (!strcmp(psz, "FLOPPY"))
1205 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
1206 else if (!strcmp(psz, "LAN"))
1207 *penmBoot = DEVPCBIOSBOOT_LAN;
1208 else if (!strcmp(psz, "NONE"))
1209 *penmBoot = DEVPCBIOSBOOT_NONE;
1210 else
1211 {
1212 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1213 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
1214 pszParam, psz);
1215 rc = VERR_INTERNAL_ERROR;
1216 }
1217 MMR3HeapFree(psz);
1218 return rc;
1219}
1220
1221/**
1222 * Construct a device instance for a VM.
1223 *
1224 * @returns VBox status.
1225 * @param pDevIns The device instance data.
1226 * If the registration structure is needed, pDevIns->pDevReg points to it.
1227 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1228 * The device number is also found in pDevIns->iInstance, but since it's
1229 * likely to be freqently used PDM passes it as parameter.
1230 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1231 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1232 * iInstance it's expected to be used a bit in this function.
1233 */
1234static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1235{
1236 unsigned i;
1237 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1238 int rc;
1239 int cb;
1240
1241 Assert(iInstance == 0);
1242
1243 /*
1244 * Validate configuration.
1245 */
1246 if (!CFGMR3AreValuesValid(pCfgHandle,
1247 "BootDevice0\0"
1248 "BootDevice1\0"
1249 "BootDevice2\0"
1250 "BootDevice3\0"
1251 "RamSize\0"
1252 "HardDiskDevice\0"
1253 "SataHardDiskDevice\0"
1254 "SataPrimaryMasterLUN\0"
1255 "SataPrimarySlaveLUN\0"
1256 "SataSecondaryMasterLUN\0"
1257 "SataSecondarySlaveLUN\0"
1258 "FloppyDevice\0"
1259 "DelayBoot\0"
1260 "BiosRom\0"
1261 "LanBootRom\0"
1262 "PXEDebug\0"
1263 "UUID\0"
1264 "IOAPIC\0"
1265 "DmiBIOSVendor\0"
1266 "DmiBIOSVersion\0"
1267 "DmiBIOSReleaseDate\0"
1268 "DmiBIOSReleaseMajor\0"
1269 "DmiBIOSReleaseMinor\0"
1270 "DmiBIOSFirmwareMajor\0"
1271 "DmiBIOSFirmwareMinor\0"
1272 "DmiSystemFamily\0"
1273 "DmiSystemProduct\0"
1274 "DmiSystemSerial\0"
1275 "DmiSystemUuid\0"
1276 "DmiSystemVendor\0"
1277 "DmiSystemVersion\0"))
1278 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1279 N_("Invalid configuraton for device pcbios device"));
1280
1281 /*
1282 * Init the data.
1283 */
1284 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
1285 if (VBOX_FAILURE(rc))
1286 return PDMDEV_SET_ERROR(pDevIns, rc,
1287 N_("Configuration error: Querying \"RamSize\" as integer failed"));
1288
1289 rc = CFGMR3QueryU8 (pCfgHandle, "IOAPIC", &pData->u8IOAPIC);
1290 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1291 pData->u8IOAPIC = 1;
1292 else if (VBOX_FAILURE (rc))
1293 return PDMDEV_SET_ERROR(pDevIns, rc,
1294 N_("Configuration error: Failed to read \"IOAPIC\""));
1295
1296 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
1297 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
1298 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
1299 {
1300 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
1301 if (VBOX_FAILURE(rc))
1302 return rc;
1303 }
1304
1305 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
1306 if (VBOX_FAILURE(rc))
1307 return PDMDEV_SET_ERROR(pDevIns, rc,
1308 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1309
1310 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
1311 if (VBOX_FAILURE(rc))
1312 return PDMDEV_SET_ERROR(pDevIns, rc,
1313 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1314
1315 rc = CFGMR3QueryStringAlloc(pCfgHandle, "SataHardDiskDevice", &pData->pszSataDevice);
1316 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1317 pData->pszSataDevice = NULL;
1318 else if (VBOX_FAILURE(rc))
1319 return PDMDEV_SET_ERROR(pDevIns, rc,
1320 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1321
1322 if (pData->pszSataDevice)
1323 {
1324 static const char * const s_apszSataDisks[] =
1325 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1326 Assert(ELEMENTS(s_apszSataDisks) == ELEMENTS(pData->iSataHDLUN));
1327 for (i = 0; i < ELEMENTS(pData->iSataHDLUN); i++)
1328 {
1329 rc = CFGMR3QueryU32(pCfgHandle, s_apszSataDisks[i], &pData->iSataHDLUN[i]);
1330 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1331 pData->iSataHDLUN[i] = i;
1332 else if (VBOX_FAILURE(rc))
1333 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1334 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1335 }
1336 }
1337 /*
1338 * Register I/O Ports and PC BIOS.
1339 */
1340 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1341 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1342 if (VBOX_FAILURE(rc))
1343 return rc;
1344 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1345 NULL, NULL, "Bochs PC BIOS - Shutdown");
1346 if (VBOX_FAILURE(rc))
1347 return rc;
1348
1349 /*
1350 * Query the machine's UUID for SMBIOS/DMI use.
1351 */
1352 RTUUID uuid;
1353 rc = CFGMR3QueryBytes(pCfgHandle, "UUID", &uuid, sizeof(uuid));
1354 if (VBOX_FAILURE(rc))
1355 return PDMDEV_SET_ERROR(pDevIns, rc,
1356 N_("Configuration error: Querying \"UUID\" failed"));
1357
1358
1359 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1360 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1361 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1362 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1363 rc = pcbiosPlantDMITable(pDevIns, pData->au8DMIPage, VBOX_DMI_TABLE_SIZE, &uuid, pCfgHandle);
1364 if (VBOX_FAILURE(rc))
1365 return rc;
1366 if (pData->u8IOAPIC)
1367 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + VBOX_DMI_TABLE_SIZE);
1368
1369 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, false /* fShadow */, "DMI tables");
1370 if (VBOX_FAILURE(rc))
1371 return rc;
1372
1373 /*
1374 * Read the PXE debug logging option.
1375 */
1376 rc = CFGMR3QueryU8(pCfgHandle, "PXEDebug", &pData->u8PXEDebug);
1377 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1378 pData->u8PXEDebug = 0;
1379 else if (VBOX_FAILURE(rc))
1380 return PDMDEV_SET_ERROR(pDevIns, rc,
1381 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1382
1383 /*
1384 * Get the system BIOS ROM file name.
1385 */
1386 rc = CFGMR3QueryStringAlloc(pCfgHandle, "BiosRom", &pData->pszPcBiosFile);
1387 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1388 {
1389 pData->pszPcBiosFile = NULL;
1390 rc = VINF_SUCCESS;
1391 }
1392 else if (VBOX_FAILURE(rc))
1393 return PDMDEV_SET_ERROR(pDevIns, rc,
1394 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1395 else if (!*pData->pszPcBiosFile)
1396 {
1397 MMR3HeapFree(pData->pszPcBiosFile);
1398 pData->pszPcBiosFile = NULL;
1399 }
1400
1401 const uint8_t *pu8PcBiosBinary = NULL;
1402 uint64_t cbPcBiosBinary;
1403 /*
1404 * Determine the system BIOS ROM size, open specified ROM file in the process.
1405 */
1406 RTFILE FilePcBios = NIL_RTFILE;
1407 if (pData->pszPcBiosFile)
1408 {
1409 rc = RTFileOpen(&FilePcBios, pData->pszPcBiosFile,
1410 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1411 if (VBOX_SUCCESS(rc))
1412 {
1413 rc = RTFileGetSize(FilePcBios, &pData->cbPcBios);
1414 if (VBOX_SUCCESS(rc))
1415 {
1416 /* The following checks should be in sync the AssertReleaseMsg's below. */
1417 if ( RT_ALIGN(pData->cbPcBios, _64K) != pData->cbPcBios
1418 || pData->cbPcBios > 32 * _64K
1419 || pData->cbPcBios < _64K)
1420 rc = VERR_TOO_MUCH_DATA;
1421 }
1422 }
1423 if (VBOX_FAILURE(rc))
1424 {
1425 /*
1426 * In case of failure simply fall back to the built-in BIOS ROM.
1427 */
1428 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Vrc!\n", pData->pszPcBiosFile, rc));
1429 RTFileClose(FilePcBios);
1430 FilePcBios = NIL_RTFILE;
1431 MMR3HeapFree(pData->pszPcBiosFile);
1432 pData->pszPcBiosFile = NULL;
1433 }
1434 }
1435
1436 /*
1437 * Attempt to get the system BIOS ROM data from file.
1438 */
1439 if (pData->pszPcBiosFile)
1440 {
1441 /*
1442 * Allocate buffer for the system BIOS ROM data.
1443 */
1444 pData->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pData->cbPcBios);
1445 if (pData->pu8PcBios)
1446 {
1447 rc = RTFileRead(FilePcBios, pData->pu8PcBios, pData->cbPcBios, NULL);
1448 if (VBOX_FAILURE(rc))
1449 {
1450 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", pData->cbPcBios, rc));
1451 MMR3HeapFree(pData->pu8PcBios);
1452 pData->pu8PcBios = NULL;
1453 }
1454 rc = VINF_SUCCESS;
1455 }
1456 else
1457 rc = VERR_NO_MEMORY;
1458 }
1459 else
1460 pData->pu8PcBios = NULL;
1461
1462 /* cleanup */
1463 if (FilePcBios != NIL_RTFILE)
1464 RTFileClose(FilePcBios);
1465
1466 /* If we were unable to get the data from file for whatever reason, fall
1467 * back to the built-in ROM image.
1468 */
1469 if (pData->pu8PcBios == NULL)
1470 {
1471 pu8PcBiosBinary = g_abPcBiosBinary;
1472 cbPcBiosBinary = g_cbPcBiosBinary;
1473 }
1474 else
1475 {
1476 pu8PcBiosBinary = pData->pu8PcBios;
1477 cbPcBiosBinary = pData->cbPcBios;
1478 }
1479
1480 /*
1481 * Map the BIOS into memory.
1482 * There are two mappings:
1483 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1484 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1485 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1486 */
1487 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1488 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1489 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1490 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1491 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1492 false /* fShadow */, "PC BIOS - 0xfffff");
1493 if (VBOX_FAILURE(rc))
1494 return rc;
1495 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1496 false /* fShadow */, "PC BIOS - 0xffffffff");
1497 if (VBOX_FAILURE(rc))
1498 return rc;
1499
1500 /*
1501 * Call reset to set values and stuff.
1502 */
1503 pcbiosReset(pDevIns);
1504
1505 /*
1506 * Get the LAN boot ROM file name.
1507 */
1508 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1509 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1510 {
1511 pData->pszLanBootFile = NULL;
1512 rc = VINF_SUCCESS;
1513 }
1514 else if (VBOX_FAILURE(rc))
1515 return PDMDEV_SET_ERROR(pDevIns, rc,
1516 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1517 else if (!*pData->pszLanBootFile)
1518 {
1519 MMR3HeapFree(pData->pszLanBootFile);
1520 pData->pszLanBootFile = NULL;
1521 }
1522
1523 uint64_t cbFileLanBoot;
1524 const uint8_t *pu8LanBootBinary = NULL;
1525 uint64_t cbLanBootBinary;
1526
1527 /*
1528 * Determine the LAN boot ROM size, open specified ROM file in the process.
1529 */
1530 RTFILE FileLanBoot = NIL_RTFILE;
1531 if (pData->pszLanBootFile)
1532 {
1533 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1534 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1535 if (VBOX_SUCCESS(rc))
1536 {
1537 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1538 if (VBOX_SUCCESS(rc))
1539 {
1540 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1541 || cbFileLanBoot > _64K)
1542 rc = VERR_TOO_MUCH_DATA;
1543 }
1544 }
1545 if (VBOX_FAILURE(rc))
1546 {
1547 /*
1548 * Ignore failure and fall back to the built-in LAN boot ROM.
1549 */
1550 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1551 RTFileClose(FileLanBoot);
1552 FileLanBoot = NIL_RTFILE;
1553 MMR3HeapFree(pData->pszLanBootFile);
1554 pData->pszLanBootFile = NULL;
1555 }
1556 }
1557
1558 /*
1559 * Get the LAN boot ROM data.
1560 */
1561 if (pData->pszLanBootFile)
1562 {
1563 /*
1564 * Allocate buffer for the LAN boot ROM data.
1565 */
1566 pData->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1567 if (pData->pu8LanBoot)
1568 {
1569 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1570 if (VBOX_FAILURE(rc))
1571 {
1572 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1573 MMR3HeapFree(pData->pu8LanBoot);
1574 pData->pu8LanBoot = NULL;
1575 }
1576 rc = VINF_SUCCESS;
1577 }
1578 else
1579 rc = VERR_NO_MEMORY;
1580 }
1581 else
1582 pData->pu8LanBoot = NULL;
1583
1584 /* cleanup */
1585 if (FileLanBoot != NIL_RTFILE)
1586 RTFileClose(FileLanBoot);
1587
1588 /* If we were unable to get the data from file for whatever reason, fall
1589 * back to the built-in LAN boot ROM image.
1590 */
1591 if (pData->pu8LanBoot == NULL)
1592 {
1593 pu8LanBootBinary = g_abNetBiosBinary;
1594 cbLanBootBinary = g_cbNetBiosBinary;
1595 }
1596 else
1597 {
1598 pu8LanBootBinary = pData->pu8LanBoot;
1599 cbLanBootBinary = cbFileLanBoot;
1600 }
1601
1602 /*
1603 * Map the Network Boot ROM into memory.
1604 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1605 * the (up to) 32 kb ROM image.
1606 */
1607 if (pu8LanBootBinary)
1608 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1609 true /* fShadow */, "Net Boot ROM");
1610
1611 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1612 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1613 {
1614 pData->uBootDelay = 0;
1615 rc = VINF_SUCCESS;
1616 }
1617 else
1618 {
1619 if (VBOX_FAILURE(rc))
1620 return PDMDEV_SET_ERROR(pDevIns, rc,
1621 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1622 if (pData->uBootDelay > 15)
1623 pData->uBootDelay = 15;
1624 }
1625
1626 return rc;
1627}
1628
1629
1630/**
1631 * The device registration structure.
1632 */
1633const PDMDEVREG g_DevicePcBios =
1634{
1635 /* u32Version */
1636 PDM_DEVREG_VERSION,
1637 /* szDeviceName */
1638 "pcbios",
1639 /* szGCMod */
1640 "",
1641 /* szR0Mod */
1642 "",
1643 /* pszDescription */
1644 "PC BIOS Device",
1645 /* fFlags */
1646 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1647 /* fClass */
1648 PDM_DEVREG_CLASS_ARCH_BIOS,
1649 /* cMaxInstances */
1650 1,
1651 /* cbInstance */
1652 sizeof(DEVPCBIOS),
1653 /* pfnConstruct */
1654 pcbiosConstruct,
1655 /* pfnDestruct */
1656 pcbiosDestruct,
1657 /* pfnRelocate */
1658 NULL,
1659 /* pfnIOCtl */
1660 NULL,
1661 /* pfnPowerOn */
1662 NULL,
1663 /* pfnReset */
1664 pcbiosReset,
1665 /* pfnSuspend */
1666 NULL,
1667 /* pfnResume */
1668 NULL,
1669 /* pfnAttach */
1670 NULL,
1671 /* pfnDetach */
1672 NULL,
1673 /* pfnQueryInterface. */
1674 NULL,
1675 /* pfnInitComplete. */
1676 pcbiosInitComplete
1677};
1678
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