VirtualBox

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

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

Main, shared f/w: changed DMI passthrough defaults

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