VirtualBox

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

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

Added code to optionally load system and/or network ROM from external file (selected via setextradata).

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