VirtualBox

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

Last change on this file since 44760 was 44752, checked in by vboxsync, 12 years ago

DMI: update Processor Information table (tyoe 4): do not refer to non-existent Cache Information table (type 7) handles since we do not provide them.

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