]> mj.ucw.cz Git - pciutils.git/commitdiff
windows: Improve version detection
authorPali Rohár <pali@kernel.org>
Sat, 16 Aug 2025 01:17:25 +0000 (03:17 +0200)
committerMartin Mareš <mj@ucw.cz>
Sun, 28 Dec 2025 20:49:06 +0000 (21:49 +0100)
Move version detection code into helper functions, which can be reused.

For 32-bit x86 builds use GetVersion() which is available in all Windows
versions instead of GetVersionEx().

lib/physmem-windows.c
lib/win32-helpers.c
lib/win32-helpers.h
lib/win32-kldbg.c

index ed827bacd9154f7836614c87b275ada4a004d7fd..6263d28b7a92dab65239b5f4cf8e5c0b8269ce50 100644 (file)
@@ -524,8 +524,10 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a)
 {
   HMODULE w32skrnl;
   LPVOID (WINAPI *GetThunkBuff)(VOID);
-  OSVERSIONINFOA version;
   LPVOID buf_ptr;
+  DWORD raw_version;
+  USHORT build_num;
+  BOOL build_num_valid;
 
   a->debug("resolving DPMI function via GetThunkBuff() function from w32skrnl.dll...");
   w32skrnl = GetModuleHandleA("w32skrnl.dll");
@@ -544,16 +546,12 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a)
       return 0;
     }
 
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (!GetVersionExA(&version))
-    {
-      a->debug("failed: cannot detect version.");
-      errno = EINVAL;
-      return 0;
-    }
+  raw_version = GetVersion();
+  build_num = (raw_version >> 16) & 0x3FFF;
+  build_num_valid = ((raw_version & 0xC0000000) == 0x80000000 && (raw_version & 0xff) < 4);
 
-  /* Versions before 1.1 (1.1.88) are not supported. */
-  if (version.dwMajorVersion < 1 || (version.dwMajorVersion == 1 && version.dwMinorVersion < 1))
+  /* Builds older than 88 (match version 1.1) are not supported. */
+  if (build_num_valid && build_num < 88)
     {
       a->debug("failed: found old incompatible version.");
       errno = ENOENT;
@@ -576,15 +574,11 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a)
     }
 
   /*
-   * Versions 1.1 (1.1.88) - 1.15 (1.15.103) have DPMI function at offset 0xa0.
-   * Versions 1.15a (1.15.111) - 1.30c (1.30.172) have DPMI function at offset 0xa4.
+   * Builds 88-103 (match versions 1.1-1.15) have DPMI function at offset 0xa0.
+   * Builds 111-172 (match versions 1.15a-1.30c) have DPMI function at offset 0xa4.
+   * If build number is unavailable then expects the latest version.
    */
-  if (version.dwMajorVersion > 1 ||
-      (version.dwMajorVersion == 1 && version.dwMinorVersion > 15) ||
-      (version.dwMajorVersion == 1 && version.dwMinorVersion == 15 && version.dwBuildNumber >= 111))
-    physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + 0xa4);
-  else
-    physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + 0xa0);
+  physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + ((build_num_valid && build_num < 111) ? 0xa0 : 0xa4));
 
   a->debug("success.");
   return 1;
index 3b182aa2fef6d7ba927a8d8598f9315fc31f3e3e..df09d64c2569d8487ef90454a2d2870bf2a23ae5 100644 (file)
@@ -177,11 +177,89 @@ win32_get_process_machine(void)
 BOOL
 win32_is_non_nt_system(void)
 {
-  OSVERSIONINFOA version;
+#if defined(_M_IX86) || defined(__i386__)
+  /* Highest bit set indicates the non-NT system. */
+  return GetVersion() >> 31;
+#else
+  /* Non-i386 systems are not pre-NT compatible. */
+  return FALSE;
+#endif
+}
+
+static BOOL
+win32_is_nt40_system(void)
+{
+#if defined(_M_IX86) || defined(__i386__)
+  /* Check for Windows NT 4.0. Highest two bits are zero for NT and in lowest 8 bits is major os version. */
+  DWORD raw_version = GetVersion();
+  return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 4;
+#else
+  /* Modern non-i386 systems have at least version 5.2 (XP x64). */
+  return TRUE;
+#endif
+}
+
+static BOOL
+win32_is_win2k_system(void)
+{
+#if defined(_M_IX86) || defined(__i386__)
+  /* Check for Windows 2000 (NT 5.0). Highest two bits are zero for NT and in lowest 8 bits is major os version. */
+  DWORD raw_version = GetVersion();
+  return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 5;
+#else
+  /* Modern non-i386 systems have at least version 5.2 (XP x64). */
+  return TRUE;
+#endif
+}
+
+BOOL
+win32_is_vista_system(void)
+{
+#if defined(_M_IX86) || defined(__i386__)
+  /* Check for Windows Vista (NT 6.0). Highest two bits are zero for NT and in lowest 8 bits is major os version. */
+  DWORD raw_version = GetVersion();
+  return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 6;
+#else
+  /* Check for Windows Vista (NT 6.0). */
+  OSVERSIONINFO version;
   version.dwOSVersionInfoSize = sizeof(version);
-  return GetVersionExA(&version) && version.dwPlatformId < VER_PLATFORM_WIN32_NT;
+  if (!GetVersionEx(&version) ||
+      version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
+      version.dwMajorVersion >= 6)
+    return FALSE;
+  else
+    return TRUE;
+#endif
 }
 
+#ifndef _WIN64
+static BOOL
+win32_is_win8_system(void)
+{
+#if defined(_M_IX86) || defined(__i386__)
+  /* Check for Windows 8 (NT 6.2). Highest two bits are zero for NT and in lowest 16 bits are minor<<8 + major os version. */
+  DWORD raw_version = GetVersion();
+  if ((raw_version >> 30) != 0 ||
+      (raw_version & 0xff) < 6 ||
+      ((raw_version & 0xff) == 6 && ((raw_version >> 8) & 0xff) < 2))
+    return FALSE;
+  else
+    return TRUE;
+#else
+  /* Check for Windows 8 (NT 6.2). */
+  OSVERSIONINFO version;
+  version.dwOSVersionInfoSize = sizeof(version);
+  if (!GetVersionEx(&version) ||
+      version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
+      version.dwMajorVersion < 6 ||
+      (version.dwMajorVersion == 6 && version.dwMinorVersion < 2))
+    return FALSE;
+  else
+    return TRUE;
+#endif
+}
+#endif
+
 BOOL
 win32_is_32bit_on_64bit_system(void)
 {
@@ -223,17 +301,7 @@ win32_is_32bit_on_win8_64bit_system(void)
 #ifdef _WIN64
   return FALSE;
 #else
-  OSVERSIONINFOA version;
-
-  /* Check for Windows 8 (NT 6.2). */
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (!GetVersionExA(&version) ||
-      version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
-      version.dwMajorVersion < 6 ||
-      (version.dwMajorVersion == 6 && version.dwMinorVersion < 2))
-    return FALSE;
-
-  return win32_is_32bit_on_64bit_system();
+  return win32_is_win8_system() && win32_is_32bit_on_64bit_system();
 #endif
 }
 
@@ -350,7 +418,6 @@ UINT
 win32_change_error_mode(UINT new_mode)
 {
   SetThreadErrorModeProt MySetThreadErrorMode = NULL;
-  OSVERSIONINFOA version;
   HMODULE kernel32;
   HMODULE ntdll;
   DWORD old_mode;
@@ -383,10 +450,7 @@ win32_change_error_mode(UINT new_mode)
    * On Windows NT 4.0+ systems fallback to thread HardErrorMode API.
    * It depends on architecture specific offset for HardErrorMode field in TEB.
    */
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (GetVersionExA(&version) &&
-      version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
-      version.dwMajorVersion >= 4)
+  if (win32_is_nt40_system())
     {
       ULONG *hard_error_mode_ptr = (ULONG *)((BYTE *)NtCurrentTeb() + TEB_HARD_ERROR_MODE_OFFSET);
       old_mode = *hard_error_mode_ptr;
@@ -748,7 +812,6 @@ prepare_security_descriptor_for_set_operation(PSECURITY_DESCRIPTOR security_desc
   SECURITY_DESCRIPTOR_CONTROL bits_mask;
   SECURITY_DESCRIPTOR_CONTROL bits_set;
   SECURITY_DESCRIPTOR_CONTROL control;
-  OSVERSIONINFO version;
   HMODULE advapi32;
   DWORD revision;
 
@@ -778,10 +841,7 @@ prepare_security_descriptor_for_set_operation(PSECURITY_DESCRIPTOR security_desc
    * older versions of advapi32.dll library, so resolve it at runtime.
    */
 
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (!GetVersionEx(&version) ||
-      version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
-      version.dwMajorVersion < 5)
+  if (!win32_is_win2k_system())
     return TRUE;
 
   if (!GetSecurityDescriptorControl(security_descriptor, &control, &revision))
@@ -1024,7 +1084,6 @@ open_process_for_query(DWORD pid, BOOL with_vm_read)
 {
   BOOL revert_only_privilege;
   LUID luid_debug_privilege;
-  OSVERSIONINFO version;
   DWORD process_right;
   HANDLE revert_token;
   HANDLE process;
@@ -1044,10 +1103,7 @@ open_process_for_query(DWORD pid, BOOL with_vm_read)
    * PROCESS_QUERY_LIMITED_INFORMATION right on older systems than
    * Windows Vista (NT 6.0).
    */
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (GetVersionEx(&version) &&
-      version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
-      version.dwMajorVersion >= 6)
+  if (win32_is_vista_system())
     process_right = PROCESS_QUERY_LIMITED_INFORMATION;
   else
     process_right = PROCESS_QUERY_INFORMATION;
index 93f2a4b4ec9ec9443655446e0db7d80fabeaede8..87843d7ace30453007253540654bce6788b6dfc9 100644 (file)
@@ -1,6 +1,7 @@
 const char *win32_strerror(DWORD win32_error_id);
 USHORT win32_get_process_machine(void);
 BOOL win32_is_non_nt_system(void);
+BOOL win32_is_vista_system(void);
 BOOL win32_is_32bit_on_64bit_system(void);
 BOOL win32_is_32bit_on_win8_64bit_system(void);
 BOOL win32_is_not_native_process(USHORT *native_machine);
index 089fbe0977a537451cc226bdc43f1d6fe7961c26..96242396b0095daecff52adadce805dde055c745 100644 (file)
@@ -467,7 +467,6 @@ out:
 static int
 win32_kldbg_setup(struct pci_access *a)
 {
-  OSVERSIONINFO version;
   DWORD ret_len;
   DWORD error;
   DWORD id;
@@ -475,11 +474,7 @@ win32_kldbg_setup(struct pci_access *a)
   if (kldbg_dev != INVALID_HANDLE_VALUE)
     return 1;
 
-  /* Check for Windows Vista (NT 6.0). */
-  version.dwOSVersionInfoSize = sizeof(version);
-  if (!GetVersionEx(&version) ||
-      version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
-      version.dwMajorVersion < 6)
+  if (!win32_is_vista_system())
     {
       a->debug("Accessing PCI config space via Kernel Local Debugging Driver requires Windows Vista or higher version.");
       return 0;