VirtualBox

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

Last change on this file since 24873 was 24706, checked in by vboxsync, 15 years ago

EFI: ACPI work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: DevFwCommon.cpp 24706 2009-11-16 17:57:20Z vboxsync $ */
2/** @file
3 * Shared firmware code.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25/** @todo: what should it be? */
26#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
27#include <VBox/pdmdev.h>
28
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/alloc.h>
32#include <iprt/buildconfig.h>
33#include <iprt/file.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <VBox/err.h>
37#include <VBox/param.h>
38
39#include "../Builtins.h"
40#include "../Builtins2.h"
41#include "DevFwCommon.h"
42
43#pragma pack(1)
44
45/** DMI header */
46typedef struct DMIHDR
47{
48 uint8_t u8Type;
49 uint8_t u8Length;
50 uint16_t u16Handle;
51} *PDMIHDR;
52AssertCompileSize(DMIHDR, 4);
53
54/** DMI BIOS information (Type 0) */
55typedef struct DMIBIOSINF
56{
57 DMIHDR header;
58 uint8_t u8Vendor;
59 uint8_t u8Version;
60 uint16_t u16Start;
61 uint8_t u8Release;
62 uint8_t u8ROMSize;
63 uint64_t u64Characteristics;
64 uint8_t u8CharacteristicsByte1;
65 uint8_t u8CharacteristicsByte2;
66 uint8_t u8ReleaseMajor;
67 uint8_t u8ReleaseMinor;
68 uint8_t u8FirmwareMajor;
69 uint8_t u8FirmwareMinor;
70} *PDMIBIOSINF;
71AssertCompileSize(DMIBIOSINF, 0x18);
72
73/** DMI system information (Type 1) */
74typedef struct DMISYSTEMINF
75{
76 DMIHDR header;
77 uint8_t u8Manufacturer;
78 uint8_t u8ProductName;
79 uint8_t u8Version;
80 uint8_t u8SerialNumber;
81 uint8_t au8Uuid[16];
82 uint8_t u8WakeupType;
83 uint8_t u8SKUNumber;
84 uint8_t u8Family;
85} *PDMISYSTEMINF;
86AssertCompileSize(DMISYSTEMINF, 0x1b);
87
88/** DMI system enclosure or chassis type (Type 3) */
89typedef struct DMICHASSIS
90{
91 DMIHDR header;
92 uint8_t u8Manufacturer;
93 uint8_t u8Type;
94 uint8_t u8Version;
95 uint8_t u8SerialNumber;
96 uint8_t u8AssetTag;
97 uint8_t u8BootupState;
98 uint8_t u8PowerSupplyState;
99 uint8_t u8ThermalState;
100 uint8_t u8SecurityStatus;
101 /* v2.3+, currently not supported */
102 uint32_t u32OEMdefined;
103 uint8_t u8Height;
104 uint8_t u8NumPowerChords;
105 uint8_t u8ContElems;
106 uint8_t u8ContElemRecLen;
107} *PDMICHASSIS;
108AssertCompileSize(DMICHASSIS, 0x15);
109
110/** DMI processor information (Type 4) */
111typedef struct DMIPROCESSORINF
112{
113 DMIHDR header;
114 uint8_t u8SocketDesignation;
115 uint8_t u8ProcessorType;
116 uint8_t u8ProcessorFamily;
117 uint8_t u8ProcessorManufacturer;
118 uint64_t u64ProcessorIdentification;
119 uint8_t u8ProcessorVersion;
120 uint8_t u8Voltage;
121 uint16_t u16ExternalClock;
122 uint16_t u16MaxSpeed;
123 uint16_t u16CurrentSpeed;
124 uint8_t u8Status;
125 uint8_t u8ProcessorUpgrade;
126 uint16_t u16L1CacheHandle;
127 uint16_t u16L2CacheHandle;
128 uint16_t u16L3CacheHandle;
129 uint8_t u8SerialNumber;
130 uint8_t u8AssetTag;
131 uint8_t u8PartNumber;
132 uint8_t u8CoreCount;
133 uint8_t u8CoreEnabled;
134 uint8_t u8ThreadCount;
135 uint16_t u16ProcessorCharacteristics;
136 uint16_t u16ProcessorFamily2;
137} *PDMIPROCESSORINF;
138AssertCompileSize(DMIPROCESSORINF, 0x2a);
139
140/** DMI OEM strings (Type 11) */
141typedef struct DMIOEMSTRINGS
142{
143 DMIHDR header;
144 uint8_t u8Count;
145 uint8_t u8VBoxVersion;
146 uint8_t u8VBoxRevision;
147} *PDMIOEMSTRINGS;
148AssertCompileSize(DMIOEMSTRINGS, 0x7);
149
150/** MPS floating pointer structure */
151typedef struct MPSFLOATPTR
152{
153 uint8_t au8Signature[4];
154 uint32_t u32MPSAddr;
155 uint8_t u8Length;
156 uint8_t u8SpecRev;
157 uint8_t u8Checksum;
158 uint8_t au8Feature[5];
159} *PMPSFLOATPTR;
160AssertCompileSize(MPSFLOATPTR, 16);
161
162/** MPS config table header */
163typedef struct MPSCFGTBLHEADER
164{
165 uint8_t au8Signature[4];
166 uint16_t u16Length;
167 uint8_t u8SpecRev;
168 uint8_t u8Checksum;
169 uint8_t au8OemId[8];
170 uint8_t au8ProductId[12];
171 uint32_t u32OemTablePtr;
172 uint16_t u16OemTableSize;
173 uint16_t u16EntryCount;
174 uint32_t u32AddrLocalApic;
175 uint16_t u16ExtTableLength;
176 uint8_t u8ExtTableChecksxum;
177 uint8_t u8Reserved;
178} *PMPSCFGTBLHEADER;
179AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
180
181/** MPS processor entry */
182typedef struct MPSPROCENTRY
183{
184 uint8_t u8EntryType;
185 uint8_t u8LocalApicId;
186 uint8_t u8LocalApicVersion;
187 uint8_t u8CPUFlags;
188 uint32_t u32CPUSignature;
189 uint32_t u32CPUFeatureFlags;
190 uint32_t u32Reserved[2];
191} *PMPSPROCENTRY;
192AssertCompileSize(MPSPROCENTRY, 20);
193
194/** MPS bus entry */
195typedef struct MPSBUSENTRY
196{
197 uint8_t u8EntryType;
198 uint8_t u8BusId;
199 uint8_t au8BusTypeStr[6];
200} *PMPSBUSENTRY;
201AssertCompileSize(MPSBUSENTRY, 8);
202
203/** MPS I/O-APIC entry */
204typedef struct MPSIOAPICENTRY
205{
206 uint8_t u8EntryType;
207 uint8_t u8Id;
208 uint8_t u8Version;
209 uint8_t u8Flags;
210 uint32_t u32Addr;
211} *PMPSIOAPICENTRY;
212AssertCompileSize(MPSIOAPICENTRY, 8);
213
214/** MPS I/O-Interrupt entry */
215typedef struct MPSIOINTERRUPTENTRY
216{
217 uint8_t u8EntryType;
218 uint8_t u8Type;
219 uint16_t u16Flags;
220 uint8_t u8SrcBusId;
221 uint8_t u8SrcBusIrq;
222 uint8_t u8DstIOAPICId;
223 uint8_t u8DstIOAPICInt;
224} *PMPSIOIRQENTRY;
225AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
226
227#pragma pack()
228
229
230/**
231 * Calculate a simple checksum for the MPS table.
232 *
233 * @param data data
234 * @param len size of data
235 */
236static uint8_t sharedfwChecksum(const uint8_t * const au8Data, uint32_t u32Length)
237{
238 uint8_t u8Sum = 0;
239 for (size_t i = 0; i < u32Length; ++i)
240 u8Sum += au8Data[i];
241 return -u8Sum;
242}
243
244/**
245 * Construct the DMI table.
246 *
247 * @returns VBox status code.
248 * @param pDevIns The device instance.
249 * @param pTable Where to create the DMI table.
250 * @param cbMax The max size of the DMI table.
251 * @param pUuid Pointer to the UUID to use if the DmiUuid
252 * configuration string isn't present.
253 * @param pCfgHandle The handle to our config node.
254 */
255int sharedfwPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PRTUUID pUuid, PCFGMNODE pCfgHandle)
256{
257 char *pszStr = (char *)pTable;
258 int iStrNr;
259 int rc;
260 char *pszDmiBIOSVendor, *pszDmiBIOSVersion, *pszDmiBIOSReleaseDate;
261 int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor, iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
262 char *pszDmiSystemVendor, *pszDmiSystemProduct, *pszDmiSystemVersion, *pszDmiSystemSerial, *pszDmiSystemUuid, *pszDmiSystemFamily;
263 char *pszDmiChassisVendor, *pszDmiChassisVersion, *pszDmiChassisSerial, *pszDmiChassisAssetTag;
264 char *pszDmiOEMVBoxVer, *pszDmiOEMVBoxRev;
265
266#define CHECKSIZE(want) \
267 do { \
268 size_t _max = (size_t)(pszStr + want - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
269 if (_max > cbMax) \
270 { \
271 return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
272 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"), _max, cbMax); \
273 } \
274 } while (0)
275#define SETSTRING(memb, str) \
276 do { \
277 if (!str[0]) \
278 memb = 0; /* empty string */ \
279 else \
280 { \
281 memb = iStrNr++; \
282 size_t _len = strlen(str) + 1; \
283 CHECKSIZE(_len); \
284 memcpy(pszStr, str, _len); \
285 pszStr += _len; \
286 } \
287 } while (0)
288#define READCFGSTR(name, variable, default_value) \
289 do { \
290 rc = CFGMR3QueryStringAlloc(pCfgHandle, name, & variable); \
291 if (rc == VERR_CFGM_VALUE_NOT_FOUND) \
292 variable = MMR3HeapStrDup(PDMDevHlpGetVM(pDevIns), MM_TAG_CFGM, default_value); \
293 else if (RT_FAILURE(rc)) \
294 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
295 N_("Configuration error: Querying \"" name "\" as a string failed")); \
296 else if (!strcmp(variable, "<EMPTY>")) \
297 variable[0] = '\0'; \
298 } while (0)
299#define READCFGINT(name, variable, default_value) \
300 do { \
301 rc = CFGMR3QueryS32(pCfgHandle, name, & variable); \
302 if (rc == VERR_CFGM_VALUE_NOT_FOUND) \
303 variable = default_value; \
304 else if (RT_FAILURE(rc)) \
305 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
306 N_("Configuration error: Querying \"" name "\" as a Int failed")); \
307 } while (0)
308
309
310 /*
311 * Don't change this information otherwise Windows guests will demand re-activation!
312 */
313 READCFGSTR("DmiBIOSVendor", pszDmiBIOSVendor, "innotek GmbH");
314 READCFGSTR("DmiBIOSVersion", pszDmiBIOSVersion, "VirtualBox");
315 READCFGSTR("DmiBIOSReleaseDate", pszDmiBIOSReleaseDate, "12/01/2006");
316 READCFGINT("DmiBIOSReleaseMajor", iDmiBIOSReleaseMajor, 0);
317 READCFGINT("DmiBIOSReleaseMinor", iDmiBIOSReleaseMinor, 0);
318 READCFGINT("DmiBIOSFirmwareMajor", iDmiBIOSFirmwareMajor, 0);
319 READCFGINT("DmiBIOSFirmwareMinor", iDmiBIOSFirmwareMinor, 0);
320 READCFGSTR("DmiSystemVendor", pszDmiSystemVendor, "innotek GmbH");
321 READCFGSTR("DmiSystemProduct", pszDmiSystemProduct, "VirtualBox");
322 READCFGSTR("DmiSystemVersion", pszDmiSystemVersion, "1.2");
323 READCFGSTR("DmiSystemSerial", pszDmiSystemSerial, "0");
324 rc = CFGMR3QueryStringAlloc(pCfgHandle, "DmiSystemUuid", &pszDmiSystemUuid);
325 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
326 pszDmiSystemUuid = NULL;
327 else if (RT_FAILURE(rc))
328 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
329 N_("Configuration error: Querying \"DmiUuid\" as a string failed"));
330 READCFGSTR("DmiSystemFamily", pszDmiSystemFamily, "Virtual Machine");
331 READCFGSTR("DmiChassisVendor", pszDmiChassisVendor, "Sun Microsystems, Inc.");
332 READCFGSTR("DmiChassisVersion", pszDmiChassisVersion, ""); /* default not specified */
333 READCFGSTR("DmiChassisSerial", pszDmiChassisSerial, ""); /* default not specified */
334 READCFGSTR("DmiChassisAssetTag", pszDmiChassisAssetTag, ""); /* default not specified */
335
336 /* DMI BIOS information (Type 0) */
337 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
338 CHECKSIZE(sizeof(*pBIOSInf));
339
340 pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
341 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
342
343 /* don't set these fields by default for legacy compatibility */
344 if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
345 {
346 pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
347 pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
348 pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
349 pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
350 if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
351 {
352 pszStr = (char *)(pBIOSInf + 1);
353 pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
354 pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
355 pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
356 }
357 }
358
359 iStrNr = 1;
360 pBIOSInf->header.u8Type = 0; /* BIOS Information */
361 pBIOSInf->header.u16Handle = 0x0000;
362 SETSTRING(pBIOSInf->u8Vendor, pszDmiBIOSVendor);
363 SETSTRING(pBIOSInf->u8Version, pszDmiBIOSVersion);
364 pBIOSInf->u16Start = 0xE000;
365 SETSTRING(pBIOSInf->u8Release, pszDmiBIOSReleaseDate);
366 pBIOSInf->u8ROMSize = 1; /* 128K */
367 pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
368 | RT_BIT(7) /* PCI is supported */
369 | RT_BIT(15) /* Boot from CD is supported */
370 | RT_BIT(16) /* Selectable Boot is supported */
371 | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
372 | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
373 /* any more?? */
374 ;
375 pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
376 /* any more?? */
377 ;
378 pBIOSInf->u8CharacteristicsByte2 = 0
379 /* any more?? */
380 ;
381 *pszStr++ = '\0';
382
383 /* DMI system information (Type 1) */
384 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
385 CHECKSIZE(sizeof(*pSystemInf));
386 pszStr = (char *)(pSystemInf + 1);
387 iStrNr = 1;
388 pSystemInf->header.u8Type = 1; /* System Information */
389 pSystemInf->header.u8Length = sizeof(*pSystemInf);
390 pSystemInf->header.u16Handle = 0x0001;
391 SETSTRING(pSystemInf->u8Manufacturer, pszDmiSystemVendor);
392 SETSTRING(pSystemInf->u8ProductName, pszDmiSystemProduct);
393 SETSTRING(pSystemInf->u8Version, pszDmiSystemVersion);
394 SETSTRING(pSystemInf->u8SerialNumber, pszDmiSystemSerial);
395
396 RTUUID uuid;
397 if (pszDmiSystemUuid)
398 {
399 int rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
400 if (RT_FAILURE(rc))
401 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
402 N_("Invalid UUID for DMI tables specified"));
403 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
404 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
405 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
406 pUuid = &uuid;
407 }
408 memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
409
410 pSystemInf->u8WakeupType = 6; /* Power Switch */
411 pSystemInf->u8SKUNumber = 0;
412 SETSTRING(pSystemInf->u8Family, pszDmiSystemFamily);
413 *pszStr++ = '\0';
414
415 /* DMI System Enclosure or Chassis (Type 3) */
416 PDMICHASSIS pChassis = (PDMICHASSIS)pszStr;
417 CHECKSIZE(sizeof(*pChassis));
418 pszStr = (char*)&pChassis->u32OEMdefined;
419 iStrNr = 1;
420#ifdef VBOX_WITH_DMI_CHASSIS
421 pChassis->header.u8Type = 3; /* System Enclosure or Chassis */
422#else
423 pChassis->header.u8Type = 0x7e; /* inactive */
424#endif
425 pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
426 pChassis->header.u16Handle = 0x0003;
427 SETSTRING(pChassis->u8Manufacturer, pszDmiChassisVendor);
428 pChassis->u8Type = 0x01; /* ''other'', no chassis lock present */
429 SETSTRING(pChassis->u8Version, pszDmiChassisVersion);
430 SETSTRING(pChassis->u8SerialNumber, pszDmiChassisSerial);
431 SETSTRING(pChassis->u8AssetTag, pszDmiChassisAssetTag);
432 pChassis->u8BootupState = 0x03; /* safe */
433 pChassis->u8PowerSupplyState = 0x03; /* safe */
434 pChassis->u8ThermalState = 0x03; /* safe */
435 pChassis->u8SecurityStatus = 0x03; /* none XXX */
436# if 0
437 /* v2.3+, currently not supported */
438 pChassis->u32OEMdefined = 0;
439 pChassis->u8Height = 0; /* unspecified */
440 pChassis->u8NumPowerChords = 0; /* unspecified */
441 pChassis->u8ContElems = 0; /* no contained elements */
442 pChassis->u8ContElemRecLen = 0; /* no contained elements */
443# endif
444 *pszStr++ = '\0';
445
446 /* DMI OEM strings */
447 PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr;
448 CHECKSIZE(sizeof(*pOEMStrings));
449 pszStr = (char *)(pOEMStrings + 1);
450 iStrNr = 1;
451#ifdef VBOX_WITH_DMI_OEMSTRINGS
452 pOEMStrings->header.u8Type = 0xb; /* OEM Strings */
453#else
454 pOEMStrings->header.u8Type = 0x7e; /* inactive */
455#endif
456 pOEMStrings->header.u8Length = sizeof(*pOEMStrings);
457 pOEMStrings->header.u16Handle = 0x0002;
458 pOEMStrings->u8Count = 2;
459
460 char szTmp[64];
461 RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
462 RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
463 READCFGSTR("DmiOEMVBoxVer", pszDmiOEMVBoxVer, szTmp);
464 RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
465 READCFGSTR("DmiOEMVBoxRev", pszDmiOEMVBoxRev, szTmp);
466 SETSTRING(pOEMStrings->u8VBoxVersion, pszDmiOEMVBoxVer);
467 SETSTRING(pOEMStrings->u8VBoxRevision, pszDmiOEMVBoxRev);
468 *pszStr++ = '\0';
469
470 /* End-of-table marker - includes padding to account for fixed table size. */
471 PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
472 pEndOfTable->u8Type = 0x7f;
473 pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2;
474 pEndOfTable->u16Handle = 0xFEFF;
475
476 /* If more fields are added here, fix the size check in SETSTRING */
477
478#undef SETSTRING
479#undef READCFGSTR
480#undef READCFGINT
481#undef CHECKSIZE
482
483 MMR3HeapFree(pszDmiBIOSVendor);
484 MMR3HeapFree(pszDmiBIOSVersion);
485 MMR3HeapFree(pszDmiBIOSReleaseDate);
486 MMR3HeapFree(pszDmiSystemVendor);
487 MMR3HeapFree(pszDmiSystemProduct);
488 MMR3HeapFree(pszDmiSystemVersion);
489 MMR3HeapFree(pszDmiSystemSerial);
490 MMR3HeapFree(pszDmiSystemUuid);
491 MMR3HeapFree(pszDmiSystemFamily);
492 MMR3HeapFree(pszDmiChassisVendor);
493 MMR3HeapFree(pszDmiChassisVersion);
494 MMR3HeapFree(pszDmiChassisSerial);
495 MMR3HeapFree(pszDmiChassisAssetTag);
496 MMR3HeapFree(pszDmiOEMVBoxVer);
497 MMR3HeapFree(pszDmiOEMVBoxRev);
498
499 return VINF_SUCCESS;
500}
501AssertCompile(VBOX_DMI_TABLE_ENTR == 5);
502
503/**
504 * Construct the MPS table. Only applicable if IOAPIC is active!
505 *
506 * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'':
507 * ``1.3 Scope
508 * ...
509 * The hardware required to implement the MP specification is kept to a
510 * minimum, as follows:
511 * * One or more processors that are Intel architecture instruction set
512 * compatible, such as the CPUs in the Intel486 or Pentium processor
513 * family.
514 * * One or more APICs, such as the Intel 82489DX Advanced Programmable
515 * Interrupt Controller or the integrated APIC, such as that on the
516 * Intel Pentium 735\90 and 815\100 processors, together with a discrete
517 * I/O APIC unit.''
518 * and later:
519 * ``4.3.3 I/O APIC Entries
520 * The configuration table contains one or more entries for I/O APICs.
521 * ...
522 * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
523 * operating system should not attempt to access
524 * this I/O APIC.
525 * At least one I/O APIC must be enabled.''
526 *
527 * @param pDevIns The device instance data.
528 * @param addr physical address in guest memory.
529 */
530void sharedfwPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, uint16_t numCpus)
531{
532 /* configuration table */
533 PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
534 memcpy(pCfgTab->au8Signature, "PCMP", 4);
535 pCfgTab->u8SpecRev = 4; /* 1.4 */
536 memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
537 memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
538 pCfgTab->u32OemTablePtr = 0;
539 pCfgTab->u16OemTableSize = 0;
540 pCfgTab->u16EntryCount = numCpus /* Processors */
541 + 1 /* ISA Bus */
542 + 1 /* I/O-APIC */
543 + 16 /* Interrupts */;
544 pCfgTab->u32AddrLocalApic = 0xfee00000;
545 pCfgTab->u16ExtTableLength = 0;
546 pCfgTab->u8ExtTableChecksxum = 0;
547 pCfgTab->u8Reserved = 0;
548
549 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
550 uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
551 uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
552 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
553 if (u32Eax >= 1)
554 {
555 PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
556 u32CPUSignature = u32Eax & 0xfff;
557 /* Local APIC will be enabled later so override it here. Since we provide
558 * an MP table we have an IOAPIC and therefore a Local APIC. */
559 u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
560 }
561 /* Construct MPS table for each VCPU. */
562 PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
563 for (int i = 0; i<numCpus; i++)
564 {
565 pProcEntry->u8EntryType = 0; /* processor entry */
566 pProcEntry->u8LocalApicId = i;
567 pProcEntry->u8LocalApicVersion = 0x11;
568 pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
569 pProcEntry->u32CPUSignature = u32CPUSignature;
570 pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
571 pProcEntry->u32Reserved[0] =
572 pProcEntry->u32Reserved[1] = 0;
573 pProcEntry++;
574 }
575
576 /* ISA bus */
577 PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1);
578 pBusEntry->u8EntryType = 1; /* bus entry */
579 pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */
580 memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
581
582 /* PCI bus? */
583
584 /* I/O-APIC.
585 * MP spec: "The configuration table contains one or more entries for I/O APICs.
586 * ... At least one I/O APIC must be enabled." */
587 PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1);
588 uint16_t apicId = numCpus;
589 pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
590 pIOAPICEntry->u8Id = apicId; /* this ID is referenced by the interrupt entries */
591 pIOAPICEntry->u8Version = 0x11;
592 pIOAPICEntry->u8Flags = 1 /* enable */;
593 pIOAPICEntry->u32Addr = 0xfec00000;
594
595 PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
596 for (int i = 0; i < 16; i++, pIrqEntry++)
597 {
598 pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
599 pIrqEntry->u8Type = 0; /* INT, vectored interrupt */
600 pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
601 trigger mode = conforms to bus */
602 pIrqEntry->u8SrcBusId = 0; /* ISA bus */
603 pIrqEntry->u8SrcBusIrq = i;
604 pIrqEntry->u8DstIOAPICId = apicId;
605 pIrqEntry->u8DstIOAPICInt = i;
606 }
607
608 pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
609 pCfgTab->u8Checksum = sharedfwChecksum(pTable, pCfgTab->u16Length);
610
611 AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100,
612 ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
613 pCfgTab->u16Length, 0x1000-0x100));
614
615 MPSFLOATPTR floatPtr;
616 floatPtr.au8Signature[0] = '_';
617 floatPtr.au8Signature[1] = 'M';
618 floatPtr.au8Signature[2] = 'P';
619 floatPtr.au8Signature[3] = '_';
620 floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE;
621 floatPtr.u8Length = 1; /* structure size in paragraphs */
622 floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
623 floatPtr.u8Checksum = 0;
624 floatPtr.au8Feature[0] = 0;
625 floatPtr.au8Feature[1] = 0;
626 floatPtr.au8Feature[2] = 0;
627 floatPtr.au8Feature[3] = 0;
628 floatPtr.au8Feature[4] = 0;
629 floatPtr.u8Checksum = sharedfwChecksum((uint8_t*)&floatPtr, 16);
630 PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16);
631}
632
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