VirtualBox

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

Last change on this file since 39931 was 39707, checked in by vboxsync, 13 years ago

BIOS: allow to expose the processor informtion

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