/** * Looking Glass * Copyright © 2017-2024 The Looking Glass Authors * https://looking-glass.io * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "CPlatformInfo.h" #include "Debug.h" #include size_t CPlatformInfo::m_pageSize = 0; std::string CPlatformInfo::m_productName = "Unknown"; uint8_t CPlatformInfo::m_uuid[16]; std::string CPlatformInfo::m_model = "Unknown"; int CPlatformInfo::m_cores = 0; int CPlatformInfo::m_procs = 0; int CPlatformInfo::m_sockets = 0; void CPlatformInfo::Init() { SYSTEM_INFO si; GetSystemInfo(&si); m_pageSize = (size_t)si.dwPageSize; // we only use this for reporting, it's OK that it might not be exactly accurate #pragma warning(push) #pragma warning(disable : 4996) OSVERSIONINFOA osvi = {}; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionExA(&osvi); #pragma warning(pop) DWORD bufferSize = 0; LSTATUS status = RegGetValueA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", RRF_RT_REG_SZ, nullptr, nullptr, &bufferSize); if (status == ERROR_SUCCESS) { m_productName.resize(bufferSize); status = RegGetValueA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", RRF_RT_REG_SZ, nullptr, &m_productName[0], &bufferSize); if (status != ERROR_SUCCESS) { m_productName = "Unknown"; DBGPRINT("Failed to read the ProductName"); } else m_productName.resize(bufferSize - 1); // remove the double null termination } else { m_productName = "Windows " + std::to_string(osvi.dwMajorVersion) + "." + std::to_string(osvi.dwMinorVersion); } m_productName += " (Build: " + std::to_string(osvi.dwBuildNumber) + ") " + osvi.szCSDVersion; InitUUID(); InitCPUInfo(); } #define TABLE_SIG(x) (\ ((uint32_t)(x[0]) << 24) | \ ((uint32_t)(x[1]) << 16) | \ ((uint32_t)(x[2]) << 8 ) | \ ((uint32_t)(x[3]) << 0 )) #define SMB_SST_SystemInformation 1 #define SMBVER(major, minor) \ ((smbData->SMBIOSMajorVersion == major && \ smbData->SMBIOSMinorVersion >= minor) || \ (smbData->SMBIOSMajorVersion > major)) #define REVERSE32(x) \ *(uint32_t*)(x) = ((*(uint32_t*)(x) & 0xFFFF0000) >> 16) | \ ((*(uint32_t*)(x) & 0x0000FFFF) << 16) #define REVERSE16(x) \ *(uint16_t*)(x) = ((*(uint16_t*)(x) & 0xFF00) >> 8) | \ ((*(uint16_t*)(x) & 0x00FF) << 8) static void* smbParseData(uint8_t** data, char* strings[]) { #pragma pack(push, 1) struct SMBHeader { uint8_t type; uint8_t length; }; #pragma pack(pop) SMBHeader* h = (SMBHeader*)*data; *data += h->length; if (**data) for (int i = 1; i < 256 && **data; ++i) { strings[i] = (char*)*data; *data += strlen((char*)*data) + 1; } else ++* data; ++* data; return h; } void CPlatformInfo::InitUUID() { // don't warn on zero length arrays #pragma warning(push) #pragma warning(disable: 4200) struct RawSMBIOSData { BYTE Used20CallingMethod; BYTE SMBIOSMajorVersion; BYTE SMBIOSMinorVersion; BYTE DmiRevision; DWORD Length; BYTE SMBIOSTableData[]; }; #pragma warning(pop) #pragma pack(push, 1) struct SMBSystemInformation { uint8_t type; uint8_t length; uint16_t handle; uint8_t manufacturerStr; uint8_t productStr; uint8_t versionStr; uint8_t serialStr; uint8_t uuid[16]; uint8_t wakeupType; uint8_t skuNumberStr; uint8_t familyStr; }; #pragma pack(pop) DWORD smbDataSize; RawSMBIOSData * smbData; smbDataSize = GetSystemFirmwareTable(TABLE_SIG("RSMB"), 0, nullptr, 0); smbData = (RawSMBIOSData*)new BYTE[smbDataSize]; if (!smbData) { DBGPRINT("out of memory"); return; } if (GetSystemFirmwareTable(TABLE_SIG("RSMB"), 0, smbData, smbDataSize) != smbDataSize) { DBGPRINT("Failed to read the RSMB table"); delete[] smbData; return; } uint8_t * data = (uint8_t *)smbData->SMBIOSTableData; uint8_t * end = (uint8_t *)smbData->SMBIOSTableData + smbData->Length; char * strings[256] = {}; while (data != end) { if (data[0] == SMB_SST_SystemInformation) { SMBSystemInformation * info = (SMBSystemInformation *)smbParseData(&data, strings); memcpy(&m_uuid, &info->uuid, 16); REVERSE32(&m_uuid[0]); REVERSE16(&m_uuid[0]); REVERSE16(&m_uuid[2]); REVERSE16(&m_uuid[4]); REVERSE16(&m_uuid[6]); break; } smbParseData(&data, strings); } delete[] smbData; } void CPlatformInfo::InitCPUInfo() { DWORD bufferSize = 0; LSTATUS status = RegGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0", "ProcessorNameString", RRF_RT_REG_SZ, nullptr, nullptr, &bufferSize); if (status == ERROR_SUCCESS) { m_model.resize(bufferSize); status = RegGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0", "ProcessorNameString", RRF_RT_REG_SZ, nullptr, &m_model[0], &bufferSize); if (status != ERROR_SUCCESS) { m_model = "Unknown"; DBGPRINT("Failed to read the CPU Model"); } else { m_model.resize(bufferSize - 1); // remove the double null termination m_model.erase(m_model.find_last_not_of(" \t\n\r\f\v") + 1); } } DWORD cb = 0; GetLogicalProcessorInformationEx(RelationAll, nullptr, &cb); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { DBGPRINT("Failed to call GetLogicalProcessorInformationEx"); return; } BYTE * buffer = static_cast(_malloca(cb)); if (!buffer) { DBGPRINT("Failed to allocate buffer for processor information"); return; } if (!GetLogicalProcessorInformationEx(RelationAll, (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)buffer, &cb)) { DBGPRINT("Failed to call GetLogicalProcessorInformationEx"); _freea(buffer); return; } DWORD offset = 0; while (offset < cb) { PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)(buffer + offset); switch (lpi->Relationship) { case RelationProcessorCore: ++m_cores; for(int i = 0; i < lpi->Processor.GroupCount; ++i) m_procs += (int)__popcnt64(lpi->Processor.GroupMask[i].Mask); break; case RelationProcessorPackage: ++m_sockets; default: break; } offset += lpi->Size; } _freea(buffer); }