VirtualBox

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

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

BIOS/DMI: fixed a bug where structures without strings were not properly terminated and increase the limit for DMI strings a little bit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/* $Id: DevFwCommon.cpp 26728 2010-02-24 10:22:51Z 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 system enclosure or chassis type (Type 3) */
147typedef struct DMICHASSIS
148{
149 DMIHDR header;
150 uint8_t u8Manufacturer;
151 uint8_t u8Type;
152 uint8_t u8Version;
153 uint8_t u8SerialNumber;
154 uint8_t u8AssetTag;
155 uint8_t u8BootupState;
156 uint8_t u8PowerSupplyState;
157 uint8_t u8ThermalState;
158 uint8_t u8SecurityStatus;
159 /* v2.3+, currently not supported */
160 uint32_t u32OEMdefined;
161 uint8_t u8Height;
162 uint8_t u8NumPowerChords;
163 uint8_t u8ContElems;
164 uint8_t u8ContElemRecLen;
165} *PDMICHASSIS;
166AssertCompileSize(DMICHASSIS, 0x15);
167
168/** DMI processor information (Type 4) */
169typedef struct DMIPROCESSORINF
170{
171 DMIHDR header;
172 uint8_t u8SocketDesignation;
173 uint8_t u8ProcessorType;
174 uint8_t u8ProcessorFamily;
175 uint8_t u8ProcessorManufacturer;
176 uint64_t u64ProcessorIdentification;
177 uint8_t u8ProcessorVersion;
178 uint8_t u8Voltage;
179 uint16_t u16ExternalClock;
180 uint16_t u16MaxSpeed;
181 uint16_t u16CurrentSpeed;
182 uint8_t u8Status;
183 uint8_t u8ProcessorUpgrade;
184 uint16_t u16L1CacheHandle;
185 uint16_t u16L2CacheHandle;
186 uint16_t u16L3CacheHandle;
187 uint8_t u8SerialNumber;
188 uint8_t u8AssetTag;
189 uint8_t u8PartNumber;
190 uint8_t u8CoreCount;
191 uint8_t u8CoreEnabled;
192 uint8_t u8ThreadCount;
193 uint16_t u16ProcessorCharacteristics;
194 uint16_t u16ProcessorFamily2;
195} *PDMIPROCESSORINF;
196AssertCompileSize(DMIPROCESSORINF, 0x2a);
197
198/** DMI OEM strings (Type 11) */
199typedef struct DMIOEMSTRINGS
200{
201 DMIHDR header;
202 uint8_t u8Count;
203 uint8_t u8VBoxVersion;
204 uint8_t u8VBoxRevision;
205} *PDMIOEMSTRINGS;
206AssertCompileSize(DMIOEMSTRINGS, 0x7);
207
208/** MPS floating pointer structure */
209typedef struct MPSFLOATPTR
210{
211 uint8_t au8Signature[4];
212 uint32_t u32MPSAddr;
213 uint8_t u8Length;
214 uint8_t u8SpecRev;
215 uint8_t u8Checksum;
216 uint8_t au8Feature[5];
217} *PMPSFLOATPTR;
218AssertCompileSize(MPSFLOATPTR, 16);
219
220/** MPS config table header */
221typedef struct MPSCFGTBLHEADER
222{
223 uint8_t au8Signature[4];
224 uint16_t u16Length;
225 uint8_t u8SpecRev;
226 uint8_t u8Checksum;
227 uint8_t au8OemId[8];
228 uint8_t au8ProductId[12];
229 uint32_t u32OemTablePtr;
230 uint16_t u16OemTableSize;
231 uint16_t u16EntryCount;
232 uint32_t u32AddrLocalApic;
233 uint16_t u16ExtTableLength;
234 uint8_t u8ExtTableChecksxum;
235 uint8_t u8Reserved;
236} *PMPSCFGTBLHEADER;
237AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
238
239/** MPS processor entry */
240typedef struct MPSPROCENTRY
241{
242 uint8_t u8EntryType;
243 uint8_t u8LocalApicId;
244 uint8_t u8LocalApicVersion;
245 uint8_t u8CPUFlags;
246 uint32_t u32CPUSignature;
247 uint32_t u32CPUFeatureFlags;
248 uint32_t u32Reserved[2];
249} *PMPSPROCENTRY;
250AssertCompileSize(MPSPROCENTRY, 20);
251
252/** MPS bus entry */
253typedef struct MPSBUSENTRY
254{
255 uint8_t u8EntryType;
256 uint8_t u8BusId;
257 uint8_t au8BusTypeStr[6];
258} *PMPSBUSENTRY;
259AssertCompileSize(MPSBUSENTRY, 8);
260
261/** MPS I/O-APIC entry */
262typedef struct MPSIOAPICENTRY
263{
264 uint8_t u8EntryType;
265 uint8_t u8Id;
266 uint8_t u8Version;
267 uint8_t u8Flags;
268 uint32_t u32Addr;
269} *PMPSIOAPICENTRY;
270AssertCompileSize(MPSIOAPICENTRY, 8);
271
272/** MPS I/O-Interrupt entry */
273typedef struct MPSIOINTERRUPTENTRY
274{
275 uint8_t u8EntryType;
276 uint8_t u8Type;
277 uint16_t u16Flags;
278 uint8_t u8SrcBusId;
279 uint8_t u8SrcBusIrq;
280 uint8_t u8DstIOAPICId;
281 uint8_t u8DstIOAPICInt;
282} *PMPSIOIRQENTRY;
283AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
284
285#pragma pack()
286
287
288/**
289 * Calculate a simple checksum for the MPS table.
290 *
291 * @param data data
292 * @param len size of data
293 */
294static uint8_t fwCommonChecksum(const uint8_t * const au8Data, uint32_t u32Length)
295{
296 uint8_t u8Sum = 0;
297 for (size_t i = 0; i < u32Length; ++i)
298 u8Sum += au8Data[i];
299 return -u8Sum;
300}
301
302static bool fwCommonChecksumOk(const uint8_t * const au8Data, uint32_t u32Length)
303{
304 uint8_t u8Sum = 0;
305 for (size_t i = 0; i < u32Length; i++)
306 u8Sum += au8Data[i];
307 return (u8Sum == 0);
308}
309
310/*
311 * Macmini2,1 - matches Mac Mini
312 */
313static void fwCommonUseHostDMIStrings(void)
314{
315 int rc;
316
317 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME,
318 g_szHostDmiSystemProduct, sizeof(g_szHostDmiSystemProduct));
319 if (RT_SUCCESS(rc))
320 {
321 s_szDefDmiSystemProduct = g_szHostDmiSystemProduct;
322 LogRel(("DMI: Using DmiSystemProduct from host: %s\n", g_szHostDmiSystemProduct));
323 }
324
325 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION,
326 g_szHostDmiSystemVersion, sizeof(g_szHostDmiSystemVersion));
327 if (RT_SUCCESS(rc))
328 {
329 s_szDefDmiSystemVersion = g_szHostDmiSystemVersion;
330 LogRel(("DMI: Using DmiSystemVersion from host: %s\n", g_szHostDmiSystemVersion));
331 }
332}
333
334/**
335 * Construct the DMI table.
336 *
337 * @returns VBox status code.
338 * @param pDevIns The device instance.
339 * @param pTable Where to create the DMI table.
340 * @param cbMax The maximum size of the DMI table.
341 * @param pUuid Pointer to the UUID to use if the DmiUuid
342 * configuration string isn't present.
343 * @param pCfg The handle to our config node.
344 * @param fPutSmbiosHeaders Plant SMBIOS headers if true.
345 */
346int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid,
347 PCFGMNODE pCfg, bool fPutSmbiosHeaders)
348{
349#define CHECKSIZE(cbWant) \
350 { \
351 size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
352 if (cbNeed > cbMax) \
353 { \
354 if (fHideErrors) \
355 { \
356 LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
357 continue; \
358 } \
359 return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
360 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); \
361 } \
362 }
363
364#define READCFGSTRDEF(variable, name, default_value) \
365 { \
366 if (fForceDefault) \
367 pszTmp = default_value; \
368 else \
369 { \
370 rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
371 if (RT_FAILURE(rc)) \
372 { \
373 if (fHideErrors) \
374 { \
375 LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
376 continue; \
377 } \
378 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
379 N_("Configuration error: Querying \"" name "\" as a string failed")); \
380 } \
381 else if (!strcmp(szBuf, "<EMPTY>")) \
382 pszTmp = ""; \
383 else \
384 pszTmp = szBuf; \
385 } \
386 if (!pszTmp[0]) \
387 variable = 0; /* empty string */ \
388 else \
389 { \
390 variable = iStrNr++; \
391 size_t cStr = strlen(pszTmp) + 1; \
392 CHECKSIZE(cStr); \
393 memcpy(pszStr, pszTmp, cStr); \
394 pszStr += cStr ; \
395 } \
396 }
397
398#define READCFGSTR(variable, name) \
399 READCFGSTRDEF(variable, # name, s_szDef ## name)
400
401#define READCFGINT(variable, name) \
402 { \
403 if (fForceDefault) \
404 variable = s_iDef ## name; \
405 else \
406 { \
407 rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \
408 if (RT_FAILURE(rc)) \
409 { \
410 if (fHideErrors) \
411 { \
412 LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
413 continue; \
414 } \
415 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
416 N_("Configuration error: Querying \"" # name "\" as an int failed")); \
417 } \
418 } \
419 }
420
421#define TERM_STRUCT \
422 { \
423 *pszStr++ = '\0'; /* terminate set of text strings */ \
424 if (iStrNr == 1) \
425 *pszStr++ = '\0'; /* terminate a structure without strings */ \
426 }
427
428 bool fForceDefault = false;
429#ifdef VBOX_BIOS_DMI_FALLBACK
430 /*
431 * There will be two passes. If an error occurs during the first pass, a
432 * message will be written to the release log and we fall back to default
433 * DMI data and start a second pass.
434 */
435 bool fHideErrors = true;
436#else
437 /*
438 * There will be one pass, every error is fatal and will prevent the VM
439 * from starting.
440 */
441 bool fHideErrors = false;
442#endif
443
444 uint8_t fDmiUseHostInfo;
445 int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
446 if (RT_FAILURE (rc))
447 return PDMDEV_SET_ERROR(pDevIns, rc,
448 N_("Configuration error: Failed to read \"DmiUseHostInfo\""));
449
450 /* Sync up with host default DMI values */
451 if (fDmiUseHostInfo)
452 fwCommonUseHostDMIStrings();
453
454 for (;; fForceDefault = true, fHideErrors = false)
455 {
456 int iStrNr;
457 char szBuf[256];
458 char *pszStr = (char *)pTable;
459 char szDmiSystemUuid[64];
460 char *pszDmiSystemUuid;
461 const char *pszTmp;
462
463 if (fForceDefault)
464 pszDmiSystemUuid = NULL;
465 else
466 {
467 rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
468 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
469 pszDmiSystemUuid = NULL;
470 else if (RT_FAILURE(rc))
471 {
472 if (fHideErrors)
473 {
474 LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
475 continue;
476 }
477 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
478 N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
479 }
480 else
481 pszDmiSystemUuid = szDmiSystemUuid;
482 }
483
484 /*********************************
485 * DMI BIOS information (Type 0) *
486 *********************************/
487 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
488 CHECKSIZE(sizeof(*pBIOSInf));
489
490 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
491 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
492
493 /* don't set these fields by default for legacy compatibility */
494 int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
495 READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
496 READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
497 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
498 {
499 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
500 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
501 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
502 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
503
504 int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
505 READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
506 READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
507 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
508 {
509 pszStr = (char *)(pBIOSInf + 1);
510 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
511 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
512 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
513 }
514 }
515
516 iStrNr = 1;
517 pBIOSInf->header.u8Type = 0; /* BIOS Information */
518 pBIOSInf->header.u16Handle = 0x0000;
519 READCFGSTR(pBIOSInf->u8Vendor, DmiBIOSVendor);
520 READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion);
521 pBIOSInf->u16Start = 0xE000;
522 READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
523 pBIOSInf->u8ROMSize = 1; /* 128K */
524 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
525 | RT_BIT(7) /* PCI is supported */
526 | RT_BIT(15) /* Boot from CD is supported */
527 | RT_BIT(16) /* Selectable Boot is supported */
528 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
529 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
530 /* any more?? */
531 ;
532 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
533 /* any more?? */
534 ;
535 pBIOSInf->u8CharacteristicsByte2 = 0
536 /* any more?? */
537 ;
538 TERM_STRUCT;
539
540 /***********************************
541 * DMI system information (Type 1) *
542 ***********************************/
543 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
544 CHECKSIZE(sizeof(*pSystemInf));
545 pszStr = (char *)(pSystemInf + 1);
546 iStrNr = 1;
547 pSystemInf->header.u8Type = 1; /* System Information */
548 pSystemInf->header.u8Length = sizeof(*pSystemInf);
549 pSystemInf->header.u16Handle = 0x0001;
550 READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor);
551 READCFGSTR(pSystemInf->u8ProductName, DmiSystemProduct);
552 READCFGSTR(pSystemInf->u8Version, DmiSystemVersion);
553 READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial);
554
555 RTUUID uuid;
556 if (pszDmiSystemUuid)
557 {
558 rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
559 if (RT_FAILURE(rc))
560 {
561 if (fHideErrors)
562 {
563 LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
564 continue;
565 }
566 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
567 N_("Configuration error: Invalid UUID for DMI tables specified"));
568 }
569 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
570 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
571 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
572 pUuid = &uuid;
573 }
574 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
575
576 pSystemInf->u8WakeupType = 6; /* Power Switch */
577 pSystemInf->u8SKUNumber = 0;
578 READCFGSTR(pSystemInf->u8Family, DmiSystemFamily);
579 TERM_STRUCT;
580
581 /********************************************
582 * DMI System Enclosure or Chassis (Type 3) *
583 ********************************************/
584 PDMICHASSIS pChassis = (PDMICHASSIS)pszStr;
585 CHECKSIZE(sizeof(*pChassis));
586 pszStr = (char*)&pChassis->u32OEMdefined;
587 iStrNr = 1;
588#ifdef VBOX_WITH_DMI_CHASSIS
589 pChassis->header.u8Type = 3; /* System Enclosure or Chassis */
590#else
591 pChassis->header.u8Type = 0x7e; /* inactive */
592#endif
593 pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
594 pChassis->header.u16Handle = 0x0003;
595 READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor);
596 pChassis->u8Type = 0x01; /* ''other'', no chassis lock present */
597 READCFGSTR(pChassis->u8Version, DmiChassisVersion);
598 READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial);
599 READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag);
600 pChassis->u8BootupState = 0x03; /* safe */
601 pChassis->u8PowerSupplyState = 0x03; /* safe */
602 pChassis->u8ThermalState = 0x03; /* safe */
603 pChassis->u8SecurityStatus = 0x03; /* none XXX */
604# if 0
605 /* v2.3+, currently not supported */
606 pChassis->u32OEMdefined = 0;
607 pChassis->u8Height = 0; /* unspecified */
608 pChassis->u8NumPowerChords = 0; /* unspecified */
609 pChassis->u8ContElems = 0; /* no contained elements */
610 pChassis->u8ContElemRecLen = 0; /* no contained elements */
611# endif
612 TERM_STRUCT;
613
614 /*****************************
615 * DMI OEM strings (Type 11) *
616 *****************************/
617 PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr;
618 CHECKSIZE(sizeof(*pOEMStrings));
619 pszStr = (char *)(pOEMStrings + 1);
620 iStrNr = 1;
621#ifdef VBOX_WITH_DMI_OEMSTRINGS
622 pOEMStrings->header.u8Type = 0xb; /* OEM Strings */
623#else
624 pOEMStrings->header.u8Type = 0x7e; /* inactive */
625#endif
626 pOEMStrings->header.u8Length = sizeof(*pOEMStrings);
627 pOEMStrings->header.u16Handle = 0x0002;
628 pOEMStrings->u8Count = 2;
629
630 char szTmp[64];
631 RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
632 RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
633 READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
634 RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
635 READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
636 TERM_STRUCT;
637
638 /* End-of-table marker - includes padding to account for fixed table size. */
639 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
640 pEndOfTable->u8Type = 0x7f;
641 pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2;
642 pEndOfTable->u16Handle = 0xFEFF;
643
644 /* If more fields are added here, fix the size check in READCFGSTR */
645
646 /* Success! */
647 break;
648 }
649
650#undef READCFGSTR
651#undef READCFGINT
652#undef CHECKSIZE
653
654 if (fPutSmbiosHeaders)
655 {
656 struct {
657 struct SMBIOSHDR smbios;
658 struct DMIMAINHDR dmi;
659 } aBiosHeaders
660 =
661 {
662 // The SMBIOS header
663 {
664 { 0x5f, 0x53, 0x4d, 0x5f}, // "_SM_" signature
665 0x00, // checksum
666 0x1f, // EPS length, defined by standard
667 VBOX_SMBIOS_MAJOR_VER, // SMBIOS major version
668 VBOX_SMBIOS_MINOR_VER, // SMBIOS minor version
669 VBOX_SMBIOS_MAXSS, // Maximum structure size
670 0x00, // Entry point revision
671 { 0x00, 0x00, 0x00, 0x00, 0x00 } // padding
672 },
673 // The DMI header
674 {
675 { 0x5f, 0x44, 0x4d, 0x49, 0x5f }, // "_DMI_" signature
676 0x00, // checksum
677 VBOX_DMI_TABLE_SIZE, // DMI tables length
678 VBOX_DMI_TABLE_BASE, // DMI tables base
679 VBOX_DMI_TABLE_ENTR, // DMI tables entries
680 VBOX_DMI_TABLE_VER, // DMI version
681 }
682 };
683
684 aBiosHeaders.smbios.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.smbios, sizeof(aBiosHeaders.smbios));
685 aBiosHeaders.dmi.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.dmi, sizeof(aBiosHeaders.dmi));
686
687 PDMDevHlpPhysWrite (pDevIns, 0xfe300, &aBiosHeaders, sizeof(aBiosHeaders));
688 }
689
690 return VINF_SUCCESS;
691}
692AssertCompile(VBOX_DMI_TABLE_ENTR == 5);
693
694/**
695 * Construct the MPS table. Only applicable if IOAPIC is active!
696 *
697 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
698 * ``1.3 Scope
699 * ...
700 * The hardware required to implement the MP specification is kept to a
701 * minimum, as follows:
702 * * One or more processors that are Intel architecture instruction set
703 * compatible, such as the CPUs in the Intel486 or Pentium processor
704 * family.
705 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
706 * Interrupt Controller or the integrated APIC, such as that on the
707 * Intel Pentium 735\\90 and 815\\100 processors, together with a discrete
708 * I/O APIC unit.''
709 * and later:
710 * ``4.3.3 I/O APIC Entries
711 * The configuration table contains one or more entries for I/O APICs.
712 * ...
713 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
714 * operating system should not attempt to access
715 * this I/O APIC.
716 * At least one I/O APIC must be enabled.''
717 *
718 * @param pDevIns The device instance data.
719 * @param pTable Where to write the table.
720 * @param cbMax The maximum size of the MPS table.
721 * @param cCpus The number of guest CPUs.
722 */
723void FwCommonPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, uint16_t cCpus)
724{
725 /* configuration table */
726 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
727 memcpy(pCfgTab->au8Signature, "PCMP", 4);
728 pCfgTab->u8SpecRev = 4; /* 1.4 */
729 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
730 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
731 pCfgTab->u32OemTablePtr = 0;
732 pCfgTab->u16OemTableSize = 0;
733 pCfgTab->u16EntryCount = cCpus /* Processors */
734 + 1 /* ISA Bus */
735 + 1 /* I/O-APIC */
736 + 16 /* Interrupts */;
737 pCfgTab->u32AddrLocalApic = 0xfee00000;
738 pCfgTab->u16ExtTableLength = 0;
739 pCfgTab->u8ExtTableChecksxum = 0;
740 pCfgTab->u8Reserved = 0;
741
742 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
743 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
744 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
745 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
746 if (u32Eax >= 1)
747 {
748 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
749 u32CPUSignature = u32Eax & 0xfff;
750 /* Local APIC will be enabled later so override it here. Since we provide
751 * an MP table we have an IOAPIC and therefore a Local APIC. */
752 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
753 }
754 /* Construct MPS table for each VCPU. */
755 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
756 for (int i = 0; i < cCpus; i++)
757 {
758 pProcEntry->u8EntryType = 0; /* processor entry */
759 pProcEntry->u8LocalApicId = i;
760 pProcEntry->u8LocalApicVersion = 0x11;
761 pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
762 pProcEntry->u32CPUSignature = u32CPUSignature;
763 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
764 pProcEntry->u32Reserved[0] =
765 pProcEntry->u32Reserved[1] = 0;
766 pProcEntry++;
767 }
768
769 /* ISA bus */
770 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)pProcEntry;
771 pBusEntry->u8EntryType = 1; /* bus entry */
772 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
773 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
774
775 /* PCI bus? */
776
777 /* I/O-APIC.
778 * MP spec: "The configuration table contains one or more entries for I/O APICs.
779 * ... At least one I/O APIC must be enabled." */
780 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
781 uint16_t apicId = cCpus;
782 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
783 pIOAPICEntry->u8Id = apicId; /* this ID is referenced by the interrupt entries */
784 pIOAPICEntry->u8Version = 0x11;
785 pIOAPICEntry->u8Flags = 1 /* enable */;
786 pIOAPICEntry->u32Addr = 0xfec00000;
787
788 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
789 for (int i = 0; i < 16; i++, pIrqEntry++)
790 {
791 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
792 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
793 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
794 trigger mode = conforms to bus */
795 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
796 pIrqEntry->u8SrcBusIrq = i;
797 pIrqEntry->u8DstIOAPICId = apicId;
798 pIrqEntry->u8DstIOAPICInt = i;
799 }
800
801 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
802 pCfgTab->u8Checksum = fwCommonChecksum(pTable, pCfgTab->u16Length);
803
804 AssertMsg(pCfgTab->u16Length < cbMax,
805 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
806 pCfgTab->u16Length, cbMax));
807
808 MPSFLOATPTR floatPtr;
809 floatPtr.au8Signature[0] = '_';
810 floatPtr.au8Signature[1] = 'M';
811 floatPtr.au8Signature[2] = 'P';
812 floatPtr.au8Signature[3] = '_';
813 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
814 floatPtr.u8Length = 1; /* structure size in paragraphs */
815 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
816 floatPtr.u8Checksum = 0;
817 floatPtr.au8Feature[0] = 0;
818 floatPtr.au8Feature[1] = 0;
819 floatPtr.au8Feature[2] = 0;
820 floatPtr.au8Feature[3] = 0;
821 floatPtr.au8Feature[4] = 0;
822 floatPtr.u8Checksum = fwCommonChecksum((uint8_t*)&floatPtr, 16);
823 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
824}
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