[PULL 0/9] qemu-ga-win patches
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEwsLBCepDxjwUI+uE711egWG6hOcFAmHjRNEACgkQ711egWG6 hOeLaQ/+IwvZEaf98SdzG+v0U/e88kfC5dnsRQPywnsmr9gHTIHxcOA7tcfrCVE3 s1odyoe1tzypVetNTIW0enguGxB2d0ifr1BloBx5rrRxa8NwIDMOOTW5TnvHZaay zD4Z+5cZr9miD2Al4Wojoni7C0HAwnFsXOzMBzAgT7LLx7hdNrCU2q/YNhwsI+UK 2kZPPNfzF2rsFgo3IiyCHG+C6fWdTXHWeNXd5VdFpfnC7x70Z4HtB68ohIx7nMjS LkvXDMNDycoNdLsDJTPDsNOV1GvsvBFeRyD5dXThDAgUlZVIaQPy1tbZ3jeenFoT UoJqB+WCZx1mHtYagLufBs8AU+oF1vZ35vS9Ncq6VeCDw4Qb6883q+bjyDf0PH3J HRXoFs7gejjqs1NP5yeqX7e687f/+FZkJsqhZucQFIl5Ped8JmBYTpjLQChf3yq1 ssUrIHVmCwg0nQivVPpDzh+z1XSlOUVF0nYb2iP2VoztAh6AZYt8hnp8xaI0EyNR BJXBqNKnmpdY3IJRnkLK6q3OgYah/7EtuMj9E82jcc/NRasMXeQmUZDqfPDFxLu7 l7pDOYc+1/GJQBYOokSlHcmmWlbfyf+2TKReoqb0XryEXa9kTomlMDxBQ//LjEP8 DGzIzvI3l4P5CUZ6WCHLCLsGFp39H9ryWdYzRyeEN3Oi12SRa+o= =US9k -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/konstantin/tags/qga-win32-pull-2022-01-10' into staging [PULL 0/9] qemu-ga-win patches # gpg: Signature made Sat 15 Jan 2022 22:04:01 GMT # gpg: using RSA key C2C2C109EA43C63C1423EB84EF5D5E8161BA84E7 # gpg: Good signature from "Kostiantyn Kostiuk (Upstream PR sign) <kkostiuk@redhat.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: C2C2 C109 EA43 C63C 1423 EB84 EF5D 5E81 61BA 84E7 * remotes/konstantin/tags/qga-win32-pull-2022-01-10: qga-win: Detect Windows 11 by build number qga-win: Detect OS based on Windows 10 by first build number gqa-win: get_pci_info: Replace 'while' with 2 calls of the function gqa-win: get_pci_info: Add g_autofree for few variables gqa-win: get_pci_info: Split logic to separate functions gqa-win: get_pci_info: Free parent_dev_info properly gqa-win: get_pci_info: Use common 'end' label gqa-win: get_pci_info: Clean dev_info if handle is valid MAINTAINERS: Add entry for QEMU Guest Agent Windows components Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
69353c332c
@ -2741,6 +2741,14 @@ F: scripts/qemu-guest-agent/
|
|||||||
F: tests/unit/test-qga.c
|
F: tests/unit/test-qga.c
|
||||||
T: git https://github.com/mdroth/qemu.git qga
|
T: git https://github.com/mdroth/qemu.git qga
|
||||||
|
|
||||||
|
QEMU Guest Agent Win32
|
||||||
|
M: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||||
|
S: Maintained
|
||||||
|
F: qga/*win32*
|
||||||
|
F: qga/vss-win32/
|
||||||
|
F: qga/installer/
|
||||||
|
T: git https://github.com/kostyanf14/qemu.git qga-win32
|
||||||
|
|
||||||
QOM
|
QOM
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
R: Daniel P. Berrange <berrange@redhat.com>
|
R: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
@ -512,15 +512,102 @@ DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT,
|
|||||||
0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82,
|
0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82,
|
||||||
0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
|
0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
|
||||||
|
|
||||||
|
static void get_pci_address_for_device(GuestPCIAddress *pci,
|
||||||
|
HDEVINFO dev_info)
|
||||||
|
{
|
||||||
|
SP_DEVINFO_DATA dev_info_data;
|
||||||
|
DWORD j;
|
||||||
|
DWORD size;
|
||||||
|
bool partial_pci = false;
|
||||||
|
|
||||||
|
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
|
||||||
|
for (j = 0;
|
||||||
|
SetupDiEnumDeviceInfo(dev_info, j, &dev_info_data);
|
||||||
|
j++) {
|
||||||
|
DWORD addr, bus, ui_slot, type;
|
||||||
|
int func, slot;
|
||||||
|
size = sizeof(DWORD);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no need to allocate buffer in the next functions. The
|
||||||
|
* size is known and ULONG according to
|
||||||
|
* https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
if (!SetupDiGetDeviceRegistryProperty(
|
||||||
|
dev_info, &dev_info_data, SPDRP_BUSNUMBER,
|
||||||
|
&type, (PBYTE)&bus, size, NULL)) {
|
||||||
|
debug_error("failed to get PCI bus");
|
||||||
|
bus = -1;
|
||||||
|
partial_pci = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The function retrieves the device's address. This value will be
|
||||||
|
* transformed into device function and number
|
||||||
|
*/
|
||||||
|
if (!SetupDiGetDeviceRegistryProperty(
|
||||||
|
dev_info, &dev_info_data, SPDRP_ADDRESS,
|
||||||
|
&type, (PBYTE)&addr, size, NULL)) {
|
||||||
|
debug_error("failed to get PCI address");
|
||||||
|
addr = -1;
|
||||||
|
partial_pci = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This call returns UINumber of DEVICE_CAPABILITIES structure.
|
||||||
|
* This number is typically a user-perceived slot number.
|
||||||
|
*/
|
||||||
|
if (!SetupDiGetDeviceRegistryProperty(
|
||||||
|
dev_info, &dev_info_data, SPDRP_UI_NUMBER,
|
||||||
|
&type, (PBYTE)&ui_slot, size, NULL)) {
|
||||||
|
debug_error("failed to get PCI slot");
|
||||||
|
ui_slot = -1;
|
||||||
|
partial_pci = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SetupApi gives us the same information as driver with
|
||||||
|
* IoGetDeviceProperty. According to Microsoft:
|
||||||
|
*
|
||||||
|
* FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF)
|
||||||
|
* DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF)
|
||||||
|
* SPDRP_ADDRESS is propertyAddress, so we do the same.
|
||||||
|
*
|
||||||
|
* https://docs.microsoft.com/en-us/windows/desktop/api/setupapi/nf-setupapi-setupdigetdeviceregistrypropertya
|
||||||
|
*/
|
||||||
|
if (partial_pci) {
|
||||||
|
pci->domain = -1;
|
||||||
|
pci->slot = -1;
|
||||||
|
pci->function = -1;
|
||||||
|
pci->bus = -1;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
func = ((int)addr == -1) ? -1 : addr & 0x0000FFFF;
|
||||||
|
slot = ((int)addr == -1) ? -1 : (addr >> 16) & 0x0000FFFF;
|
||||||
|
if ((int)ui_slot != slot) {
|
||||||
|
g_debug("mismatch with reported slot values: %d vs %d",
|
||||||
|
(int)ui_slot, slot);
|
||||||
|
}
|
||||||
|
pci->domain = 0;
|
||||||
|
pci->slot = (int)ui_slot;
|
||||||
|
pci->function = func;
|
||||||
|
pci->bus = (int)bus;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
||||||
{
|
{
|
||||||
HDEVINFO dev_info;
|
HDEVINFO dev_info = INVALID_HANDLE_VALUE;
|
||||||
|
HDEVINFO parent_dev_info = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
SP_DEVINFO_DATA dev_info_data;
|
SP_DEVINFO_DATA dev_info_data;
|
||||||
SP_DEVICE_INTERFACE_DATA dev_iface_data;
|
SP_DEVICE_INTERFACE_DATA dev_iface_data;
|
||||||
HANDLE dev_file;
|
HANDLE dev_file;
|
||||||
int i;
|
int i;
|
||||||
GuestPCIAddress *pci = NULL;
|
GuestPCIAddress *pci = NULL;
|
||||||
bool partial_pci = false;
|
|
||||||
|
|
||||||
pci = g_malloc0(sizeof(*pci));
|
pci = g_malloc0(sizeof(*pci));
|
||||||
pci->domain = -1;
|
pci->domain = -1;
|
||||||
@ -532,29 +619,27 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||||
if (dev_info == INVALID_HANDLE_VALUE) {
|
if (dev_info == INVALID_HANDLE_VALUE) {
|
||||||
error_setg_win32(errp, GetLastError(), "failed to get devices tree");
|
error_setg_win32(errp, GetLastError(), "failed to get devices tree");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_debug("enumerating devices");
|
g_debug("enumerating devices");
|
||||||
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||||
for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
|
for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_iface_detail_data = NULL;
|
g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_iface_detail_data = NULL;
|
||||||
STORAGE_DEVICE_NUMBER sdn;
|
STORAGE_DEVICE_NUMBER sdn;
|
||||||
char *parent_dev_id = NULL;
|
g_autofree char *parent_dev_id = NULL;
|
||||||
HDEVINFO parent_dev_info;
|
|
||||||
SP_DEVINFO_DATA parent_dev_info_data;
|
SP_DEVINFO_DATA parent_dev_info_data;
|
||||||
DWORD j;
|
|
||||||
DWORD size = 0;
|
DWORD size = 0;
|
||||||
|
|
||||||
g_debug("getting device path");
|
g_debug("getting device path");
|
||||||
if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data,
|
if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data,
|
||||||
&GUID_DEVINTERFACE_DISK, 0,
|
&GUID_DEVINTERFACE_DISK, 0,
|
||||||
&dev_iface_data)) {
|
&dev_iface_data)) {
|
||||||
while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
|
if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
|
||||||
pdev_iface_detail_data,
|
pdev_iface_detail_data,
|
||||||
size, &size,
|
size, &size,
|
||||||
&dev_info_data)) {
|
&dev_info_data)) {
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
pdev_iface_detail_data = g_malloc(size);
|
pdev_iface_detail_data = g_malloc(size);
|
||||||
pdev_iface_detail_data->cbSize =
|
pdev_iface_detail_data->cbSize =
|
||||||
@ -562,21 +647,30 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
} else {
|
} else {
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get device interfaces");
|
"failed to get device interfaces");
|
||||||
goto free_dev_info;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
|
||||||
|
pdev_iface_detail_data,
|
||||||
|
size, &size,
|
||||||
|
&dev_info_data)) {
|
||||||
|
// pdev_iface_detail_data already is allocated
|
||||||
|
error_setg_win32(errp, GetLastError(),
|
||||||
|
"failed to get device interfaces");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,
|
dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,
|
||||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
|
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
|
||||||
NULL);
|
NULL);
|
||||||
g_free(pdev_iface_detail_data);
|
|
||||||
|
|
||||||
if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
||||||
NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
|
NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
|
||||||
CloseHandle(dev_file);
|
CloseHandle(dev_file);
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get device slot number");
|
"failed to get device slot number");
|
||||||
goto free_dev_info;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(dev_file);
|
CloseHandle(dev_file);
|
||||||
@ -586,7 +680,7 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
} else {
|
} else {
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get device interfaces");
|
"failed to get device interfaces");
|
||||||
goto free_dev_info;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_debug("found device slot %d. Getting storage controller", number);
|
g_debug("found device slot %d. Getting storage controller", number);
|
||||||
@ -596,17 +690,25 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
ULONG dev_id_size = 0;
|
ULONG dev_id_size = 0;
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
while (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
|
if (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
|
||||||
parent_dev_id, size, &size)) {
|
parent_dev_id, size, &size)) {
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
parent_dev_id = g_malloc(size);
|
parent_dev_id = g_malloc(size);
|
||||||
} else {
|
} else {
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get device instance ID");
|
"failed to get device instance ID");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
|
||||||
|
parent_dev_id, size, &size)) {
|
||||||
|
// parent_dev_id already is allocated
|
||||||
|
error_setg_win32(errp, GetLastError(),
|
||||||
|
"failed to get device instance ID");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CM API used here as opposed to
|
* CM API used here as opposed to
|
||||||
* SetupDiGetDeviceProperty(..., DEVPKEY_Device_Parent, ...)
|
* SetupDiGetDeviceProperty(..., DEVPKEY_Device_Parent, ...)
|
||||||
@ -617,14 +719,14 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
g_error("CM_Locate_DevInst failed with code %lx", cr);
|
g_error("CM_Locate_DevInst failed with code %lx", cr);
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get device instance");
|
"failed to get device instance");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
cr = CM_Get_Parent(&parent_dev_inst, dev_inst, 0);
|
cr = CM_Get_Parent(&parent_dev_inst, dev_inst, 0);
|
||||||
if (cr != CR_SUCCESS) {
|
if (cr != CR_SUCCESS) {
|
||||||
g_error("CM_Get_Parent failed with code %lx", cr);
|
g_error("CM_Get_Parent failed with code %lx", cr);
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get parent device instance");
|
"failed to get parent device instance");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
cr = CM_Get_Device_ID_Size(&dev_id_size, parent_dev_inst, 0);
|
cr = CM_Get_Device_ID_Size(&dev_id_size, parent_dev_inst, 0);
|
||||||
@ -632,7 +734,7 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
g_error("CM_Get_Device_ID_Size failed with code %lx", cr);
|
g_error("CM_Get_Device_ID_Size failed with code %lx", cr);
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get parent device ID length");
|
"failed to get parent device ID length");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
++dev_id_size;
|
++dev_id_size;
|
||||||
@ -647,7 +749,7 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
g_error("CM_Get_Device_ID failed with code %lx", cr);
|
g_error("CM_Get_Device_ID failed with code %lx", cr);
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get parent device ID");
|
"failed to get parent device ID");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,101 +758,32 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
|
|||||||
parent_dev_info =
|
parent_dev_info =
|
||||||
SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev_id,
|
SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev_id,
|
||||||
NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||||
g_free(parent_dev_id);
|
|
||||||
|
|
||||||
if (parent_dev_info == INVALID_HANDLE_VALUE) {
|
if (parent_dev_info == INVALID_HANDLE_VALUE) {
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get parent device");
|
"failed to get parent device");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
parent_dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_data)) {
|
if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_data)) {
|
||||||
error_setg_win32(errp, GetLastError(),
|
error_setg_win32(errp, GetLastError(),
|
||||||
"failed to get parent device data");
|
"failed to get parent device data");
|
||||||
goto out;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0;
|
get_pci_address_for_device(pci, parent_dev_info);
|
||||||
SetupDiEnumDeviceInfo(parent_dev_info, j, &parent_dev_info_data);
|
|
||||||
j++) {
|
|
||||||
DWORD addr, bus, ui_slot, type;
|
|
||||||
int func, slot;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There is no need to allocate buffer in the next functions. The
|
|
||||||
* size is known and ULONG according to
|
|
||||||
* https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
|
|
||||||
*/
|
|
||||||
if (!SetupDiGetDeviceRegistryProperty(
|
|
||||||
parent_dev_info, &parent_dev_info_data, SPDRP_BUSNUMBER,
|
|
||||||
&type, (PBYTE)&bus, size, NULL)) {
|
|
||||||
debug_error("failed to get PCI bus");
|
|
||||||
bus = -1;
|
|
||||||
partial_pci = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The function retrieves the device's address. This value will be
|
|
||||||
* transformed into device function and number
|
|
||||||
*/
|
|
||||||
if (!SetupDiGetDeviceRegistryProperty(
|
|
||||||
parent_dev_info, &parent_dev_info_data, SPDRP_ADDRESS,
|
|
||||||
&type, (PBYTE)&addr, size, NULL)) {
|
|
||||||
debug_error("failed to get PCI address");
|
|
||||||
addr = -1;
|
|
||||||
partial_pci = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This call returns UINumber of DEVICE_CAPABILITIES structure.
|
|
||||||
* This number is typically a user-perceived slot number.
|
|
||||||
*/
|
|
||||||
if (!SetupDiGetDeviceRegistryProperty(
|
|
||||||
parent_dev_info, &parent_dev_info_data, SPDRP_UI_NUMBER,
|
|
||||||
&type, (PBYTE)&ui_slot, size, NULL)) {
|
|
||||||
debug_error("failed to get PCI slot");
|
|
||||||
ui_slot = -1;
|
|
||||||
partial_pci = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SetupApi gives us the same information as driver with
|
|
||||||
* IoGetDeviceProperty. According to Microsoft:
|
|
||||||
*
|
|
||||||
* FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF)
|
|
||||||
* DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF)
|
|
||||||
* SPDRP_ADDRESS is propertyAddress, so we do the same.
|
|
||||||
*
|
|
||||||
* https://docs.microsoft.com/en-us/windows/desktop/api/setupapi/nf-setupapi-setupdigetdeviceregistrypropertya
|
|
||||||
*/
|
|
||||||
if (partial_pci) {
|
|
||||||
pci->domain = -1;
|
|
||||||
pci->slot = -1;
|
|
||||||
pci->function = -1;
|
|
||||||
pci->bus = -1;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
func = ((int)addr == -1) ? -1 : addr & 0x0000FFFF;
|
|
||||||
slot = ((int)addr == -1) ? -1 : (addr >> 16) & 0x0000FFFF;
|
|
||||||
if ((int)ui_slot != slot) {
|
|
||||||
g_debug("mismatch with reported slot values: %d vs %d",
|
|
||||||
(int)ui_slot, slot);
|
|
||||||
}
|
|
||||||
pci->domain = 0;
|
|
||||||
pci->slot = (int)ui_slot;
|
|
||||||
pci->function = func;
|
|
||||||
pci->bus = (int)bus;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetupDiDestroyDeviceInfoList(parent_dev_info);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_dev_info:
|
end:
|
||||||
SetupDiDestroyDeviceInfoList(dev_info);
|
if (parent_dev_info != INVALID_HANDLE_VALUE) {
|
||||||
out:
|
SetupDiDestroyDeviceInfoList(parent_dev_info);
|
||||||
|
}
|
||||||
|
if (dev_info != INVALID_HANDLE_VALUE) {
|
||||||
|
SetupDiDestroyDeviceInfoList(dev_info);
|
||||||
|
}
|
||||||
return pci;
|
return pci;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2137,7 +2170,7 @@ typedef struct _ga_matrix_lookup_t {
|
|||||||
char const *version_id;
|
char const *version_id;
|
||||||
} ga_matrix_lookup_t;
|
} ga_matrix_lookup_t;
|
||||||
|
|
||||||
static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
|
static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][7] = {
|
||||||
{
|
{
|
||||||
/* Desktop editions */
|
/* Desktop editions */
|
||||||
{ 5, 0, "Microsoft Windows 2000", "2000"},
|
{ 5, 0, "Microsoft Windows 2000", "2000"},
|
||||||
@ -2146,7 +2179,6 @@ static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
|
|||||||
{ 6, 1, "Microsoft Windows 7" "7"},
|
{ 6, 1, "Microsoft Windows 7" "7"},
|
||||||
{ 6, 2, "Microsoft Windows 8", "8"},
|
{ 6, 2, "Microsoft Windows 8", "8"},
|
||||||
{ 6, 3, "Microsoft Windows 8.1", "8.1"},
|
{ 6, 3, "Microsoft Windows 8.1", "8.1"},
|
||||||
{10, 0, "Microsoft Windows 10", "10"},
|
|
||||||
{ 0, 0, 0}
|
{ 0, 0, 0}
|
||||||
},{
|
},{
|
||||||
/* Server editions */
|
/* Server editions */
|
||||||
@ -2156,24 +2188,29 @@ static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
|
|||||||
{ 6, 2, "Microsoft Windows Server 2012", "2012"},
|
{ 6, 2, "Microsoft Windows Server 2012", "2012"},
|
||||||
{ 6, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
|
{ 6, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
|
||||||
{ 0, 0, 0},
|
{ 0, 0, 0},
|
||||||
{ 0, 0, 0},
|
|
||||||
{ 0, 0, 0}
|
{ 0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _ga_win_10_0_server_t {
|
typedef struct _ga_win_10_0_t {
|
||||||
int final_build;
|
int first_build;
|
||||||
char const *version;
|
char const *version;
|
||||||
char const *version_id;
|
char const *version_id;
|
||||||
} ga_win_10_0_server_t;
|
} ga_win_10_0_t;
|
||||||
|
|
||||||
static ga_win_10_0_server_t const WIN_10_0_SERVER_VERSION_MATRIX[4] = {
|
static ga_win_10_0_t const WIN_10_0_SERVER_VERSION_MATRIX[4] = {
|
||||||
{14393, "Microsoft Windows Server 2016", "2016"},
|
{14393, "Microsoft Windows Server 2016", "2016"},
|
||||||
{17763, "Microsoft Windows Server 2019", "2019"},
|
{17763, "Microsoft Windows Server 2019", "2019"},
|
||||||
{20344, "Microsoft Windows Server 2022", "2022"},
|
{20344, "Microsoft Windows Server 2022", "2022"},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ga_win_10_0_t const WIN_10_0_CLIENT_VERSION_MATRIX[3] = {
|
||||||
|
{10240, "Microsoft Windows 10", "10"},
|
||||||
|
{22000, "Microsoft Windows 11", "11"},
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
|
static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
|
||||||
{
|
{
|
||||||
typedef NTSTATUS(WINAPI *rtl_get_version_t)(
|
typedef NTSTATUS(WINAPI *rtl_get_version_t)(
|
||||||
@ -2201,19 +2238,24 @@ static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id)
|
|||||||
DWORD build = os_version->dwBuildNumber;
|
DWORD build = os_version->dwBuildNumber;
|
||||||
int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
|
int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
|
||||||
ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
|
ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
|
||||||
ga_win_10_0_server_t const *win_10_0_table = WIN_10_0_SERVER_VERSION_MATRIX;
|
ga_win_10_0_t const *win_10_0_table = tbl_idx ?
|
||||||
|
WIN_10_0_SERVER_VERSION_MATRIX : WIN_10_0_CLIENT_VERSION_MATRIX;
|
||||||
|
ga_win_10_0_t const *win_10_0_version = NULL;
|
||||||
while (table->version != NULL) {
|
while (table->version != NULL) {
|
||||||
if (major == 10 && minor == 0 && tbl_idx) {
|
if (major == 10 && minor == 0) {
|
||||||
while (win_10_0_table->version != NULL) {
|
while (win_10_0_table->version != NULL) {
|
||||||
if (build <= win_10_0_table->final_build) {
|
if (build >= win_10_0_table->first_build) {
|
||||||
if (id) {
|
win_10_0_version = win_10_0_table;
|
||||||
return g_strdup(win_10_0_table->version_id);
|
|
||||||
} else {
|
|
||||||
return g_strdup(win_10_0_table->version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
win_10_0_table++;
|
win_10_0_table++;
|
||||||
}
|
}
|
||||||
|
if (win_10_0_table) {
|
||||||
|
if (id) {
|
||||||
|
return g_strdup(win_10_0_version->version_id);
|
||||||
|
} else {
|
||||||
|
return g_strdup(win_10_0_version->version);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (major == table->major && minor == table->minor) {
|
} else if (major == table->major && minor == table->minor) {
|
||||||
if (id) {
|
if (id) {
|
||||||
return g_strdup(table->version_id);
|
return g_strdup(table->version_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user