Skip to content

Commit 7fe617c

Browse files
authored
Restore ability to handle non-hex string in device discovery vendor/device id. (microsoft#25427)
### Description <!-- Describe your changes. --> Restore ability to handle "VEN_QCOM" from an ACPI entry. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. -->
1 parent 3a5f75b commit 7fe617c

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

onnxruntime/core/platform/windows/device_discovery.cc

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,29 @@ struct DriverInfo {
7777
}
7878
};
7979

80+
bool IsHexString(const std::wstring& str) {
81+
for (const wchar_t& c : str) {
82+
if (!((c >= L'0' && c <= L'9') || (c >= L'A' && c <= L'F') || (c >= L'a' && c <= L'f'))) {
83+
return false;
84+
}
85+
}
86+
return true;
87+
}
88+
89+
// Converts a wide string ACPI (up to 4 characters) representing a hardware ID component from into a uint32_t.
90+
// e.g., "QCOM" from "VEN_QCOM". The conversion is done in a little-endian manner, meaning the first character
91+
// of the string becomes the least significant byte of the integer, and the fourth character
92+
// becomes the most significant byte.
93+
uint32_t AcpiWStringToUint32Id(const std::wstring& vendor_name) {
94+
uint32_t vendor_id = 0;
95+
for (size_t i = 0; i < 4 && i < vendor_name.size(); ++i) {
96+
// For little-endian, place each character at the appropriate byte position
97+
// First character goes into lowest byte, last character into highest byte
98+
vendor_id |= static_cast<unsigned char>(vendor_name[i] & 0xFF) << (i * 8);
99+
}
100+
return vendor_id;
101+
}
102+
80103
uint64_t GetDeviceKey(uint32_t vendor_id, uint32_t device_id) {
81104
return (uint64_t(vendor_id) << 32) | device_id;
82105
}
@@ -134,25 +157,35 @@ std::unordered_map<uint64_t, DeviceInfo> GetDeviceInfoSetupApi(const std::unorde
134157
// PCI\VEN_xxxx&DEV_yyyy&...
135158
// ACPI\VEN_xxxx&DEV_yyyy&... if we're lucky.
136159
// ACPI values seem to be very inconsistent, so we check fairly carefully and always require a device id.
137-
const auto get_id = [](const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t {
160+
const auto get_id = [](bool is_pci, const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t {
138161
if (auto idx = hardware_id.find(prefix); idx != std::wstring::npos) {
139162
auto id = hardware_id.substr(idx + prefix.size(), 4);
163+
140164
if (id.size() == 4) {
141-
return static_cast<uint32_t>(std::stoul(id, nullptr, 16));
165+
if (is_pci || IsHexString(id)) {
166+
// PCI entries have hex numbers. ACPI might.
167+
return static_cast<uint32_t>(std::stoul(id, nullptr, 16));
168+
} else {
169+
// ACPI can have things like "VEN_QCOM". Fallback to using this conversion where the characters
170+
// are converted in little-endian order.
171+
return AcpiWStringToUint32Id(id);
172+
}
142173
}
143174
}
144175

145176
return 0;
146177
};
147178

148-
// Processor ID should come from CPUID mapping.
179+
const bool is_pci = std::wstring(buffer, 3) == std::wstring(L"PCI");
180+
149181
if (guid == GUID_DEVCLASS_PROCESSOR) {
182+
// Processor ID should come from CPUID mapping.
150183
vendor_id = CPUIDInfo::GetCPUIDInfo().GetCPUVendorId();
151184
} else {
152-
vendor_id = get_id(buffer, L"VEN_");
185+
vendor_id = get_id(is_pci, buffer, L"VEN_");
153186
}
154187

155-
device_id = get_id(buffer, L"DEV_");
188+
device_id = get_id(is_pci, buffer, L"DEV_");
156189

157190
// Won't always have a vendor id from an ACPI entry. ACPI is not defined for this purpose.
158191
if (vendor_id == 0 && device_id == 0) {

0 commit comments

Comments
 (0)