VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevFwCommon.cpp@ 28580

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

review feedback

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.5 KB
Line 
1/* $Id: DevFwCommon.cpp 28580 2010-04-22 07:21:06Z vboxsync $ */
2/** @file
3 * FwCommon - Shared firmware code (used by DevPcBios & DevEFI).
4 */
5
6/*
7 * Copyright (C) 2009 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
26#include <VBox/pdmdev.h>
27
28#include <VBox/log.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31
32#include <iprt/assert.h>
33#include <iprt/buildconfig.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38#include <iprt/system.h>
39
40#include "../Builtins.h"
41#include "../Builtins2.h"
42#include "DevFwCommon.h"
43
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48
49/*
50 * Default DMI data (legacy).
51 * Don't change this information otherwise Windows guests will demand re-activation!
52 */
53static const int32_t s_iDefDmiBIOSReleaseMajor = 0;
54static const int32_t s_iDefDmiBIOSReleaseMinor = 0;
55static const int32_t s_iDefDmiBIOSFirmwareMajor = 0;
56static const int32_t s_iDefDmiBIOSFirmwareMinor = 0;
57static const char *s_szDefDmiBIOSVendor = "innotek GmbH";
58static const char *s_szDefDmiBIOSVersion = "VirtualBox";
59static const char *s_szDefDmiBIOSReleaseDate = "12/01/2006";
60static const char *s_szDefDmiSystemVendor = "innotek GmbH";
61static const char *s_szDefDmiSystemProduct = "VirtualBox";
62static const char *s_szDefDmiSystemVersion = "1.2";
63static const char *s_szDefDmiSystemSerial = "0";
64static const char *s_szDefDmiSystemFamily = "Virtual Machine";
65static const char *s_szDefDmiChassisVendor = "Sun Microsystems, Inc.";
66static const char *s_szDefDmiChassisVersion = "";
67static const char *s_szDefDmiChassisSerial = "";
68static const char *s_szDefDmiChassisAssetTag = "";
69
70static char g_szHostDmiSystemProduct[64];
71static char g_szHostDmiSystemVersion[64];
72
73
74/*******************************************************************************
75* Structures and Typedefs *
76*******************************************************************************/
77#pragma pack(1)
78
79typedef struct SMBIOSHDR
80{
81 uint8_t au8Signature[4];
82 uint8_t u8Checksum;
83 uint8_t u8Eps;
84 uint8_t u8VersionMajor;
85 uint8_t u8VersionMinor;
86 uint16_t u16MaxStructureSize;
87 uint8_t u8EntryPointRevision;
88 uint8_t u8Pad[5];
89} *SMBIOSHDRPTR;
90AssertCompileSize(SMBIOSHDR, 16);
91
92typedef struct DMIMAINHDR
93{
94 uint8_t au8Signature[5];
95 uint8_t u8Checksum;
96 uint16_t u16TablesLength;
97 uint32_t u32TableBase;
98 uint16_t u16TableEntries;
99 uint8_t u8TableVersion;
100} *DMIMAINHDRPTR;
101AssertCompileSize(DMIMAINHDR, 15);
102
103/** DMI header */
104typedef struct DMIHDR
105{
106 uint8_t u8Type;
107 uint8_t u8Length;
108 uint16_t u16Handle;
109} *PDMIHDR;
110AssertCompileSize(DMIHDR, 4);
111
112/** DMI BIOS information (Type 0) */
113typedef struct DMIBIOSINF
114{
115 DMIHDR header;
116 uint8_t u8Vendor;
117 uint8_t u8Version;
118 uint16_t u16Start;
119 uint8_t u8Release;
120 uint8_t u8ROMSize;
121 uint64_t u64Characteristics;
122 uint8_t u8CharacteristicsByte1;
123 uint8_t u8CharacteristicsByte2;
124 uint8_t u8ReleaseMajor;
125 uint8_t u8ReleaseMinor;
126 uint8_t u8FirmwareMajor;
127 uint8_t u8FirmwareMinor;
128} *PDMIBIOSINF;
129AssertCompileSize(DMIBIOSINF, 0x18);
130
131/** DMI system information (Type 1) */
132typedef struct DMISYSTEMINF
133{
134 DMIHDR header;
135 uint8_t u8Manufacturer;
136 uint8_t u8ProductName;
137 uint8_t u8Version;
138 uint8_t u8SerialNumber;
139 uint8_t au8Uuid[16];
140 uint8_t u8WakeupType;
141 uint8_t u8SKUNumber;
142 uint8_t u8Family;
143} *PDMISYSTEMINF;
144AssertCompileSize(DMISYSTEMINF, 0x1b);
145
146/** DMI board (or module) information (Type 2) */
147typedef struct DMIBOARDINF
148{
149 DMIHDR header;
150 uint8_t u8Manufacturer;
151 uint8_t u8Product;
152 uint8_t u8Version;
153 uint8_t u8SerialNumber;
154 uint8_t u8AssetTag;
155 uint8_t u8FeatureFlags;
156 uint8_t u8LocationInChassis;
157 uint16_t u16ChassisHandle;
158 uint8_t u8BoardType;
159 uint8_t u8cObjectHandles;
160} *PDMIBOARDINF;
161AssertCompileSize(DMIBOARDINF, 0x0f);
162
163/** DMI system enclosure or chassis type (Type 3) */
164typedef struct DMICHASSIS
165{
166 DMIHDR header;
167 uint8_t u8Manufacturer;
168 uint8_t u8Type;
169 uint8_t u8Version;
170 uint8_t u8SerialNumber;
171 uint8_t u8AssetTag;
172 uint8_t u8BootupState;
173 uint8_t u8PowerSupplyState;
174 uint8_t u8ThermalState;
175 uint8_t u8SecurityStatus;
176 /* v2.3+, currently not supported */
177 uint32_t u32OEMdefined;
178 uint8_t u8Height;
179 uint8_t u8NumPowerChords;
180 uint8_t u8ContElems;
181 uint8_t u8ContElemRecLen;
182} *PDMICHASSIS;
183AssertCompileSize(DMICHASSIS, 0x15);
184
185/** DMI processor information (Type 4) */
186typedef struct DMIPROCESSORINF
187{
188 DMIHDR header;
189 uint8_t u8SocketDesignation;
190 uint8_t u8ProcessorType;
191 uint8_t u8ProcessorFamily;
192 uint8_t u8ProcessorManufacturer;
193 uint64_t u64ProcessorIdentification;
194 uint8_t u8ProcessorVersion;
195 uint8_t u8Voltage;
196 uint16_t u16ExternalClock;
197 uint16_t u16MaxSpeed;
198 uint16_t u16CurrentSpeed;
199 uint8_t u8Status;
200 uint8_t u8ProcessorUpgrade;
201 uint16_t u16L1CacheHandle;
202 uint16_t u16L2CacheHandle;
203 uint16_t u16L3CacheHandle;
204 uint8_t u8SerialNumber;
205 uint8_t u8AssetTag;
206 uint8_t u8PartNumber;
207 uint8_t u8CoreCount;
208 uint8_t u8CoreEnabled;
209 uint8_t u8ThreadCount;
210 uint16_t u16ProcessorCharacteristics;
211 uint16_t u16ProcessorFamily2;
212} *PDMIPROCESSORINF;
213AssertCompileSize(DMIPROCESSORINF, 0x2a);
214
215/** DMI OEM strings (Type 11) */
216typedef struct DMIOEMSTRINGS
217{
218 DMIHDR header;
219 uint8_t u8Count;
220 uint8_t u8VBoxVersion;
221 uint8_t u8VBoxRevision;
222} *PDMIOEMSTRINGS;
223AssertCompileSize(DMIOEMSTRINGS, 0x7);
224
225/** Physical memory array (Type 16) */
226typedef struct DMIRAMARRAY
227{
228 DMIHDR header;
229 uint8_t u8Location;
230 uint8_t u8Use;
231 uint8_t u8MemErrorCorrection;
232 uint32_t u32MaxCapacity;
233 uint16_t u16MemErrorHandle;
234 uint16_t u16NumberOfMemDevices;
235} *PDMIRAMARRAY;
236AssertCompileSize(DMIRAMARRAY, 15);
237
238/** DMI Memory Device (Type 17) */
239typedef struct DMIMEMORYDEV
240{
241 DMIHDR header;
242 uint16_t u16PhysMemArrayHandle;
243 uint16_t u16MemErrHandle;
244 uint16_t u16TotalWidth;
245 uint16_t u16DataWidth;
246 uint16_t u16Size;
247 uint8_t u8FormFactor;
248 uint8_t u8DeviceSet;
249 uint8_t u8DeviceLocator;
250 uint8_t u8BankLocator;
251 uint8_t u8MemoryType;
252 uint16_t u16TypeDetail;
253 uint16_t u16Speed;
254 uint8_t u8Manufacturer;
255 uint8_t u8SerialNumber;
256 uint8_t u8AssetTag;
257 uint8_t u8PartNumber;
258 /* v2.6+ */
259 uint8_t u8Attributes;
260} *PDMIMEMORYDEV;
261AssertCompileSize(DMIMEMORYDEV, 28);
262
263/** MPS floating pointer structure */
264typedef struct MPSFLOATPTR
265{
266 uint8_t au8Signature[4];
267 uint32_t u32MPSAddr;
268 uint8_t u8Length;
269 uint8_t u8SpecRev;
270 uint8_t u8Checksum;
271 uint8_t au8Feature[5];
272} *PMPSFLOATPTR;
273AssertCompileSize(MPSFLOATPTR, 16);
274
275/** MPS config table header */
276typedef struct MPSCFGTBLHEADER
277{
278 uint8_t au8Signature[4];
279 uint16_t u16Length;
280 uint8_t u8SpecRev;
281 uint8_t u8Checksum;
282 uint8_t au8OemId[8];
283 uint8_t au8ProductId[12];
284 uint32_t u32OemTablePtr;
285 uint16_t u16OemTableSize;
286 uint16_t u16EntryCount;
287 uint32_t u32AddrLocalApic;
288 uint16_t u16ExtTableLength;
289 uint8_t u8ExtTableChecksum;
290 uint8_t u8Reserved;
291} *PMPSCFGTBLHEADER;
292AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
293
294/** MPS processor entry */
295typedef struct MPSPROCENTRY
296{
297 uint8_t u8EntryType;
298 uint8_t u8LocalApicId;
299 uint8_t u8LocalApicVersion;
300 uint8_t u8CPUFlags;
301 uint32_t u32CPUSignature;
302 uint32_t u32CPUFeatureFlags;
303 uint32_t u32Reserved[2];
304} *PMPSPROCENTRY;
305AssertCompileSize(MPSPROCENTRY, 20);
306
307/** MPS bus entry */
308typedef struct MPSBUSENTRY
309{
310 uint8_t u8EntryType;
311 uint8_t u8BusId;
312 uint8_t au8BusTypeStr[6];
313} *PMPSBUSENTRY;
314AssertCompileSize(MPSBUSENTRY, 8);
315
316/** MPS I/O-APIC entry */
317typedef struct MPSIOAPICENTRY
318{
319 uint8_t u8EntryType;
320 uint8_t u8Id;
321 uint8_t u8Version;
322 uint8_t u8Flags;
323 uint32_t u32Addr;
324} *PMPSIOAPICENTRY;
325AssertCompileSize(MPSIOAPICENTRY, 8);
326
327/** MPS I/O-Interrupt entry */
328typedef struct MPSIOINTERRUPTENTRY
329{
330 uint8_t u8EntryType;
331 uint8_t u8Type;
332 uint16_t u16Flags;
333 uint8_t u8SrcBusId;
334 uint8_t u8SrcBusIrq;
335 uint8_t u8DstIOAPICId;
336 uint8_t u8DstIOAPICInt;
337} *PMPSIOIRQENTRY;
338AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
339
340#pragma pack()
341
342
343/**
344 * Calculate a simple checksum for the MPS table.
345 *
346 * @param data data
347 * @param len size of data
348 */
349static uint8_t fwCommonChecksum(const uint8_t * const au8Data, uint32_t u32Length)
350{
351 uint8_t u8Sum = 0;
352 for (size_t i = 0; i < u32Length; ++i)
353 u8Sum += au8Data[i];
354 return -u8Sum;
355}
356
357#if 0 /* unused */
358static bool fwCommonChecksumOk(const uint8_t * const au8Data, uint32_t u32Length)
359{
360 uint8_t u8Sum = 0;
361 for (size_t i = 0; i < u32Length; i++)
362 u8Sum += au8Data[i];
363 return (u8Sum == 0);
364}
365#endif
366
367/**
368 * Try fetch the DMI strings from the system.
369 */
370static void fwCommonUseHostDMIStrings(void)
371{
372 int rc;
373
374 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME,
375 g_szHostDmiSystemProduct, sizeof(g_szHostDmiSystemProduct));
376 if (RT_SUCCESS(rc))
377 {
378 s_szDefDmiSystemProduct = g_szHostDmiSystemProduct;
379 LogRel(("DMI: Using DmiSystemProduct from host: %s\n", g_szHostDmiSystemProduct));
380 }
381
382 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION,
383 g_szHostDmiSystemVersion, sizeof(g_szHostDmiSystemVersion));
384 if (RT_SUCCESS(rc))
385 {
386 s_szDefDmiSystemVersion = g_szHostDmiSystemVersion;
387 LogRel(("DMI: Using DmiSystemVersion from host: %s\n", g_szHostDmiSystemVersion));
388 }
389}
390
391/**
392 * Construct the DMI table.
393 *
394 * @returns VBox status code.
395 * @param pDevIns The device instance.
396 * @param pTable Where to create the DMI table.
397 * @param cbMax The maximum size of the DMI table.
398 * @param pUuid Pointer to the UUID to use if the DmiUuid
399 * configuration string isn't present.
400 * @param pCfg The handle to our config node.
401 */
402int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg)
403{
404#define CHECKSIZE(cbWant) \
405 { \
406 size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
407 if (cbNeed > cbMax) \
408 { \
409 if (fHideErrors) \
410 { \
411 LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
412 continue; \
413 } \
414 return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
415 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"), cbNeed, cbMax); \
416 } \
417 }
418
419#define READCFGSTRDEF(variable, name, default_value) \
420 { \
421 if (fForceDefault) \
422 pszTmp = default_value; \
423 else \
424 { \
425 rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
426 if (RT_FAILURE(rc)) \
427 { \
428 if (fHideErrors) \
429 { \
430 LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
431 continue; \
432 } \
433 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
434 N_("Configuration error: Querying \"" name "\" as a string failed")); \
435 } \
436 else if (!strcmp(szBuf, "<EMPTY>")) \
437 pszTmp = ""; \
438 else \
439 pszTmp = szBuf; \
440 } \
441 if (!pszTmp[0]) \
442 variable = 0; /* empty string */ \
443 else \
444 { \
445 variable = iStrNr++; \
446 size_t cStr = strlen(pszTmp) + 1; \
447 CHECKSIZE(cStr); \
448 memcpy(pszStr, pszTmp, cStr); \
449 pszStr += cStr ; \
450 } \
451 }
452
453#define READCFGSTR(variable, name) \
454 READCFGSTRDEF(variable, # name, s_szDef ## name)
455
456#define READCFGINT(variable, name) \
457 { \
458 if (fForceDefault) \
459 variable = s_iDef ## name; \
460 else \
461 { \
462 rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \
463 if (RT_FAILURE(rc)) \
464 { \
465 if (fHideErrors) \
466 { \
467 LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
468 continue; \
469 } \
470 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
471 N_("Configuration error: Querying \"" # name "\" as an int failed")); \
472 } \
473 } \
474 }
475
476#define START_STRUCT(tbl) \
477 pszStr = (char *)(tbl + 1); \
478 iStrNr = 1;
479
480#define TERM_STRUCT \
481 { \
482 *pszStr++ = '\0'; /* terminate set of text strings */ \
483 if (iStrNr == 1) \
484 *pszStr++ = '\0'; /* terminate a structure without strings */ \
485 }
486
487 bool fForceDefault = false;
488#ifdef VBOX_BIOS_DMI_FALLBACK
489 /*
490 * There will be two passes. If an error occurs during the first pass, a
491 * message will be written to the release log and we fall back to default
492 * DMI data and start a second pass.
493 */
494 bool fHideErrors = true;
495#else
496 /*
497 * There will be one pass, every error is fatal and will prevent the VM
498 * from starting.
499 */
500 bool fHideErrors = false;
501#endif
502
503 uint8_t fDmiUseHostInfo;
504 int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
505 if (RT_FAILURE (rc))
506 return PDMDEV_SET_ERROR(pDevIns, rc,
507 N_("Configuration error: Failed to read \"DmiUseHostInfo\""));
508
509 /* Sync up with host default DMI values */
510 if (fDmiUseHostInfo)
511 fwCommonUseHostDMIStrings();
512
513 uint8_t fDmiExposeMemoryTable;
514 rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0);
515 if (RT_FAILURE (rc))
516 return PDMDEV_SET_ERROR(pDevIns, rc,
517 N_("Configuration error: Failed to read \"DmiExposeMemoryTable\""));
518
519 for (;; fForceDefault = true, fHideErrors = false)
520 {
521 int iStrNr;
522 char szBuf[256];
523 char *pszStr = (char *)pTable;
524 char szDmiSystemUuid[64];
525 char *pszDmiSystemUuid;
526 const char *pszTmp;
527
528 if (fForceDefault)
529 pszDmiSystemUuid = NULL;
530 else
531 {
532 rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
533 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
534 pszDmiSystemUuid = NULL;
535 else if (RT_FAILURE(rc))
536 {
537 if (fHideErrors)
538 {
539 LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
540 continue;
541 }
542 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
543 N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
544 }
545 else
546 pszDmiSystemUuid = szDmiSystemUuid;
547 }
548
549 /*********************************
550 * DMI BIOS information (Type 0) *
551 *********************************/
552 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
553 CHECKSIZE(sizeof(*pBIOSInf));
554
555 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
556 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
557
558 /* don't set these fields by default for legacy compatibility */
559 int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
560 READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
561 READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
562 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
563 {
564 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
565 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
566 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
567 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
568
569 int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
570 READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
571 READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
572 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
573 {
574 pszStr = (char *)(pBIOSInf + 1);
575 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
576 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
577 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
578 }
579 }
580
581 iStrNr = 1;
582 pBIOSInf->header.u8Type = 0; /* BIOS Information */
583 pBIOSInf->header.u16Handle = 0x0000;
584 READCFGSTR(pBIOSInf->u8Vendor, DmiBIOSVendor);
585 READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion);
586 pBIOSInf->u16Start = 0xE000;
587 READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
588 pBIOSInf->u8ROMSize = 1; /* 128K */
589 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
590 | RT_BIT(7) /* PCI is supported */
591 | RT_BIT(15) /* Boot from CD is supported */
592 | RT_BIT(16) /* Selectable Boot is supported */
593 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
594 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
595 /* any more?? */
596 ;
597 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
598 /* any more?? */
599 ;
600 pBIOSInf->u8CharacteristicsByte2 = 0
601 /* any more?? */
602 ;
603 TERM_STRUCT;
604
605 /***********************************
606 * DMI system information (Type 1) *
607 ***********************************/
608 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
609 CHECKSIZE(sizeof(*pSystemInf));
610 pszStr = (char *)(pSystemInf + 1);
611 iStrNr = 1;
612 pSystemInf->header.u8Type = 1; /* System Information */
613 pSystemInf->header.u8Length = sizeof(*pSystemInf);
614 pSystemInf->header.u16Handle = 0x0001;
615 READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor);
616 READCFGSTR(pSystemInf->u8ProductName, DmiSystemProduct);
617 READCFGSTR(pSystemInf->u8Version, DmiSystemVersion);
618 READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial);
619
620 RTUUID uuid;
621 if (pszDmiSystemUuid)
622 {
623 rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
624 if (RT_FAILURE(rc))
625 {
626 if (fHideErrors)
627 {
628 LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
629 continue;
630 }
631 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
632 N_("Configuration error: Invalid UUID for DMI tables specified"));
633 }
634 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
635 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
636 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
637 pUuid = &uuid;
638 }
639 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
640
641 pSystemInf->u8WakeupType = 6; /* Power Switch */
642 pSystemInf->u8SKUNumber = 0;
643 READCFGSTR(pSystemInf->u8Family, DmiSystemFamily);
644 TERM_STRUCT;
645
646 /********************************************
647 * DMI System Enclosure or Chassis (Type 3) *
648 ********************************************/
649 PDMICHASSIS pChassis = (PDMICHASSIS)pszStr;
650 CHECKSIZE(sizeof(*pChassis));
651 pszStr = (char*)&pChassis->u32OEMdefined;
652 iStrNr = 1;
653#ifdef VBOX_WITH_DMI_CHASSIS
654 pChassis->header.u8Type = 3; /* System Enclosure or Chassis */
655#else
656 pChassis->header.u8Type = 0x7e; /* inactive */
657#endif
658 pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
659 pChassis->header.u16Handle = 0x0003;
660 READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor);
661 pChassis->u8Type = 0x01; /* ''other'', no chassis lock present */
662 READCFGSTR(pChassis->u8Version, DmiChassisVersion);
663 READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial);
664 READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag);
665 pChassis->u8BootupState = 0x03; /* safe */
666 pChassis->u8PowerSupplyState = 0x03; /* safe */
667 pChassis->u8ThermalState = 0x03; /* safe */
668 pChassis->u8SecurityStatus = 0x03; /* none XXX */
669# if 0
670 /* v2.3+, currently not supported */
671 pChassis->u32OEMdefined = 0;
672 pChassis->u8Height = 0; /* unspecified */
673 pChassis->u8NumPowerChords = 0; /* unspecified */
674 pChassis->u8ContElems = 0; /* no contained elements */
675 pChassis->u8ContElemRecLen = 0; /* no contained elements */
676# endif
677 TERM_STRUCT;
678
679 if (fDmiExposeMemoryTable)
680 {
681 /***************************************
682 * DMI Physical Memory Array (Type 16) *
683 ***************************************/
684 uint64_t u64RamSize;
685 rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize);
686 if (RT_FAILURE (rc))
687 return PDMDEV_SET_ERROR(pDevIns, rc,
688 N_("Configuration error: Failed to read \"RamSize\""));
689
690 PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
691 CHECKSIZE(sizeof(*pMemArray));
692
693 START_STRUCT(pMemArray);
694 pMemArray->header.u8Type = 16; /* Physical Memory Array */
695 pMemArray->header.u8Length = sizeof(*pMemArray);
696 pMemArray->header.u16Handle = 0x0005;
697 pMemArray->u8Location = 0x03; /* Motherboard */
698 pMemArray->u8Use = 0x03; /* System memory */
699 pMemArray->u8MemErrorCorrection = 0x01; /* Other */
700 uint32_t u32RamSizeK = (uint32_t)(u64RamSize / _1K);
701 pMemArray->u32MaxCapacity = u32RamSizeK; /* RAM size in K */
702 pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */
703 pMemArray->u16NumberOfMemDevices = 1;
704 TERM_STRUCT;
705
706 /***************************************
707 * DMI Memory Device (Type 17) *
708 ***************************************/
709 PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr;
710 CHECKSIZE(sizeof(*pMemDev));
711
712 START_STRUCT(pMemDev);
713 pMemDev->header.u8Type = 17; /* Memory Device */
714 pMemDev->header.u8Length = sizeof(*pMemDev);
715 pMemDev->header.u16Handle = 0x0006;
716 pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */
717 pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */
718 pMemDev->u16TotalWidth = 0xffff; /* Unknown */
719 pMemDev->u16DataWidth = 0xffff; /* Unknown */
720 int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M);
721 if (u16RamSizeM == 0)
722 u16RamSizeM = 0x400; /* 1G */
723 pMemDev->u16Size = u16RamSizeM; /* RAM size */
724 pMemDev->u8FormFactor = 0x09; /* DIMM */
725 pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */
726 READCFGSTRDEF(pMemDev->u8DeviceLocator, " ", "DIMM 0");
727 READCFGSTRDEF(pMemDev->u8BankLocator, " ", "Bank 0");
728 pMemDev->u8MemoryType = 0x03; /* DRAM */
729 pMemDev->u16TypeDetail = 0; /* Nothing special */
730 pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */
731 READCFGSTR(pMemDev->u8Manufacturer, DmiSystemVendor);
732 READCFGSTRDEF(pMemDev->u8SerialNumber, " ", "00000000");
733 READCFGSTRDEF(pMemDev->u8AssetTag, " ", "00000000");
734 READCFGSTRDEF(pMemDev->u8PartNumber, " ", "00000000");
735 pMemDev->u8Attributes = 0; /* Unknown */
736 TERM_STRUCT;
737 }
738
739 /*****************************
740 * DMI OEM strings (Type 11) *
741 *****************************/
742 PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr;
743 CHECKSIZE(sizeof(*pOEMStrings));
744 pszStr = (char *)(pOEMStrings + 1);
745 iStrNr = 1;
746#ifdef VBOX_WITH_DMI_OEMSTRINGS
747 pOEMStrings->header.u8Type = 0xb; /* OEM Strings */
748#else
749 pOEMStrings->header.u8Type = 0x7e; /* inactive */
750#endif
751 pOEMStrings->header.u8Length = sizeof(*pOEMStrings);
752 pOEMStrings->header.u16Handle = 0x0002;
753 pOEMStrings->u8Count = 2;
754
755 char szTmp[64];
756 RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
757 RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
758 READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
759 RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
760 READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
761 TERM_STRUCT;
762
763 /* End-of-table marker - includes padding to account for fixed table size. */
764 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
765 pEndOfTable->u8Type = 0x7f;
766 pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2;
767 pEndOfTable->u16Handle = 0xFEFF;
768
769 /* If more fields are added here, fix the size check in READCFGSTR */
770
771 /* Success! */
772 break;
773 }
774
775#undef READCFGSTR
776#undef READCFGINT
777#undef CHECKSIZE
778 return VINF_SUCCESS;
779}
780
781/**
782 * Construct the SMBIOS and DMI headers table pointer at VM construction and
783 * reset.
784 *
785 * @param pDevIns The device instance data.
786 */
787void FwCommonPlantSmbiosAndDmiHdrs(PPDMDEVINS pDevIns)
788{
789 struct
790 {
791 struct SMBIOSHDR smbios;
792 struct DMIMAINHDR dmi;
793 } aBiosHeaders =
794 {
795 // The SMBIOS header
796 {
797 { 0x5f, 0x53, 0x4d, 0x5f}, // "_SM_" signature
798 0x00, // checksum
799 0x1f, // EPS length, defined by standard
800 VBOX_SMBIOS_MAJOR_VER, // SMBIOS major version
801 VBOX_SMBIOS_MINOR_VER, // SMBIOS minor version
802 VBOX_SMBIOS_MAXSS, // Maximum structure size
803 0x00, // Entry point revision
804 { 0x00, 0x00, 0x00, 0x00, 0x00 } // padding
805 },
806 // The DMI header
807 {
808 { 0x5f, 0x44, 0x4d, 0x49, 0x5f }, // "_DMI_" signature
809 0x00, // checksum
810 VBOX_DMI_TABLE_SIZE, // DMI tables length
811 VBOX_DMI_TABLE_BASE, // DMI tables base
812 VBOX_DMI_TABLE_ENTR, // DMI tables entries
813 VBOX_DMI_TABLE_VER, // DMI version
814 }
815 };
816
817 aBiosHeaders.smbios.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.smbios, sizeof(aBiosHeaders.smbios));
818 aBiosHeaders.dmi.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.dmi, sizeof(aBiosHeaders.dmi));
819
820 PDMDevHlpPhysWrite(pDevIns, 0xfe300, &aBiosHeaders, sizeof(aBiosHeaders));
821}
822AssertCompile(VBOX_DMI_TABLE_ENTR == 5);
823
824/**
825 * Construct the MPS table for implanting as a ROM page.
826 *
827 * Only applicable if IOAPIC is active!
828 *
829 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
830 * ``1.3 Scope
831 * ...
832 * The hardware required to implement the MP specification is kept to a
833 * minimum, as follows:
834 * * One or more processors that are Intel architecture instruction set
835 * compatible, such as the CPUs in the Intel486 or Pentium processor
836 * family.
837 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
838 * Interrupt Controller or the integrated APIC, such as that on the
839 * Intel Pentium 735\\90 and 815\\100 processors, together with a discrete
840 * I/O APIC unit.''
841 * and later:
842 * ``4.3.3 I/O APIC Entries
843 * The configuration table contains one or more entries for I/O APICs.
844 * ...
845 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
846 * operating system should not attempt to access
847 * this I/O APIC.
848 * At least one I/O APIC must be enabled.''
849 *
850 * @param pDevIns The device instance data.
851 * @param pTable Where to write the table.
852 * @param cbMax The maximum size of the MPS table.
853 * @param cCpus The number of guest CPUs.
854 */
855void FwCommonPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, uint16_t cCpus)
856{
857 /* configuration table */
858 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
859 memcpy(pCfgTab->au8Signature, "PCMP", 4);
860 pCfgTab->u8SpecRev = 4; /* 1.4 */
861 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
862 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
863 pCfgTab->u32OemTablePtr = 0;
864 pCfgTab->u16OemTableSize = 0;
865 pCfgTab->u16EntryCount = cCpus /* Processors */
866 + 1 /* ISA Bus */
867 + 1 /* PCI Bus */
868 + 1 /* I/O-APIC */
869 + 16 /* Interrupts */
870 + 1 /* Local interrupts */;
871 pCfgTab->u32AddrLocalApic = 0xfee00000;
872 pCfgTab->u16ExtTableLength = 0;
873 pCfgTab->u8ExtTableChecksum = 0;
874 pCfgTab->u8Reserved = 0;
875
876 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
877 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
878 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
879 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
880 if (u32Eax >= 1)
881 {
882 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
883 u32CPUSignature = u32Eax & 0xfff;
884 /* Local APIC will be enabled later so override it here. Since we provide
885 * an MP table we have an IOAPIC and therefore a Local APIC. */
886 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
887 }
888 /* Construct MPS table for each VCPU. */
889 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
890 for (int i = 0; i < cCpus; i++)
891 {
892 pProcEntry->u8EntryType = 0; /* processor entry */
893 pProcEntry->u8LocalApicId = i;
894 pProcEntry->u8LocalApicVersion = 0x14;
895 pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
896 pProcEntry->u32CPUSignature = u32CPUSignature;
897 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
898 pProcEntry->u32Reserved[0] =
899 pProcEntry->u32Reserved[1] = 0;
900 pProcEntry++;
901 }
902
903 uint32_t iBusIdPci0 = 0;
904 uint32_t iBusIdIsa = 1;
905
906 /* ISA bus */
907 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)pProcEntry;
908 pBusEntry->u8EntryType = 1; /* bus entry */
909 pBusEntry->u8BusId = iBusIdIsa; /* this ID is referenced by the interrupt entries */
910 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
911 pBusEntry++;
912
913 /* PCI bus */
914 pBusEntry->u8EntryType = 1; /* bus entry */
915 pBusEntry->u8BusId = iBusIdPci0; /* this ID can be referenced by the interrupt entries */
916 memcpy(pBusEntry->au8BusTypeStr, "PCI ", 6);
917
918
919 /* I/O-APIC.
920 * MP spec: "The configuration table contains one or more entries for I/O APICs.
921 * ... At least one I/O APIC must be enabled." */
922 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
923 uint16_t iApicId = 0;
924 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
925 pIOAPICEntry->u8Id = iApicId; /* this ID is referenced by the interrupt entries */
926 pIOAPICEntry->u8Version = 0x11;
927 pIOAPICEntry->u8Flags = 1 /* enable */;
928 pIOAPICEntry->u32Addr = 0xfec00000;
929
930 /* Interrupt tables */
931 /* Bus vectors */
932 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
933 for (int iPin = 0; iPin < 16; iPin++, pIrqEntry++)
934 {
935 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
936 /*
937 * 0 - INT, vectored interrupt,
938 * 3 - ExtINT, vectored interrupt provided by PIC
939 * As we emulate system with both APIC and PIC, it's needed for their coexistence.
940 */
941 pIrqEntry->u8Type = (iPin == 0) ? 3 : 0;
942 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
943 trigger mode = conforms to bus */
944 pIrqEntry->u8SrcBusId = iBusIdIsa; /* ISA bus */
945 /* IRQ0 mapped to pin 2, other are identity mapped */
946 /* If changing, also update PDMIsaSetIrq() and MADT */
947 pIrqEntry->u8SrcBusIrq = (iPin == 2) ? 0 : iPin; /* IRQ on the bus */
948 pIrqEntry->u8DstIOAPICId = iApicId; /* destintion IO-APIC */
949 pIrqEntry->u8DstIOAPICInt = iPin; /* pin on destination IO-APIC */
950 }
951 /* Local delivery */
952 pIrqEntry->u8EntryType = 4; /* Local interrupt entry */
953 pIrqEntry->u8Type = 3; /* ExtINT */
954 pIrqEntry->u16Flags = (1 << 2) | 1; /* active-high, edge-triggered */
955 pIrqEntry->u8SrcBusId = iBusIdIsa;
956 pIrqEntry->u8SrcBusIrq = 0;
957 pIrqEntry->u8DstIOAPICId = 0xff;
958 pIrqEntry->u8DstIOAPICInt = 0;
959 pIrqEntry++;
960
961 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
962 pCfgTab->u8Checksum = fwCommonChecksum(pTable, pCfgTab->u16Length);
963
964 AssertMsg(pCfgTab->u16Length < cbMax,
965 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
966 pCfgTab->u16Length, cbMax));
967}
968
969/**
970 * Construct the MPS table pointer at VM construction and reset.
971 *
972 * Only applicable if IOAPIC is active!
973 *
974 * @param pDevIns The device instance data.
975 */
976void FwCommonPlantMpsFloatPtr(PPDMDEVINS pDevIns)
977{
978 MPSFLOATPTR floatPtr;
979 floatPtr.au8Signature[0] = '_';
980 floatPtr.au8Signature[1] = 'M';
981 floatPtr.au8Signature[2] = 'P';
982 floatPtr.au8Signature[3] = '_';
983 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
984 floatPtr.u8Length = 1; /* structure size in paragraphs */
985 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
986 floatPtr.u8Checksum = 0;
987 floatPtr.au8Feature[0] = 0;
988 floatPtr.au8Feature[1] = 0;
989 floatPtr.au8Feature[2] = 0;
990 floatPtr.au8Feature[3] = 0;
991 floatPtr.au8Feature[4] = 0;
992 floatPtr.u8Checksum = fwCommonChecksum((uint8_t*)&floatPtr, 16);
993 PDMDevHlpPhysWrite(pDevIns, 0x9fff0, &floatPtr, 16);
994}
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