VirtualBox

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

Last change on this file since 11410 was 11284, checked in by vboxsync, 16 years ago

Devices: %Vrc -> %Rrc (just preferred, not mandatory (yet))

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