VirtualBox

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

Last change on this file since 22277 was 21889, checked in by vboxsync, 15 years ago

Dev/PCBios: Vbox* -> VBox*

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