VirtualBox

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

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

iprt/asm*.h: split out asm-math.h, don't include asm-*.h from asm.h, don't include asm.h from sup.h. Fixed a couple file headers.

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