VirtualBox

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

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

DevPcBios.cpp: Don't use RTStrAPrintf for simple stuff like this, it may fail.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 69.1 KB
Line 
1/* $Id: DevPcBios.cpp 22907 2009-09-10 11:27:09Z 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 * @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 szTmp[64];
1152 RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
1153 RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
1154 READCFGSTR("DmiOEMVBoxVer", pszDmiOEMVBoxVer, szTmp);
1155 RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
1156 READCFGSTR("DmiOEMVBoxRev", pszDmiOEMVBoxRev, szTmp);
1157 SETSTRING(pOEMStrings->u8VBoxVersion, pszDmiOEMVBoxVer);
1158 SETSTRING(pOEMStrings->u8VBoxRevision, pszDmiOEMVBoxRev);
1159 *pszStr++ = '\0';
1160
1161 /* End-of-table marker - includes padding to account for fixed table size. */
1162 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
1163 pEndOfTable->u8Type = 0x7f;
1164 pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2;
1165 pEndOfTable->u16Handle = 0xFEFF;
1166
1167 /* If more fields are added here, fix the size check in SETSTRING */
1168
1169#undef SETSTRING
1170#undef READCFGSTR
1171#undef READCFGINT
1172#undef CHECKSIZE
1173
1174 MMR3HeapFree(pszDmiBIOSVendor);
1175 MMR3HeapFree(pszDmiBIOSVersion);
1176 MMR3HeapFree(pszDmiBIOSReleaseDate);
1177 MMR3HeapFree(pszDmiSystemVendor);
1178 MMR3HeapFree(pszDmiSystemProduct);
1179 MMR3HeapFree(pszDmiSystemVersion);
1180 MMR3HeapFree(pszDmiSystemSerial);
1181 MMR3HeapFree(pszDmiSystemUuid);
1182 MMR3HeapFree(pszDmiSystemFamily);
1183 MMR3HeapFree(pszDmiChassisVendor);
1184 MMR3HeapFree(pszDmiChassisVersion);
1185 MMR3HeapFree(pszDmiChassisSerial);
1186 MMR3HeapFree(pszDmiChassisAssetTag);
1187 MMR3HeapFree(pszDmiOEMVBoxVer);
1188 MMR3HeapFree(pszDmiOEMVBoxRev);
1189
1190 return VINF_SUCCESS;
1191}
1192AssertCompile(VBOX_DMI_TABLE_ENTR == 5);
1193
1194/**
1195 * Calculate a simple checksum for the MPS table.
1196 *
1197 * @param data data
1198 * @param len size of data
1199 */
1200static uint8_t pcbiosChecksum(const uint8_t * const au8Data, uint32_t u32Length)
1201{
1202 uint8_t u8Sum = 0;
1203 for (size_t i = 0; i < u32Length; ++i)
1204 u8Sum += au8Data[i];
1205 return -u8Sum;
1206}
1207
1208
1209/**
1210 * Construct the MPS table. Only applicable if IOAPIC is active!
1211 *
1212 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
1213 * ``1.3 Scope
1214 * ...
1215 * The hardware required to implement the MP specification is kept to a
1216 * minimum, as follows:
1217 * * One or more processors that are Intel architecture instruction set
1218 * compatible, such as the CPUs in the Intel486 or Pentium processor
1219 * family.
1220 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
1221 * Interrupt Controller or the integrated APIC, such as that on the
1222 * Intel Pentium 735\90 and 815\100 processors, together with a discrete
1223 * I/O APIC unit.''
1224 * and later:
1225 * ``4.3.3 I/O APIC Entries
1226 * The configuration table contains one or more entries for I/O APICs.
1227 * ...
1228 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
1229 * operating system should not attempt to access
1230 * this I/O APIC.
1231 * At least one I/O APIC must be enabled.''
1232 *
1233 * @param pDevIns The device instance data.
1234 * @param addr physical address in guest memory.
1235 */
1236static void pcbiosPlantMPStable(PPDMDEVINS pDevIns, uint8_t *pTable, uint16_t numCpus)
1237{
1238 /* configuration table */
1239 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
1240 memcpy(pCfgTab->au8Signature, "PCMP", 4);
1241 pCfgTab->u8SpecRev = 4; /* 1.4 */
1242 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
1243 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
1244 pCfgTab->u32OemTablePtr = 0;
1245 pCfgTab->u16OemTableSize = 0;
1246 pCfgTab->u16EntryCount = numCpus /* Processors */
1247 + 1 /* ISA Bus */
1248 + 1 /* I/O-APIC */
1249 + 16 /* Interrupts */;
1250 pCfgTab->u32AddrLocalApic = 0xfee00000;
1251 pCfgTab->u16ExtTableLength = 0;
1252 pCfgTab->u8ExtTableChecksxum = 0;
1253 pCfgTab->u8Reserved = 0;
1254
1255 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
1256 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
1257 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
1258 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1259 if (u32Eax >= 1)
1260 {
1261 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1262 u32CPUSignature = u32Eax & 0xfff;
1263 /* Local APIC will be enabled later so override it here. Since we provide
1264 * an MP table we have an IOAPIC and therefore a Local APIC. */
1265 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
1266 }
1267 /* Construct MPS table for each VCPU. */
1268 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
1269 for (int i = 0; i<numCpus; i++)
1270 {
1271 pProcEntry->u8EntryType = 0; /* processor entry */
1272 pProcEntry->u8LocalApicId = i;
1273 pProcEntry->u8LocalApicVersion = 0x11;
1274 pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
1275 pProcEntry->u32CPUSignature = u32CPUSignature;
1276 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
1277 pProcEntry->u32Reserved[0] =
1278 pProcEntry->u32Reserved[1] = 0;
1279 pProcEntry++;
1280 }
1281
1282 /* ISA bus */
1283 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1);
1284 pBusEntry->u8EntryType = 1; /* bus entry */
1285 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
1286 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
1287
1288 /* PCI bus? */
1289
1290 /* I/O-APIC.
1291 * MP spec: "The configuration table contains one or more entries for I/O APICs.
1292 * ... At least one I/O APIC must be enabled." */
1293 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
1294 uint16_t apicId = numCpus;
1295 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
1296 pIOAPICEntry->u8Id = apicId; /* this ID is referenced by the interrupt entries */
1297 pIOAPICEntry->u8Version = 0x11;
1298 pIOAPICEntry->u8Flags = 1 /* enable */;
1299 pIOAPICEntry->u32Addr = 0xfec00000;
1300
1301 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
1302 for (int i = 0; i < 16; i++, pIrqEntry++)
1303 {
1304 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
1305 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
1306 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
1307 trigger mode = conforms to bus */
1308 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
1309 pIrqEntry->u8SrcBusIrq = i;
1310 pIrqEntry->u8DstIOAPICId = apicId;
1311 pIrqEntry->u8DstIOAPICInt = i;
1312 }
1313
1314 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
1315 pCfgTab->u8Checksum = pcbiosChecksum(pTable, pCfgTab->u16Length);
1316
1317 AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100,
1318 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
1319 pCfgTab->u16Length, 0x1000-0x100));
1320
1321 MPSFLOATPTR floatPtr;
1322 floatPtr.au8Signature[0] = '_';
1323 floatPtr.au8Signature[1] = 'M';
1324 floatPtr.au8Signature[2] = 'P';
1325 floatPtr.au8Signature[3] = '_';
1326 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
1327 floatPtr.u8Length = 1; /* structure size in paragraphs */
1328 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
1329 floatPtr.u8Checksum = 0;
1330 floatPtr.au8Feature[0] = 0;
1331 floatPtr.au8Feature[1] = 0;
1332 floatPtr.au8Feature[2] = 0;
1333 floatPtr.au8Feature[3] = 0;
1334 floatPtr.au8Feature[4] = 0;
1335 floatPtr.u8Checksum = pcbiosChecksum((uint8_t*)&floatPtr, 16);
1336 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
1337}
1338
1339
1340/**
1341 * Reset notification.
1342 *
1343 * @returns VBox status.
1344 * @param pDevIns The device instance data.
1345 */
1346static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
1347{
1348 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
1349 LogFlow(("pcbiosReset:\n"));
1350
1351 if (pThis->u8IOAPIC)
1352 pcbiosPlantMPStable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1353
1354 /*
1355 * Re-shadow the LAN ROM image and make it RAM/RAM.
1356 *
1357 * This is normally done by the BIOS code, but since we're currently lacking
1358 * the chipset support for this we do it here (and in the constructor).
1359 */
1360 uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, PAGE_SIZE) >> PAGE_SHIFT;
1361 RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
1362 while (cPages > 0)
1363 {
1364 uint8_t abPage[PAGE_SIZE];
1365 int rc;
1366
1367 /* Read the (original) ROM page and write it back to the RAM page. */
1368 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
1369 AssertLogRelRC(rc);
1370
1371 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
1372 AssertLogRelRC(rc);
1373 if (RT_FAILURE(rc))
1374 memset(abPage, 0xcc, sizeof(abPage));
1375
1376 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
1377 AssertLogRelRC(rc);
1378
1379 /* Switch to the RAM/RAM mode. */
1380 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
1381 AssertLogRelRC(rc);
1382
1383 /* Advance */
1384 GCPhys += PAGE_SIZE;
1385 cPages--;
1386 }
1387}
1388
1389
1390/**
1391 * Destruct a device instance.
1392 *
1393 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1394 * resources can be freed correctly.
1395 *
1396 * @param pDevIns The device instance data.
1397 */
1398static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
1399{
1400 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
1401 LogFlow(("pcbiosDestruct:\n"));
1402
1403 /*
1404 * Free MM heap pointers.
1405 */
1406 if (pThis->pu8PcBios)
1407 {
1408 MMR3HeapFree(pThis->pu8PcBios);
1409 pThis->pu8PcBios = NULL;
1410 }
1411
1412 if (pThis->pszPcBiosFile)
1413 {
1414 MMR3HeapFree(pThis->pszPcBiosFile);
1415 pThis->pszPcBiosFile = NULL;
1416 }
1417
1418 if (pThis->pu8LanBoot)
1419 {
1420 MMR3HeapFree(pThis->pu8LanBoot);
1421 pThis->pu8LanBoot = NULL;
1422 }
1423
1424 if (pThis->pszLanBootFile)
1425 {
1426 MMR3HeapFree(pThis->pszLanBootFile);
1427 pThis->pszLanBootFile = NULL;
1428 }
1429
1430 return VINF_SUCCESS;
1431}
1432
1433
1434/**
1435 * Convert config value to DEVPCBIOSBOOT.
1436 *
1437 * @returns VBox status code.
1438 * @param pCfgHandle Configuration handle.
1439 * @param pszParam The name of the value to read.
1440 * @param penmBoot Where to store the boot method.
1441 */
1442static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
1443{
1444 char *psz;
1445 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
1446 if (RT_FAILURE(rc))
1447 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1448 N_("Configuration error: Querying \"%s\" as a string failed"),
1449 pszParam);
1450 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
1451 *penmBoot = DEVPCBIOSBOOT_DVD;
1452 else if (!strcmp(psz, "IDE"))
1453 *penmBoot = DEVPCBIOSBOOT_HD;
1454 else if (!strcmp(psz, "FLOPPY"))
1455 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
1456 else if (!strcmp(psz, "LAN"))
1457 *penmBoot = DEVPCBIOSBOOT_LAN;
1458 else if (!strcmp(psz, "NONE"))
1459 *penmBoot = DEVPCBIOSBOOT_NONE;
1460 else
1461 {
1462 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1463 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
1464 pszParam, psz);
1465 rc = VERR_INTERNAL_ERROR;
1466 }
1467 MMR3HeapFree(psz);
1468 return rc;
1469}
1470
1471/**
1472 * Construct a device instance for a VM.
1473 *
1474 * @returns VBox status.
1475 * @param pDevIns The device instance data.
1476 * If the registration structure is needed, pDevIns->pDevReg points to it.
1477 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1478 * The device number is also found in pDevIns->iInstance, but since it's
1479 * likely to be freqently used PDM passes it as parameter.
1480 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1481 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1482 * iInstance it's expected to be used a bit in this function.
1483 */
1484static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1485{
1486 unsigned i;
1487 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
1488 int rc;
1489 int cb;
1490
1491 Assert(iInstance == 0);
1492
1493 /*
1494 * Validate configuration.
1495 */
1496 if (!CFGMR3AreValuesValid(pCfgHandle,
1497 "BootDevice0\0"
1498 "BootDevice1\0"
1499 "BootDevice2\0"
1500 "BootDevice3\0"
1501 "RamSize\0"
1502 "RamHoleSize\0"
1503 "HardDiskDevice\0"
1504 "SataHardDiskDevice\0"
1505 "SataPrimaryMasterLUN\0"
1506 "SataPrimarySlaveLUN\0"
1507 "SataSecondaryMasterLUN\0"
1508 "SataSecondarySlaveLUN\0"
1509 "FloppyDevice\0"
1510 "DelayBoot\0"
1511 "BiosRom\0"
1512 "LanBootRom\0"
1513 "PXEDebug\0"
1514 "UUID\0"
1515 "IOAPIC\0"
1516 "NumCPUs\0"
1517 "DmiBIOSVendor\0"
1518 "DmiBIOSVersion\0"
1519 "DmiBIOSReleaseDate\0"
1520 "DmiBIOSReleaseMajor\0"
1521 "DmiBIOSReleaseMinor\0"
1522 "DmiBIOSFirmwareMajor\0"
1523 "DmiBIOSFirmwareMinor\0"
1524 "DmiSystemFamily\0"
1525 "DmiSystemProduct\0"
1526 "DmiSystemSerial\0"
1527 "DmiSystemUuid\0"
1528 "DmiSystemVendor\0"
1529 "DmiSystemVersion\0"
1530 "DmiChassisVendor\0"
1531 "DmiChassisVersion\0"
1532 "DmiChassisSerial\0"
1533 "DmiChassisAssetTag\0"
1534#ifdef VBOX_WITH_DMI_OEMSTRINGS
1535 "DmiOEMVBoxVer\0"
1536 "DmiOEMVBoxRev\0"
1537#endif
1538 ))
1539 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1540 N_("Invalid configuraton for device pcbios device"));
1541
1542 /*
1543 * Init the data.
1544 */
1545 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pThis->cbRam);
1546 if (RT_FAILURE(rc))
1547 return PDMDEV_SET_ERROR(pDevIns, rc,
1548 N_("Configuration error: Querying \"RamSize\" as integer failed"));
1549
1550 rc = CFGMR3QueryU32Def(pCfgHandle, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
1551 if (RT_FAILURE(rc))
1552 return PDMDEV_SET_ERROR(pDevIns, rc,
1553 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
1554
1555 rc = CFGMR3QueryU16Def(pCfgHandle, "NumCPUs", &pThis->cCpus, 1);
1556 if (RT_FAILURE(rc))
1557 return PDMDEV_SET_ERROR(pDevIns, rc,
1558 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
1559
1560 LogRel(("[SMP] BIOS with %u CPUs\n", pThis->cCpus));
1561
1562 rc = CFGMR3QueryU8Def(pCfgHandle, "IOAPIC", &pThis->u8IOAPIC, 1);
1563 if (RT_FAILURE (rc))
1564 return PDMDEV_SET_ERROR(pDevIns, rc,
1565 N_("Configuration error: Failed to read \"IOAPIC\""));
1566
1567 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
1568 Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
1569 for (i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
1570 {
1571 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
1572 if (RT_FAILURE(rc))
1573 return rc;
1574 }
1575
1576 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pThis->pszHDDevice);
1577 if (RT_FAILURE(rc))
1578 return PDMDEV_SET_ERROR(pDevIns, rc,
1579 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1580
1581 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pThis->pszFDDevice);
1582 if (RT_FAILURE(rc))
1583 return PDMDEV_SET_ERROR(pDevIns, rc,
1584 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1585
1586 rc = CFGMR3QueryStringAlloc(pCfgHandle, "SataHardDiskDevice", &pThis->pszSataDevice);
1587 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1588 pThis->pszSataDevice = NULL;
1589 else if (RT_FAILURE(rc))
1590 return PDMDEV_SET_ERROR(pDevIns, rc,
1591 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1592
1593 if (pThis->pszSataDevice)
1594 {
1595 static const char * const s_apszSataDisks[] =
1596 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1597 Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
1598 for (i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
1599 {
1600 rc = CFGMR3QueryU32(pCfgHandle, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
1601 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1602 pThis->iSataHDLUN[i] = i;
1603 else if (RT_FAILURE(rc))
1604 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1605 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1606 }
1607 }
1608 /*
1609 * Register I/O Ports and PC BIOS.
1610 */
1611 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1612 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1613 if (RT_FAILURE(rc))
1614 return rc;
1615 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1616 NULL, NULL, "Bochs PC BIOS - Shutdown");
1617 if (RT_FAILURE(rc))
1618 return rc;
1619
1620 /*
1621 * Query the machine's UUID for SMBIOS/DMI use.
1622 */
1623 RTUUID uuid;
1624 rc = CFGMR3QueryBytes(pCfgHandle, "UUID", &uuid, sizeof(uuid));
1625 if (RT_FAILURE(rc))
1626 return PDMDEV_SET_ERROR(pDevIns, rc,
1627 N_("Configuration error: Querying \"UUID\" failed"));
1628
1629
1630 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1631 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1632 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1633 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1634 rc = pcbiosPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE, &uuid, pCfgHandle);
1635 if (RT_FAILURE(rc))
1636 return rc;
1637 if (pThis->u8IOAPIC)
1638 pcbiosPlantMPStable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1639
1640 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage,
1641 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1642 if (RT_FAILURE(rc))
1643 return rc;
1644
1645 /*
1646 * Read the PXE debug logging option.
1647 */
1648 rc = CFGMR3QueryU8Def(pCfgHandle, "PXEDebug", &pThis->u8PXEDebug, false);
1649 if (RT_FAILURE(rc))
1650 return PDMDEV_SET_ERROR(pDevIns, rc,
1651 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1652
1653 /*
1654 * Get the system BIOS ROM file name.
1655 */
1656 rc = CFGMR3QueryStringAlloc(pCfgHandle, "BiosRom", &pThis->pszPcBiosFile);
1657 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1658 {
1659 pThis->pszPcBiosFile = NULL;
1660 rc = VINF_SUCCESS;
1661 }
1662 else if (RT_FAILURE(rc))
1663 return PDMDEV_SET_ERROR(pDevIns, rc,
1664 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1665 else if (!*pThis->pszPcBiosFile)
1666 {
1667 MMR3HeapFree(pThis->pszPcBiosFile);
1668 pThis->pszPcBiosFile = NULL;
1669 }
1670
1671 const uint8_t *pu8PcBiosBinary = NULL;
1672 uint64_t cbPcBiosBinary;
1673 /*
1674 * Determine the system BIOS ROM size, open specified ROM file in the process.
1675 */
1676 RTFILE FilePcBios = NIL_RTFILE;
1677 if (pThis->pszPcBiosFile)
1678 {
1679 rc = RTFileOpen(&FilePcBios, pThis->pszPcBiosFile,
1680 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1681 if (RT_SUCCESS(rc))
1682 {
1683 rc = RTFileGetSize(FilePcBios, &pThis->cbPcBios);
1684 if (RT_SUCCESS(rc))
1685 {
1686 /* The following checks should be in sync the AssertReleaseMsg's below. */
1687 if ( RT_ALIGN(pThis->cbPcBios, _64K) != pThis->cbPcBios
1688 || pThis->cbPcBios > 32 * _64K
1689 || pThis->cbPcBios < _64K)
1690 rc = VERR_TOO_MUCH_DATA;
1691 }
1692 }
1693 if (RT_FAILURE(rc))
1694 {
1695 /*
1696 * In case of failure simply fall back to the built-in BIOS ROM.
1697 */
1698 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Rrc!\n", pThis->pszPcBiosFile, rc));
1699 RTFileClose(FilePcBios);
1700 FilePcBios = NIL_RTFILE;
1701 MMR3HeapFree(pThis->pszPcBiosFile);
1702 pThis->pszPcBiosFile = NULL;
1703 }
1704 }
1705
1706 /*
1707 * Attempt to get the system BIOS ROM data from file.
1708 */
1709 if (pThis->pszPcBiosFile)
1710 {
1711 /*
1712 * Allocate buffer for the system BIOS ROM data.
1713 */
1714 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
1715 if (pThis->pu8PcBios)
1716 {
1717 rc = RTFileRead(FilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
1718 if (RT_FAILURE(rc))
1719 {
1720 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbPcBios, rc));
1721 MMR3HeapFree(pThis->pu8PcBios);
1722 pThis->pu8PcBios = NULL;
1723 }
1724 rc = VINF_SUCCESS;
1725 }
1726 else
1727 rc = VERR_NO_MEMORY;
1728 }
1729 else
1730 pThis->pu8PcBios = NULL;
1731
1732 /* cleanup */
1733 if (FilePcBios != NIL_RTFILE)
1734 RTFileClose(FilePcBios);
1735
1736 /* If we were unable to get the data from file for whatever reason, fall
1737 back to the built-in ROM image. */
1738 uint32_t fFlags = 0;
1739 if (pThis->pu8PcBios == NULL)
1740 {
1741 pu8PcBiosBinary = g_abPcBiosBinary;
1742 cbPcBiosBinary = g_cbPcBiosBinary;
1743 fFlags = PGMPHYS_ROM_FLAGS_PERMANENT_BINARY;
1744 }
1745 else
1746 {
1747 pu8PcBiosBinary = pThis->pu8PcBios;
1748 cbPcBiosBinary = pThis->cbPcBios;
1749 }
1750
1751 /*
1752 * Map the BIOS into memory.
1753 * There are two mappings:
1754 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1755 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1756 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1757 */
1758 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1759 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1760 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1761 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1762 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1763 fFlags, "PC BIOS - 0xfffff");
1764 if (RT_FAILURE(rc))
1765 return rc;
1766 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1767 fFlags, "PC BIOS - 0xffffffff");
1768 if (RT_FAILURE(rc))
1769 return rc;
1770
1771#ifdef VBOX_WITH_VMI
1772 /*
1773 * Map the VMI BIOS into memory.
1774 */
1775 AssertReleaseMsg(g_cbVmiBiosBinary == _4K, ("cbVmiBiosBinary=%#x\n", g_cbVmiBiosBinary));
1776 rc = PDMDevHlpROMRegister(pDevIns, VBOX_VMI_BIOS_BASE, g_cbVmiBiosBinary, g_abVmiBiosBinary,
1777 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "VMI BIOS");
1778 if (RT_FAILURE(rc))
1779 return rc;
1780#endif /* VBOX_WITH_VMI */
1781
1782 /*
1783 * Call reset to set values and stuff.
1784 */
1785 pcbiosReset(pDevIns);
1786
1787 /*
1788 * Get the LAN boot ROM file name.
1789 */
1790 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pThis->pszLanBootFile);
1791 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1792 {
1793 pThis->pszLanBootFile = NULL;
1794 rc = VINF_SUCCESS;
1795 }
1796 else if (RT_FAILURE(rc))
1797 return PDMDEV_SET_ERROR(pDevIns, rc,
1798 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1799 else if (!*pThis->pszLanBootFile)
1800 {
1801 MMR3HeapFree(pThis->pszLanBootFile);
1802 pThis->pszLanBootFile = NULL;
1803 }
1804
1805 uint64_t cbFileLanBoot;
1806 const uint8_t *pu8LanBootBinary = NULL;
1807 uint64_t cbLanBootBinary;
1808
1809 /*
1810 * Determine the LAN boot ROM size, open specified ROM file in the process.
1811 */
1812 RTFILE FileLanBoot = NIL_RTFILE;
1813 if (pThis->pszLanBootFile)
1814 {
1815 rc = RTFileOpen(&FileLanBoot, pThis->pszLanBootFile,
1816 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1817 if (RT_SUCCESS(rc))
1818 {
1819 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1820 if (RT_SUCCESS(rc))
1821 {
1822 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1823 || cbFileLanBoot > _64K)
1824 rc = VERR_TOO_MUCH_DATA;
1825 }
1826 }
1827 if (RT_FAILURE(rc))
1828 {
1829 /*
1830 * Ignore failure and fall back to the built-in LAN boot ROM.
1831 */
1832 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
1833 RTFileClose(FileLanBoot);
1834 FileLanBoot = NIL_RTFILE;
1835 MMR3HeapFree(pThis->pszLanBootFile);
1836 pThis->pszLanBootFile = NULL;
1837 }
1838 }
1839
1840 /*
1841 * Get the LAN boot ROM data.
1842 */
1843 if (pThis->pszLanBootFile)
1844 {
1845 /*
1846 * Allocate buffer for the LAN boot ROM data.
1847 */
1848 pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1849 if (pThis->pu8LanBoot)
1850 {
1851 rc = RTFileRead(FileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
1852 if (RT_FAILURE(rc))
1853 {
1854 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", cbFileLanBoot, rc));
1855 MMR3HeapFree(pThis->pu8LanBoot);
1856 pThis->pu8LanBoot = NULL;
1857 }
1858 rc = VINF_SUCCESS;
1859 }
1860 else
1861 rc = VERR_NO_MEMORY;
1862 }
1863 else
1864 pThis->pu8LanBoot = NULL;
1865
1866 /* cleanup */
1867 if (FileLanBoot != NIL_RTFILE)
1868 RTFileClose(FileLanBoot);
1869
1870 /* If we were unable to get the data from file for whatever reason, fall
1871 * back to the built-in LAN boot ROM image.
1872 */
1873 if (pThis->pu8LanBoot == NULL)
1874 {
1875 pu8LanBootBinary = g_abNetBiosBinary;
1876 cbLanBootBinary = g_cbNetBiosBinary;
1877 }
1878 else
1879 {
1880 pu8LanBootBinary = pThis->pu8LanBoot;
1881 cbLanBootBinary = cbFileLanBoot;
1882 }
1883
1884 /*
1885 * Map the Network Boot ROM into memory.
1886 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1887 * the (up to) 32 kb ROM image.
1888 */
1889 if (pu8LanBootBinary)
1890 {
1891 pThis->cbLanBoot = cbLanBootBinary;
1892
1893 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1894 PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
1895 if (RT_SUCCESS(rc))
1896 {
1897 rc = PDMDevHlpROMProtectShadow(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, PGMROMPROT_READ_RAM_WRITE_RAM);
1898 AssertRCReturn(rc, rc);
1899 rc = PDMDevHlpPhysWrite(pDevIns, VBOX_LANBOOT_SEG << 4, pu8LanBootBinary, cbLanBootBinary);
1900 AssertRCReturn(rc, rc);
1901 }
1902 }
1903
1904 rc = CFGMR3QueryU8Def(pCfgHandle, "DelayBoot", &pThis->uBootDelay, 0);
1905 if (RT_FAILURE(rc))
1906 return PDMDEV_SET_ERROR(pDevIns, rc,
1907 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1908 if (pThis->uBootDelay > 15)
1909 pThis->uBootDelay = 15;
1910
1911 return rc;
1912}
1913
1914
1915/**
1916 * The device registration structure.
1917 */
1918const PDMDEVREG g_DevicePcBios =
1919{
1920 /* u32Version */
1921 PDM_DEVREG_VERSION,
1922 /* szDeviceName */
1923 "pcbios",
1924 /* szRCMod */
1925 "",
1926 /* szR0Mod */
1927 "",
1928 /* pszDescription */
1929 "PC BIOS Device",
1930 /* fFlags */
1931 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1932 /* fClass */
1933 PDM_DEVREG_CLASS_ARCH_BIOS,
1934 /* cMaxInstances */
1935 1,
1936 /* cbInstance */
1937 sizeof(DEVPCBIOS),
1938 /* pfnConstruct */
1939 pcbiosConstruct,
1940 /* pfnDestruct */
1941 pcbiosDestruct,
1942 /* pfnRelocate */
1943 NULL,
1944 /* pfnIOCtl */
1945 NULL,
1946 /* pfnPowerOn */
1947 NULL,
1948 /* pfnReset */
1949 pcbiosReset,
1950 /* pfnSuspend */
1951 NULL,
1952 /* pfnResume */
1953 NULL,
1954 /* pfnAttach */
1955 NULL,
1956 /* pfnDetach */
1957 NULL,
1958 /* pfnQueryInterface. */
1959 NULL,
1960 /* pfnInitComplete. */
1961 pcbiosInitComplete,
1962 /* pfnPowerOff */
1963 NULL,
1964 /* pfnSoftReset */
1965 NULL,
1966 /* u32VersionEnd */
1967 PDM_DEVREG_VERSION
1968};
1969
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