VirtualBox

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

Last change on this file since 9566 was 9454, checked in by vboxsync, 16 years ago

spelling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 57.9 KB
Line 
1/* $Id: DevPcBios.cpp 9454 2008-06-06 09:42:15Z 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) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
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 /*
859 * Don't change this information otherwise Windows guests will demand re-activation!
860 */
861 READCFGSTR("DmiBIOSVendor", pszDmiBIOSVendor, "innotek GmbH");
862 READCFGSTR("DmiBIOSVersion", pszDmiBIOSVersion, "VirtualBox");
863 READCFGSTR("DmiBIOSReleaseDate", pszDmiBIOSReleaseDate, "12/01/2006");
864 READCFGINT("DmiBIOSReleaseMajor", iDmiBIOSReleaseMajor, 0);
865 READCFGINT("DmiBIOSReleaseMinor", iDmiBIOSReleaseMinor, 0);
866 READCFGINT("DmiBIOSFirmwareMajor", iDmiBIOSFirmwareMajor, 0);
867 READCFGINT("DmiBIOSFirmwareMinor", iDmiBIOSFirmwareMinor, 0);
868 READCFGSTR("DmiSystemVendor", pszDmiSystemVendor, "innotek GmbH");
869 READCFGSTR("DmiSystemProduct", pszDmiSystemProduct, "VirtualBox");
870 READCFGSTR("DmiSystemVersion", pszDmiSystemVersion, "1.2");
871 READCFGSTR("DmiSystemSerial", pszDmiSystemSerial, "0");
872 rc = CFGMR3QueryStringAlloc(pCfgHandle, "DmiSystemUuid", &pszDmiSystemUuid);
873 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
874 pszDmiSystemUuid = NULL;
875 else if (VBOX_FAILURE(rc))
876 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
877 N_("Configuration error: Querying \"DmiUuid\" as a string failed"));
878 READCFGSTR("DmiSystemFamily", pszDmiSystemFamily, "Virtual Machine");
879
880 /* DMI BIOS information */
881 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
882
883 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
884 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
885
886 /* don't set these fields by default for legacy compatibility */
887 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
888 {
889 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
890 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
891 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
892 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
893 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
894 {
895 pszStr = (char *)(pBIOSInf + 1);
896 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
897 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
898 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
899 }
900 }
901
902 iStrNr = 1;
903 pBIOSInf->header.u8Type = 0; /* BIOS Information */
904 pBIOSInf->header.u16Handle = 0x0000;
905 pBIOSInf->u8Vendor = iStrNr++;
906 STRCPY(pszStr, pszDmiBIOSVendor);
907 pBIOSInf->u8Version = iStrNr++;
908 STRCPY(pszStr, pszDmiBIOSVersion);
909 pBIOSInf->u16Start = 0xE000;
910 pBIOSInf->u8Release = iStrNr++;
911 STRCPY(pszStr, pszDmiBIOSReleaseDate);
912 pBIOSInf->u8ROMSize = 1; /* 128K */
913 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
914 | RT_BIT(7) /* PCI is supported */
915 | RT_BIT(15) /* Boot from CD is supported */
916 | RT_BIT(16) /* Selectable Boot is supported */
917 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
918 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
919 /* any more?? */
920 ;
921 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
922 /* any more?? */
923 ;
924 pBIOSInf->u8CharacteristicsByte2 = 0
925 /* any more?? */
926 ;
927 *pszStr++ = '\0';
928
929 /* DMI system information */
930 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
931 pszStr = (char *)(pSystemInf + 1);
932 iStrNr = 1;
933 pSystemInf->header.u8Type = 1; /* System Information */
934 pSystemInf->header.u8Length = sizeof(*pSystemInf);
935 pSystemInf->header.u16Handle = 0x0001;
936 pSystemInf->u8Manufacturer = iStrNr++;
937 STRCPY(pszStr, pszDmiSystemVendor);
938 pSystemInf->u8ProductName = iStrNr++;
939 STRCPY(pszStr, pszDmiSystemProduct);
940 pSystemInf->u8Version = iStrNr++;
941 STRCPY(pszStr, pszDmiSystemVersion);
942 pSystemInf->u8SerialNumber = iStrNr++;
943 STRCPY(pszStr, pszDmiSystemSerial);
944
945 RTUUID uuid;
946 if (pszDmiSystemUuid)
947 {
948 int rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
949 if (VBOX_FAILURE(rc))
950 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
951 N_("Invalid UUID for DMI tables specified"));
952 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
953 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
954 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
955 pUuid = &uuid;
956 }
957 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
958
959 pSystemInf->u8WakeupType = 6; /* Power Switch */
960 pSystemInf->u8SKUNumber = 0;
961 pSystemInf->u8Family = iStrNr++;
962 STRCPY(pszStr, pszDmiSystemFamily);
963 *pszStr++ = '\0';
964
965 /* End-of-table marker - includes padding to account for fixed table size. */
966 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
967 pEndOfTable->u8Type = 0x7f;
968 pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2;
969 pEndOfTable->u16Handle = 0xFFFF;
970
971 /* If more fields are added here, fix the size check in STRCPY */
972
973#undef STRCPY
974#undef READCFG
975
976 MMR3HeapFree(pszDmiBIOSVendor);
977 MMR3HeapFree(pszDmiBIOSVersion);
978 MMR3HeapFree(pszDmiBIOSReleaseDate);
979 MMR3HeapFree(pszDmiSystemVendor);
980 MMR3HeapFree(pszDmiSystemProduct);
981 MMR3HeapFree(pszDmiSystemVersion);
982 MMR3HeapFree(pszDmiSystemSerial);
983 MMR3HeapFree(pszDmiSystemUuid);
984 MMR3HeapFree(pszDmiSystemFamily);
985
986 return VINF_SUCCESS;
987}
988AssertCompile(VBOX_DMI_TABLE_ENTR == 3);
989
990
991/**
992 * Calculate a simple checksum for the MPS table.
993 *
994 * @param data data
995 * @param len size of data
996 */
997static uint8_t pcbiosChecksum(const uint8_t * const au8Data, uint32_t u32Length)
998{
999 uint8_t u8Sum = 0;
1000 for (size_t i = 0; i < u32Length; ++i)
1001 u8Sum += au8Data[i];
1002 return -u8Sum;
1003}
1004
1005
1006/**
1007 * Construct the MPS table. Only applicable if IOAPIC is active!
1008 *
1009 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
1010 * ``1.3 Scope
1011 * ...
1012 * The hardware required to implement the MP specification is kept to a
1013 * minimum, as follows:
1014 * * One or more processors that are Intel architecture instruction set
1015 * compatible, such as the CPUs in the Intel486 or Pentium processor
1016 * family.
1017 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
1018 * Interrupt Controller or the integrated APIC, such as that on the
1019 * Intel Pentium 735\90 and 815\100 processors, together with a discrete
1020 * I/O APIC unit.''
1021 * and later:
1022 * ``4.3.3 I/O APIC Entries
1023 * The configuration table contains one or more entries for I/O APICs.
1024 * ...
1025 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
1026 * operating system should not attempt to access
1027 * this I/O APIC.
1028 * At least one I/O APIC must be enabled.''
1029 *
1030 * @param pDevIns The device instance data.
1031 * @param addr physical address in guest memory.
1032 */
1033static void pcbiosPlantMPStable(PPDMDEVINS pDevIns, uint8_t *pTable)
1034{
1035 /* configuration table */
1036 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
1037 memcpy(pCfgTab->au8Signature, "PCMP", 4);
1038 pCfgTab->u8SpecRev = 4; /* 1.4 */
1039 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
1040 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
1041 pCfgTab->u32OemTablePtr = 0;
1042 pCfgTab->u16OemTableSize = 0;
1043 pCfgTab->u16EntryCount = 1 /* Processor */
1044 + 1 /* ISA Bus */
1045 + 1 /* I/O-APIC */
1046 + 16 /* Interrupts */;
1047 pCfgTab->u32AddrLocalApic = 0xfee00000;
1048 pCfgTab->u16ExtTableLength = 0;
1049 pCfgTab->u8ExtTableChecksxum = 0;
1050 pCfgTab->u8Reserved = 0;
1051
1052 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
1053 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
1054 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
1055 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1056 if (u32Eax >= 1)
1057 {
1058 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1059 u32CPUSignature = u32Eax & 0xfff;
1060 /* Local APIC will be enabled later so override it here. Since we provide
1061 * an MP table we have an IOAPIC and therefore a Local APIC. */
1062 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
1063 }
1064
1065 /* one processor so far */
1066 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
1067 pProcEntry->u8EntryType = 0; /* processor entry */
1068 pProcEntry->u8LocalApicId = 0;
1069 pProcEntry->u8LocalApicVersion = 0x11;
1070 pProcEntry->u8CPUFlags = 2 /* bootstrap processor */ | 1 /* enabled */;
1071 pProcEntry->u32CPUSignature = u32CPUSignature;
1072 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
1073 pProcEntry->u32Reserved[0] =
1074 pProcEntry->u32Reserved[1] = 0;
1075
1076 /* ISA bus */
1077 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1);
1078 pBusEntry->u8EntryType = 1; /* bus entry */
1079 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
1080 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
1081
1082 /* PCI bus? */
1083
1084 /* I/O-APIC.
1085 * MP spec: "The configuration table contains one or more entries for I/O APICs.
1086 * ... At least one I/O APIC must be enabled." */
1087 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
1088 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
1089 pIOAPICEntry->u8Id = 1; /* this ID is referenced by the interrupt entries */
1090 pIOAPICEntry->u8Version = 0x11;
1091 pIOAPICEntry->u8Flags = 1 /* enable */;
1092 pIOAPICEntry->u32Addr = 0xfec00000;
1093
1094 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
1095 for (int i = 0; i < 16; i++, pIrqEntry++)
1096 {
1097 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
1098 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
1099 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
1100 trigger mode = conforms to bus */
1101 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
1102 pIrqEntry->u8SrcBusIrq = i;
1103 pIrqEntry->u8DstIOAPICId = 1;
1104 pIrqEntry->u8DstIOAPICInt = i;
1105 }
1106
1107 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
1108 pCfgTab->u8Checksum = pcbiosChecksum(pTable, pCfgTab->u16Length);
1109
1110 AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100,
1111 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
1112 pCfgTab->u16Length, 0x1000-0x100));
1113
1114 MPSFLOATPTR floatPtr;
1115 floatPtr.au8Signature[0] = '_';
1116 floatPtr.au8Signature[1] = 'M';
1117 floatPtr.au8Signature[2] = 'P';
1118 floatPtr.au8Signature[3] = '_';
1119 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
1120 floatPtr.u8Length = 1; /* structure size in paragraphs */
1121 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
1122 floatPtr.u8Checksum = 0;
1123 floatPtr.au8Feature[0] = 0;
1124 floatPtr.au8Feature[1] = 0;
1125 floatPtr.au8Feature[2] = 0;
1126 floatPtr.au8Feature[3] = 0;
1127 floatPtr.au8Feature[4] = 0;
1128 floatPtr.u8Checksum = pcbiosChecksum((uint8_t*)&floatPtr, 16);
1129 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
1130}
1131
1132
1133/**
1134 * Reset notification.
1135 *
1136 * @returns VBox status.
1137 * @param pDevIns The device instance data.
1138 */
1139static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
1140{
1141 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1142 LogFlow(("pcbiosReset:\n"));
1143
1144 if (pData->u8IOAPIC)
1145 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + 0x100);
1146}
1147
1148
1149/**
1150 * Destruct a device instance.
1151 *
1152 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1153 * resources can be freed correctly.
1154 *
1155 * @param pDevIns The device instance data.
1156 */
1157static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
1158{
1159 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1160 LogFlow(("pcbiosDestruct:\n"));
1161
1162 /*
1163 * Free MM heap pointers.
1164 */
1165 if (pData->pu8PcBios)
1166 {
1167 MMR3HeapFree(pData->pu8PcBios);
1168 pData->pu8PcBios = NULL;
1169 }
1170
1171 if (pData->pszPcBiosFile)
1172 {
1173 MMR3HeapFree(pData->pszPcBiosFile);
1174 pData->pszPcBiosFile = NULL;
1175 }
1176
1177 if (pData->pu8LanBoot)
1178 {
1179 MMR3HeapFree(pData->pu8LanBoot);
1180 pData->pu8LanBoot = NULL;
1181 }
1182
1183 if (pData->pszLanBootFile)
1184 {
1185 MMR3HeapFree(pData->pszLanBootFile);
1186 pData->pszLanBootFile = NULL;
1187 }
1188
1189 return VINF_SUCCESS;
1190}
1191
1192
1193/**
1194 * Convert config value to DEVPCBIOSBOOT.
1195 *
1196 * @returns VBox status code.
1197 * @param pCfgHandle Configuration handle.
1198 * @param pszParam The name of the value to read.
1199 * @param penmBoot Where to store the boot method.
1200 */
1201static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
1202{
1203 char *psz;
1204 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
1205 if (VBOX_FAILURE(rc))
1206 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1207 N_("Configuration error: Querying \"%s\" as a string failed"),
1208 pszParam);
1209 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
1210 *penmBoot = DEVPCBIOSBOOT_DVD;
1211 else if (!strcmp(psz, "IDE"))
1212 *penmBoot = DEVPCBIOSBOOT_HD;
1213 else if (!strcmp(psz, "FLOPPY"))
1214 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
1215 else if (!strcmp(psz, "LAN"))
1216 *penmBoot = DEVPCBIOSBOOT_LAN;
1217 else if (!strcmp(psz, "NONE"))
1218 *penmBoot = DEVPCBIOSBOOT_NONE;
1219 else
1220 {
1221 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1222 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
1223 pszParam, psz);
1224 rc = VERR_INTERNAL_ERROR;
1225 }
1226 MMR3HeapFree(psz);
1227 return rc;
1228}
1229
1230/**
1231 * Construct a device instance for a VM.
1232 *
1233 * @returns VBox status.
1234 * @param pDevIns The device instance data.
1235 * If the registration structure is needed, pDevIns->pDevReg points to it.
1236 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1237 * The device number is also found in pDevIns->iInstance, but since it's
1238 * likely to be freqently used PDM passes it as parameter.
1239 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1240 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1241 * iInstance it's expected to be used a bit in this function.
1242 */
1243static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1244{
1245 unsigned i;
1246 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1247 int rc;
1248 int cb;
1249
1250 Assert(iInstance == 0);
1251
1252 /*
1253 * Validate configuration.
1254 */
1255 if (!CFGMR3AreValuesValid(pCfgHandle,
1256 "BootDevice0\0"
1257 "BootDevice1\0"
1258 "BootDevice2\0"
1259 "BootDevice3\0"
1260 "RamSize\0"
1261 "HardDiskDevice\0"
1262 "SataHardDiskDevice\0"
1263 "SataPrimaryMasterLUN\0"
1264 "SataPrimarySlaveLUN\0"
1265 "SataSecondaryMasterLUN\0"
1266 "SataSecondarySlaveLUN\0"
1267 "FloppyDevice\0"
1268 "DelayBoot\0"
1269 "BiosRom\0"
1270 "LanBootRom\0"
1271 "PXEDebug\0"
1272 "UUID\0"
1273 "IOAPIC\0"
1274 "DmiBIOSVendor\0"
1275 "DmiBIOSVersion\0"
1276 "DmiBIOSReleaseDate\0"
1277 "DmiBIOSReleaseMajor\0"
1278 "DmiBIOSReleaseMinor\0"
1279 "DmiBIOSFirmwareMajor\0"
1280 "DmiBIOSFirmwareMinor\0"
1281 "DmiSystemFamily\0"
1282 "DmiSystemProduct\0"
1283 "DmiSystemSerial\0"
1284 "DmiSystemUuid\0"
1285 "DmiSystemVendor\0"
1286 "DmiSystemVersion\0"))
1287 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1288 N_("Invalid configuraton for device pcbios device"));
1289
1290 /*
1291 * Init the data.
1292 */
1293 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
1294 if (VBOX_FAILURE(rc))
1295 return PDMDEV_SET_ERROR(pDevIns, rc,
1296 N_("Configuration error: Querying \"RamSize\" as integer failed"));
1297
1298 rc = CFGMR3QueryU8 (pCfgHandle, "IOAPIC", &pData->u8IOAPIC);
1299 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1300 pData->u8IOAPIC = 1;
1301 else if (VBOX_FAILURE (rc))
1302 return PDMDEV_SET_ERROR(pDevIns, rc,
1303 N_("Configuration error: Failed to read \"IOAPIC\""));
1304
1305 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
1306 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
1307 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
1308 {
1309 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
1310 if (VBOX_FAILURE(rc))
1311 return rc;
1312 }
1313
1314 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
1315 if (VBOX_FAILURE(rc))
1316 return PDMDEV_SET_ERROR(pDevIns, rc,
1317 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1318
1319 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
1320 if (VBOX_FAILURE(rc))
1321 return PDMDEV_SET_ERROR(pDevIns, rc,
1322 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1323
1324 rc = CFGMR3QueryStringAlloc(pCfgHandle, "SataHardDiskDevice", &pData->pszSataDevice);
1325 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1326 pData->pszSataDevice = NULL;
1327 else if (VBOX_FAILURE(rc))
1328 return PDMDEV_SET_ERROR(pDevIns, rc,
1329 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1330
1331 if (pData->pszSataDevice)
1332 {
1333 static const char * const s_apszSataDisks[] =
1334 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1335 Assert(ELEMENTS(s_apszSataDisks) == ELEMENTS(pData->iSataHDLUN));
1336 for (i = 0; i < ELEMENTS(pData->iSataHDLUN); i++)
1337 {
1338 rc = CFGMR3QueryU32(pCfgHandle, s_apszSataDisks[i], &pData->iSataHDLUN[i]);
1339 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1340 pData->iSataHDLUN[i] = i;
1341 else if (VBOX_FAILURE(rc))
1342 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1343 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1344 }
1345 }
1346 /*
1347 * Register I/O Ports and PC BIOS.
1348 */
1349 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1350 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1351 if (VBOX_FAILURE(rc))
1352 return rc;
1353 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1354 NULL, NULL, "Bochs PC BIOS - Shutdown");
1355 if (VBOX_FAILURE(rc))
1356 return rc;
1357
1358 /*
1359 * Query the machine's UUID for SMBIOS/DMI use.
1360 */
1361 RTUUID uuid;
1362 rc = CFGMR3QueryBytes(pCfgHandle, "UUID", &uuid, sizeof(uuid));
1363 if (VBOX_FAILURE(rc))
1364 return PDMDEV_SET_ERROR(pDevIns, rc,
1365 N_("Configuration error: Querying \"UUID\" failed"));
1366
1367
1368 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1369 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1370 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1371 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1372 rc = pcbiosPlantDMITable(pDevIns, pData->au8DMIPage, VBOX_DMI_TABLE_SIZE, &uuid, pCfgHandle);
1373 if (VBOX_FAILURE(rc))
1374 return rc;
1375 if (pData->u8IOAPIC)
1376 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + VBOX_DMI_TABLE_SIZE);
1377
1378 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, false /* fShadow */, "DMI tables");
1379 if (VBOX_FAILURE(rc))
1380 return rc;
1381
1382 /*
1383 * Read the PXE debug logging option.
1384 */
1385 rc = CFGMR3QueryU8(pCfgHandle, "PXEDebug", &pData->u8PXEDebug);
1386 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1387 pData->u8PXEDebug = 0;
1388 else if (VBOX_FAILURE(rc))
1389 return PDMDEV_SET_ERROR(pDevIns, rc,
1390 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1391
1392 /*
1393 * Get the system BIOS ROM file name.
1394 */
1395 rc = CFGMR3QueryStringAlloc(pCfgHandle, "BiosRom", &pData->pszPcBiosFile);
1396 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1397 {
1398 pData->pszPcBiosFile = NULL;
1399 rc = VINF_SUCCESS;
1400 }
1401 else if (VBOX_FAILURE(rc))
1402 return PDMDEV_SET_ERROR(pDevIns, rc,
1403 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1404 else if (!*pData->pszPcBiosFile)
1405 {
1406 MMR3HeapFree(pData->pszPcBiosFile);
1407 pData->pszPcBiosFile = NULL;
1408 }
1409
1410 const uint8_t *pu8PcBiosBinary = NULL;
1411 uint64_t cbPcBiosBinary;
1412 /*
1413 * Determine the system BIOS ROM size, open specified ROM file in the process.
1414 */
1415 RTFILE FilePcBios = NIL_RTFILE;
1416 if (pData->pszPcBiosFile)
1417 {
1418 rc = RTFileOpen(&FilePcBios, pData->pszPcBiosFile,
1419 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1420 if (VBOX_SUCCESS(rc))
1421 {
1422 rc = RTFileGetSize(FilePcBios, &pData->cbPcBios);
1423 if (VBOX_SUCCESS(rc))
1424 {
1425 /* The following checks should be in sync the AssertReleaseMsg's below. */
1426 if ( RT_ALIGN(pData->cbPcBios, _64K) != pData->cbPcBios
1427 || pData->cbPcBios > 32 * _64K
1428 || pData->cbPcBios < _64K)
1429 rc = VERR_TOO_MUCH_DATA;
1430 }
1431 }
1432 if (VBOX_FAILURE(rc))
1433 {
1434 /*
1435 * In case of failure simply fall back to the built-in BIOS ROM.
1436 */
1437 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Vrc!\n", pData->pszPcBiosFile, rc));
1438 RTFileClose(FilePcBios);
1439 FilePcBios = NIL_RTFILE;
1440 MMR3HeapFree(pData->pszPcBiosFile);
1441 pData->pszPcBiosFile = NULL;
1442 }
1443 }
1444
1445 /*
1446 * Attempt to get the system BIOS ROM data from file.
1447 */
1448 if (pData->pszPcBiosFile)
1449 {
1450 /*
1451 * Allocate buffer for the system BIOS ROM data.
1452 */
1453 pData->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pData->cbPcBios);
1454 if (pData->pu8PcBios)
1455 {
1456 rc = RTFileRead(FilePcBios, pData->pu8PcBios, pData->cbPcBios, NULL);
1457 if (VBOX_FAILURE(rc))
1458 {
1459 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", pData->cbPcBios, rc));
1460 MMR3HeapFree(pData->pu8PcBios);
1461 pData->pu8PcBios = NULL;
1462 }
1463 rc = VINF_SUCCESS;
1464 }
1465 else
1466 rc = VERR_NO_MEMORY;
1467 }
1468 else
1469 pData->pu8PcBios = NULL;
1470
1471 /* cleanup */
1472 if (FilePcBios != NIL_RTFILE)
1473 RTFileClose(FilePcBios);
1474
1475 /* If we were unable to get the data from file for whatever reason, fall
1476 * back to the built-in ROM image.
1477 */
1478 if (pData->pu8PcBios == NULL)
1479 {
1480 pu8PcBiosBinary = g_abPcBiosBinary;
1481 cbPcBiosBinary = g_cbPcBiosBinary;
1482 }
1483 else
1484 {
1485 pu8PcBiosBinary = pData->pu8PcBios;
1486 cbPcBiosBinary = pData->cbPcBios;
1487 }
1488
1489 /*
1490 * Map the BIOS into memory.
1491 * There are two mappings:
1492 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1493 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1494 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1495 */
1496 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1497 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1498 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1499 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1500 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1501 false /* fShadow */, "PC BIOS - 0xfffff");
1502 if (VBOX_FAILURE(rc))
1503 return rc;
1504 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1505 false /* fShadow */, "PC BIOS - 0xffffffff");
1506 if (VBOX_FAILURE(rc))
1507 return rc;
1508
1509 /*
1510 * Call reset to set values and stuff.
1511 */
1512 pcbiosReset(pDevIns);
1513
1514 /*
1515 * Get the LAN boot ROM file name.
1516 */
1517 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1518 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1519 {
1520 pData->pszLanBootFile = NULL;
1521 rc = VINF_SUCCESS;
1522 }
1523 else if (VBOX_FAILURE(rc))
1524 return PDMDEV_SET_ERROR(pDevIns, rc,
1525 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1526 else if (!*pData->pszLanBootFile)
1527 {
1528 MMR3HeapFree(pData->pszLanBootFile);
1529 pData->pszLanBootFile = NULL;
1530 }
1531
1532 uint64_t cbFileLanBoot;
1533 const uint8_t *pu8LanBootBinary = NULL;
1534 uint64_t cbLanBootBinary;
1535
1536 /*
1537 * Determine the LAN boot ROM size, open specified ROM file in the process.
1538 */
1539 RTFILE FileLanBoot = NIL_RTFILE;
1540 if (pData->pszLanBootFile)
1541 {
1542 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1543 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1544 if (VBOX_SUCCESS(rc))
1545 {
1546 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1547 if (VBOX_SUCCESS(rc))
1548 {
1549 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1550 || cbFileLanBoot > _64K)
1551 rc = VERR_TOO_MUCH_DATA;
1552 }
1553 }
1554 if (VBOX_FAILURE(rc))
1555 {
1556 /*
1557 * Ignore failure and fall back to the built-in LAN boot ROM.
1558 */
1559 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1560 RTFileClose(FileLanBoot);
1561 FileLanBoot = NIL_RTFILE;
1562 MMR3HeapFree(pData->pszLanBootFile);
1563 pData->pszLanBootFile = NULL;
1564 }
1565 }
1566
1567 /*
1568 * Get the LAN boot ROM data.
1569 */
1570 if (pData->pszLanBootFile)
1571 {
1572 /*
1573 * Allocate buffer for the LAN boot ROM data.
1574 */
1575 pData->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1576 if (pData->pu8LanBoot)
1577 {
1578 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1579 if (VBOX_FAILURE(rc))
1580 {
1581 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1582 MMR3HeapFree(pData->pu8LanBoot);
1583 pData->pu8LanBoot = NULL;
1584 }
1585 rc = VINF_SUCCESS;
1586 }
1587 else
1588 rc = VERR_NO_MEMORY;
1589 }
1590 else
1591 pData->pu8LanBoot = NULL;
1592
1593 /* cleanup */
1594 if (FileLanBoot != NIL_RTFILE)
1595 RTFileClose(FileLanBoot);
1596
1597 /* If we were unable to get the data from file for whatever reason, fall
1598 * back to the built-in LAN boot ROM image.
1599 */
1600 if (pData->pu8LanBoot == NULL)
1601 {
1602 pu8LanBootBinary = g_abNetBiosBinary;
1603 cbLanBootBinary = g_cbNetBiosBinary;
1604 }
1605 else
1606 {
1607 pu8LanBootBinary = pData->pu8LanBoot;
1608 cbLanBootBinary = cbFileLanBoot;
1609 }
1610
1611 /*
1612 * Map the Network Boot ROM into memory.
1613 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1614 * the (up to) 32 kb ROM image.
1615 */
1616 if (pu8LanBootBinary)
1617 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1618 true /* fShadow */, "Net Boot ROM");
1619
1620 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1621 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1622 {
1623 pData->uBootDelay = 0;
1624 rc = VINF_SUCCESS;
1625 }
1626 else
1627 {
1628 if (VBOX_FAILURE(rc))
1629 return PDMDEV_SET_ERROR(pDevIns, rc,
1630 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1631 if (pData->uBootDelay > 15)
1632 pData->uBootDelay = 15;
1633 }
1634
1635 return rc;
1636}
1637
1638
1639/**
1640 * The device registration structure.
1641 */
1642const PDMDEVREG g_DevicePcBios =
1643{
1644 /* u32Version */
1645 PDM_DEVREG_VERSION,
1646 /* szDeviceName */
1647 "pcbios",
1648 /* szGCMod */
1649 "",
1650 /* szR0Mod */
1651 "",
1652 /* pszDescription */
1653 "PC BIOS Device",
1654 /* fFlags */
1655 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1656 /* fClass */
1657 PDM_DEVREG_CLASS_ARCH_BIOS,
1658 /* cMaxInstances */
1659 1,
1660 /* cbInstance */
1661 sizeof(DEVPCBIOS),
1662 /* pfnConstruct */
1663 pcbiosConstruct,
1664 /* pfnDestruct */
1665 pcbiosDestruct,
1666 /* pfnRelocate */
1667 NULL,
1668 /* pfnIOCtl */
1669 NULL,
1670 /* pfnPowerOn */
1671 NULL,
1672 /* pfnReset */
1673 pcbiosReset,
1674 /* pfnSuspend */
1675 NULL,
1676 /* pfnResume */
1677 NULL,
1678 /* pfnAttach */
1679 NULL,
1680 /* pfnDetach */
1681 NULL,
1682 /* pfnQueryInterface. */
1683 NULL,
1684 /* pfnInitComplete. */
1685 pcbiosInitComplete
1686};
1687
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