]> mj.ucw.cz Git - pciutils.git/blob - lib/init.c
fe40f91ccc36c1d4fd5c52595116ab78899f1340
[pciutils.git] / lib / init.c
1 /*
2  *      The PCI Library -- Initialization and related things
3  *
4  *      Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13
14 #include "internal.h"
15
16 #ifdef PCI_OS_DJGPP
17 #include <crt0.h> /* for __dos_argv0 */
18 #endif
19
20 #ifdef PCI_OS_WINDOWS
21
22 #include <windows.h>
23
24 /* Force usage of ANSI (char*) variant of GetModuleFileName() function */
25 #ifdef _WIN32
26 #ifdef GetModuleFileName
27 #undef GetModuleFileName
28 #endif
29 #define GetModuleFileName GetModuleFileNameA
30 #endif
31
32 /* Define __ImageBase for all linkers */
33 #ifdef _WIN32
34 /* GNU LD provides __ImageBase symbol since 2.19, in previous versions it is
35  * under name _image_base__, so add weak alias for compatibility. */
36 #ifdef __GNUC__
37 asm(".weak\t" PCI_STRINGIFY(__MINGW_USYMBOL(__ImageBase)) "\n\t"
38     ".set\t"  PCI_STRINGIFY(__MINGW_USYMBOL(__ImageBase)) "," PCI_STRINGIFY(__MINGW_USYMBOL(_image_base__)));
39 #endif
40 /*
41  * MSVC link.exe provides __ImageBase symbol since 12.00 (MSVC 6.0), for
42  * previous versions resolve it at runtime via GetModuleHandleA() which
43  * returns base for main executable or via VirtualQuery() for DLL builds.
44  */
45 #if defined(_MSC_VER) && _MSC_VER < 1200
46 static HMODULE
47 get_current_module_handle(void)
48 {
49 #ifdef PCI_SHARED_LIB
50   MEMORY_BASIC_INFORMATION info;
51   size_t len = VirtualQuery(&get_current_module_handle, &info, sizeof(info));
52   if (len != sizeof(info))
53     return NULL;
54   return (HMODULE)info.AllocationBase;
55 #else
56   return GetModuleHandleA(NULL);
57 #endif
58 }
59 #define __ImageBase (*(IMAGE_DOS_HEADER *)get_current_module_handle())
60 #else
61 extern IMAGE_DOS_HEADER __ImageBase;
62 #endif
63 #endif
64
65 #if defined(_WINDLL)
66 extern HINSTANCE _hModule;
67 #elif defined(_WINDOWS)
68 extern HINSTANCE _hInstance;
69 #endif
70
71 #endif
72
73 static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
74   NULL,
75 #ifdef PCI_HAVE_PM_LINUX_SYSFS
76   &pm_linux_sysfs,
77 #else
78   NULL,
79 #endif
80 #ifdef PCI_HAVE_PM_LINUX_PROC
81   &pm_linux_proc,
82 #else
83   NULL,
84 #endif
85 #ifdef PCI_HAVE_PM_INTEL_CONF
86   &pm_intel_conf1,
87   &pm_intel_conf2,
88 #else
89   NULL,
90   NULL,
91 #endif
92 #ifdef PCI_HAVE_PM_FBSD_DEVICE
93   &pm_fbsd_device,
94 #else
95   NULL,
96 #endif
97 #ifdef PCI_HAVE_PM_AIX_DEVICE
98   &pm_aix_device,
99 #else
100   NULL,
101 #endif
102 #ifdef PCI_HAVE_PM_NBSD_LIBPCI
103   &pm_nbsd_libpci,
104 #else
105   NULL,
106 #endif
107 #ifdef PCI_HAVE_PM_OBSD_DEVICE
108   &pm_obsd_device,
109 #else
110   NULL,
111 #endif
112 #ifdef PCI_HAVE_PM_DUMP
113   &pm_dump,
114 #else
115   NULL,
116 #endif
117 #ifdef PCI_HAVE_PM_DARWIN_DEVICE
118   &pm_darwin,
119 #else
120   NULL,
121 #endif
122 #ifdef PCI_HAVE_PM_SYLIXOS_DEVICE
123   &pm_sylixos_device,
124 #else
125   NULL,
126 #endif
127 #ifdef PCI_HAVE_PM_HURD_CONF
128   &pm_hurd,
129 #else
130   NULL,
131 #endif
132 #ifdef PCI_HAVE_PM_WIN32_CFGMGR32
133   &pm_win32_cfgmgr32,
134 #else
135   NULL,
136 #endif
137 #ifdef PCI_HAVE_PM_WIN32_KLDBG
138   &pm_win32_kldbg,
139 #else
140   NULL,
141 #endif
142 #ifdef PCI_HAVE_PM_WIN32_SYSDBG
143   &pm_win32_sysdbg,
144 #else
145   NULL,
146 #endif
147 #ifdef PCI_HAVE_PM_MMIO_CONF
148   &pm_mmio_conf1,
149   &pm_mmio_conf1_ext,
150 #else
151   NULL,
152   NULL,
153 #endif
154 #if defined(PCI_HAVE_PM_ECAM)
155   &pm_ecam,
156 #else
157   NULL,
158 #endif
159 };
160
161 // If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
162 static int probe_sequence[] = {
163   // System-specific methods
164   PCI_ACCESS_SYS_BUS_PCI,
165   PCI_ACCESS_PROC_BUS_PCI,
166   PCI_ACCESS_FBSD_DEVICE,
167   PCI_ACCESS_AIX_DEVICE,
168   PCI_ACCESS_NBSD_LIBPCI,
169   PCI_ACCESS_OBSD_DEVICE,
170   PCI_ACCESS_DARWIN,
171   PCI_ACCESS_SYLIXOS_DEVICE,
172   PCI_ACCESS_HURD,
173   PCI_ACCESS_WIN32_CFGMGR32,
174   PCI_ACCESS_WIN32_KLDBG,
175   PCI_ACCESS_WIN32_SYSDBG,
176   // Low-level methods poking the hardware directly
177   PCI_ACCESS_ECAM,
178   PCI_ACCESS_I386_TYPE1,
179   PCI_ACCESS_I386_TYPE2,
180   PCI_ACCESS_MMIO_TYPE1_EXT,
181   PCI_ACCESS_MMIO_TYPE1,
182   -1,
183 };
184
185 static void PCI_NONRET
186 pci_generic_error(char *msg, ...)
187 {
188   va_list args;
189
190   va_start(args, msg);
191   fputs("pcilib: ", stderr);
192   vfprintf(stderr, msg, args);
193   va_end(args);
194   fputc('\n', stderr);
195   exit(1);
196 }
197
198 static void
199 pci_generic_warn(char *msg, ...)
200 {
201   va_list args;
202
203   va_start(args, msg);
204   fputs("pcilib: ", stderr);
205   vfprintf(stderr, msg, args);
206   va_end(args);
207   fputc('\n', stderr);
208 }
209
210 static void
211 pci_generic_debug(char *msg, ...)
212 {
213   va_list args;
214
215   va_start(args, msg);
216   vfprintf(stdout, msg, args);
217   va_end(args);
218 }
219
220 static void
221 pci_null_debug(char *msg UNUSED, ...)
222 {
223 }
224
225 // Memory allocation functions are safe to call if pci_access is not fully initalized or even NULL
226
227 void *
228 pci_malloc(struct pci_access *a, int size)
229 {
230   void *x = malloc(size);
231
232   if (!x)
233     (a && a->error ? a->error : pci_generic_error)("Out of memory (allocation of %d bytes failed)", size);
234   return x;
235 }
236
237 void
238 pci_mfree(void *x)
239 {
240   if (x)
241     free(x);
242 }
243
244 char *
245 pci_strdup(struct pci_access *a, const char *s)
246 {
247   int len = strlen(s) + 1;
248   char *t = pci_malloc(a, len);
249   memcpy(t, s, len);
250   return t;
251 }
252
253 int
254 pci_lookup_method(char *name)
255 {
256   int i;
257
258   for (i=0; i<PCI_ACCESS_MAX; i++)
259     if (pci_methods[i] && !strcmp(pci_methods[i]->name, name))
260       return i;
261   return -1;
262 }
263
264 char *
265 pci_get_method_name(int index)
266 {
267   if (index < 0 || index >= PCI_ACCESS_MAX)
268     return NULL;
269   else if (!pci_methods[index])
270     return "";
271   else
272     return pci_methods[index]->name;
273 }
274
275 #if defined(PCI_OS_WINDOWS) || defined(PCI_OS_DJGPP)
276
277 static void
278 pci_init_name_list_path(struct pci_access *a)
279 {
280   if ((PCI_PATH_IDS_DIR)[0])
281     pci_set_name_list_path(a, PCI_PATH_IDS_DIR "\\" PCI_IDS, 0);
282   else
283     {
284       char *path, *sep;
285       size_t len;
286
287 #if defined(PCI_OS_WINDOWS) && (defined(_WIN32) || defined(_WINDLL) || defined(_WINDOWS))
288
289       HMODULE module;
290       size_t size;
291
292 #if defined(_WIN32)
293       module = (HINSTANCE)&__ImageBase;
294 #elif defined(_WINDLL)
295       module = _hModule;
296 #elif defined(_WINDOWS)
297       module = _hInstance;
298 #endif
299
300       /*
301        * Module file name can have arbitrary length despite all MS examples say
302        * about MAX_PATH upper limit. This limit does not apply for example when
303        * executable is running from network disk with very long UNC paths or
304        * when using "\\??\\" prefix for specifying executable binary path.
305        * Function GetModuleFileName() returns passed size argument when passed
306        * buffer is too small and does not signal any error. In this case retry
307        * again with larger buffer.
308        */
309       size = 256; /* initial buffer size (more than sizeof(PCI_IDS)-4) */
310 retry:
311       path = pci_malloc(a, size);
312       len = GetModuleFileName(module, path, size-sizeof(PCI_IDS)-4); /* 4 for "\\\\?\\" */
313       if (len >= size-sizeof(PCI_IDS)-4)
314         {
315           free(path);
316           size *= 2;
317           goto retry;
318         }
319       else if (len == 0)
320         path[0] = '\0';
321
322       /*
323        * GetModuleFileName() has bugs. On Windows 10 it prepends current drive
324        * letter if path is just pure NT namespace (with "\\??\\" prefix). Such
325        * extra drive letter makes path fully invalid and unusable. So remove
326        * extra drive letter to make path valid again.
327        * Reproduce: CreateProcessW("\\??\\C:\\lspci.exe", ...)
328        */
329       if (((path[0] >= 'a' && path[0] <= 'z') ||
330            (path[0] >= 'A' && path[0] <= 'Z')) &&
331           strncmp(path+1, ":\\??\\", 5) == 0)
332         {
333           memmove(path, path+2, len-2);
334           len -= 2;
335           path[len] = '\0';
336         }
337
338       /*
339        * GetModuleFileName() has bugs. On Windows 10 it does not add "\\\\?\\"
340        * prefix when path is in native NT UNC namespace. Such path is treated by
341        * WinAPI/DOS functions as standard DOS path relative to the current
342        * directory, hence something completely different. So prepend missing
343        * "\\\\?\\" prefix to make path valid again.
344        * Reproduce: CreateProcessW("\\??\\UNC\\10.0.2.4\\qemu\\lspci.exe", ...)
345        *
346        * If path starts with DOS drive letter and with appended PCI_IDS is
347        * longer than 260 bytes and is without "\\\\?\\" prefix then append it.
348        * This prefix is required for paths and file names with DOS drive letter
349        * longer than 260 bytes.
350        */
351       if (strncmp(path, "\\UNC\\", 5) == 0 ||
352           strncmp(path, "UNC\\", 4) == 0 ||
353           (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
354            len + sizeof(PCI_IDS) >= 260))
355         {
356           memmove(path+4, path, len);
357           memcpy(path, "\\\\?\\", 4);
358           len += 4;
359           path[len] = '\0';
360         }
361
362 #elif defined(PCI_OS_DJGPP) || defined(PCI_OS_WINDOWS)
363
364       const char *exe_path;
365
366 #ifdef PCI_OS_DJGPP
367       exe_path = __dos_argv0;
368 #else
369       exe_path = _pgmptr;
370 #endif
371
372       len = strlen(exe_path);
373       path = pci_malloc(a, len+sizeof(PCI_IDS));
374       memcpy(path, exe_path, len+1);
375
376 #endif
377
378       sep = strrchr(path, '\\');
379       if (!sep)
380         {
381           /*
382            * If current module path (current executable for static builds or
383            * current DLL library for shared build) cannot be determined then
384            * fallback to the current directory.
385            */
386           free(path);
387           pci_set_name_list_path(a, PCI_IDS, 0);
388         }
389       else
390         {
391           memcpy(sep+1, PCI_IDS, sizeof(PCI_IDS));
392           pci_set_name_list_path(a, path, 1);
393         }
394     }
395 }
396
397 #else
398
399 static void
400 pci_init_name_list_path(struct pci_access *a)
401 {
402   pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0);
403 }
404
405 #endif
406
407 struct pci_access *
408 pci_alloc(void)
409 {
410   struct pci_access *a = pci_malloc(NULL, sizeof(struct pci_access));
411   int i;
412
413   memset(a, 0, sizeof(*a));
414   pci_init_name_list_path(a);
415 #ifdef PCI_USE_DNS
416   pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
417   pci_define_param(a, "net.cache_name", "~/.pciids-cache", "Name of the ID cache file");
418   a->id_lookup_mode = PCI_LOOKUP_CACHE;
419 #endif
420 #ifdef PCI_HAVE_HWDB
421   pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero");
422 #endif
423   for (i=0; i<PCI_ACCESS_MAX; i++)
424     if (pci_methods[i] && pci_methods[i]->config)
425       pci_methods[i]->config(a);
426   return a;
427 }
428
429 int
430 pci_init_internal(struct pci_access *a, int skip_method)
431 {
432   if (!a->error)
433     a->error = pci_generic_error;
434   if (!a->warning)
435     a->warning = pci_generic_warn;
436   if (!a->debug)
437     a->debug = pci_generic_debug;
438   if (!a->debugging)
439     a->debug = pci_null_debug;
440
441   if (a->method != PCI_ACCESS_AUTO)
442     {
443       if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
444         a->error("This access method is not supported.");
445       a->methods = pci_methods[a->method];
446     }
447   else
448     {
449       unsigned int i;
450       for (i=0; probe_sequence[i] >= 0; i++)
451         {
452           struct pci_methods *m = pci_methods[probe_sequence[i]];
453           if (!m)
454             continue;
455           if (skip_method == probe_sequence[i])
456             continue;
457           a->debug("Trying method %s...", m->name);
458           if (m->detect(a))
459             {
460               a->debug("...OK\n");
461               a->methods = m;
462               a->method = probe_sequence[i];
463               break;
464             }
465           a->debug("...No.\n");
466         }
467       if (!a->methods)
468         return 0;
469     }
470   a->debug("Decided to use %s\n", a->methods->name);
471   a->methods->init(a);
472   return 1;
473 }
474
475 void
476 pci_init_v35(struct pci_access *a)
477 {
478   if (!pci_init_internal(a, -1))
479     a->error("Cannot find any working access method.");
480 }
481
482 STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v35(a));
483 DEFINE_ALIAS(void pci_init_v30(struct pci_access *a), pci_init_v35);
484 SYMBOL_VERSION(pci_init_v30, pci_init@LIBPCI_3.0);
485 SYMBOL_VERSION(pci_init_v35, pci_init@@LIBPCI_3.5);
486
487 struct pci_access *
488 pci_clone_access(struct pci_access *a)
489 {
490   struct pci_access *b = pci_alloc();
491
492   b->writeable = a->writeable;
493   b->buscentric = a->buscentric;
494   b->debugging = a->debugging;
495   b->error = a->error;
496   b->warning = a->warning;
497   b->debug = a->debug;
498
499   return b;
500 }
501
502 void
503 pci_cleanup(struct pci_access *a)
504 {
505   struct pci_dev *d, *e;
506
507   for (d=a->devices; d; d=e)
508     {
509       e = d->next;
510       pci_free_dev(d);
511     }
512   if (a->methods)
513     a->methods->cleanup(a);
514   pci_free_name_list(a);
515   pci_free_params(a);
516   pci_set_name_list_path(a, NULL, 0);
517   pci_mfree(a);
518 }