VirtualBox

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

Last change on this file since 69498 was 69498, checked in by vboxsync, 7 years ago

backed out r118835 as it incorrectly updated the 'This file is based on' file headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.4 KB
Line 
1/* $Id: DevFwCommon.cpp 69498 2017-10-28 15:07:25Z vboxsync $ */
2/** @file
3 * FwCommon - Shared firmware code (used by DevPcBios & DevEFI).
4 */
5
6/*
7 * Copyright (C) 2009-2016 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV
23#include <VBox/vmm/pdmdev.h>
24
25#include <VBox/log.h>
26#include <VBox/err.h>
27#include <VBox/param.h>
28
29#include <iprt/asm.h>
30#include <iprt/assert.h>
31#include <iprt/buildconfig.h>
32#include <iprt/file.h>
33#include <iprt/mem.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <iprt/system.h>
37#include <iprt/cdefs.h>
38
39#include "VBoxDD.h"
40#include "VBoxDD2.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 might demand re-activation!
51 */
52
53/* type 0 -- DMI BIOS information */
54static const int32_t g_iDefDmiBIOSReleaseMajor = 0;
55static const int32_t g_iDefDmiBIOSReleaseMinor = 0;
56static const int32_t g_iDefDmiBIOSFirmwareMajor = 0;
57static const int32_t g_iDefDmiBIOSFirmwareMinor = 0;
58static const char *g_pszDefDmiBIOSVendor = "innotek GmbH";
59static const char *g_pszDefDmiBIOSVersion = "VirtualBox";
60static const char *g_pszDefDmiBIOSReleaseDate = "12/01/2006";
61/* type 1 -- DMI system information */
62static const char *g_pszDefDmiSystemVendor = "innotek GmbH";
63static const char *g_pszDefDmiSystemProduct = "VirtualBox";
64static const char *g_pszDefDmiSystemVersion = "1.2";
65static const char *g_pszDefDmiSystemSerial = "0";
66static const char *g_pszDefDmiSystemSKU = "";
67static const char *g_pszDefDmiSystemFamily = "Virtual Machine";
68/* type 2 -- DMI board information */
69static const char *g_pszDefDmiBoardVendor = "Oracle Corporation";
70static const char *g_pszDefDmiBoardProduct = "VirtualBox";
71static const char *g_pszDefDmiBoardVersion = "1.2";
72static const char *g_pszDefDmiBoardSerial = "0";
73static const char *g_pszDefDmiBoardAssetTag = "";
74static const char *g_pszDefDmiBoardLocInChass = "";
75static const int32_t g_iDefDmiBoardBoardType = 0x0A; /* Motherboard */
76/* type 3 -- DMI chassis information */
77static const char *g_pszDefDmiChassisVendor = "Oracle Corporation";
78static const int32_t g_iDefDmiChassisType = 0x01; /* ''other'', no chassis lock present */
79static const char *g_pszDefDmiChassisVersion = "";
80static const char *g_pszDefDmiChassisSerial = "";
81static const char *g_pszDefDmiChassisAssetTag = "";
82/* type 4 -- DMI processor information */
83static const char *g_pszDefDmiProcManufacturer= "GenuineIntel";
84static const char *g_pszDefDmiProcVersion = "Pentium(R) III";
85
86/** The host DMI system product value, for DmiUseHostInfo=1. */
87static char g_szHostDmiSystemProduct[64];
88/** The host DMI system version value, for DmiUseHostInfo=1. */
89static char g_szHostDmiSystemVersion[64];
90
91
92/*********************************************************************************************************************************
93* Structures and Typedefs *
94*********************************************************************************************************************************/
95#pragma pack(1)
96
97typedef struct SMBIOSHDR
98{
99 uint8_t au8Signature[4];
100 uint8_t u8Checksum;
101 uint8_t u8Eps;
102 uint8_t u8VersionMajor;
103 uint8_t u8VersionMinor;
104 uint16_t u16MaxStructureSize;
105 uint8_t u8EntryPointRevision;
106 uint8_t u8Pad[5];
107} *SMBIOSHDRPTR;
108AssertCompileSize(SMBIOSHDR, 16);
109
110typedef struct DMIMAINHDR
111{
112 uint8_t au8Signature[5];
113 uint8_t u8Checksum;
114 uint16_t u16TablesLength;
115 uint32_t u32TableBase;
116 uint16_t u16TableEntries;
117 uint8_t u8TableVersion;
118} *DMIMAINHDRPTR;
119AssertCompileSize(DMIMAINHDR, 15);
120
121/** DMI header */
122typedef struct DMIHDR
123{
124 uint8_t u8Type;
125 uint8_t u8Length;
126 uint16_t u16Handle;
127} *PDMIHDR;
128AssertCompileSize(DMIHDR, 4);
129
130/** DMI BIOS information (Type 0) */
131typedef struct DMIBIOSINF
132{
133 DMIHDR header;
134 uint8_t u8Vendor;
135 uint8_t u8Version;
136 uint16_t u16Start;
137 uint8_t u8Release;
138 uint8_t u8ROMSize;
139 uint64_t u64Characteristics;
140 uint8_t u8CharacteristicsByte1;
141 uint8_t u8CharacteristicsByte2;
142 uint8_t u8ReleaseMajor;
143 uint8_t u8ReleaseMinor;
144 uint8_t u8FirmwareMajor;
145 uint8_t u8FirmwareMinor;
146} *PDMIBIOSINF;
147AssertCompileSize(DMIBIOSINF, 0x18);
148
149/** DMI system information (Type 1) */
150typedef struct DMISYSTEMINF
151{
152 DMIHDR header;
153 uint8_t u8Manufacturer;
154 uint8_t u8ProductName;
155 uint8_t u8Version;
156 uint8_t u8SerialNumber;
157 uint8_t au8Uuid[16];
158 uint8_t u8WakeupType;
159 uint8_t u8SKUNumber;
160 uint8_t u8Family;
161} *PDMISYSTEMINF;
162AssertCompileSize(DMISYSTEMINF, 0x1b);
163
164/** DMI board (or module) information (Type 2) */
165typedef struct DMIBOARDINF
166{
167 DMIHDR header;
168 uint8_t u8Manufacturer;
169 uint8_t u8Product;
170 uint8_t u8Version;
171 uint8_t u8SerialNumber;
172 uint8_t u8AssetTag;
173 uint8_t u8FeatureFlags;
174 uint8_t u8LocationInChass;
175 uint16_t u16ChassisHandle;
176 uint8_t u8BoardType;
177 uint8_t u8cObjectHandles;
178} *PDMIBOARDINF;
179AssertCompileSize(DMIBOARDINF, 0x0f);
180
181/** DMI system enclosure or chassis type (Type 3) */
182typedef struct DMICHASSIS
183{
184 DMIHDR header;
185 uint8_t u8Manufacturer;
186 uint8_t u8Type;
187 uint8_t u8Version;
188 uint8_t u8SerialNumber;
189 uint8_t u8AssetTag;
190 uint8_t u8BootupState;
191 uint8_t u8PowerSupplyState;
192 uint8_t u8ThermalState;
193 uint8_t u8SecurityStatus;
194 /* v2.3+, currently not supported */
195 uint32_t u32OEMdefined;
196 uint8_t u8Height;
197 uint8_t u8NumPowerChords;
198 uint8_t u8ContElems;
199 uint8_t u8ContElemRecLen;
200} *PDMICHASSIS;
201AssertCompileSize(DMICHASSIS, 0x15);
202
203/** DMI processor information (Type 4) */
204typedef struct DMIPROCESSORINF
205{
206 DMIHDR header;
207 uint8_t u8SocketDesignation;
208 uint8_t u8ProcessorType;
209 uint8_t u8ProcessorFamily;
210 uint8_t u8ProcessorManufacturer;
211 uint64_t u64ProcessorID;
212 uint8_t u8ProcessorVersion;
213 uint8_t u8Voltage;
214 uint16_t u16ExternalClock;
215 uint16_t u16MaxSpeed;
216 uint16_t u16CurrentSpeed;
217 uint8_t u8Status;
218 uint8_t u8ProcessorUpgrade;
219 /* v2.1+ */
220 uint16_t u16L1CacheHandle;
221 uint16_t u16L2CacheHandle;
222 uint16_t u16L3CacheHandle;
223 /* v2.3+ */
224 uint8_t u8SerialNumber;
225 uint8_t u8AssetTag;
226 uint8_t u8PartNumber;
227 /* v2.5+ */
228 uint8_t u8CoreCount;
229 uint8_t u8CoreEnabled;
230 uint8_t u8ThreadCount;
231 uint16_t u16ProcessorCharacteristics;
232 /* v2.6+ */
233 uint16_t u16ProcessorFamily2;
234} *PDMIPROCESSORINF;
235AssertCompileSize(DMIPROCESSORINF, 0x2a);
236
237/** DMI OEM strings (Type 11) */
238typedef struct DMIOEMSTRINGS
239{
240 DMIHDR header;
241 uint8_t u8Count;
242 uint8_t u8VBoxVersion;
243 uint8_t u8VBoxRevision;
244} *PDMIOEMSTRINGS;
245AssertCompileSize(DMIOEMSTRINGS, 0x7);
246
247/** DMI OEM-specific table (Type 128) */
248typedef struct DMIOEMSPECIFIC
249{
250 DMIHDR header;
251 uint32_t u32CpuFreqKHz;
252} *PDMIOEMSPECIFIC;
253AssertCompileSize(DMIOEMSPECIFIC, 0x8);
254
255/** Physical memory array (Type 16) */
256typedef struct DMIRAMARRAY
257{
258 DMIHDR header;
259 uint8_t u8Location;
260 uint8_t u8Use;
261 uint8_t u8MemErrorCorrection;
262 uint32_t u32MaxCapacity;
263 uint16_t u16MemErrorHandle;
264 uint16_t u16NumberOfMemDevices;
265} *PDMIRAMARRAY;
266AssertCompileSize(DMIRAMARRAY, 15);
267
268/** DMI Memory Device (Type 17) */
269typedef struct DMIMEMORYDEV
270{
271 DMIHDR header;
272 uint16_t u16PhysMemArrayHandle;
273 uint16_t u16MemErrHandle;
274 uint16_t u16TotalWidth;
275 uint16_t u16DataWidth;
276 uint16_t u16Size;
277 uint8_t u8FormFactor;
278 uint8_t u8DeviceSet;
279 uint8_t u8DeviceLocator;
280 uint8_t u8BankLocator;
281 uint8_t u8MemoryType;
282 uint16_t u16TypeDetail;
283 uint16_t u16Speed;
284 uint8_t u8Manufacturer;
285 uint8_t u8SerialNumber;
286 uint8_t u8AssetTag;
287 uint8_t u8PartNumber;
288 /* v2.6+ */
289 uint8_t u8Attributes;
290} *PDMIMEMORYDEV;
291AssertCompileSize(DMIMEMORYDEV, 28);
292
293/** MPS floating pointer structure */
294typedef struct MPSFLOATPTR
295{
296 uint8_t au8Signature[4];
297 uint32_t u32MPSAddr;
298 uint8_t u8Length;
299 uint8_t u8SpecRev;
300 uint8_t u8Checksum;
301 uint8_t au8Feature[5];
302} *PMPSFLOATPTR;
303AssertCompileSize(MPSFLOATPTR, 16);
304
305/** MPS config table header */
306typedef struct MPSCFGTBLHEADER
307{
308 uint8_t au8Signature[4];
309 uint16_t u16Length;
310 uint8_t u8SpecRev;
311 uint8_t u8Checksum;
312 uint8_t au8OemId[8];
313 uint8_t au8ProductId[12];
314 uint32_t u32OemTablePtr;
315 uint16_t u16OemTableSize;
316 uint16_t u16EntryCount;
317 uint32_t u32AddrLocalApic;
318 uint16_t u16ExtTableLength;
319 uint8_t u8ExtTableChecksum;
320 uint8_t u8Reserved;
321} *PMPSCFGTBLHEADER;
322AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
323
324/** MPS processor entry */
325typedef struct MPSPROCENTRY
326{
327 uint8_t u8EntryType;
328 uint8_t u8LocalApicId;
329 uint8_t u8LocalApicVersion;
330 uint8_t u8CPUFlags;
331 uint32_t u32CPUSignature;
332 uint32_t u32CPUFeatureFlags;
333 uint32_t u32Reserved[2];
334} *PMPSPROCENTRY;
335AssertCompileSize(MPSPROCENTRY, 20);
336
337/** MPS bus entry */
338typedef struct MPSBUSENTRY
339{
340 uint8_t u8EntryType;
341 uint8_t u8BusId;
342 uint8_t au8BusTypeStr[6];
343} *PMPSBUSENTRY;
344AssertCompileSize(MPSBUSENTRY, 8);
345
346/** MPS I/O-APIC entry */
347typedef struct MPSIOAPICENTRY
348{
349 uint8_t u8EntryType;
350 uint8_t u8Id;
351 uint8_t u8Version;
352 uint8_t u8Flags;
353 uint32_t u32Addr;
354} *PMPSIOAPICENTRY;
355AssertCompileSize(MPSIOAPICENTRY, 8);
356
357/** MPS I/O-Interrupt entry */
358typedef struct MPSIOINTERRUPTENTRY
359{
360 uint8_t u8EntryType;
361 uint8_t u8Type;
362 uint16_t u16Flags;
363 uint8_t u8SrcBusId;
364 uint8_t u8SrcBusIrq;
365 uint8_t u8DstIOAPICId;
366 uint8_t u8DstIOAPICInt;
367} *PMPSIOIRQENTRY;
368AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
369
370#pragma pack()
371
372
373/**
374 * Calculate a simple checksum for the MPS table.
375 *
376 * @param au8Data data
377 * @param u32Length size of data
378 */
379static uint8_t fwCommonChecksum(const uint8_t * const au8Data, uint32_t u32Length)
380{
381 uint8_t u8Sum = 0;
382 for (size_t i = 0; i < u32Length; ++i)
383 u8Sum += au8Data[i];
384 return -u8Sum;
385}
386
387#if 0 /* unused */
388static bool fwCommonChecksumOk(const uint8_t * const au8Data, uint32_t u32Length)
389{
390 uint8_t u8Sum = 0;
391 for (size_t i = 0; i < u32Length; i++)
392 u8Sum += au8Data[i];
393 return (u8Sum == 0);
394}
395#endif
396
397/**
398 * Try fetch the DMI strings from the system.
399 */
400static void fwCommonUseHostDMIStrings(void)
401{
402 int rc;
403
404 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME,
405 g_szHostDmiSystemProduct, sizeof(g_szHostDmiSystemProduct));
406 if (RT_SUCCESS(rc))
407 {
408 g_pszDefDmiSystemProduct = g_szHostDmiSystemProduct;
409 LogRel(("DMI: Using DmiSystemProduct from host: %s\n", g_szHostDmiSystemProduct));
410 }
411
412 rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION,
413 g_szHostDmiSystemVersion, sizeof(g_szHostDmiSystemVersion));
414 if (RT_SUCCESS(rc))
415 {
416 g_pszDefDmiSystemVersion = g_szHostDmiSystemVersion;
417 LogRel(("DMI: Using DmiSystemVersion from host: %s\n", g_szHostDmiSystemVersion));
418 }
419}
420
421/**
422 * Construct the DMI table.
423 *
424 * @returns VBox status code.
425 * @param pDevIns The device instance.
426 * @param pTable Where to create the DMI table.
427 * @param cbMax The maximum size of the DMI table.
428 * @param pUuid Pointer to the UUID to use if the DmiUuid
429 * configuration string isn't present.
430 * @param pCfg The handle to our config node.
431 * @param cCpus Number of VCPUs.
432 * @param pcbDmiTables Size of DMI data in bytes.
433 * @param pcNumDmiTables Number of DMI tables.
434 */
435int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg, uint16_t cCpus, uint16_t *pcbDmiTables, uint16_t *pcNumDmiTables)
436{
437 /*
438 * CFGM Hint!
439 *
440 * The macros below makes it a bit hard to figure out the config options
441 * available here. To get a quick hint, take a look a the CFGM
442 * validation in the calling code (DevEFI.cpp and DevPcBios.cpp).
443 *
444 * 32-bit signed integer CFGM options are read by DMI_READ_CFG_S32, the 2nd
445 * parameter is the CFGM value name.
446 *
447 * Strings are read by DMI_READ_CFG_STR and DMI_READ_CFG_STR_DEF, the 2nd parameter is
448 * the CFGM value name.
449 */
450#define DMI_CHECK_SIZE(cbWant) \
451 { \
452 size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
453 if (cbNeed > cbMax) \
454 { \
455 if (fHideErrors) \
456 { \
457 LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
458 continue; \
459 } \
460 return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
461 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); \
462 } \
463 }
464
465#define DMI_READ_CFG_STR_DEF(variable, name, default_value) \
466 { \
467 if (fForceDefault) \
468 pszTmp = default_value; \
469 else \
470 { \
471 rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
472 if (RT_FAILURE(rc)) \
473 { \
474 if (fHideErrors) \
475 { \
476 LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
477 continue; \
478 } \
479 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
480 N_("Configuration error: Querying \"" name "\" as a string failed")); \
481 } \
482 else if (!strcmp(szBuf, "<EMPTY>")) \
483 pszTmp = ""; \
484 else \
485 pszTmp = szBuf; \
486 } \
487 if (!pszTmp[0]) \
488 variable = 0; /* empty string */ \
489 else \
490 { \
491 variable = iStrNr++; \
492 size_t cStr = strlen(pszTmp) + 1; \
493 DMI_CHECK_SIZE(cStr); \
494 memcpy(pszStr, pszTmp, cStr); \
495 pszStr += cStr ; \
496 } \
497 }
498
499#define DMI_READ_CFG_STR(variable, name) \
500 DMI_READ_CFG_STR_DEF(variable, # name, g_pszDef ## name)
501
502#define DMI_READ_CFG_S32(variable, name) \
503 { \
504 if (fForceDefault) \
505 variable = g_iDef ## name; \
506 else \
507 { \
508 rc = CFGMR3QueryS32Def(pCfg, # name, & variable, g_iDef ## name); \
509 if (RT_FAILURE(rc)) \
510 { \
511 if (fHideErrors) \
512 { \
513 LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
514 continue; \
515 } \
516 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
517 N_("Configuration error: Querying \"" # name "\" as an int failed")); \
518 } \
519 } \
520 }
521
522#define DMI_START_STRUCT(tbl) \
523 pszStr = (char *)(tbl + 1); \
524 iStrNr = 1;
525
526#define DMI_TERM_STRUCT \
527 { \
528 *pszStr++ = '\0'; /* terminate set of text strings */ \
529 if (iStrNr == 1) \
530 *pszStr++ = '\0'; /* terminate a structure without strings */ \
531 }
532
533 bool fForceDefault = false;
534#ifdef VBOX_BIOS_DMI_FALLBACK
535 /*
536 * There will be two passes. If an error occurs during the first pass, a
537 * message will be written to the release log and we fall back to default
538 * DMI data and start a second pass.
539 */
540 bool fHideErrors = true;
541#else
542 /*
543 * There will be one pass, every error is fatal and will prevent the VM
544 * from starting.
545 */
546 bool fHideErrors = false;
547#endif
548
549 uint8_t fDmiUseHostInfo;
550 int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
551 if (RT_FAILURE (rc))
552 return PDMDEV_SET_ERROR(pDevIns, rc,
553 N_("Configuration error: Failed to read \"DmiUseHostInfo\""));
554
555 /* Sync up with host default DMI values */
556 if (fDmiUseHostInfo)
557 fwCommonUseHostDMIStrings();
558
559 uint8_t fDmiExposeMemoryTable;
560 rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0);
561 if (RT_FAILURE (rc))
562 return PDMDEV_SET_ERROR(pDevIns, rc,
563 N_("Configuration error: Failed to read \"DmiExposeMemoryTable\""));
564 uint8_t fDmiExposeProcessorInf;
565 rc = CFGMR3QueryU8Def(pCfg, "DmiExposeProcInf", &fDmiExposeProcessorInf, 0);
566 if (RT_FAILURE (rc))
567 return PDMDEV_SET_ERROR(pDevIns, rc,
568 N_("Configuration error: Failed to read \"DmiExposeProcInf\""));
569
570 for (;; fForceDefault = true, fHideErrors = false)
571 {
572 int iStrNr;
573 char szBuf[256];
574 char *pszStr = (char *)pTable;
575 char szDmiSystemUuid[64];
576 char *pszDmiSystemUuid;
577 const char *pszTmp;
578
579 if (fForceDefault)
580 pszDmiSystemUuid = NULL;
581 else
582 {
583 rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
584 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
585 pszDmiSystemUuid = NULL;
586 else if (RT_FAILURE(rc))
587 {
588 if (fHideErrors)
589 {
590 LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
591 continue;
592 }
593 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
594 N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
595 }
596 else
597 pszDmiSystemUuid = szDmiSystemUuid;
598 }
599
600 /*********************************
601 * DMI BIOS information (Type 0) *
602 *********************************/
603 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
604 DMI_CHECK_SIZE(sizeof(*pBIOSInf));
605
606 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
607 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
608
609 /* don't set these fields by default for legacy compatibility */
610 int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
611 DMI_READ_CFG_S32(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
612 DMI_READ_CFG_S32(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
613 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
614 {
615 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
616 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
617 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
618 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
619
620 int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
621 DMI_READ_CFG_S32(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
622 DMI_READ_CFG_S32(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
623 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
624 {
625 pszStr = (char *)(pBIOSInf + 1);
626 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
627 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
628 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
629 }
630 }
631
632 iStrNr = 1;
633 pBIOSInf->header.u8Type = 0; /* BIOS Information */
634 pBIOSInf->header.u16Handle = 0x0000;
635 DMI_READ_CFG_STR(pBIOSInf->u8Vendor, DmiBIOSVendor);
636 DMI_READ_CFG_STR(pBIOSInf->u8Version, DmiBIOSVersion);
637 pBIOSInf->u16Start = 0xE000;
638 DMI_READ_CFG_STR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
639 pBIOSInf->u8ROMSize = 1; /* 128K */
640 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
641 | RT_BIT(7) /* PCI is supported */
642 | RT_BIT(15) /* Boot from CD is supported */
643 | RT_BIT(16) /* Selectable Boot is supported */
644 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
645 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
646 /* any more?? */
647 ;
648 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
649 /* any more?? */
650 ;
651 pBIOSInf->u8CharacteristicsByte2 = 0
652 /* any more?? */
653 ;
654 DMI_TERM_STRUCT;
655
656 /***********************************
657 * DMI system information (Type 1) *
658 ***********************************/
659 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
660 DMI_CHECK_SIZE(sizeof(*pSystemInf));
661 DMI_START_STRUCT(pSystemInf);
662 pSystemInf->header.u8Type = 1; /* System Information */
663 pSystemInf->header.u8Length = sizeof(*pSystemInf);
664 pSystemInf->header.u16Handle = 0x0001;
665 DMI_READ_CFG_STR(pSystemInf->u8Manufacturer, DmiSystemVendor);
666 DMI_READ_CFG_STR(pSystemInf->u8ProductName, DmiSystemProduct);
667 DMI_READ_CFG_STR(pSystemInf->u8Version, DmiSystemVersion);
668 DMI_READ_CFG_STR(pSystemInf->u8SerialNumber, DmiSystemSerial);
669
670 RTUUID uuid;
671 if (pszDmiSystemUuid)
672 {
673 rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
674 if (RT_FAILURE(rc))
675 {
676 if (fHideErrors)
677 {
678 LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
679 continue;
680 }
681 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
682 N_("Configuration error: Invalid UUID for DMI tables specified"));
683 }
684 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
685 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
686 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
687 pUuid = &uuid;
688 }
689 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
690
691 pSystemInf->u8WakeupType = 6; /* Power Switch */
692 DMI_READ_CFG_STR(pSystemInf->u8SKUNumber, DmiSystemSKU);
693 DMI_READ_CFG_STR(pSystemInf->u8Family, DmiSystemFamily);
694 DMI_TERM_STRUCT;
695
696 /**********************************
697 * DMI board information (Type 2) *
698 **********************************/
699 PDMIBOARDINF pBoardInf = (PDMIBOARDINF)pszStr;
700 DMI_CHECK_SIZE(sizeof(*pBoardInf));
701 DMI_START_STRUCT(pBoardInf);
702 int iDmiBoardBoardType;
703 pBoardInf->header.u8Type = 2; /* Board Information */
704 pBoardInf->header.u8Length = sizeof(*pBoardInf);
705 pBoardInf->header.u16Handle = 0x0008;
706 DMI_READ_CFG_STR(pBoardInf->u8Manufacturer, DmiBoardVendor);
707 DMI_READ_CFG_STR(pBoardInf->u8Product, DmiBoardProduct);
708 DMI_READ_CFG_STR(pBoardInf->u8Version, DmiBoardVersion);
709 DMI_READ_CFG_STR(pBoardInf->u8SerialNumber, DmiBoardSerial);
710 DMI_READ_CFG_STR(pBoardInf->u8AssetTag, DmiBoardAssetTag);
711 pBoardInf->u8FeatureFlags = RT_BIT(0) /* hosting board, e.g. motherboard */
712 ;
713 DMI_READ_CFG_STR(pBoardInf->u8LocationInChass, DmiBoardLocInChass);
714 pBoardInf->u16ChassisHandle = 0x0003; /* see type 3 */
715 DMI_READ_CFG_S32(iDmiBoardBoardType, DmiBoardBoardType);
716 pBoardInf->u8BoardType = iDmiBoardBoardType;
717 pBoardInf->u8cObjectHandles = 0;
718
719 DMI_TERM_STRUCT;
720
721 /********************************************
722 * DMI System Enclosure or Chassis (Type 3) *
723 ********************************************/
724 PDMICHASSIS pChassis = (PDMICHASSIS)pszStr;
725 DMI_CHECK_SIZE(sizeof(*pChassis));
726 pszStr = (char*)&pChassis->u32OEMdefined;
727 iStrNr = 1;
728#ifdef VBOX_WITH_DMI_CHASSIS
729 pChassis->header.u8Type = 3; /* System Enclosure or Chassis */
730#else
731 pChassis->header.u8Type = 0x7e; /* inactive */
732#endif
733 pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
734 pChassis->header.u16Handle = 0x0003;
735 DMI_READ_CFG_STR(pChassis->u8Manufacturer, DmiChassisVendor);
736 int iDmiChassisType;
737 DMI_READ_CFG_S32(iDmiChassisType, DmiChassisType);
738 pChassis->u8Type = iDmiChassisType;
739 DMI_READ_CFG_STR(pChassis->u8Version, DmiChassisVersion);
740 DMI_READ_CFG_STR(pChassis->u8SerialNumber, DmiChassisSerial);
741 DMI_READ_CFG_STR(pChassis->u8AssetTag, DmiChassisAssetTag);
742 pChassis->u8BootupState = 0x03; /* safe */
743 pChassis->u8PowerSupplyState = 0x03; /* safe */
744 pChassis->u8ThermalState = 0x03; /* safe */
745 pChassis->u8SecurityStatus = 0x03; /* none XXX */
746# if 0
747 /* v2.3+, currently not supported */
748 pChassis->u32OEMdefined = 0;
749 pChassis->u8Height = 0; /* unspecified */
750 pChassis->u8NumPowerChords = 0; /* unspecified */
751 pChassis->u8ContElems = 0; /* no contained elements */
752 pChassis->u8ContElemRecLen = 0; /* no contained elements */
753# endif
754 DMI_TERM_STRUCT;
755
756 /**************************************
757 * DMI Processor Information (Type 4) *
758 **************************************/
759
760 /*
761 * This is just a dummy processor. Should we expose the real guest CPU features
762 * here? Accessing this information at this point is difficult.
763 */
764 char szSocket[32];
765 PDMIPROCESSORINF pProcessorInf = (PDMIPROCESSORINF)pszStr;
766 DMI_CHECK_SIZE(sizeof(*pProcessorInf));
767 DMI_START_STRUCT(pProcessorInf);
768 if (fDmiExposeProcessorInf)
769 pProcessorInf->header.u8Type = 4; /* Processor Information */
770 else
771 pProcessorInf->header.u8Type = 126; /* inactive structure */
772 pProcessorInf->header.u8Length = sizeof(*pProcessorInf);
773 pProcessorInf->header.u16Handle = 0x0007;
774 RTStrPrintf(szSocket, sizeof(szSocket), "Socket #%u", 0);
775 pProcessorInf->u8SocketDesignation = iStrNr++;
776 {
777 size_t cStr = strlen(szSocket) + 1;
778 DMI_CHECK_SIZE(cStr);
779 memcpy(pszStr, szSocket, cStr);
780 pszStr += cStr;
781 }
782 pProcessorInf->u8ProcessorType = 0x03; /* Central Processor */
783 pProcessorInf->u8ProcessorFamily = 0xB1; /* Pentium III with Intel SpeedStep(TM) */
784 DMI_READ_CFG_STR(pProcessorInf->u8ProcessorManufacturer, DmiProcManufacturer);
785
786 pProcessorInf->u64ProcessorID = UINT64_C(0x0FEBFBFF00010676);
787 /* Ext Family ID = 0
788 * Ext Model ID = 2
789 * Processor Type = 0
790 * Family ID = 6
791 * Model = 7
792 * Stepping = 6
793 * Features: FPU, VME, DE, PSE, TSC, MSR, PAE, MCE, CX8,
794 * APIC, SEP, MTRR, PGE, MCA, CMOV, PAT, PSE-36,
795 * CFLSH, DS, ACPI, MMX, FXSR, SSE, SSE2, SS */
796 DMI_READ_CFG_STR(pProcessorInf->u8ProcessorVersion, DmiProcVersion);
797 pProcessorInf->u8Voltage = 0x02; /* 3.3V */
798 pProcessorInf->u16ExternalClock = 0x00; /* unknown */
799 pProcessorInf->u16MaxSpeed = 3000; /* 3GHz */
800 pProcessorInf->u16CurrentSpeed = 3000; /* 3GHz */
801 pProcessorInf->u8Status = RT_BIT(6) /* CPU socket populated */
802 | RT_BIT(0) /* CPU enabled */
803 ;
804 pProcessorInf->u8ProcessorUpgrade = 0x04; /* ZIF Socket */
805 pProcessorInf->u16L1CacheHandle = 0xFFFF; /* not specified */
806 pProcessorInf->u16L2CacheHandle = 0xFFFF; /* not specified */
807 pProcessorInf->u16L3CacheHandle = 0xFFFF; /* not specified */
808 pProcessorInf->u8SerialNumber = 0; /* not specified */
809 pProcessorInf->u8AssetTag = 0; /* not specified */
810 pProcessorInf->u8PartNumber = 0; /* not specified */
811 pProcessorInf->u8CoreCount = cCpus; /* */
812 pProcessorInf->u8CoreEnabled = cCpus;
813 pProcessorInf->u8ThreadCount = 1;
814 pProcessorInf->u16ProcessorCharacteristics
815 = RT_BIT(2); /* 64-bit capable */
816 pProcessorInf->u16ProcessorFamily2 = 0;
817 DMI_TERM_STRUCT;
818
819 /***************************************
820 * DMI Physical Memory Array (Type 16) *
821 ***************************************/
822 uint64_t const cbRamSize = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
823
824 PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
825 DMI_CHECK_SIZE(sizeof(*pMemArray));
826 DMI_START_STRUCT(pMemArray);
827 if (fDmiExposeMemoryTable)
828 pMemArray->header.u8Type = 16; /* Physical Memory Array */
829 else
830 pMemArray->header.u8Type = 126; /* inactive structure */
831 pMemArray->header.u8Length = sizeof(*pMemArray);
832 pMemArray->header.u16Handle = 0x0005;
833 pMemArray->u8Location = 0x03; /* Motherboard */
834 pMemArray->u8Use = 0x03; /* System memory */
835 pMemArray->u8MemErrorCorrection = 0x01; /* Other */
836 if (cbRamSize / _1K > INT32_MAX)
837 {
838 /** @todo 2TB-1K limit. In such cases we probably need to provide multiple type-16 descriptors.
839 * Or use 0x8000'0000 = 'capacity unknown'? */
840 AssertLogRelMsgFailed(("DMI: RAM size %#RX64 does not fit into type-16 descriptor, clipping to %#RX64\n",
841 cbRamSize, (uint64_t)INT32_MAX * _1K));
842 pMemArray->u32MaxCapacity = INT32_MAX;
843 }
844 else
845 pMemArray->u32MaxCapacity = (int32_t)(cbRamSize / _1K); /* RAM size in K */
846 pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */
847 pMemArray->u16NumberOfMemDevices = 1;
848 DMI_TERM_STRUCT;
849
850 /***************************************
851 * DMI Memory Device (Type 17) *
852 ***************************************/
853 PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr;
854 DMI_CHECK_SIZE(sizeof(*pMemDev));
855 DMI_START_STRUCT(pMemDev);
856 if (fDmiExposeMemoryTable)
857 pMemDev->header.u8Type = 17; /* Memory Device */
858 else
859 pMemDev->header.u8Type = 126; /* inactive structure */
860 pMemDev->header.u8Length = sizeof(*pMemDev);
861 pMemDev->header.u16Handle = 0x0006;
862 pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */
863 pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */
864 pMemDev->u16TotalWidth = 0xffff; /* Unknown */
865 pMemDev->u16DataWidth = 0xffff; /* Unknown */
866 int16_t u16RamSizeM;
867 if (cbRamSize / _1M > INT16_MAX)
868 {
869 /** @todo 32G-1M limit. Provide multiple type-17 descriptors.
870 * The highest bit of u16Size must be 0 to specify 'GB' units / 1 would be 'KB' */
871 AssertLogRelMsgFailed(("DMI: RAM size %#RX64 too big for one type-17 descriptor, clipping to %#RX64\n",
872 cbRamSize, (uint64_t)INT16_MAX * _1M));
873 u16RamSizeM = INT16_MAX;
874 }
875 else
876 u16RamSizeM = (uint16_t)(cbRamSize / _1M);
877 if (u16RamSizeM == 0)
878 u16RamSizeM = 0x400; /* 1G */
879 pMemDev->u16Size = u16RamSizeM; /* RAM size */
880 pMemDev->u8FormFactor = 0x09; /* DIMM */
881 pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */
882 DMI_READ_CFG_STR_DEF(pMemDev->u8DeviceLocator, " ", "DIMM 0");
883 DMI_READ_CFG_STR_DEF(pMemDev->u8BankLocator, " ", "Bank 0");
884 pMemDev->u8MemoryType = 0x03; /* DRAM */
885 pMemDev->u16TypeDetail = 0; /* Nothing special */
886 pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */
887 DMI_READ_CFG_STR(pMemDev->u8Manufacturer, DmiSystemVendor);
888 DMI_READ_CFG_STR_DEF(pMemDev->u8SerialNumber, " ", "00000000");
889 DMI_READ_CFG_STR_DEF(pMemDev->u8AssetTag, " ", "00000000");
890 DMI_READ_CFG_STR_DEF(pMemDev->u8PartNumber, " ", "00000000");
891 pMemDev->u8Attributes = 0; /* Unknown */
892 DMI_TERM_STRUCT;
893
894 /*****************************
895 * DMI OEM strings (Type 11) *
896 *****************************/
897 PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr;
898 DMI_CHECK_SIZE(sizeof(*pOEMStrings));
899 DMI_START_STRUCT(pOEMStrings);
900#ifdef VBOX_WITH_DMI_OEMSTRINGS
901 pOEMStrings->header.u8Type = 0xb; /* OEM Strings */
902#else
903 pOEMStrings->header.u8Type = 126; /* inactive structure */
904#endif
905 pOEMStrings->header.u8Length = sizeof(*pOEMStrings);
906 pOEMStrings->header.u16Handle = 0x0002;
907 pOEMStrings->u8Count = 2;
908
909 char szTmp[64];
910 RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
911 RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
912 DMI_READ_CFG_STR_DEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
913 RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
914 DMI_READ_CFG_STR_DEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
915 DMI_TERM_STRUCT;
916
917 /*************************************
918 * DMI OEM specific table (Type 128) *
919 ************************************/
920 PDMIOEMSPECIFIC pOEMSpecific = (PDMIOEMSPECIFIC)pszStr;
921 DMI_CHECK_SIZE(sizeof(*pOEMSpecific));
922 DMI_START_STRUCT(pOEMSpecific);
923 pOEMSpecific->header.u8Type = 0x80; /* OEM specific */
924 pOEMSpecific->header.u8Length = sizeof(*pOEMSpecific);
925 pOEMSpecific->header.u16Handle = 0x0008; /* Just next free handle */
926 pOEMSpecific->u32CpuFreqKHz = RT_H2LE_U32((uint32_t)((uint64_t)TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns)) / 1000));
927 DMI_TERM_STRUCT;
928
929 /* End-of-table marker - includes padding to account for fixed table size. */
930 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
931 pszStr = (char *)(pEndOfTable + 1);
932 pEndOfTable->u8Type = 0x7f;
933
934 pEndOfTable->u8Length = sizeof(*pEndOfTable);
935 pEndOfTable->u16Handle = 0xFEFF;
936 *pcbDmiTables = ((uintptr_t)pszStr - (uintptr_t)pTable) + 2;
937
938 /* We currently plant 10 DMI tables. Update this if tables number changed. */
939 *pcNumDmiTables = 10;
940
941 /* If more fields are added here, fix the size check in DMI_READ_CFG_STR */
942
943 /* Success! */
944 break;
945 }
946
947#undef DMI_READ_CFG_STR
948#undef DMI_READ_CFG_S32
949#undef DMI_CHECK_SIZE
950 return VINF_SUCCESS;
951}
952
953/**
954 * Construct the SMBIOS and DMI headers table pointer at VM construction and
955 * reset.
956 *
957 * @param pDevIns The device instance data.
958 * @param cbDmiTables Size of all DMI tables planted in bytes.
959 * @param cNumDmiTables Number of DMI tables planted.
960 */
961void FwCommonPlantSmbiosAndDmiHdrs(PPDMDEVINS pDevIns, uint16_t cbDmiTables, uint16_t cNumDmiTables)
962{
963 struct
964 {
965 struct SMBIOSHDR smbios;
966 struct DMIMAINHDR dmi;
967 }
968 aBiosHeaders =
969 {
970 // The SMBIOS header
971 {
972 { 0x5f, 0x53, 0x4d, 0x5f}, // "_SM_" signature
973 0x00, // checksum
974 0x1f, // EPS length, defined by standard
975 VBOX_SMBIOS_MAJOR_VER, // SMBIOS major version
976 VBOX_SMBIOS_MINOR_VER, // SMBIOS minor version
977 VBOX_SMBIOS_MAXSS, // Maximum structure size
978 0x00, // Entry point revision
979 { 0x00, 0x00, 0x00, 0x00, 0x00 } // padding
980 },
981 // The DMI header
982 {
983 { 0x5f, 0x44, 0x4d, 0x49, 0x5f }, // "_DMI_" signature
984 0x00, // checksum
985 0, // DMI tables length
986 VBOX_DMI_TABLE_BASE, // DMI tables base
987 0, // DMI tables entries
988 VBOX_DMI_TABLE_VER, // DMI version
989 }
990 };
991
992 aBiosHeaders.dmi.u16TablesLength = cbDmiTables;
993 aBiosHeaders.dmi.u16TableEntries = cNumDmiTables;
994 aBiosHeaders.smbios.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.smbios, sizeof(aBiosHeaders.smbios));
995 aBiosHeaders.dmi.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.dmi, sizeof(aBiosHeaders.dmi));
996
997 PDMDevHlpPhysWrite(pDevIns, 0xfe300, &aBiosHeaders, sizeof(aBiosHeaders));
998}
999
1000/**
1001 * Construct the MPS table for implanting as a ROM page.
1002 *
1003 * Only applicable if IOAPIC is active!
1004 *
1005 * See ``MultiProcessor Specification Version 1.4 (May 1997)'':
1006 * ``1.3 Scope
1007 * ...
1008 * The hardware required to implement the MP specification is kept to a
1009 * minimum, as follows:
1010 * * One or more processors that are Intel architecture instruction set
1011 * compatible, such as the CPUs in the Intel486 or Pentium processor
1012 * family.
1013 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
1014 * Interrupt Controller or the integrated APIC, such as that on the
1015 * Intel Pentium 735\\90 and 815\\100 processors, together with a discrete
1016 * I/O APIC unit.''
1017 * and later:
1018 * ``4.3.3 I/O APIC Entries
1019 * The configuration table contains one or more entries for I/O APICs.
1020 * ...
1021 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
1022 * operating system should not attempt to access
1023 * this I/O APIC.
1024 * At least one I/O APIC must be enabled.''
1025 *
1026 * @param pDevIns The device instance data.
1027 * @param pTable Where to write the table.
1028 * @param cbMax The maximum size of the MPS table.
1029 * @param cCpus The number of guest CPUs.
1030 */
1031void FwCommonPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, uint16_t cCpus)
1032{
1033 RT_NOREF1(cbMax);
1034
1035 /* configuration table */
1036 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
1037 memcpy(pCfgTab->au8Signature, "PCMP", 4);
1038 pCfgTab->u8SpecRev = 4; /* 1.4 */
1039 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
1040 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
1041 pCfgTab->u32OemTablePtr = 0;
1042 pCfgTab->u16OemTableSize = 0;
1043 pCfgTab->u16EntryCount = 0; /* Incremented as we go. */
1044 pCfgTab->u32AddrLocalApic = 0xfee00000;
1045 pCfgTab->u16ExtTableLength = 0;
1046 pCfgTab->u8ExtTableChecksum = 0;
1047 pCfgTab->u8Reserved = 0;
1048
1049 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
1050 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
1051 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
1052 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1053 if (u32Eax >= 1)
1054 {
1055 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1056 u32CPUSignature = u32Eax & 0xfff;
1057 /* Local APIC will be enabled later so override it here. Since we provide
1058 * an MP table we have an IOAPIC and therefore a Local APIC. */
1059 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
1060 }
1061 /* Construct MPS table for each VCPU. */
1062 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
1063 for (int i = 0; i < cCpus; i++)
1064 {
1065 pProcEntry->u8EntryType = 0; /* processor entry */
1066 pProcEntry->u8LocalApicId = i;
1067 pProcEntry->u8LocalApicVersion = 0x14;
1068 pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
1069 pProcEntry->u32CPUSignature = u32CPUSignature;
1070 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
1071 pProcEntry->u32Reserved[0] =
1072 pProcEntry->u32Reserved[1] = 0;
1073 pProcEntry++;
1074 pCfgTab->u16EntryCount++;
1075 }
1076
1077 uint32_t iBusIdIsa = 0;
1078 uint32_t iBusIdPci0 = 1;
1079
1080 /* ISA bus */
1081 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)pProcEntry;
1082 pBusEntry->u8EntryType = 1; /* bus entry */
1083 pBusEntry->u8BusId = iBusIdIsa; /* this ID is referenced by the interrupt entries */
1084 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
1085 pBusEntry++;
1086 pCfgTab->u16EntryCount++;
1087
1088 /* PCI bus */
1089 pBusEntry->u8EntryType = 1; /* bus entry */
1090 pBusEntry->u8BusId = iBusIdPci0; /* this ID can be referenced by the interrupt entries */
1091 memcpy(pBusEntry->au8BusTypeStr, "PCI ", 6);
1092 pBusEntry++;
1093 pCfgTab->u16EntryCount++;
1094
1095
1096 /* I/O-APIC.
1097 * MP spec: "The configuration table contains one or more entries for I/O APICs.
1098 * ... At least one I/O APIC must be enabled." */
1099 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry);
1100 uint16_t iApicId = 0;
1101 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
1102 pIOAPICEntry->u8Id = iApicId; /* this ID is referenced by the interrupt entries */
1103 pIOAPICEntry->u8Version = 0x11;
1104 pIOAPICEntry->u8Flags = 1 /* enable */;
1105 pIOAPICEntry->u32Addr = 0xfec00000;
1106 pCfgTab->u16EntryCount++;
1107
1108 /* Interrupt tables */
1109 /* Bus vectors */
1110 /* Note: The PIC is currently not routed to the I/O APIC. Therefore we skip
1111 * pin 0 on the I/O APIC.
1112 */
1113 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
1114 for (int iPin = 1; iPin < 16; iPin++, pIrqEntry++)
1115 {
1116 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
1117 /*
1118 * 0 - INT, vectored interrupt,
1119 * 3 - ExtINT, vectored interrupt provided by PIC
1120 * As we emulate system with both APIC and PIC, it's needed for their coexistence.
1121 */
1122 pIrqEntry->u8Type = (iPin == 0) ? 3 : 0;
1123 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
1124 trigger mode = conforms to bus */
1125 pIrqEntry->u8SrcBusId = iBusIdIsa; /* ISA bus */
1126 /* IRQ0 mapped to pin 2, other are identity mapped */
1127 /* If changing, also update PDMIsaSetIrq() and MADT */
1128 pIrqEntry->u8SrcBusIrq = (iPin == 2) ? 0 : iPin; /* IRQ on the bus */
1129 pIrqEntry->u8DstIOAPICId = iApicId; /* destination IO-APIC */
1130 pIrqEntry->u8DstIOAPICInt = iPin; /* pin on destination IO-APIC */
1131 pCfgTab->u16EntryCount++;
1132 }
1133 /* Local delivery */
1134 pIrqEntry->u8EntryType = 4; /* Local interrupt entry */
1135 pIrqEntry->u8Type = 3; /* ExtINT */
1136 pIrqEntry->u16Flags = (1 << 2) | 1; /* active-high, edge-triggered */
1137 pIrqEntry->u8SrcBusId = iBusIdIsa;
1138 pIrqEntry->u8SrcBusIrq = 0;
1139 pIrqEntry->u8DstIOAPICId = 0xff;
1140 pIrqEntry->u8DstIOAPICInt = 0;
1141 pIrqEntry++;
1142 pCfgTab->u16EntryCount++;
1143 pIrqEntry->u8EntryType = 4; /* Local interrupt entry */
1144 pIrqEntry->u8Type = 1; /* NMI */
1145 pIrqEntry->u16Flags = (1 << 2) | 1; /* active-high, edge-triggered */
1146 pIrqEntry->u8SrcBusId = iBusIdIsa;
1147 pIrqEntry->u8SrcBusIrq = 0;
1148 pIrqEntry->u8DstIOAPICId = 0xff;
1149 pIrqEntry->u8DstIOAPICInt = 1;
1150 pIrqEntry++;
1151 pCfgTab->u16EntryCount++;
1152
1153 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
1154 pCfgTab->u8Checksum = fwCommonChecksum(pTable, pCfgTab->u16Length);
1155
1156 AssertMsg(pCfgTab->u16Length < cbMax,
1157 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
1158 pCfgTab->u16Length, cbMax));
1159}
1160
1161/**
1162 * Construct the MPS table pointer at VM construction and reset.
1163 *
1164 * Only applicable if IOAPIC is active!
1165 *
1166 * @param pDevIns The device instance data.
1167 */
1168void FwCommonPlantMpsFloatPtr(PPDMDEVINS pDevIns)
1169{
1170 MPSFLOATPTR floatPtr;
1171 floatPtr.au8Signature[0] = '_';
1172 floatPtr.au8Signature[1] = 'M';
1173 floatPtr.au8Signature[2] = 'P';
1174 floatPtr.au8Signature[3] = '_';
1175 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
1176 floatPtr.u8Length = 1; /* structure size in paragraphs */
1177 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
1178 floatPtr.u8Checksum = 0;
1179 floatPtr.au8Feature[0] = 0;
1180 floatPtr.au8Feature[1] = 0;
1181 floatPtr.au8Feature[2] = 0;
1182 floatPtr.au8Feature[3] = 0;
1183 floatPtr.au8Feature[4] = 0;
1184 floatPtr.u8Checksum = fwCommonChecksum((uint8_t*)&floatPtr, 16);
1185 PDMDevHlpPhysWrite(pDevIns, 0x9fff0, &floatPtr, 16);
1186}
1187
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