/* $Id: DevFwCommon.cpp 24706 2009-11-16 17:57:20Z vboxsync $ */ /** @file * Shared firmware code. */ /* * Copyright (C) 2009 Sun Microsystems, Inc. * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 USA or visit http://www.sun.com if you need * additional information or have any questions. */ /******************************************************************************* * Header Files * *******************************************************************************/ /** @todo: what should it be? */ #define LOG_GROUP LOG_GROUP_DEV_PC_BIOS #include #include #include #include #include #include #include #include #include #include #include "../Builtins.h" #include "../Builtins2.h" #include "DevFwCommon.h" #pragma pack(1) /** DMI header */ typedef struct DMIHDR { uint8_t u8Type; uint8_t u8Length; uint16_t u16Handle; } *PDMIHDR; AssertCompileSize(DMIHDR, 4); /** DMI BIOS information (Type 0) */ typedef struct DMIBIOSINF { DMIHDR header; uint8_t u8Vendor; uint8_t u8Version; uint16_t u16Start; uint8_t u8Release; uint8_t u8ROMSize; uint64_t u64Characteristics; uint8_t u8CharacteristicsByte1; uint8_t u8CharacteristicsByte2; uint8_t u8ReleaseMajor; uint8_t u8ReleaseMinor; uint8_t u8FirmwareMajor; uint8_t u8FirmwareMinor; } *PDMIBIOSINF; AssertCompileSize(DMIBIOSINF, 0x18); /** DMI system information (Type 1) */ typedef struct DMISYSTEMINF { DMIHDR header; uint8_t u8Manufacturer; uint8_t u8ProductName; uint8_t u8Version; uint8_t u8SerialNumber; uint8_t au8Uuid[16]; uint8_t u8WakeupType; uint8_t u8SKUNumber; uint8_t u8Family; } *PDMISYSTEMINF; AssertCompileSize(DMISYSTEMINF, 0x1b); /** DMI system enclosure or chassis type (Type 3) */ typedef struct DMICHASSIS { DMIHDR header; uint8_t u8Manufacturer; uint8_t u8Type; uint8_t u8Version; uint8_t u8SerialNumber; uint8_t u8AssetTag; uint8_t u8BootupState; uint8_t u8PowerSupplyState; uint8_t u8ThermalState; uint8_t u8SecurityStatus; /* v2.3+, currently not supported */ uint32_t u32OEMdefined; uint8_t u8Height; uint8_t u8NumPowerChords; uint8_t u8ContElems; uint8_t u8ContElemRecLen; } *PDMICHASSIS; AssertCompileSize(DMICHASSIS, 0x15); /** DMI processor information (Type 4) */ typedef struct DMIPROCESSORINF { DMIHDR header; uint8_t u8SocketDesignation; uint8_t u8ProcessorType; uint8_t u8ProcessorFamily; uint8_t u8ProcessorManufacturer; uint64_t u64ProcessorIdentification; uint8_t u8ProcessorVersion; uint8_t u8Voltage; uint16_t u16ExternalClock; uint16_t u16MaxSpeed; uint16_t u16CurrentSpeed; uint8_t u8Status; uint8_t u8ProcessorUpgrade; uint16_t u16L1CacheHandle; uint16_t u16L2CacheHandle; uint16_t u16L3CacheHandle; uint8_t u8SerialNumber; uint8_t u8AssetTag; uint8_t u8PartNumber; uint8_t u8CoreCount; uint8_t u8CoreEnabled; uint8_t u8ThreadCount; uint16_t u16ProcessorCharacteristics; uint16_t u16ProcessorFamily2; } *PDMIPROCESSORINF; AssertCompileSize(DMIPROCESSORINF, 0x2a); /** DMI OEM strings (Type 11) */ typedef struct DMIOEMSTRINGS { DMIHDR header; uint8_t u8Count; uint8_t u8VBoxVersion; uint8_t u8VBoxRevision; } *PDMIOEMSTRINGS; AssertCompileSize(DMIOEMSTRINGS, 0x7); /** MPS floating pointer structure */ typedef struct MPSFLOATPTR { uint8_t au8Signature[4]; uint32_t u32MPSAddr; uint8_t u8Length; uint8_t u8SpecRev; uint8_t u8Checksum; uint8_t au8Feature[5]; } *PMPSFLOATPTR; AssertCompileSize(MPSFLOATPTR, 16); /** MPS config table header */ typedef struct MPSCFGTBLHEADER { uint8_t au8Signature[4]; uint16_t u16Length; uint8_t u8SpecRev; uint8_t u8Checksum; uint8_t au8OemId[8]; uint8_t au8ProductId[12]; uint32_t u32OemTablePtr; uint16_t u16OemTableSize; uint16_t u16EntryCount; uint32_t u32AddrLocalApic; uint16_t u16ExtTableLength; uint8_t u8ExtTableChecksxum; uint8_t u8Reserved; } *PMPSCFGTBLHEADER; AssertCompileSize(MPSCFGTBLHEADER, 0x2c); /** MPS processor entry */ typedef struct MPSPROCENTRY { uint8_t u8EntryType; uint8_t u8LocalApicId; uint8_t u8LocalApicVersion; uint8_t u8CPUFlags; uint32_t u32CPUSignature; uint32_t u32CPUFeatureFlags; uint32_t u32Reserved[2]; } *PMPSPROCENTRY; AssertCompileSize(MPSPROCENTRY, 20); /** MPS bus entry */ typedef struct MPSBUSENTRY { uint8_t u8EntryType; uint8_t u8BusId; uint8_t au8BusTypeStr[6]; } *PMPSBUSENTRY; AssertCompileSize(MPSBUSENTRY, 8); /** MPS I/O-APIC entry */ typedef struct MPSIOAPICENTRY { uint8_t u8EntryType; uint8_t u8Id; uint8_t u8Version; uint8_t u8Flags; uint32_t u32Addr; } *PMPSIOAPICENTRY; AssertCompileSize(MPSIOAPICENTRY, 8); /** MPS I/O-Interrupt entry */ typedef struct MPSIOINTERRUPTENTRY { uint8_t u8EntryType; uint8_t u8Type; uint16_t u16Flags; uint8_t u8SrcBusId; uint8_t u8SrcBusIrq; uint8_t u8DstIOAPICId; uint8_t u8DstIOAPICInt; } *PMPSIOIRQENTRY; AssertCompileSize(MPSIOINTERRUPTENTRY, 8); #pragma pack() /** * Calculate a simple checksum for the MPS table. * * @param data data * @param len size of data */ static uint8_t sharedfwChecksum(const uint8_t * const au8Data, uint32_t u32Length) { uint8_t u8Sum = 0; for (size_t i = 0; i < u32Length; ++i) u8Sum += au8Data[i]; return -u8Sum; } /** * Construct the DMI table. * * @returns VBox status code. * @param pDevIns The device instance. * @param pTable Where to create the DMI table. * @param cbMax The max size of the DMI table. * @param pUuid Pointer to the UUID to use if the DmiUuid * configuration string isn't present. * @param pCfgHandle The handle to our config node. */ int sharedfwPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PRTUUID pUuid, PCFGMNODE pCfgHandle) { char *pszStr = (char *)pTable; int iStrNr; int rc; char *pszDmiBIOSVendor, *pszDmiBIOSVersion, *pszDmiBIOSReleaseDate; int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor, iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor; char *pszDmiSystemVendor, *pszDmiSystemProduct, *pszDmiSystemVersion, *pszDmiSystemSerial, *pszDmiSystemUuid, *pszDmiSystemFamily; char *pszDmiChassisVendor, *pszDmiChassisVersion, *pszDmiChassisSerial, *pszDmiChassisAssetTag; char *pszDmiOEMVBoxVer, *pszDmiOEMVBoxRev; #define CHECKSIZE(want) \ do { \ size_t _max = (size_t)(pszStr + want - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \ if (_max > cbMax) \ { \ return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \ 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); \ } \ } while (0) #define SETSTRING(memb, str) \ do { \ if (!str[0]) \ memb = 0; /* empty string */ \ else \ { \ memb = iStrNr++; \ size_t _len = strlen(str) + 1; \ CHECKSIZE(_len); \ memcpy(pszStr, str, _len); \ pszStr += _len; \ } \ } while (0) #define READCFGSTR(name, variable, default_value) \ do { \ rc = CFGMR3QueryStringAlloc(pCfgHandle, name, & variable); \ if (rc == VERR_CFGM_VALUE_NOT_FOUND) \ variable = MMR3HeapStrDup(PDMDevHlpGetVM(pDevIns), MM_TAG_CFGM, default_value); \ else if (RT_FAILURE(rc)) \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" name "\" as a string failed")); \ else if (!strcmp(variable, "")) \ variable[0] = '\0'; \ } while (0) #define READCFGINT(name, variable, default_value) \ do { \ rc = CFGMR3QueryS32(pCfgHandle, name, & variable); \ if (rc == VERR_CFGM_VALUE_NOT_FOUND) \ variable = default_value; \ else if (RT_FAILURE(rc)) \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" name "\" as a Int failed")); \ } while (0) /* * Don't change this information otherwise Windows guests will demand re-activation! */ READCFGSTR("DmiBIOSVendor", pszDmiBIOSVendor, "innotek GmbH"); READCFGSTR("DmiBIOSVersion", pszDmiBIOSVersion, "VirtualBox"); READCFGSTR("DmiBIOSReleaseDate", pszDmiBIOSReleaseDate, "12/01/2006"); READCFGINT("DmiBIOSReleaseMajor", iDmiBIOSReleaseMajor, 0); READCFGINT("DmiBIOSReleaseMinor", iDmiBIOSReleaseMinor, 0); READCFGINT("DmiBIOSFirmwareMajor", iDmiBIOSFirmwareMajor, 0); READCFGINT("DmiBIOSFirmwareMinor", iDmiBIOSFirmwareMinor, 0); READCFGSTR("DmiSystemVendor", pszDmiSystemVendor, "innotek GmbH"); READCFGSTR("DmiSystemProduct", pszDmiSystemProduct, "VirtualBox"); READCFGSTR("DmiSystemVersion", pszDmiSystemVersion, "1.2"); READCFGSTR("DmiSystemSerial", pszDmiSystemSerial, "0"); rc = CFGMR3QueryStringAlloc(pCfgHandle, "DmiSystemUuid", &pszDmiSystemUuid); if (rc == VERR_CFGM_VALUE_NOT_FOUND) pszDmiSystemUuid = NULL; else if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: Querying \"DmiUuid\" as a string failed")); READCFGSTR("DmiSystemFamily", pszDmiSystemFamily, "Virtual Machine"); READCFGSTR("DmiChassisVendor", pszDmiChassisVendor, "Sun Microsystems, Inc."); READCFGSTR("DmiChassisVersion", pszDmiChassisVersion, ""); /* default not specified */ READCFGSTR("DmiChassisSerial", pszDmiChassisSerial, ""); /* default not specified */ READCFGSTR("DmiChassisAssetTag", pszDmiChassisAssetTag, ""); /* default not specified */ /* DMI BIOS information (Type 0) */ PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr; CHECKSIZE(sizeof(*pBIOSInf)); pszStr = (char *)&pBIOSInf->u8ReleaseMajor; pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor); /* don't set these fields by default for legacy compatibility */ if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0) { pszStr = (char *)&pBIOSInf->u8FirmwareMajor; pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor); pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor; pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor; if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0) { pszStr = (char *)(pBIOSInf + 1); pBIOSInf->header.u8Length = sizeof(DMIBIOSINF); pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor; pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor; } } iStrNr = 1; pBIOSInf->header.u8Type = 0; /* BIOS Information */ pBIOSInf->header.u16Handle = 0x0000; SETSTRING(pBIOSInf->u8Vendor, pszDmiBIOSVendor); SETSTRING(pBIOSInf->u8Version, pszDmiBIOSVersion); pBIOSInf->u16Start = 0xE000; SETSTRING(pBIOSInf->u8Release, pszDmiBIOSReleaseDate); pBIOSInf->u8ROMSize = 1; /* 128K */ pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */ | RT_BIT(7) /* PCI is supported */ | RT_BIT(15) /* Boot from CD is supported */ | RT_BIT(16) /* Selectable Boot is supported */ | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */ | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */ /* any more?? */ ; pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */ /* any more?? */ ; pBIOSInf->u8CharacteristicsByte2 = 0 /* any more?? */ ; *pszStr++ = '\0'; /* DMI system information (Type 1) */ PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr; CHECKSIZE(sizeof(*pSystemInf)); pszStr = (char *)(pSystemInf + 1); iStrNr = 1; pSystemInf->header.u8Type = 1; /* System Information */ pSystemInf->header.u8Length = sizeof(*pSystemInf); pSystemInf->header.u16Handle = 0x0001; SETSTRING(pSystemInf->u8Manufacturer, pszDmiSystemVendor); SETSTRING(pSystemInf->u8ProductName, pszDmiSystemProduct); SETSTRING(pSystemInf->u8Version, pszDmiSystemVersion); SETSTRING(pSystemInf->u8SerialNumber, pszDmiSystemSerial); RTUUID uuid; if (pszDmiSystemUuid) { int rc = RTUuidFromStr(&uuid, pszDmiSystemUuid); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Invalid UUID for DMI tables specified")); uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow); uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid); uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion); pUuid = &uuid; } memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID)); pSystemInf->u8WakeupType = 6; /* Power Switch */ pSystemInf->u8SKUNumber = 0; SETSTRING(pSystemInf->u8Family, pszDmiSystemFamily); *pszStr++ = '\0'; /* DMI System Enclosure or Chassis (Type 3) */ PDMICHASSIS pChassis = (PDMICHASSIS)pszStr; CHECKSIZE(sizeof(*pChassis)); pszStr = (char*)&pChassis->u32OEMdefined; iStrNr = 1; #ifdef VBOX_WITH_DMI_CHASSIS pChassis->header.u8Type = 3; /* System Enclosure or Chassis */ #else pChassis->header.u8Type = 0x7e; /* inactive */ #endif pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined); pChassis->header.u16Handle = 0x0003; SETSTRING(pChassis->u8Manufacturer, pszDmiChassisVendor); pChassis->u8Type = 0x01; /* ''other'', no chassis lock present */ SETSTRING(pChassis->u8Version, pszDmiChassisVersion); SETSTRING(pChassis->u8SerialNumber, pszDmiChassisSerial); SETSTRING(pChassis->u8AssetTag, pszDmiChassisAssetTag); pChassis->u8BootupState = 0x03; /* safe */ pChassis->u8PowerSupplyState = 0x03; /* safe */ pChassis->u8ThermalState = 0x03; /* safe */ pChassis->u8SecurityStatus = 0x03; /* none XXX */ # if 0 /* v2.3+, currently not supported */ pChassis->u32OEMdefined = 0; pChassis->u8Height = 0; /* unspecified */ pChassis->u8NumPowerChords = 0; /* unspecified */ pChassis->u8ContElems = 0; /* no contained elements */ pChassis->u8ContElemRecLen = 0; /* no contained elements */ # endif *pszStr++ = '\0'; /* DMI OEM strings */ PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr; CHECKSIZE(sizeof(*pOEMStrings)); pszStr = (char *)(pOEMStrings + 1); iStrNr = 1; #ifdef VBOX_WITH_DMI_OEMSTRINGS pOEMStrings->header.u8Type = 0xb; /* OEM Strings */ #else pOEMStrings->header.u8Type = 0x7e; /* inactive */ #endif pOEMStrings->header.u8Length = sizeof(*pOEMStrings); pOEMStrings->header.u16Handle = 0x0002; pOEMStrings->u8Count = 2; char szTmp[64]; RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u", RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild()); READCFGSTR("DmiOEMVBoxVer", pszDmiOEMVBoxVer, szTmp); RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision()); READCFGSTR("DmiOEMVBoxRev", pszDmiOEMVBoxRev, szTmp); SETSTRING(pOEMStrings->u8VBoxVersion, pszDmiOEMVBoxVer); SETSTRING(pOEMStrings->u8VBoxRevision, pszDmiOEMVBoxRev); *pszStr++ = '\0'; /* End-of-table marker - includes padding to account for fixed table size. */ PDMIHDR pEndOfTable = (PDMIHDR)pszStr; pEndOfTable->u8Type = 0x7f; pEndOfTable->u8Length = cbMax - ((char *)pszStr - (char *)pTable) - 2; pEndOfTable->u16Handle = 0xFEFF; /* If more fields are added here, fix the size check in SETSTRING */ #undef SETSTRING #undef READCFGSTR #undef READCFGINT #undef CHECKSIZE MMR3HeapFree(pszDmiBIOSVendor); MMR3HeapFree(pszDmiBIOSVersion); MMR3HeapFree(pszDmiBIOSReleaseDate); MMR3HeapFree(pszDmiSystemVendor); MMR3HeapFree(pszDmiSystemProduct); MMR3HeapFree(pszDmiSystemVersion); MMR3HeapFree(pszDmiSystemSerial); MMR3HeapFree(pszDmiSystemUuid); MMR3HeapFree(pszDmiSystemFamily); MMR3HeapFree(pszDmiChassisVendor); MMR3HeapFree(pszDmiChassisVersion); MMR3HeapFree(pszDmiChassisSerial); MMR3HeapFree(pszDmiChassisAssetTag); MMR3HeapFree(pszDmiOEMVBoxVer); MMR3HeapFree(pszDmiOEMVBoxRev); return VINF_SUCCESS; } AssertCompile(VBOX_DMI_TABLE_ENTR == 5); /** * Construct the MPS table. Only applicable if IOAPIC is active! * * See ``MultiProcessor Specificatiton Version 1.4 (May 1997)'': * ``1.3 Scope * ... * The hardware required to implement the MP specification is kept to a * minimum, as follows: * * One or more processors that are Intel architecture instruction set * compatible, such as the CPUs in the Intel486 or Pentium processor * family. * * One or more APICs, such as the Intel 82489DX Advanced Programmable * Interrupt Controller or the integrated APIC, such as that on the * Intel Pentium 735\90 and 815\100 processors, together with a discrete * I/O APIC unit.'' * and later: * ``4.3.3 I/O APIC Entries * The configuration table contains one or more entries for I/O APICs. * ... * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the * operating system should not attempt to access * this I/O APIC. * At least one I/O APIC must be enabled.'' * * @param pDevIns The device instance data. * @param addr physical address in guest memory. */ void sharedfwPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, uint16_t numCpus) { /* configuration table */ PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable; memcpy(pCfgTab->au8Signature, "PCMP", 4); pCfgTab->u8SpecRev = 4; /* 1.4 */ memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8); memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12); pCfgTab->u32OemTablePtr = 0; pCfgTab->u16OemTableSize = 0; pCfgTab->u16EntryCount = numCpus /* Processors */ + 1 /* ISA Bus */ + 1 /* I/O-APIC */ + 16 /* Interrupts */; pCfgTab->u32AddrLocalApic = 0xfee00000; pCfgTab->u16ExtTableLength = 0; pCfgTab->u8ExtTableChecksxum = 0; pCfgTab->u8Reserved = 0; uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx; uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */ uint32_t u32FeatureFlags = 0x0001; /* default: FPU */ PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx); if (u32Eax >= 1) { PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx); u32CPUSignature = u32Eax & 0xfff; /* Local APIC will be enabled later so override it here. Since we provide * an MP table we have an IOAPIC and therefore a Local APIC. */ u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC; } /* Construct MPS table for each VCPU. */ PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1); for (int i = 0; iu8EntryType = 0; /* processor entry */ pProcEntry->u8LocalApicId = i; pProcEntry->u8LocalApicVersion = 0x11; pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */; pProcEntry->u32CPUSignature = u32CPUSignature; pProcEntry->u32CPUFeatureFlags = u32FeatureFlags; pProcEntry->u32Reserved[0] = pProcEntry->u32Reserved[1] = 0; pProcEntry++; } /* ISA bus */ PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)(pProcEntry+1); pBusEntry->u8EntryType = 1; /* bus entry */ pBusEntry->u8BusId = 0; /* this ID is referenced by the interrupt entries */ memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6); /* PCI bus? */ /* I/O-APIC. * MP spec: "The configuration table contains one or more entries for I/O APICs. * ... At least one I/O APIC must be enabled." */ PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry+1); uint16_t apicId = numCpus; pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */ pIOAPICEntry->u8Id = apicId; /* this ID is referenced by the interrupt entries */ pIOAPICEntry->u8Version = 0x11; pIOAPICEntry->u8Flags = 1 /* enable */; pIOAPICEntry->u32Addr = 0xfec00000; PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1); for (int i = 0; i < 16; i++, pIrqEntry++) { pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */ pIrqEntry->u8Type = 0; /* INT, vectored interrupt */ pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus, trigger mode = conforms to bus */ pIrqEntry->u8SrcBusId = 0; /* ISA bus */ pIrqEntry->u8SrcBusIrq = i; pIrqEntry->u8DstIOAPICId = apicId; pIrqEntry->u8DstIOAPICInt = i; } pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable; pCfgTab->u8Checksum = sharedfwChecksum(pTable, pCfgTab->u16Length); AssertMsg(pCfgTab->u16Length < 0x1000 - 0x100, ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d", pCfgTab->u16Length, 0x1000-0x100)); MPSFLOATPTR floatPtr; floatPtr.au8Signature[0] = '_'; floatPtr.au8Signature[1] = 'M'; floatPtr.au8Signature[2] = 'P'; floatPtr.au8Signature[3] = '_'; floatPtr.u32MPSAddr = VBOX_MPS_TABLE_BASE; floatPtr.u8Length = 1; /* structure size in paragraphs */ floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */ floatPtr.u8Checksum = 0; floatPtr.au8Feature[0] = 0; floatPtr.au8Feature[1] = 0; floatPtr.au8Feature[2] = 0; floatPtr.au8Feature[3] = 0; floatPtr.au8Feature[4] = 0; floatPtr.u8Checksum = sharedfwChecksum((uint8_t*)&floatPtr, 16); PDMDevHlpPhysWrite (pDevIns, 0x9fff0, &floatPtr, 16); }