VirtualBox

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

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

Squash a few evil TAB characters which have crept in.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 57.9 KB
Line 
1/* $Id: DevPcBios.cpp 6374 2008-01-18 09:34:15Z 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 = RT_MIN(1024, 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 if (rc == VERR_VDI_IMAGE_READ_ONLY)
575 {
576 LogRel(("DevPcBios: ATA LUN#%d: failed to update LCHS geometry\n", i));
577 rc = VINF_SUCCESS;
578 }
579 AssertRC(rc);
580 }
581 if (i < 4)
582 {
583 /* Award BIOS extended drive types for first to fourth disk.
584 * Used by the BIOS for setting the logical geometry. */
585 int offType, offInfo;
586 switch (i)
587 {
588 case 0:
589 offType = 0x19;
590 offInfo = 0x1e;
591 break;
592 case 1:
593 offType = 0x1a;
594 offInfo = 0x26;
595 break;
596 case 2:
597 offType = 0x00;
598 offInfo = 0x67;
599 break;
600 case 3:
601 default:
602 offType = 0x00;
603 offInfo = 0x70;
604 break;
605 }
606 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
607 &LCHSGeometry);
608 }
609 LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
610 }
611 }
612
613 /* 0Fh means extended and points to 19h, 1Ah */
614 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
615 pcbiosCmosWrite(pDevIns, 0x12, u32);
616
617 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
618 return VINF_SUCCESS;
619}
620
621
622/**
623 * Port I/O Handler for IN operations.
624 *
625 * @returns VBox status code.
626 *
627 * @param pDevIns The device instance.
628 * @param pvUser User argument - ignored.
629 * @param Port Port number used for the IN operation.
630 * @param pu32 Where to store the result.
631 * @param cb Number of bytes read.
632 */
633static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
634{
635 NOREF(pDevIns);
636 NOREF(pvUser);
637 NOREF(Port);
638 NOREF(pu32);
639 NOREF(cb);
640 return VERR_IOM_IOPORT_UNUSED;
641}
642
643
644/**
645 * Port I/O Handler for OUT operations.
646 *
647 * @returns VBox status code.
648 *
649 * @param pDevIns The device instance.
650 * @param pvUser User argument - ignored.
651 * @param Port Port number used for the IN operation.
652 * @param u32 The value to output.
653 * @param cb The value size in bytes.
654 */
655static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
656{
657 /*
658 * Bochs BIOS Panic
659 */
660 if ( cb == 2
661 && ( Port == 0x400
662 || Port == 0x401))
663 {
664 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
665 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
666 return VERR_INTERNAL_ERROR;
667 }
668
669 /*
670 * Bochs BIOS char printing.
671 */
672 if ( cb == 1
673 && ( Port == 0x402
674 || Port == 0x403))
675 {
676 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
677 /* The raw version. */
678 switch (u32)
679 {
680 case '\r': Log2(("pcbios: <return>\n")); break;
681 case '\n': Log2(("pcbios: <newline>\n")); break;
682 case '\t': Log2(("pcbios: <tab>\n")); break;
683 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
684 }
685
686 /* The readable, buffered version. */
687 if (u32 == '\n' || u32 == '\r')
688 {
689 pData->szMsg[pData->iMsg] = '\0';
690 if (pData->iMsg)
691 Log(("pcbios: %s\n", pData->szMsg));
692 pData->iMsg = 0;
693 }
694 else
695 {
696 if (pData->iMsg >= sizeof(pData->szMsg)-1)
697 {
698 pData->szMsg[pData->iMsg] = '\0';
699 Log(("pcbios: %s\n", pData->szMsg));
700 pData->iMsg = 0;
701 }
702 pData->szMsg[pData->iMsg] = (char )u32;
703 pData->szMsg[++pData->iMsg] = '\0';
704 }
705 return VINF_SUCCESS;
706 }
707
708 /*
709 * Bochs BIOS shutdown request.
710 */
711 if (cb == 1 && Port == 0x8900)
712 {
713 static const unsigned char szShutdown[] = "Shutdown";
714 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
715 if (u32 == szShutdown[pData->iShutdown])
716 {
717 pData->iShutdown++;
718 if (pData->iShutdown == 8)
719 {
720 pData->iShutdown = 0;
721 LogRel(("8900h shutdown request.\n"));
722 return PDMDevHlpVMPowerOff(pDevIns);
723 }
724 }
725 else
726 pData->iShutdown = 0;
727 return VINF_SUCCESS;
728 }
729
730 /* not in use. */
731 return VINF_SUCCESS;
732}
733
734
735/**
736 * LOGO port I/O Handler for IN operations.
737 *
738 * @returns VBox status code.
739 *
740 * @param pDevIns The device instance.
741 * @param pvUser User argument - ignored.
742 * @param uPort Port number used for the IN operation.
743 * @param pu32 Where to store the result.
744 * @param cb Number of bytes read.
745 */
746static DECLCALLBACK(int) logoIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
747{
748 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
749 Log(("logoIOPortRead call Port:%x pu32:%x cb:%d (%d)\n", Port, pu32, cb, pData->offLogoData));
750
751 PRTUINT64U p;
752 if (pData->fDefaultLogo)
753 {
754 /*
755 * Default bios logo.
756 */
757 if (pData->offLogoData + cb > g_cbPcDefBiosLogo)
758 {
759 Log(("logoIOPortRead: Requested address is out of Logo data!!! offLogoData=%#x(%d) cbLogo=%#x(%d)\n",
760 pData->offLogoData, pData->offLogoData, g_cbPcDefBiosLogo, g_cbPcDefBiosLogo));
761 return VINF_SUCCESS;
762 }
763 p = (PRTUINT64U)&g_abPcDefBiosLogo[pData->offLogoData];
764 }
765 else
766 {
767 /*
768 * Custom logo.
769 */
770 if (pData->offLogoData + cb > pData->cbLogo)
771 {
772 Log(("logoIOPortRead: Requested address is out of Logo data!!! offLogoData=%#x(%d) cbLogo=%#x(%d)\n",
773 pData->offLogoData, pData->offLogoData, pData->cbLogo, pData->cbLogo));
774 return VINF_SUCCESS;
775 }
776 p = (PRTUINT64U)&pData->pu8Logo[pData->offLogoData];
777 }
778
779 switch (cb)
780 {
781 case 1: *pu32 = p->au8[0]; break;
782 case 2: *pu32 = p->au16[0]; break;
783 case 4: *pu32 = p->au32[0]; break;
784 //case 8: *pu32 = p->au64[0]; break;
785 default: AssertFailed(); break;
786 }
787 Log(("logoIOPortRead: LogoOffset=%#x(%d) cb=%#x %.*Vhxs\n", pData->offLogoData, pData->offLogoData, cb, cb, pu32));
788 pData->offLogoData += cb;
789
790 return VINF_SUCCESS;
791}
792
793
794/**
795 * LOGO port I/O Handler for OUT operations.
796 *
797 * @returns VBox status code.
798 *
799 * @param pDevIns The device instance.
800 * @param pvUser User argument - ignored.
801 * @param uPort Port number used for the IN operation.
802 * @param u32 The value to output.
803 * @param cb The value size in bytes.
804 */
805static DECLCALLBACK(int) logoIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
806{
807 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
808 Log(("logoIOPortWrite: Port=%x cb=%d u32=%#04x (byte)\n", Port, cb, u32));
809
810 /* Switch to default BIOS logo or change logo data offset. */
811 if ( cb == 2
812 && u32 == LOGO_DEFAULT_LOGO)
813 {
814 pData->fDefaultLogo = true;
815 pData->offLogoData = 0;
816 }
817 else
818 pData->offLogoData = u32;
819
820 return VINF_SUCCESS;
821}
822
823
824/**
825 * Construct the DMI table.
826 *
827 * @param table pointer to DMI table.
828 */
829#define STRCPY(p, s) do { memcpy (p, s, sizeof(s)); p += sizeof(s); } while (0)
830static void pcbiosPlantDMITable(uint8_t *pTable, PRTUUID puuid)
831{
832 char *pszStr = (char*)pTable;
833 int iStrNr;
834
835 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
836 pszStr = (char*)(pBIOSInf+1);
837 iStrNr = 1;
838 pBIOSInf->header.u8Type = 0; /* BIOS Information */
839 pBIOSInf->header.u8Length = sizeof(*pBIOSInf);
840 pBIOSInf->header.u16Handle = 0x0000;
841 pBIOSInf->u8Vendor = iStrNr++;
842 STRCPY(pszStr, "innotek GmbH");
843 pBIOSInf->u8Version = iStrNr++;
844 STRCPY(pszStr, "VirtualBox");
845 pBIOSInf->u16Start = 0xE000;
846 pBIOSInf->u8Release = iStrNr++;
847 STRCPY(pszStr, "12/01/2006");
848 pBIOSInf->u8ROMSize = 1; /* 128K */
849 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
850 | RT_BIT(7) /* PCI is supported */
851 | RT_BIT(15) /* Boot from CD is supported */
852 | RT_BIT(16) /* Selectable Boot is supported */
853 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
854 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
855 /* any more?? */
856 ;
857 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
858 /* any more?? */
859 ;
860 pBIOSInf->u8CharacteristicsByte2 = 0
861 /* any more?? */
862 ;
863 *pszStr++ = '\0';
864
865
866 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
867 pszStr = (char*)(pSystemInf+1);
868 iStrNr = 1;
869 pSystemInf->header.u8Type = 1; /* System Information */
870 pSystemInf->header.u8Length = sizeof(*pSystemInf);
871 pSystemInf->header.u16Handle = 0x0001;
872 pSystemInf->u8Manufacturer = iStrNr++;
873 STRCPY(pszStr, "innotek GmbH");
874 pSystemInf->u8ProductName = iStrNr++;
875 STRCPY(pszStr, "VirtualBox");
876 pSystemInf->u8Version = iStrNr++;
877 STRCPY(pszStr, "1.2");
878 pSystemInf->u8SerialNumber = iStrNr++;
879 STRCPY(pszStr, "0");
880 memcpy(pSystemInf->au8Uuid, puuid, sizeof(RTUUID));
881 pSystemInf->u8WakeupType = 6; /* Power Switch */
882 pSystemInf->u8SKUNumber = 0;
883 pSystemInf->u8Family = iStrNr++;
884 STRCPY(pszStr, "Virtual Machine");
885 *pszStr++ = '\0';
886
887 AssertMsg(pszStr - (char*)pTable == VBOX_DMI_TABLE_SIZE,
888 ("VBOX_DMI_TABLE_SIZE=%d, actual DMI table size is %d",
889 VBOX_DMI_TABLE_SIZE, pszStr - (char*)pTable));
890}
891AssertCompile(VBOX_DMI_TABLE_ENTR == 2);
892
893
894/**
895 * Calculate a simple checksum for the MPS table.
896 *
897 * @param data data
898 * @param len size of data
899 */
900static uint8_t pcbiosChecksum(const uint8_t * const au8Data, uint32_t u32Length)
901{
902 uint8_t u8Sum = 0;
903 for (size_t i = 0; i < u32Length; ++i)
904 u8Sum += au8Data[i];
905 return -u8Sum;
906}
907
908
909/**
910 * Construct the MPS table. Only applicable if IOAPIC is active.
911 *
912 * @param pDevIns The device instance data.
913 * @param addr physical address in guest memory.
914 */
915static void pcbiosPlantMPStable(PPDMDEVINS pDevIns, uint8_t *pTable)
916{
917 /* configuration table */
918 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
919 memcpy(pCfgTab->au8Signature, "PCMP", 4);
920 pCfgTab->u8SpecRev = 4; /* 1.4 */
921 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
922 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
923 pCfgTab->u32OemTablePtr = 0;
924 pCfgTab->u16OemTableSize = 0;
925 pCfgTab->u16EntryCount = 1 /* Processor */
926 + 1 /* ISA Bus */
927 + 1 /* I/O-APIC */
928 + 16 /* Interrupts */;
929 pCfgTab->u32AddrLocalApic = 0xfee00000;
930 pCfgTab->u16ExtTableLength = 0;
931 pCfgTab->u8ExtTableChecksxum = 0;
932 pCfgTab->u8Reserved = 0;
933
934 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
935 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
936 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
937 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
938 if (u32Eax >= 1)
939 {
940 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
941 u32CPUSignature = u32Eax & 0xfff;
942 /* Local APIC will be enabled later so override it here. Since we provide
943 * an MP table we have an IOAPIC and therefore a Local APIC. */
944 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
945 }
946
947 /* one processor so far */
948 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
949 pProcEntry->u8EntryType = 0; /* processor entry */
950 pProcEntry->u8LocalApicId = 0;
951 pProcEntry->u8LocalApicVersion = 0x11;
952 pProcEntry->u8CPUFlags = 2 /* bootstrap processor */ | 1 /* enabled */;
953 pProcEntry->u32CPUSignature = u32CPUSignature;
954 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
955 pProcEntry->u32Reserved[0] =
956 pProcEntry->u32Reserved[1] = 0;
957
958 /* ISA bus */
959 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1);
960 pBusEntry->u8EntryType = 1; /* bus entry */
961 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
962 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
963
964 /* PCI bus? */
965
966 /* I/O-APIC.
967 * MP spec: "The configuration table contains one or more entries for I/O APICs.
968 * ... At least one I/O APIC must be enabled." */
969 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
970 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
971 pIOAPICEntry->u8Id = 1; /* this ID is referenced by the interrupt entries */
972 pIOAPICEntry->u8Version = 0x11;
973 pIOAPICEntry->u8Flags = 1 /* enable */;
974 pIOAPICEntry->u32Addr = 0xfec00000;
975
976 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
977 for (int i = 0; i < 16; i++, pIrqEntry++)
978 {
979 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
980 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
981 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
982 trigger mode = conforms to bus */
983 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
984 pIrqEntry->u8SrcBusIrq = i;
985 pIrqEntry->u8DstIOAPICId = 1;
986 pIrqEntry->u8DstIOAPICInt = i;
987 }
988
989 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
990 pCfgTab->u8Checksum = pcbiosChecksum(pTable, pCfgTab->u16Length);
991
992 AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100,
993 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
994 pCfgTab->u16Length, 0x1000-0x100));
995
996 MPSFLOATPTR floatPtr;
997 floatPtr.au8Signature[0] = '_';
998 floatPtr.au8Signature[1] = 'M';
999 floatPtr.au8Signature[2] = 'P';
1000 floatPtr.au8Signature[3] = '_';
1001 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
1002 floatPtr.u8Length = 1; /* structure size in paragraphs */
1003 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
1004 floatPtr.u8Checksum = 0;
1005 floatPtr.au8Feature[0] = 0;
1006 floatPtr.au8Feature[1] = 0;
1007 floatPtr.au8Feature[2] = 0;
1008 floatPtr.au8Feature[3] = 0;
1009 floatPtr.au8Feature[4] = 0;
1010 floatPtr.u8Checksum = pcbiosChecksum((uint8_t*)&floatPtr, 16);
1011 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
1012}
1013
1014
1015/**
1016 * Reset notification.
1017 *
1018 * @returns VBox status.
1019 * @param pDevIns The device instance data.
1020 */
1021static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
1022{
1023 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1024 LogFlow(("pcbiosReset:\n"));
1025
1026 pData->fDefaultLogo = false;
1027 pData->offLogoData = 0;
1028 /** @todo Should we perhaps do pcbiosInitComplete() on reset? */
1029
1030#if 1
1031 /*
1032 * Paranoia: Check that the BIOS ROM hasn't changed.
1033 */
1034 uint8_t abBuf[PAGE_SIZE];
1035 const uint8_t *pu8PcBiosBinary;
1036 uint64_t cbPcBiosBinary;
1037
1038 /* Work with either built-in ROM image or one loaded from file.
1039 */
1040 if (pData->pu8PcBios == NULL)
1041 {
1042 pu8PcBiosBinary = g_abPcBiosBinary;
1043 cbPcBiosBinary = g_cbPcBiosBinary;
1044 }
1045 else
1046 {
1047 pu8PcBiosBinary = pData->pu8PcBios;
1048 cbPcBiosBinary = pData->cbPcBios;
1049 }
1050 Assert(pu8PcBiosBinary);
1051 Assert(cbPcBiosBinary);
1052
1053 /* the low ROM mapping. */
1054 unsigned cb = RT_MIN(cbPcBiosBinary, 128 * _1K);
1055 RTGCPHYS GCPhys = 0x00100000 - cb;
1056 const uint8_t *pbVirgin = &pu8PcBiosBinary[cbPcBiosBinary - cb];
1057 while (GCPhys < 0x00100000)
1058 {
1059 PDMDevHlpPhysRead(pDevIns, GCPhys, abBuf, PAGE_SIZE);
1060 if (memcmp(abBuf, pbVirgin, PAGE_SIZE))
1061 {
1062 LogRel(("low ROM mismatch! GCPhys=%VGp - Ignore if you've loaded an old saved state with an different VirtualBox version.\n", GCPhys));
1063 for (unsigned off = 0; off < PAGE_SIZE; off++)
1064 if (abBuf[off] != pbVirgin[off])
1065 LogRel(("%VGp: %02x expected %02x\n", GCPhys + off, abBuf[off], pbVirgin[off]));
1066 AssertFailed();
1067 }
1068
1069 /* next page */
1070 GCPhys += PAGE_SIZE;
1071 pbVirgin += PAGE_SIZE;
1072 }
1073
1074 /* the high ROM mapping. */
1075 GCPhys = UINT32_C(0xffffffff) - (cbPcBiosBinary - 1);
1076 pbVirgin = &pu8PcBiosBinary[0];
1077 while (pbVirgin < &pu8PcBiosBinary[cbPcBiosBinary])
1078 {
1079 PDMDevHlpPhysRead(pDevIns, GCPhys, abBuf, PAGE_SIZE);
1080 if (memcmp(abBuf, pbVirgin, PAGE_SIZE))
1081 {
1082 LogRel(("high ROM mismatch! GCPhys=%VGp - Ignore if you've loaded an old saved state with an different VirtualBox version.\n", GCPhys));
1083 for (unsigned off = 0; off < PAGE_SIZE; off++)
1084 if (abBuf[off] != pbVirgin[off])
1085 LogRel(("%VGp: %02x expected %02x\n", GCPhys + off, abBuf[off], pbVirgin[off]));
1086 AssertFailed();
1087 }
1088
1089 /* next page */
1090 GCPhys += PAGE_SIZE;
1091 pbVirgin += PAGE_SIZE;
1092 }
1093#endif
1094
1095 if (pData->u8IOAPIC)
1096 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + 0x100);
1097}
1098
1099
1100/**
1101 * Destruct a device instance.
1102 *
1103 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1104 * resources can be freed correctly.
1105 *
1106 * @param pDevIns The device instance data.
1107 */
1108static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
1109{
1110 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1111 LogFlow(("pcbiosDestruct:\n"));
1112
1113 /*
1114 * Free MM heap pointers.
1115 */
1116 if (pData->pu8PcBios)
1117 {
1118 MMR3HeapFree(pData->pu8PcBios);
1119 pData->pu8PcBios = NULL;
1120 }
1121
1122 if (pData->pszPcBiosFile)
1123 {
1124 MMR3HeapFree(pData->pszPcBiosFile);
1125 pData->pszPcBiosFile = NULL;
1126 }
1127
1128 if (pData->pu8LanBoot)
1129 {
1130 MMR3HeapFree(pData->pu8LanBoot);
1131 pData->pu8LanBoot = NULL;
1132 }
1133
1134 if (pData->pszLanBootFile)
1135 {
1136 MMR3HeapFree(pData->pszLanBootFile);
1137 pData->pszLanBootFile = NULL;
1138 }
1139
1140 if (pData->pu8Logo)
1141 {
1142 MMR3HeapFree(pData->pu8Logo);
1143 pData->pu8Logo = NULL;
1144 }
1145
1146 if (pData->pszLogoFile)
1147 {
1148 MMR3HeapFree(pData->pszLogoFile);
1149 pData->pszLogoFile = NULL;
1150 }
1151
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Convert config value to DEVPCBIOSBOOT.
1158 *
1159 * @returns VBox status code.
1160 * @param pCfgHandle Configuration handle.
1161 * @param pszParam The name of the value to read.
1162 * @param penmBoot Where to store the boot method.
1163 */
1164static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
1165{
1166 char *psz;
1167 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
1168 if (VBOX_FAILURE(rc))
1169 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1170 N_("Configuration error: Querying \"%s\" as a string failed"),
1171 pszParam);
1172 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
1173 *penmBoot = DEVPCBIOSBOOT_DVD;
1174 else if (!strcmp(psz, "IDE"))
1175 *penmBoot = DEVPCBIOSBOOT_HD;
1176 else if (!strcmp(psz, "FLOPPY"))
1177 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
1178 else if (!strcmp(psz, "LAN"))
1179 *penmBoot = DEVPCBIOSBOOT_LAN;
1180 else if (!strcmp(psz, "NONE"))
1181 *penmBoot = DEVPCBIOSBOOT_NONE;
1182 else
1183 {
1184 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1185 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
1186 pszParam, psz);
1187 rc = VERR_INTERNAL_ERROR;
1188 }
1189 MMR3HeapFree(psz);
1190 return rc;
1191}
1192
1193/**
1194 * Construct a device instance for a VM.
1195 *
1196 * @returns VBox status.
1197 * @param pDevIns The device instance data.
1198 * If the registration structure is needed, pDevIns->pDevReg points to it.
1199 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1200 * The device number is also found in pDevIns->iInstance, but since it's
1201 * likely to be freqently used PDM passes it as parameter.
1202 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1203 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1204 * iInstance it's expected to be used a bit in this function.
1205 */
1206static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1207{
1208 unsigned i;
1209 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
1210 int rc;
1211 int cb;
1212
1213 Assert(iInstance == 0);
1214
1215 /*
1216 * Validate configuration.
1217 */
1218 if (!CFGMR3AreValuesValid(pCfgHandle,
1219 "BootDevice0\0"
1220 "BootDevice1\0"
1221 "BootDevice2\0"
1222 "BootDevice3\0"
1223 "RamSize\0"
1224 "HardDiskDevice\0"
1225 "FloppyDevice\0"
1226 "FadeIn\0"
1227 "FadeOut\0"
1228 "LogoTime\0"
1229 "LogoFile\0"
1230 "ShowBootMenu\0"
1231 "DelayBoot\0"
1232 "BiosRom\0"
1233 "LanBootRom\0"
1234 "PXEDebug\0"
1235 "UUID\0"
1236 "IOAPIC\0"))
1237 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1238 N_("Invalid configuraton for device pcbios device"));
1239
1240 /*
1241 * Init the data.
1242 */
1243 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
1244 if (VBOX_FAILURE(rc))
1245 return PDMDEV_SET_ERROR(pDevIns, rc,
1246 N_("Configuration error: Querying \"RamSize\" as integer failed"));
1247
1248 rc = CFGMR3QueryU8 (pCfgHandle, "IOAPIC", &pData->u8IOAPIC);
1249 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1250 pData->u8IOAPIC = 1;
1251 else if (VBOX_FAILURE (rc))
1252 return PDMDEV_SET_ERROR(pDevIns, rc,
1253 N_("Configuration error: Failed to read \"IOAPIC\""));
1254
1255 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
1256 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
1257 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
1258 {
1259 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
1260 if (VBOX_FAILURE(rc))
1261 return rc;
1262 }
1263
1264 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
1265 if (VBOX_FAILURE(rc))
1266 return PDMDEV_SET_ERROR(pDevIns, rc,
1267 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1268
1269 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
1270 if (VBOX_FAILURE(rc))
1271 return PDMDEV_SET_ERROR(pDevIns, rc,
1272 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1273
1274 /*
1275 * Register I/O Ports and PC BIOS.
1276 */
1277 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1278 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1279 if (VBOX_FAILURE(rc))
1280 return rc;
1281 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1282 NULL, NULL, "Bochs PC BIOS - Shutdown");
1283 if (VBOX_FAILURE(rc))
1284 return rc;
1285
1286 /*
1287 * Query the machine's UUID for SMBIOS/DMI use.
1288 */
1289 RTUUID uuid;
1290 rc = CFGMR3QueryBytes(pCfgHandle, "UUID", &uuid, sizeof(uuid));
1291 if (VBOX_FAILURE(rc))
1292 return PDMDEV_SET_ERROR(pDevIns, rc,
1293 N_("Configuration error: Querying \"UUID\" failed"));
1294
1295
1296 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1297 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1298 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1299 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1300 pcbiosPlantDMITable(pData->au8DMIPage, &uuid);
1301 if (pData->u8IOAPIC)
1302 pcbiosPlantMPStable(pDevIns, pData->au8DMIPage + 0x100);
1303
1304 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, false /* fShadow */, "DMI tables");
1305 if (VBOX_FAILURE(rc))
1306 return rc;
1307
1308 /*
1309 * Read the PXE debug logging option.
1310 */
1311 rc = CFGMR3QueryU8(pCfgHandle, "PXEDebug", &pData->u8PXEDebug);
1312 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1313 pData->u8PXEDebug = 0;
1314 else if (VBOX_FAILURE(rc))
1315 return PDMDEV_SET_ERROR(pDevIns, rc,
1316 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1317
1318 /*
1319 * Get the system BIOS ROM file name.
1320 */
1321 rc = CFGMR3QueryStringAlloc(pCfgHandle, "BiosRom", &pData->pszPcBiosFile);
1322 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1323 {
1324 pData->pszPcBiosFile = NULL;
1325 rc = VINF_SUCCESS;
1326 }
1327 else if (VBOX_FAILURE(rc))
1328 return PDMDEV_SET_ERROR(pDevIns, rc,
1329 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1330 else if (!*pData->pszPcBiosFile)
1331 {
1332 MMR3HeapFree(pData->pszPcBiosFile);
1333 pData->pszPcBiosFile = NULL;
1334 }
1335
1336 const uint8_t *pu8PcBiosBinary = NULL;
1337 uint64_t cbPcBiosBinary;
1338 /*
1339 * Determine the system BIOS ROM size, open specified ROM file in the process.
1340 */
1341 RTFILE FilePcBios = NIL_RTFILE;
1342 if (pData->pszPcBiosFile)
1343 {
1344 rc = RTFileOpen(&FilePcBios, pData->pszPcBiosFile,
1345 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1346 if (VBOX_SUCCESS(rc))
1347 {
1348 rc = RTFileGetSize(FilePcBios, &pData->cbPcBios);
1349 if (VBOX_SUCCESS(rc))
1350 {
1351 /* The following checks should be in sync the AssertReleaseMsg's below. */
1352 if ( RT_ALIGN(pData->cbPcBios, _64K) != pData->cbPcBios
1353 || pData->cbPcBios > 32 * _64K
1354 || pData->cbPcBios < _64K)
1355 rc = VERR_TOO_MUCH_DATA;
1356 }
1357 }
1358 if (VBOX_FAILURE(rc))
1359 {
1360 /*
1361 * In case of failure simply fall back to the built-in BIOS ROM.
1362 */
1363 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Vrc!\n", pData->pszPcBiosFile, rc));
1364 RTFileClose(FilePcBios);
1365 FilePcBios = NIL_RTFILE;
1366 MMR3HeapFree(pData->pszPcBiosFile);
1367 pData->pszPcBiosFile = NULL;
1368 }
1369 }
1370
1371 /*
1372 * Attempt to get the system BIOS ROM data from file.
1373 */
1374 if (pData->pszPcBiosFile)
1375 {
1376 /*
1377 * Allocate buffer for the system BIOS ROM data.
1378 */
1379 pData->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pData->cbPcBios);
1380 if (pData->pu8PcBios)
1381 {
1382 rc = RTFileRead(FilePcBios, pData->pu8PcBios, pData->cbPcBios, NULL);
1383 if (VBOX_FAILURE(rc))
1384 {
1385 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", pData->cbPcBios, rc));
1386 MMR3HeapFree(pData->pu8PcBios);
1387 pData->pu8PcBios = NULL;
1388 }
1389 rc = VINF_SUCCESS;
1390 }
1391 else
1392 rc = VERR_NO_MEMORY;
1393 }
1394 else
1395 pData->pu8PcBios = NULL;
1396
1397 /* cleanup */
1398 if (FilePcBios != NIL_RTFILE)
1399 RTFileClose(FilePcBios);
1400
1401 /* If we were unable to get the data from file for whatever reason, fall
1402 * back to the built-in ROM image.
1403 */
1404 if (pData->pu8PcBios == NULL)
1405 {
1406 pu8PcBiosBinary = g_abPcBiosBinary;
1407 cbPcBiosBinary = g_cbPcBiosBinary;
1408 }
1409 else
1410 {
1411 pu8PcBiosBinary = pData->pu8PcBios;
1412 cbPcBiosBinary = pData->cbPcBios;
1413 }
1414
1415 /*
1416 * Map the BIOS into memory.
1417 * There are two mappings:
1418 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1419 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1420 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1421 */
1422 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1423 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1424 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1425 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1426 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1427 false /* fShadow */, "PC BIOS - 0xfffff");
1428 if (VBOX_FAILURE(rc))
1429 return rc;
1430 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1431 false /* fShadow */, "PC BIOS - 0xffffffff");
1432 if (VBOX_FAILURE(rc))
1433 return rc;
1434
1435 /*
1436 * Register the BIOS Logo port
1437 */
1438 rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 1, NULL, logoIOPortWrite, logoIOPortRead, NULL, NULL, "PC BIOS - Logo port");
1439 if (VBOX_FAILURE(rc))
1440 return rc;
1441
1442 /*
1443 * Construct the logo header.
1444 */
1445 LOGOHDR LogoHdr = { LOGO_HDR_MAGIC, 0, 0, 0, 0, 0 };
1446
1447 rc = CFGMR3QueryU8(pCfgHandle, "FadeIn", &LogoHdr.u8FadeIn);
1448 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1449 LogoHdr.u8FadeIn = 1;
1450 else if (VBOX_FAILURE(rc))
1451 return PDMDEV_SET_ERROR(pDevIns, rc,
1452 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
1453
1454 rc = CFGMR3QueryU8(pCfgHandle, "FadeOut", &LogoHdr.u8FadeOut);
1455 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1456 LogoHdr.u8FadeOut = 1;
1457 else if (VBOX_FAILURE(rc))
1458 return PDMDEV_SET_ERROR(pDevIns, rc,
1459 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
1460
1461 rc = CFGMR3QueryU16(pCfgHandle, "LogoTime", &LogoHdr.u16LogoMillies);
1462 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1463 LogoHdr.u16LogoMillies = 1;
1464 else if (VBOX_FAILURE(rc))
1465 return PDMDEV_SET_ERROR(pDevIns, rc,
1466 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
1467
1468 rc = CFGMR3QueryU8(pCfgHandle, "ShowBootMenu", &LogoHdr.u8ShowBootMenu);
1469 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1470 LogoHdr.u8ShowBootMenu = 0;
1471 else if (VBOX_FAILURE(rc))
1472 return PDMDEV_SET_ERROR(pDevIns, rc,
1473 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
1474
1475 /*
1476 * Get the Logo file name.
1477 */
1478 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LogoFile", &pData->pszLogoFile);
1479 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1480 pData->pszLogoFile = NULL;
1481 else if (VBOX_FAILURE(rc))
1482 return PDMDEV_SET_ERROR(pDevIns, rc,
1483 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
1484 else if (!*pData->pszLogoFile)
1485 {
1486 MMR3HeapFree(pData->pszLogoFile);
1487 pData->pszLogoFile = NULL;
1488 }
1489
1490 /*
1491 * Determine the logo size, open any specified logo file in the process.
1492 */
1493 LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1494 RTFILE FileLogo = NIL_RTFILE;
1495 if (pData->pszLogoFile)
1496 {
1497 rc = RTFileOpen(&FileLogo, pData->pszLogoFile,
1498 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1499 if (VBOX_SUCCESS(rc))
1500 {
1501 uint64_t cbFile;
1502 rc = RTFileGetSize(FileLogo, &cbFile);
1503 if (VBOX_SUCCESS(rc))
1504 {
1505 if ( cbFile > 0
1506 && cbFile < LOGO_MAX_SIZE)
1507 LogoHdr.cbLogo = (uint32_t)cbFile;
1508 else
1509 rc = VERR_TOO_MUCH_DATA;
1510 }
1511 }
1512 if (VBOX_FAILURE(rc))
1513 {
1514 /*
1515 * Ignore failure and fall back to the default logo.
1516 */
1517 LogRel(("pcbiosConstruct: Failed to open logo file '%s', rc=%Vrc!\n", pData->pszLogoFile, rc));
1518 RTFileClose(FileLogo);
1519 FileLogo = NIL_RTFILE;
1520 MMR3HeapFree(pData->pszLogoFile);
1521 pData->pszLogoFile = NULL;
1522 }
1523 }
1524
1525 /*
1526 * Allocate buffer for the logo data.
1527 * RT_MAX() is applied to let us fall back to default logo on read failure.
1528 */
1529 pData->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
1530 pData->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pData->cbLogo, g_cbPcDefBiosLogo + sizeof(LogoHdr)));
1531 if (pData->pu8Logo)
1532 {
1533 /*
1534 * Write the logo header.
1535 */
1536 PLOGOHDR pLogoHdr = (PLOGOHDR)pData->pu8Logo;
1537 *pLogoHdr = LogoHdr;
1538
1539 /*
1540 * Write the logo bitmap.
1541 */
1542 if (pData->pszLogoFile)
1543 {
1544 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
1545 if (VBOX_FAILURE(rc))
1546 {
1547 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", LogoHdr.cbLogo, rc));
1548 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1549 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1550 }
1551 }
1552 else
1553 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1554
1555 /*
1556 * Call reset to set values and stuff.
1557 */
1558 pcbiosReset(pDevIns);
1559 rc = VINF_SUCCESS;
1560 }
1561 else
1562 rc = VERR_NO_MEMORY;
1563
1564 /* cleanup */
1565 if (FileLogo != NIL_RTFILE)
1566 RTFileClose(FileLogo);
1567
1568 /*
1569 * Get the LAN boot ROM file name.
1570 */
1571 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1572 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1573 {
1574 pData->pszLanBootFile = NULL;
1575 rc = VINF_SUCCESS;
1576 }
1577 else if (VBOX_FAILURE(rc))
1578 return PDMDEV_SET_ERROR(pDevIns, rc,
1579 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1580 else if (!*pData->pszLanBootFile)
1581 {
1582 MMR3HeapFree(pData->pszLanBootFile);
1583 pData->pszLanBootFile = NULL;
1584 }
1585
1586 uint64_t cbFileLanBoot;
1587 const uint8_t *pu8LanBootBinary = NULL;
1588 uint64_t cbLanBootBinary;
1589
1590 /*
1591 * Determine the LAN boot ROM size, open specified ROM file in the process.
1592 */
1593 RTFILE FileLanBoot = NIL_RTFILE;
1594 if (pData->pszLanBootFile)
1595 {
1596 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1597 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1598 if (VBOX_SUCCESS(rc))
1599 {
1600 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1601 if (VBOX_SUCCESS(rc))
1602 {
1603 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1604 || cbFileLanBoot > _64K)
1605 rc = VERR_TOO_MUCH_DATA;
1606 }
1607 }
1608 if (VBOX_FAILURE(rc))
1609 {
1610 /*
1611 * Ignore failure and fall back to the built-in LAN boot ROM.
1612 */
1613 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1614 RTFileClose(FileLanBoot);
1615 FileLanBoot = NIL_RTFILE;
1616 MMR3HeapFree(pData->pszLanBootFile);
1617 pData->pszLanBootFile = NULL;
1618 }
1619 }
1620
1621 /*
1622 * Get the LAN boot ROM data.
1623 */
1624 if (pData->pszLanBootFile)
1625 {
1626 /*
1627 * Allocate buffer for the LAN boot ROM data.
1628 */
1629 pData->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1630 if (pData->pu8LanBoot)
1631 {
1632 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1633 if (VBOX_FAILURE(rc))
1634 {
1635 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1636 MMR3HeapFree(pData->pu8LanBoot);
1637 pData->pu8LanBoot = NULL;
1638 }
1639 rc = VINF_SUCCESS;
1640 }
1641 else
1642 rc = VERR_NO_MEMORY;
1643 }
1644 else
1645 pData->pu8LanBoot = NULL;
1646
1647 /* cleanup */
1648 if (FileLanBoot != NIL_RTFILE)
1649 RTFileClose(FileLanBoot);
1650
1651 /* If we were unable to get the data from file for whatever reason, fall
1652 * back to the built-in LAN boot ROM image.
1653 */
1654 if (pData->pu8LanBoot == NULL)
1655 {
1656 pu8LanBootBinary = g_abNetBiosBinary;
1657 cbLanBootBinary = g_cbNetBiosBinary;
1658 }
1659 else
1660 {
1661 pu8LanBootBinary = pData->pu8LanBoot;
1662 cbLanBootBinary = cbFileLanBoot;
1663 }
1664
1665 /*
1666 * Map the Network Boot ROM into memory.
1667 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1668 * the (up to) 32 kb ROM image.
1669 */
1670 if (pu8LanBootBinary)
1671 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1672 true /* fShadow */, "Net Boot ROM");
1673
1674 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1675 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1676 {
1677 pData->uBootDelay = 0;
1678 rc = VINF_SUCCESS;
1679 }
1680 else
1681 {
1682 if (VBOX_FAILURE(rc))
1683 return PDMDEV_SET_ERROR(pDevIns, rc,
1684 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1685 if (pData->uBootDelay > 15)
1686 pData->uBootDelay = 15;
1687 }
1688
1689 return rc;
1690}
1691
1692
1693/**
1694 * The device registration structure.
1695 */
1696const PDMDEVREG g_DevicePcBios =
1697{
1698 /* u32Version */
1699 PDM_DEVREG_VERSION,
1700 /* szDeviceName */
1701 "pcbios",
1702 /* szGCMod */
1703 "",
1704 /* szR0Mod */
1705 "",
1706 /* pszDescription */
1707 "PC BIOS Device",
1708 /* fFlags */
1709 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1710 /* fClass */
1711 PDM_DEVREG_CLASS_ARCH_BIOS,
1712 /* cMaxInstances */
1713 1,
1714 /* cbInstance */
1715 sizeof(DEVPCBIOS),
1716 /* pfnConstruct */
1717 pcbiosConstruct,
1718 /* pfnDestruct */
1719 pcbiosDestruct,
1720 /* pfnRelocate */
1721 NULL,
1722 /* pfnIOCtl */
1723 NULL,
1724 /* pfnPowerOn */
1725 NULL,
1726 /* pfnReset */
1727 pcbiosReset,
1728 /* pfnSuspend */
1729 NULL,
1730 /* pfnResume */
1731 NULL,
1732 /* pfnAttach */
1733 NULL,
1734 /* pfnDetach */
1735 NULL,
1736 /* pfnQueryInterface. */
1737 NULL,
1738 /* pfnInitComplete. */
1739 pcbiosInitComplete
1740};
1741
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette