VirtualBox

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

Last change on this file since 23973 was 23970, checked in by vboxsync, 15 years ago

DevSB16,DevVirtioNet,DevPcBios,DrvSCSIHost: typo in error message.

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