VirtualBox

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

Last change on this file since 49469 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

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