]> mj.ucw.cz Git - pciutils.git/blobdiff - lib/i386-io-windows.h
Names: Fixed a rare bug in loading of pci.ids
[pciutils.git] / lib / i386-io-windows.h
index 6cf3a25581135efacd54249dcfd70bb3d7985e13..fd4030d9e7125942c58d4f12fe45ea39b99b0e81 100644 (file)
@@ -5,99 +5,15 @@
  *     Copyright (c) 2006 Martin Mares <mj@ucw.cz>
  *     Copyright (c) 2021 Pali Rohár <pali@kernel.org>
  *
- *     Can be freely distributed and used under the terms of the GNU GPL.
+ *     Can be freely distributed and used under the terms of the GNU GPL v2+
+ *
+ *     SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#include <io.h>
 #include <windows.h>
 #include <aclapi.h>
 
-#ifdef _MSC_VER
-/* MSVC compiler provides I/O port intrinsics for both 32 and 64-bit modes. */
-#pragma intrinsic(_outp)
-#pragma intrinsic(_outpw)
-#pragma intrinsic(_outpd)
-#pragma intrinsic(_inp)
-#pragma intrinsic(_inpw)
-#pragma intrinsic(_inpd)
-#elif defined(_WIN64) || defined(_UCRT)
-/*
- * For other compilers I/O port intrinsics are available in <intrin.h> header
- * file either as inline/external functions or macros. Beware that <intrin.h>
- * names are different than MSVC intrinsics names and glibc function names.
- * Usage of <intrin.h> is also the prefered way for 64-bit mode or when using
- * new UCRT library.
- */
-#include <intrin.h>
-#define _outp(x,y) __outbyte(x,y)
-#define _outpw(x,y) __outword(x,y)
-#define _outpd(x,y) __outdword(x,y)
-#define _inp(x) __inbyte(x)
-#define _inpw(x) __inword(x)
-#define _inpd(x) __indword(x)
-#elif defined(__CRTDLL__)
-/*
- * Old CRTDLL library does not provide I/O port functions. Even it is the oldest
- * CRT library it exists also in 64-bit variant. Implement I/O port functions
- * via inline assembly just for 32-bit mode as 64-bit mode uses above <intrin.h>
- * header.
- */
-static inline int _outp(unsigned short port, int databyte)
-{
-  asm volatile ("outb %b0, %w1" : : "a" (databyte), "Nd" (port));
-  return databyte;
-}
-static inline unsigned short _outpw(unsigned short port, unsigned short dataword)
-{
-  asm volatile ("outw %w0, %w1" : : "a" (dataword), "Nd" (port));
-  return dataword;
-}
-static inline unsigned long _outpd(unsigned short port, unsigned long dataword)
-{
-  asm volatile ("outl %0, %w1" : : "a" (dataword), "Nd" (port));
-  return dataword;
-}
-static inline int _inp(unsigned short port)
-{
-  unsigned char ret;
-  asm volatile ("inb %w1, %0" : "=a" (ret) : "Nd" (port));
-  return ret;
-}
-static inline unsigned short _inpw(unsigned short port)
-{
-  unsigned short ret;
-  asm volatile ("inw %w1, %0" : "=a" (ret) : "Nd" (port));
-  return ret;
-}
-static inline unsigned long _inpd(unsigned short port)
-{
-  unsigned long ret;
-  asm volatile ("inl %w1, %0" : "=a" (ret) : "Nd" (port));
-  return ret;
-}
-#elif !defined(__GNUC__)
-/*
- * Old 32-bit MSVCRT (non-UCRT) library provides I/O port functions. Function
- * prototypes are defined in <conio.h> header file but they are missing in
- * some MinGW toolchains. So for GCC compiler define them manually.
- */
-#include <conio.h>
-#else
-int _outp(unsigned short port, int databyte);
-unsigned short _outpw(unsigned short port, unsigned short dataword);
-unsigned long _outpd(unsigned short port, unsigned long dataword);
-int _inp(unsigned short port);
-unsigned short _inpw(unsigned short port);
-unsigned long _inpd(unsigned short port);
-#endif
-
-#define outb(x,y) _outp(y,x)
-#define outw(x,y) _outpw(y,x)
-#define outl(x,y) _outpd(y,x)
-
-#define inb(x) _inp(x)
-#define inw(x) _inpw(x)
-#define inl(x) _inpd(x)
+#include "i386-io-access.h"
 
 /*
  * Define __readeflags() for MSVC and GCC compilers.
@@ -108,16 +24,13 @@ unsigned long _inpd(unsigned short port);
  * function conflicts with some MSVC intrinsic.
  * MSVC supports inline assembly via __asm keyword in 32-bit mode only.
  * GCC version 4.9.0 and higher provides __builtin_ia32_readeflags_uXX()
- * builtin for XX-mode.
+ * builtin for XX-mode. This builtin is also available as __readeflags()
+ * function indirectly via <x86intrin.h> header file.
  */
 #if defined(_MSC_VER) && (_MSC_VER >= 1500 || (_MSC_VER >= 1400 && defined(__BUILDMACHINE__)))
 #pragma intrinsic(__readeflags)
 #elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || (__GNUC__ > 4))
-#ifdef __x86_64__
-#define __readeflags() __builtin_ia32_readeflags_u64()
-#else
-#define __readeflags() __builtin_ia32_readeflags_u32()
-#endif
+#include <x86intrin.h>
 #elif defined(_MSC_VER) && defined(_M_IX86)
 static inline unsigned int
 __readeflags(void)
@@ -594,12 +507,14 @@ grant_process_token_dacl_permissions(HANDLE process, DWORD permissions, HANDLE *
 
   if (MySetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
     {
+      LocalFree(new_dacl);
       LocalFree(*security_descriptor);
       LocalFree(owner);
       CloseHandle(*token);
       return FALSE;
     }
 
+  LocalFree(new_dacl);
   LocalFree(owner);
   return TRUE;
 }
@@ -777,10 +692,13 @@ find_and_open_process_for_query(LPCSTR exe_file)
   EnumProcessesProt MyEnumProcesses;
   HMODULE kernel32, psapi;
   UINT prev_error_mode;
-  WCHAR path[MAX_PATH];
+  DWORD partial_retry;
+  BOOL found_process;
   DWORD size, length;
   DWORD *processes;
   HANDLE process;
+  LPWSTR path;
+  DWORD error;
   DWORD count;
   DWORD i;
 
@@ -874,11 +792,72 @@ retry:
       if (!process)
         continue;
 
+      /*
+       * Set initial buffer size to 256 (wide) characters.
+       * Final path length on the modern NT-based systems can be also larger.
+       */
+      size = 256;
+      found_process = FALSE;
+      partial_retry = 0;
+
+retry_path:
+      path = (LPWSTR)LocalAlloc(LPTR, size * sizeof(*path));
+      if (!path)
+        goto end_path;
+
       if (MyGetProcessImageFileNameW)
-        length = MyGetProcessImageFileNameW(process, path, sizeof(path)/sizeof(*path));
+        length = MyGetProcessImageFileNameW(process, path, size);
       else
-        length = MyGetModuleFileNameExW(process, NULL, path, sizeof(path)/sizeof(*path));
+        length = MyGetModuleFileNameExW(process, NULL, path, size);
+
+      error = GetLastError();
+
+      /*
+       * GetModuleFileNameEx() returns zero and signal error ERROR_PARTIAL_COPY
+       * when remote process is in the middle of updating its module table.
+       * Sleep 10 ms and try again, max 10 attempts.
+       */
+      if (!MyGetProcessImageFileNameW)
+        {
+          if (length == 0 && error == ERROR_PARTIAL_COPY && partial_retry++ < 10)
+            {
+              Sleep(10);
+              goto retry_path;
+            }
+          partial_retry = 0;
+        }
+
+      /*
+       * When buffer is too small then function GetModuleFileNameEx() returns
+       * its size argument on older systems (Windows XP) or its size minus
+       * argument one on new systems (Windows 10) without signalling any error.
+       * Function GetProcessImageFileNameW() on the other hand returns zero
+       * value and signals error ERROR_INSUFFICIENT_BUFFER. So in all these
+       * cases call function again with larger buffer.
+       */
+
+      if (MyGetProcessImageFileNameW && length == 0 && error != ERROR_INSUFFICIENT_BUFFER)
+        goto end_path;
+
+      if ((MyGetProcessImageFileNameW && length == 0) ||
+          (!MyGetProcessImageFileNameW && (length == size || length == size-1)))
+        {
+          LocalFree(path);
+          size *= 2;
+          goto retry_path;
+        }
+
       if (length && check_process_name(path, length, exe_file))
+        found_process = TRUE;
+
+end_path:
+      if (path)
+        {
+          LocalFree(path);
+          path = NULL;
+        }
+
+      if (found_process)
         break;
 
       CloseHandle(process);
@@ -1081,7 +1060,7 @@ SetProcessUserModeIOPL(VOID)
    */
 
   if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid_tcb_privilege))
-    goto err_not_implemented;
+    goto err_privilege_not_held;
 
   /*
    * If the current thread has already Tcb privilege enabled then there
@@ -1283,7 +1262,8 @@ intel_setup_io(struct pci_access *a)
   /* On NT-based systems issue ProcessUserModeIOPL syscall which changes IOPL to 3. */
   if (!SetProcessUserModeIOPL())
     {
-      a->warning("NT ProcessUserModeIOPL call failed with error: %lu.", (unsigned long int)GetLastError());
+      DWORD error = GetLastError();
+      a->debug("NT ProcessUserModeIOPL call failed: %s.", error == ERROR_INVALID_FUNCTION ? "Not Implemented" : error == ERROR_PRIVILEGE_NOT_HELD ? "Access Denied" : "Operation Failed");
       return 0;
     }