VirtualBox

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

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

Devices/PC/DMI: added DmiChassisType and fixed documentation of DmiBoardBoardType

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