aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-01-16 16:32:34 +0000
committerPeter Maydell <peter.maydell@linaro.org>2022-01-16 16:32:34 +0000
commit69353c332c558cead5f8081d0bb69f989fe33fa3 (patch)
treea5ff429f6a70ceddf663fb57d30e76f2bb56301e
parent1cd2ad11d37c48f284f557954e1df675b126264c (diff)
parent206ce9699fae1f631ac74b7e1115db2affc759fd (diff)
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>
-rw-r--r--MAINTAINERS8
-rw-r--r--qga/commands-win32.c274
2 files changed, 166 insertions, 116 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 6ccdec7f02..2fd74c4642 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2741,6 +2741,14 @@ F: scripts/qemu-guest-agent/
F: tests/unit/test-qga.c
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
M: Paolo Bonzini <pbonzini@redhat.com>
R: Daniel P. Berrange <berrange@redhat.com>
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 4e84afd83b..484cb1c6bd 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -512,15 +512,102 @@ DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT,
0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82,
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)
{
- HDEVINFO dev_info;
+ HDEVINFO dev_info = INVALID_HANDLE_VALUE;
+ HDEVINFO parent_dev_info = INVALID_HANDLE_VALUE;
+
SP_DEVINFO_DATA dev_info_data;
SP_DEVICE_INTERFACE_DATA dev_iface_data;
HANDLE dev_file;
int i;
GuestPCIAddress *pci = NULL;
- bool partial_pci = false;
pci = g_malloc0(sizeof(*pci));
pci->domain = -1;
@@ -532,29 +619,27 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE) {
error_setg_win32(errp, GetLastError(), "failed to get devices tree");
- goto out;
+ goto end;
}
g_debug("enumerating devices");
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
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;
- char *parent_dev_id = NULL;
- HDEVINFO parent_dev_info;
+ g_autofree char *parent_dev_id = NULL;
SP_DEVINFO_DATA parent_dev_info_data;
- DWORD j;
DWORD size = 0;
g_debug("getting device path");
if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data,
&GUID_DEVINTERFACE_DISK, 0,
&dev_iface_data)) {
- while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
- pdev_iface_detail_data,
- size, &size,
- &dev_info_data)) {
+ if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
+ pdev_iface_detail_data,
+ size, &size,
+ &dev_info_data)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
pdev_iface_detail_data = g_malloc(size);
pdev_iface_detail_data->cbSize =
@@ -562,21 +647,30 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
} else {
error_setg_win32(errp, GetLastError(),
"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,
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
NULL);
- g_free(pdev_iface_detail_data);
if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
CloseHandle(dev_file);
error_setg_win32(errp, GetLastError(),
"failed to get device slot number");
- goto free_dev_info;
+ goto end;
}
CloseHandle(dev_file);
@@ -586,7 +680,7 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp)
} else {
error_setg_win32(errp, GetLastError(),
"failed to get device interfaces");
- goto free_dev_info;
+ goto end;
}
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;
size = 0;
- while (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
- parent_dev_id, size, &size)) {
+ if (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
+ parent_dev_id, size, &size)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
parent_dev_id = g_malloc(size);
} else {
error_setg_win32(errp, GetLastError(),
"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
* 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);
error_setg_win32(errp, GetLastError(),
"failed to get device instance");
- goto out;
+ goto end;
}
cr = CM_Get_Parent(&parent_dev_inst, dev_inst, 0);
if (cr != CR_SUCCESS) {
g_error("CM_Get_Parent failed with code %lx", cr);
error_setg_win32(errp, GetLastError(),
"failed to get parent device instance");
- goto out;
+ goto end;
}
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);
error_setg_win32(errp, GetLastError(),
"failed to get parent device ID length");
- goto out;
+ goto end;
}
++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);
error_setg_win32(errp, GetLastError(),
"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 =
SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev_id,
NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- g_free(parent_dev_id);
if (parent_dev_info == INVALID_HANDLE_VALUE) {
error_setg_win32(errp, GetLastError(),
"failed to get parent device");
- goto out;
+ goto end;
}
parent_dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_data)) {
error_setg_win32(errp, GetLastError(),
"failed to get parent device data");
- goto out;
+ goto end;
}
- for (j = 0;
- SetupDiEnumDeviceInfo(parent_dev_info, j, &parent_dev_info_data);
- j++) {
- DWORD addr, bus, ui_slot, type;
- int func, slot;
+ get_pci_address_for_device(pci, parent_dev_info);
- /*
- * 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;
}
-free_dev_info:
- SetupDiDestroyDeviceInfoList(dev_info);
-out:
+end:
+ if (parent_dev_info != INVALID_HANDLE_VALUE) {
+ SetupDiDestroyDeviceInfoList(parent_dev_info);
+ }
+ if (dev_info != INVALID_HANDLE_VALUE) {
+ SetupDiDestroyDeviceInfoList(dev_info);
+ }
return pci;
}
@@ -2137,7 +2170,7 @@ typedef struct _ga_matrix_lookup_t {
char const *version_id;
} 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 */
{ 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, 2, "Microsoft Windows 8", "8"},
{ 6, 3, "Microsoft Windows 8.1", "8.1"},
- {10, 0, "Microsoft Windows 10", "10"},
{ 0, 0, 0}
},{
/* 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, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
{ 0, 0, 0},
- { 0, 0, 0},
{ 0, 0, 0}
}
};
-typedef struct _ga_win_10_0_server_t {
- int final_build;
+typedef struct _ga_win_10_0_t {
+ int first_build;
char const *version;
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"},
{17763, "Microsoft Windows Server 2019", "2019"},
{20344, "Microsoft Windows Server 2022", "2022"},
{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)
{
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;
int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
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) {
- if (major == 10 && minor == 0 && tbl_idx) {
+ if (major == 10 && minor == 0) {
while (win_10_0_table->version != NULL) {
- if (build <= win_10_0_table->final_build) {
- if (id) {
- return g_strdup(win_10_0_table->version_id);
- } else {
- return g_strdup(win_10_0_table->version);
- }
+ if (build >= win_10_0_table->first_build) {
+ win_10_0_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) {
if (id) {
return g_strdup(table->version_id);