VirtualBox

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

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

Some more doxygen fixes, now for Core.docs.

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