/** @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) ox958R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { RT_NOREF(iInstance); PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958); bool fRCEnabled = true; bool fR0Enabled = true; bool fMsiXSupported = false; int rc; PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* * Validate and read configuration. */ if (!CFGMR3AreValuesValid(pCfg, "RCEnabled\0" "R0Enabled\0" "MsiXSupported\0" "UartCount\0")) return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, N_("OXPCIe958 configuration error: Unknown option specified")); rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: Failed to read \"RCEnabled\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"R0Enabled\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "MsiXSupported", &fMsiXSupported, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"MsiXSupported\" as boolean")); rc = CFGMR3QueryU32Def(pCfg, "UartCount", &pThis->cUarts, OX958_UARTS_MAX); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"UartCount\" as unsigned 32bit integer")); if (!pThis->cUarts || pThis->cUarts > OX958_UARTS_MAX) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("OXPCIe958 configuration error: \"UartCount\" has invalid value %u (must be in range [1 .. %u]"), pThis->cUarts, OX958_UARTS_MAX); /* * Init instance data. */ pThis->fR0Enabled = fR0Enabled; pThis->fRCEnabled = fRCEnabled; pThis->pDevInsR3 = pDevIns; pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); /* Fill PCI config space. */ PDMPciDevSetVendorId (&pThis->PciDev, OX958_PCI_VENDOR_ID); PDMPciDevSetDeviceId (&pThis->PciDev, OX958_PCI_DEVICE_ID); PDMPciDevSetCommand (&pThis->PciDev, 0x0000); #ifdef VBOX_WITH_MSI_DEVICES PDMPciDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST); PDMPciDevSetCapabilityList (&pThis->PciDev, OX958_PCI_MSI_CAP_OFS); #else PDMPciDevSetCapabilityList (&pThis->PciDev, 0x70); #endif PDMPciDevSetRevisionId (&pThis->PciDev, 0x00); PDMPciDevSetClassBase (&pThis->PciDev, 0x07); /* Communication controller. */ PDMPciDevSetClassSub (&pThis->PciDev, 0x00); /* Serial controller. */ PDMPciDevSetClassProg (&pThis->PciDev, 0x02); /* 16550. */ PDMPciDevSetRevisionId (&pThis->PciDev, 0x00); PDMPciDevSetSubSystemVendorId(&pThis->PciDev, OX958_PCI_VENDOR_ID); PDMPciDevSetSubSystemId (&pThis->PciDev, OX958_PCI_DEVICE_ID); PDMPciDevSetInterruptLine (&pThis->PciDev, 0x00); PDMPciDevSetInterruptPin (&pThis->PciDev, 0x01); /** @todo More Capabilities. */ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); if (RT_FAILURE(rc)) return rc; /* * Register PCI device and I/O region. */ rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev); if (RT_FAILURE(rc)) return rc; #ifdef VBOX_WITH_MSI_DEVICES PDMMSIREG MsiReg; RT_ZERO(MsiReg); MsiReg.cMsiVectors = 1; MsiReg.iMsiCapOffset = OX958_PCI_MSI_CAP_OFS; MsiReg.iMsiNextOffset = OX958_PCI_MSIX_CAP_OFS; MsiReg.fMsi64bit = true; if (fMsiXSupported) { MsiReg.cMsixVectors = VBOX_MSIX_MAX_ENTRIES; MsiReg.iMsixCapOffset = OX958_PCI_MSIX_CAP_OFS; MsiReg.iMsixNextOffset = 0x00; MsiReg.iMsixBar = OX958_PCI_MSIX_BAR; } rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); if (RT_FAILURE(rc)) { PCIDevSetCapabilityList(&pThis->PciDev, 0x0); /* That's OK, we can work without MSI */ } #endif rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, _16K, PCI_ADDRESS_SPACE_MEM, ox958R3Map); if (RT_FAILURE(rc)) return rc; PVM pVM = PDMDevHlpGetVM(pDevIns); RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR; RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR; if ( fRCEnabled && VM_IS_RAW_MODE_ENABLED(pVM)) { rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "ox958IrqReq", &pfnSerialIrqReqRC); if (RT_FAILURE(rc)) return rc; } if (fR0Enabled) { rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "ox958IrqReq", &pfnSerialIrqReqR0); if (RT_FAILURE(rc)) return rc; } for (uint32_t i = 0; i < pThis->cUarts; i++) { POX958UART pUart = &pThis->aUarts[i]; rc = uartR3Init(&pUart->UartCore, pDevIns, UARTTYPE_16550A, i, 0, ox958IrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("OXPCIe958 configuration error: failed to initialize UART %u"), i); } ox958R3Reset(pDevIns); return VINF_SUCCESS; }
/** * @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) gimdevR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); RT_NOREF2(iInstance, pCfg); Assert(iInstance == 0); PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV); /* * Initialize relevant state bits. */ pThis->pDevInsR3 = pDevIns; pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); /* * Get debug setup requirements from GIM. */ PVM pVM = PDMDevHlpGetVM(pDevIns); int rc = GIMR3GetDebugSetup(pVM, &pThis->DbgSetup); if ( RT_SUCCESS(rc) && pThis->DbgSetup.cbDbgRecvBuf > 0) { /* * Attach the stream driver for the debug connection. */ PPDMISTREAM pDbgDrvStream = NULL; pThis->IDbgBase.pfnQueryInterface = gimdevR3QueryInterface; rc = PDMDevHlpDriverAttach(pDevIns, GIMDEV_DEBUG_LUN, &pThis->IDbgBase, &pThis->pDbgDrvBase, "GIM Debug Port"); if (RT_SUCCESS(rc)) { pDbgDrvStream = PDMIBASE_QUERY_INTERFACE(pThis->pDbgDrvBase, PDMISTREAM); if (pDbgDrvStream) LogRel(("GIMDev: LUN#%u: Debug port configured\n", GIMDEV_DEBUG_LUN)); else { LogRel(("GIMDev: LUN#%u: No unit\n", GIMDEV_DEBUG_LUN)); rc = VERR_INTERNAL_ERROR_2; } } else { pThis->pDbgDrvBase = NULL; LogRel(("GIMDev: LUN#%u: No debug port configured! rc=%Rrc\n", GIMDEV_DEBUG_LUN, rc)); } if (!pDbgDrvStream) { Assert(rc != VINF_SUCCESS); return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Debug port configuration expected when GIM configured with debugging support")); } void *pvDbgRecvBuf = RTMemAllocZ(pThis->DbgSetup.cbDbgRecvBuf); if (RT_UNLIKELY(!pvDbgRecvBuf)) { LogRel(("GIMDev: Failed to alloc %u bytes for debug receive buffer\n", pThis->DbgSetup.cbDbgRecvBuf)); return VERR_NO_MEMORY; } /* * Update the shared debug struct. */ pThis->Dbg.pDbgDrvStream = pDbgDrvStream; pThis->Dbg.pvDbgRecvBuf = pvDbgRecvBuf; pThis->Dbg.cbDbgRecvBufRead = 0; pThis->Dbg.fDbgRecvBufRead = false; /* * Create the sempahore and the debug receive thread itself. */ rc = RTSemEventMultiCreate(&pThis->Dbg.hDbgRecvThreadSem); if (RT_SUCCESS(rc)) { rc = RTThreadCreate(&pThis->hDbgRecvThread, gimDevR3DbgRecvThread, pDevIns, 0 /*cbStack*/, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "GIMDebugRecv"); if (RT_FAILURE(rc)) { RTSemEventMultiDestroy(pThis->Dbg.hDbgRecvThreadSem); pThis->Dbg.hDbgRecvThreadSem = NIL_RTSEMEVENTMULTI; RTMemFree(pThis->Dbg.pvDbgRecvBuf); pThis->Dbg.pvDbgRecvBuf = NULL; return rc; } } else return rc; } /* * Register this device with the GIM component. */ GIMR3GimDeviceRegister(pVM, pDevIns, pThis->DbgSetup.cbDbgRecvBuf ? &pThis->Dbg : NULL); /* * Get the MMIO2 regions from the GIM provider. */ uint32_t cRegions = 0; PGIMMMIO2REGION pRegionsR3 = GIMR3GetMmio2Regions(pVM, &cRegions); if ( cRegions && pRegionsR3) { /* * Register the MMIO2 regions. */ PGIMMMIO2REGION pCur = pRegionsR3; for (uint32_t i = 0; i < cRegions; i++, pCur++) { Assert(!pCur->fRegistered); rc = PDMDevHlpMMIO2Register(pDevIns, NULL, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3, pCur->szDescription); if (RT_FAILURE(rc)) return rc; pCur->fRegistered = true; #if defined(VBOX_WITH_2X_4GB_ADDR_SPACE) RTR0PTR pR0Mapping = 0; rc = PDMDevHlpMMIO2MapKernel(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription, &pR0Mapping); AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc); pCur->pvPageR0 = pR0Mapping; #else pCur->pvPageR0 = (RTR0PTR)pCur->pvPageR3; #endif /* * Map into RC if required. */ if (pCur->fRCMapping) { RTRCPTR pRCMapping = 0; rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription, &pRCMapping); AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc); pCur->pvPageRC = pRCMapping; } else pCur->pvPageRC = NIL_RTRCPTR; LogRel(("GIMDev: Registered %s\n", pCur->szDescription)); } } /** @todo Register SSM: PDMDevHlpSSMRegister(). */ /** @todo Register statistics: STAM_REG(). */ /** @todo Register DBGFInfo: PDMDevHlpDBGFInfoRegister(). */ return VINF_SUCCESS; }
/** * @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) smcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); PDEVSMC pThis = PDMINS_2_DATA(pDevIns, PDEVSMC); Assert(iInstance == 0); /* * Init the data. */ pThis->bDollaryNumber = 1; pThis->bShutdownReason = 3; /* STOP_CAUSE_POWERKEY_GOOD_CODE */ /* * Validate configuration. */ PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceKey|GetKeyFromRealSMC", ""); /* * Read configuration. */ /* The DeviceKey sets OSK0 and OSK1. */ int rc = CFGMR3QueryStringDef(pCfg, "DeviceKey", pThis->szOsk0And1, sizeof(pThis->szOsk0And1), ""); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: Querying \"DeviceKey\" as a string failed")); /* Query the key from the real hardware if asked to do so. */ bool fGetKeyFromRealSMC; rc = CFGMR3QueryBoolDef(pCfg, "GetKeyFromRealSMC", &fGetKeyFromRealSMC, false); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed")); if (fGetKeyFromRealSMC) { rc = PDMDevHlpCallR0(pDevIns, SMC_CALLR0_READ_OSK, 0 /*u64Arg*/); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Failed to query SMC value from the host")); } /* * Register I/O Ports */ rc = PDMDevHlpIOPortRegister(pDevIns, SMC_PORT_FIRST, SMC_REG_COUNT, NULL, smcIoPortWrite, smcIoPortRead, NULL, NULL, "SMC data port"); AssertRCReturn(rc, rc); /** @todo Newer versions (2.03) have an MMIO mapping as well (ACPI). */ /* * Saved state. */ rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcSaveExec, smcLoadExec); if (RT_FAILURE(rc)) return rc; return VINF_SUCCESS; }
/** * Construct the DMI table. * * @returns VBox status code. * @param pDevIns The device instance. * @param pTable Where to create the DMI table. * @param cbMax The maximum size of the DMI table. * @param pUuid Pointer to the UUID to use if the DmiUuid * configuration string isn't present. * @param pCfg The handle to our config node. * @param cCpus Number of VCPUs. * @param pcbDmiTables Size of DMI data in bytes. * @param pcNumDmiTables Number of DMI tables. */ int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg, uint16_t cCpus, uint16_t *pcbDmiTables, uint16_t *pcNumDmiTables) { #define CHECKSIZE(cbWant) \ { \ size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \ if (cbNeed > cbMax) \ { \ if (fHideErrors) \ { \ LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \ continue; \ } \ 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"), cbNeed, cbMax); \ } \ } #define READCFGSTRDEF(variable, name, default_value) \ { \ if (fForceDefault) \ pszTmp = default_value; \ else \ { \ rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \ if (RT_FAILURE(rc)) \ { \ if (fHideErrors) \ { \ LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \ continue; \ } \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" name "\" as a string failed")); \ } \ else if (!strcmp(szBuf, "<EMPTY>")) \ pszTmp = ""; \ else \ pszTmp = szBuf; \ } \ if (!pszTmp[0]) \ variable = 0; /* empty string */ \ else \ { \ variable = iStrNr++; \ size_t cStr = strlen(pszTmp) + 1; \ CHECKSIZE(cStr); \ memcpy(pszStr, pszTmp, cStr); \ pszStr += cStr ; \ } \ } #define READCFGSTR(variable, name) \ READCFGSTRDEF(variable, # name, s_szDef ## name) #define READCFGINT(variable, name) \ { \ if (fForceDefault) \ variable = s_iDef ## name; \ else \ { \ rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \ if (RT_FAILURE(rc)) \ { \ if (fHideErrors) \ { \ LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \ continue; \ } \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" # name "\" as an int failed")); \ } \ } \ } #define START_STRUCT(tbl) \ pszStr = (char *)(tbl + 1); \ iStrNr = 1; #define TERM_STRUCT \ { \ *pszStr++ = '\0'; /* terminate set of text strings */ \ if (iStrNr == 1) \ *pszStr++ = '\0'; /* terminate a structure without strings */ \ } bool fForceDefault = false; #ifdef VBOX_BIOS_DMI_FALLBACK /* * There will be two passes. If an error occurs during the first pass, a * message will be written to the release log and we fall back to default * DMI data and start a second pass. */ bool fHideErrors = true; #else /* * There will be one pass, every error is fatal and will prevent the VM * from starting. */ bool fHideErrors = false; #endif uint8_t fDmiUseHostInfo; int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiUseHostInfo\"")); /* Sync up with host default DMI values */ if (fDmiUseHostInfo) fwCommonUseHostDMIStrings(); uint8_t fDmiExposeMemoryTable; rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiExposeMemoryTable\"")); uint8_t fDmiExposeProcessorInf; rc = CFGMR3QueryU8Def(pCfg, "DmiExposeProcInf", &fDmiExposeProcessorInf, 0); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiExposeProcInf\"")); for (;; fForceDefault = true, fHideErrors = false) { int iStrNr; char szBuf[256]; char *pszStr = (char *)pTable; char szDmiSystemUuid[64]; char *pszDmiSystemUuid; const char *pszTmp; if (fForceDefault) pszDmiSystemUuid = NULL; else { rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid)); if (rc == VERR_CFGM_VALUE_NOT_FOUND) pszDmiSystemUuid = NULL; else if (RT_FAILURE(rc)) { if (fHideErrors) { LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n")); continue; } return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed")); } else pszDmiSystemUuid = szDmiSystemUuid; } /********************************* * 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 */ int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor; READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor); READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor); if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0) { pszStr = (char *)&pBIOSInf->u8FirmwareMajor; pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor); pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor; pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor; int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor; READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor); READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor); 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; READCFGSTR(pBIOSInf->u8Vendor, DmiBIOSVendor); READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion); pBIOSInf->u16Start = 0xE000; READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate); 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?? */ ; TERM_STRUCT; /*********************************** * DMI system information (Type 1) * ***********************************/ PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr; CHECKSIZE(sizeof(*pSystemInf)); START_STRUCT(pSystemInf); pSystemInf->header.u8Type = 1; /* System Information */ pSystemInf->header.u8Length = sizeof(*pSystemInf); pSystemInf->header.u16Handle = 0x0001; READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor); READCFGSTR(pSystemInf->u8ProductName, DmiSystemProduct); READCFGSTR(pSystemInf->u8Version, DmiSystemVersion); READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial); RTUUID uuid; if (pszDmiSystemUuid) { rc = RTUuidFromStr(&uuid, pszDmiSystemUuid); if (RT_FAILURE(rc)) { if (fHideErrors) { LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n")); continue; } return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: 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 */ READCFGSTR(pSystemInf->u8SKUNumber, DmiSystemSKU); READCFGSTR(pSystemInf->u8Family, DmiSystemFamily); TERM_STRUCT; /********************************** * DMI board information (Type 2) * **********************************/ PDMIBOARDINF pBoardInf = (PDMIBOARDINF)pszStr; CHECKSIZE(sizeof(*pBoardInf)); START_STRUCT(pBoardInf); int iDmiBoardBoardType; pBoardInf->header.u8Type = 2; /* Board Information */ pBoardInf->header.u8Length = sizeof(*pBoardInf); pBoardInf->header.u16Handle = 0x0008; READCFGSTR(pBoardInf->u8Manufacturer, DmiBoardVendor); READCFGSTR(pBoardInf->u8Product, DmiBoardProduct); READCFGSTR(pBoardInf->u8Version, DmiBoardVersion); READCFGSTR(pBoardInf->u8SerialNumber, DmiBoardSerial); READCFGSTR(pBoardInf->u8AssetTag, DmiBoardAssetTag); pBoardInf->u8FeatureFlags = RT_BIT(0) /* hosting board, e.g. motherboard */ ; READCFGSTR(pBoardInf->u8LocationInChass, DmiBoardLocInChass); pBoardInf->u16ChassisHandle = 0x0003; /* see type 3 */ READCFGINT(iDmiBoardBoardType, DmiBoardBoardType); pBoardInf->u8BoardType = iDmiBoardBoardType; pBoardInf->u8cObjectHandles = 0; TERM_STRUCT; /******************************************** * 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; READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor); int iDmiChassisType; READCFGINT(iDmiChassisType, DmiChassisType); pChassis->u8Type = iDmiChassisType; READCFGSTR(pChassis->u8Version, DmiChassisVersion); READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial); READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag); 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 TERM_STRUCT; /************************************** * DMI Processor Information (Type 4) * **************************************/ /* * This is just a dummy processor. Should we expose the real guest CPU features * here? Accessing this information at this point is difficult. */ char szSocket[32]; PDMIPROCESSORINF pProcessorInf = (PDMIPROCESSORINF)pszStr; CHECKSIZE(sizeof(*pProcessorInf)); START_STRUCT(pProcessorInf); if (fDmiExposeProcessorInf) pProcessorInf->header.u8Type = 4; /* Processor Information */ else pProcessorInf->header.u8Type = 126; /* inactive structure */ pProcessorInf->header.u8Length = sizeof(*pProcessorInf); pProcessorInf->header.u16Handle = 0x0007; RTStrPrintf(szSocket, sizeof(szSocket), "Socket #%u", 0); pProcessorInf->u8SocketDesignation = iStrNr++; { size_t cStr = strlen(szSocket) + 1; CHECKSIZE(cStr); memcpy(pszStr, szSocket, cStr); pszStr += cStr; } pProcessorInf->u8ProcessorType = 0x03; /* Central Processor */ pProcessorInf->u8ProcessorFamily = 0xB1; /* Pentium III with Intel SpeedStep(TM) */ READCFGSTR(pProcessorInf->u8ProcessorManufacturer, DmiProcManufacturer); pProcessorInf->u64ProcessorID = UINT64_C(0x0FEBFBFF00010676); /* Ext Family ID = 0 * Ext Model ID = 2 * Processor Type = 0 * Family ID = 6 * Model = 7 * Stepping = 6 * Features: FPU, VME, DE, PSE, TSC, MSR, PAE, MCE, CX8, * APIC, SEP, MTRR, PGE, MCA, CMOV, PAT, PSE-36, * CFLSH, DS, ACPI, MMX, FXSR, SSE, SSE2, SS */ READCFGSTR(pProcessorInf->u8ProcessorVersion, DmiProcVersion); pProcessorInf->u8Voltage = 0x02; /* 3.3V */ pProcessorInf->u16ExternalClock = 0x00; /* unknown */ pProcessorInf->u16MaxSpeed = 3000; /* 3GHz */ pProcessorInf->u16CurrentSpeed = 3000; /* 3GHz */ pProcessorInf->u8Status = RT_BIT(6) /* CPU socket populated */ | RT_BIT(0) /* CPU enabled */ ; pProcessorInf->u8ProcessorUpgrade = 0x04; /* ZIF Socket */ pProcessorInf->u16L1CacheHandle = 0xFFFF; /* not specified */ pProcessorInf->u16L2CacheHandle = 0xFFFF; /* not specified */ pProcessorInf->u16L3CacheHandle = 0xFFFF; /* not specified */ pProcessorInf->u8SerialNumber = 0; /* not specified */ pProcessorInf->u8AssetTag = 0; /* not specified */ pProcessorInf->u8PartNumber = 0; /* not specified */ pProcessorInf->u8CoreCount = cCpus; /* */ pProcessorInf->u8CoreEnabled = cCpus; pProcessorInf->u8ThreadCount = 1; pProcessorInf->u16ProcessorCharacteristics = RT_BIT(2); /* 64-bit capable */ pProcessorInf->u16ProcessorFamily2 = 0; TERM_STRUCT; /*************************************** * DMI Physical Memory Array (Type 16) * ***************************************/ uint64_t u64RamSize; rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"RamSize\"")); PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr; CHECKSIZE(sizeof(*pMemArray)); START_STRUCT(pMemArray); if (fDmiExposeMemoryTable) pMemArray->header.u8Type = 16; /* Physical Memory Array */ else pMemArray->header.u8Type = 126; /* inactive structure */ pMemArray->header.u8Length = sizeof(*pMemArray); pMemArray->header.u16Handle = 0x0005; pMemArray->u8Location = 0x03; /* Motherboard */ pMemArray->u8Use = 0x03; /* System memory */ pMemArray->u8MemErrorCorrection = 0x01; /* Other */ pMemArray->u32MaxCapacity = (uint32_t)(u64RamSize / _1K); /* RAM size in K */ pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */ pMemArray->u16NumberOfMemDevices = 1; TERM_STRUCT; /*************************************** * DMI Memory Device (Type 17) * ***************************************/ PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr; CHECKSIZE(sizeof(*pMemDev)); START_STRUCT(pMemDev); if (fDmiExposeMemoryTable) pMemDev->header.u8Type = 17; /* Memory Device */ else pMemDev->header.u8Type = 126; /* inactive structure */ pMemDev->header.u8Length = sizeof(*pMemDev); pMemDev->header.u16Handle = 0x0006; pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */ pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */ pMemDev->u16TotalWidth = 0xffff; /* Unknown */ pMemDev->u16DataWidth = 0xffff; /* Unknown */ int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M); if (u16RamSizeM == 0) u16RamSizeM = 0x400; /* 1G */ pMemDev->u16Size = u16RamSizeM; /* RAM size */ pMemDev->u8FormFactor = 0x09; /* DIMM */ pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */ READCFGSTRDEF(pMemDev->u8DeviceLocator, " ", "DIMM 0"); READCFGSTRDEF(pMemDev->u8BankLocator, " ", "Bank 0"); pMemDev->u8MemoryType = 0x03; /* DRAM */ pMemDev->u16TypeDetail = 0; /* Nothing special */ pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */ READCFGSTR(pMemDev->u8Manufacturer, DmiSystemVendor); READCFGSTRDEF(pMemDev->u8SerialNumber, " ", "00000000"); READCFGSTRDEF(pMemDev->u8AssetTag, " ", "00000000"); READCFGSTRDEF(pMemDev->u8PartNumber, " ", "00000000"); pMemDev->u8Attributes = 0; /* Unknown */ TERM_STRUCT; /***************************** * DMI OEM strings (Type 11) * *****************************/ PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr; CHECKSIZE(sizeof(*pOEMStrings)); START_STRUCT(pOEMStrings); #ifdef VBOX_WITH_DMI_OEMSTRINGS pOEMStrings->header.u8Type = 0xb; /* OEM Strings */ #else pOEMStrings->header.u8Type = 126; /* inactive structure */ #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()); READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp); RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision()); READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp); TERM_STRUCT; /************************************* * DMI OEM specific table (Type 128) * ************************************/ PDMIOEMSPECIFIC pOEMSpecific = (PDMIOEMSPECIFIC)pszStr; CHECKSIZE(sizeof(*pOEMSpecific)); START_STRUCT(pOEMSpecific); pOEMSpecific->header.u8Type = 0x80; /* OEM specific */ pOEMSpecific->header.u8Length = sizeof(*pOEMSpecific); pOEMSpecific->header.u16Handle = 0x0008; /* Just next free handle */ pOEMSpecific->u32CpuFreqKHz = RT_H2LE_U32((uint32_t)((uint64_t)TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns)) / 1000)); TERM_STRUCT; /* End-of-table marker - includes padding to account for fixed table size. */ PDMIHDR pEndOfTable = (PDMIHDR)pszStr; pszStr = (char *)(pEndOfTable + 1); pEndOfTable->u8Type = 0x7f; pEndOfTable->u8Length = sizeof(*pEndOfTable); pEndOfTable->u16Handle = 0xFEFF; *pcbDmiTables = ((uintptr_t)pszStr - (uintptr_t)pTable) + 2; /* We currently plant 10 DMI tables. Update this if tables number changed. */ *pcNumDmiTables = 10; /* If more fields are added here, fix the size check in READCFGSTR */ /* Success! */ break; } #undef READCFGSTR #undef READCFGINT #undef CHECKSIZE return VINF_SUCCESS; }
/** * Construct the DMI table. * * @returns VBox status code. * @param pDevIns The device instance. * @param pTable Where to create the DMI table. * @param cbMax The maximum size of the DMI table. * @param pUuid Pointer to the UUID to use if the DmiUuid * configuration string isn't present. * @param pCfg The handle to our config node. */ int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg) { #define CHECKSIZE(cbWant) \ { \ size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \ if (cbNeed > cbMax) \ { \ if (fHideErrors) \ { \ LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \ continue; \ } \ 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"), cbNeed, cbMax); \ } \ } #define READCFGSTRDEF(variable, name, default_value) \ { \ if (fForceDefault) \ pszTmp = default_value; \ else \ { \ rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \ if (RT_FAILURE(rc)) \ { \ if (fHideErrors) \ { \ LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \ continue; \ } \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" name "\" as a string failed")); \ } \ else if (!strcmp(szBuf, "<EMPTY>")) \ pszTmp = ""; \ else \ pszTmp = szBuf; \ } \ if (!pszTmp[0]) \ variable = 0; /* empty string */ \ else \ { \ variable = iStrNr++; \ size_t cStr = strlen(pszTmp) + 1; \ CHECKSIZE(cStr); \ memcpy(pszStr, pszTmp, cStr); \ pszStr += cStr ; \ } \ } #define READCFGSTR(variable, name) \ READCFGSTRDEF(variable, # name, s_szDef ## name) #define READCFGINT(variable, name) \ { \ if (fForceDefault) \ variable = s_iDef ## name; \ else \ { \ rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \ if (RT_FAILURE(rc)) \ { \ if (fHideErrors) \ { \ LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \ continue; \ } \ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \ N_("Configuration error: Querying \"" # name "\" as an int failed")); \ } \ } \ } #define START_STRUCT(tbl) \ pszStr = (char *)(tbl + 1); \ iStrNr = 1; #define TERM_STRUCT \ { \ *pszStr++ = '\0'; /* terminate set of text strings */ \ if (iStrNr == 1) \ *pszStr++ = '\0'; /* terminate a structure without strings */ \ } bool fForceDefault = false; #ifdef VBOX_BIOS_DMI_FALLBACK /* * There will be two passes. If an error occurs during the first pass, a * message will be written to the release log and we fall back to default * DMI data and start a second pass. */ bool fHideErrors = true; #else /* * There will be one pass, every error is fatal and will prevent the VM * from starting. */ bool fHideErrors = false; #endif uint8_t fDmiUseHostInfo; int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiUseHostInfo\"")); /* Sync up with host default DMI values */ if (fDmiUseHostInfo) fwCommonUseHostDMIStrings(); uint8_t fDmiExposeMemoryTable; rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiExposeMemoryTable\"")); for (;; fForceDefault = true, fHideErrors = false) { int iStrNr; char szBuf[256]; char *pszStr = (char *)pTable; char szDmiSystemUuid[64]; char *pszDmiSystemUuid; const char *pszTmp; if (fForceDefault) pszDmiSystemUuid = NULL; else { rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid)); if (rc == VERR_CFGM_VALUE_NOT_FOUND) pszDmiSystemUuid = NULL; else if (RT_FAILURE(rc)) { if (fHideErrors) { LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n")); continue; } return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed")); } else pszDmiSystemUuid = szDmiSystemUuid; } /********************************* * 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 */ int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor; READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor); READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor); if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0) { pszStr = (char *)&pBIOSInf->u8FirmwareMajor; pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor); pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor; pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor; int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor; READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor); READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor); 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; READCFGSTR(pBIOSInf->u8Vendor, DmiBIOSVendor); READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion); pBIOSInf->u16Start = 0xE000; READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate); 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?? */ ; TERM_STRUCT; /*********************************** * 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; READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor); READCFGSTR(pSystemInf->u8ProductName, DmiSystemProduct); READCFGSTR(pSystemInf->u8Version, DmiSystemVersion); READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial); RTUUID uuid; if (pszDmiSystemUuid) { rc = RTUuidFromStr(&uuid, pszDmiSystemUuid); if (RT_FAILURE(rc)) { if (fHideErrors) { LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n")); continue; } return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Configuration error: 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 */ READCFGSTR(pSystemInf->u8SKUNumber, DmiSystemSKU); READCFGSTR(pSystemInf->u8Family, DmiSystemFamily); TERM_STRUCT; /******************************************** * 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; READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor); pChassis->u8Type = 0x01; /* ''other'', no chassis lock present */ READCFGSTR(pChassis->u8Version, DmiChassisVersion); READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial); READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag); 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 TERM_STRUCT; if (fDmiExposeMemoryTable) { /*************************************** * DMI Physical Memory Array (Type 16) * ***************************************/ uint64_t u64RamSize; rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize); if (RT_FAILURE (rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"RamSize\"")); PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr; CHECKSIZE(sizeof(*pMemArray)); START_STRUCT(pMemArray); pMemArray->header.u8Type = 16; /* Physical Memory Array */ pMemArray->header.u8Length = sizeof(*pMemArray); pMemArray->header.u16Handle = 0x0005; pMemArray->u8Location = 0x03; /* Motherboard */ pMemArray->u8Use = 0x03; /* System memory */ pMemArray->u8MemErrorCorrection = 0x01; /* Other */ uint32_t u32RamSizeK = (uint32_t)(u64RamSize / _1K); pMemArray->u32MaxCapacity = u32RamSizeK; /* RAM size in K */ pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */ pMemArray->u16NumberOfMemDevices = 1; TERM_STRUCT; /*************************************** * DMI Memory Device (Type 17) * ***************************************/ PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr; CHECKSIZE(sizeof(*pMemDev)); START_STRUCT(pMemDev); pMemDev->header.u8Type = 17; /* Memory Device */ pMemDev->header.u8Length = sizeof(*pMemDev); pMemDev->header.u16Handle = 0x0006; pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */ pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */ pMemDev->u16TotalWidth = 0xffff; /* Unknown */ pMemDev->u16DataWidth = 0xffff; /* Unknown */ int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M); if (u16RamSizeM == 0) u16RamSizeM = 0x400; /* 1G */ pMemDev->u16Size = u16RamSizeM; /* RAM size */ pMemDev->u8FormFactor = 0x09; /* DIMM */ pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */ READCFGSTRDEF(pMemDev->u8DeviceLocator, " ", "DIMM 0"); READCFGSTRDEF(pMemDev->u8BankLocator, " ", "Bank 0"); pMemDev->u8MemoryType = 0x03; /* DRAM */ pMemDev->u16TypeDetail = 0; /* Nothing special */ pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */ READCFGSTR(pMemDev->u8Manufacturer, DmiSystemVendor); READCFGSTRDEF(pMemDev->u8SerialNumber, " ", "00000000"); READCFGSTRDEF(pMemDev->u8AssetTag, " ", "00000000"); READCFGSTRDEF(pMemDev->u8PartNumber, " ", "00000000"); pMemDev->u8Attributes = 0; /* Unknown */ TERM_STRUCT; } /***************************** * DMI OEM strings (Type 11) * *****************************/ 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()); READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp); RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision()); READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp); TERM_STRUCT; /* 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 READCFGSTR */ /* Success! */ break; } #undef READCFGSTR #undef READCFGINT #undef CHECKSIZE return VINF_SUCCESS; }