diff --git a/onnxruntime/core/platform/windows/device_discovery.cc b/onnxruntime/core/platform/windows/device_discovery.cc index fa645939a6395..ff904ddb3e7e0 100644 --- a/onnxruntime/core/platform/windows/device_discovery.cc +++ b/onnxruntime/core/platform/windows/device_discovery.cc @@ -77,6 +77,29 @@ struct DriverInfo { } }; +bool IsHexString(const std::wstring& str) { + for (const wchar_t& c : str) { + if (!((c >= L'0' && c <= L'9') || (c >= L'A' && c <= L'F') || (c >= L'a' && c <= L'f'))) { + return false; + } + } + return true; +} + +// Converts a wide string ACPI (up to 4 characters) representing a hardware ID component from into a uint32_t. +// e.g., "QCOM" from "VEN_QCOM". The conversion is done in a little-endian manner, meaning the first character +// of the string becomes the least significant byte of the integer, and the fourth character +// becomes the most significant byte. +uint32_t AcpiWStringToUint32Id(const std::wstring& vendor_name) { + uint32_t vendor_id = 0; + for (size_t i = 0; i < 4 && i < vendor_name.size(); ++i) { + // For little-endian, place each character at the appropriate byte position + // First character goes into lowest byte, last character into highest byte + vendor_id |= static_cast(vendor_name[i] & 0xFF) << (i * 8); + } + return vendor_id; +} + uint64_t GetDeviceKey(uint32_t vendor_id, uint32_t device_id) { return (uint64_t(vendor_id) << 32) | device_id; } @@ -134,25 +157,35 @@ std::unordered_map GetDeviceInfoSetupApi(const std::unorde // PCI\VEN_xxxx&DEV_yyyy&... // ACPI\VEN_xxxx&DEV_yyyy&... if we're lucky. // ACPI values seem to be very inconsistent, so we check fairly carefully and always require a device id. - const auto get_id = [](const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t { + const auto get_id = [](bool is_pci, const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t { if (auto idx = hardware_id.find(prefix); idx != std::wstring::npos) { auto id = hardware_id.substr(idx + prefix.size(), 4); + if (id.size() == 4) { - return static_cast(std::stoul(id, nullptr, 16)); + if (is_pci || IsHexString(id)) { + // PCI entries have hex numbers. ACPI might. + return static_cast(std::stoul(id, nullptr, 16)); + } else { + // ACPI can have things like "VEN_QCOM". Fallback to using this conversion where the characters + // are converted in little-endian order. + return AcpiWStringToUint32Id(id); + } } } return 0; }; - // Processor ID should come from CPUID mapping. + const bool is_pci = std::wstring(buffer, 3) == std::wstring(L"PCI"); + if (guid == GUID_DEVCLASS_PROCESSOR) { + // Processor ID should come from CPUID mapping. vendor_id = CPUIDInfo::GetCPUIDInfo().GetCPUVendorId(); } else { - vendor_id = get_id(buffer, L"VEN_"); + vendor_id = get_id(is_pci, buffer, L"VEN_"); } - device_id = get_id(buffer, L"DEV_"); + device_id = get_id(is_pci, buffer, L"DEV_"); // Won't always have a vendor id from an ACPI entry. ACPI is not defined for this purpose. if (vendor_id == 0 && device_id == 0) {