VirtualBox

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

Last change on this file since 29085 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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