]> mj.ucw.cz Git - pciutils.git/blob - lib/init.c
a310cc54643d00dbf98a3459892cad3b61292aca
[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 };
155
156 // If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
157 static int probe_sequence[] = {
158   // System-specific methods
159   PCI_ACCESS_SYS_BUS_PCI,
160   PCI_ACCESS_PROC_BUS_PCI,
161   PCI_ACCESS_FBSD_DEVICE,
162   PCI_ACCESS_AIX_DEVICE,
163   PCI_ACCESS_NBSD_LIBPCI,
164   PCI_ACCESS_OBSD_DEVICE,
165   PCI_ACCESS_DARWIN,
166   PCI_ACCESS_SYLIXOS_DEVICE,
167   PCI_ACCESS_HURD,
168   PCI_ACCESS_WIN32_CFGMGR32,
169   PCI_ACCESS_WIN32_KLDBG,
170   PCI_ACCESS_WIN32_SYSDBG,
171   // Low-level methods poking the hardware directly
172   PCI_ACCESS_I386_TYPE1,
173   PCI_ACCESS_I386_TYPE2,
174   PCI_ACCESS_MMIO_TYPE1_EXT,
175   PCI_ACCESS_MMIO_TYPE1,
176   -1,
177 };
178
179 static void PCI_NONRET
180 pci_generic_error(char *msg, ...)
181 {
182   va_list args;
183
184   va_start(args, msg);
185   fputs("pcilib: ", stderr);
186   vfprintf(stderr, msg, args);
187   va_end(args);
188   fputc('\n', stderr);
189   exit(1);
190 }
191
192 static void
193 pci_generic_warn(char *msg, ...)
194 {
195   va_list args;
196
197   va_start(args, msg);
198   fputs("pcilib: ", stderr);
199   vfprintf(stderr, msg, args);
200   va_end(args);
201   fputc('\n', stderr);
202 }
203
204 static void
205 pci_generic_debug(char *msg, ...)
206 {
207   va_list args;
208
209   va_start(args, msg);
210   vfprintf(stdout, msg, args);
211   va_end(args);
212 }
213
214 static void
215 pci_null_debug(char *msg UNUSED, ...)
216 {
217 }
218
219 // Memory allocation functions are safe to call if pci_access is not fully initalized or even NULL
220
221 void *
222 pci_malloc(struct pci_access *a, int size)
223 {
224   void *x = malloc(size);
225
226   if (!x)
227     (a && a->error ? a->error : pci_generic_error)("Out of memory (allocation of %d bytes failed)", size);
228   return x;
229 }
230
231 void
232 pci_mfree(void *x)
233 {
234   if (x)
235     free(x);
236 }
237
238 char *
239 pci_strdup(struct pci_access *a, const char *s)
240 {
241   int len = strlen(s) + 1;
242   char *t = pci_malloc(a, len);
243   memcpy(t, s, len);
244   return t;
245 }
246
247 int
248 pci_lookup_method(char *name)
249 {
250   int i;
251
252   for (i=0; i<PCI_ACCESS_MAX; i++)
253     if (pci_methods[i] && !strcmp(pci_methods[i]->name, name))
254       return i;
255   return -1;
256 }
257
258 char *
259 pci_get_method_name(int index)
260 {
261   if (index < 0 || index >= PCI_ACCESS_MAX)
262     return NULL;
263   else if (!pci_methods[index])
264     return "";
265   else
266     return pci_methods[index]->name;
267 }
268
269 #if defined(PCI_OS_WINDOWS) || defined(PCI_OS_DJGPP)
270
271 static void
272 pci_init_name_list_path(struct pci_access *a)
273 {
274   if ((PCI_PATH_IDS_DIR)[0])
275     pci_set_name_list_path(a, PCI_PATH_IDS_DIR "\\" PCI_IDS, 0);
276   else
277     {
278       char *path, *sep;
279       size_t len;
280
281 #if defined(PCI_OS_WINDOWS) && (defined(_WIN32) || defined(_WINDLL) || defined(_WINDOWS))
282
283       HMODULE module;
284       size_t size;
285
286 #if defined(_WIN32)
287       module = (HINSTANCE)&__ImageBase;
288 #elif defined(_WINDLL)
289       module = _hModule;
290 #elif defined(_WINDOWS)
291       module = _hInstance;
292 #endif
293
294       /*
295        * Module file name can have arbitrary length despite all MS examples say
296        * about MAX_PATH upper limit. This limit does not apply for example when
297        * executable is running from network disk with very long UNC paths or
298        * when using "\\??\\" prefix for specifying executable binary path.
299        * Function GetModuleFileName() returns passed size argument when passed
300        * buffer is too small and does not signal any error. In this case retry
301        * again with larger buffer.
302        */
303       size = 256; /* initial buffer size (more than sizeof(PCI_IDS)-4) */
304 retry:
305       path = pci_malloc(a, size);
306       len = GetModuleFileName(module, path, size-sizeof(PCI_IDS)-4); /* 4 for "\\\\?\\" */
307       if (len >= size-sizeof(PCI_IDS)-4)
308         {
309           free(path);
310           size *= 2;
311           goto retry;
312         }
313       else if (len == 0)
314         path[0] = '\0';
315
316       /*
317        * GetModuleFileName() has bugs. On Windows 10 it prepends current drive
318        * letter if path is just pure NT namespace (with "\\??\\" prefix). Such
319        * extra drive letter makes path fully invalid and unusable. So remove
320        * extra drive letter to make path valid again.
321        * Reproduce: CreateProcessW("\\??\\C:\\lspci.exe", ...)
322        */
323       if (((path[0] >= 'a' && path[0] <= 'z') ||
324            (path[0] >= 'A' && path[0] <= 'Z')) &&
325           strncmp(path+1, ":\\??\\", 5) == 0)
326         {
327           memmove(path, path+2, len-2);
328           len -= 2;
329           path[len] = '\0';
330         }
331
332       /*
333        * GetModuleFileName() has bugs. On Windows 10 it does not add "\\\\?\\"
334        * prefix when path is in native NT UNC namespace. Such path is treated by
335        * WinAPI/DOS functions as standard DOS path relative to the current
336        * directory, hence something completely different. So prepend missing
337        * "\\\\?\\" prefix to make path valid again.
338        * Reproduce: CreateProcessW("\\??\\UNC\\10.0.2.4\\qemu\\lspci.exe", ...)
339        */
340       if (strncmp(path, "\\UNC\\", 5) == 0 ||
341           strncmp(path, "UNC\\", 4) == 0)
342         {
343           memmove(path+4, path, len);
344           memcpy(path, "\\\\?\\", 4);
345           len += 4;
346           path[len] = '\0';
347         }
348
349 #elif defined(PCI_OS_DJGPP) || defined(PCI_OS_WINDOWS)
350
351       const char *exe_path;
352
353 #ifdef PCI_OS_DJGPP
354       exe_path = __dos_argv0;
355 #else
356       exe_path = _pgmptr;
357 #endif
358
359       len = strlen(exe_path);
360       path = pci_malloc(a, len+sizeof(PCI_IDS));
361       memcpy(path, exe_path, len+1);
362
363 #endif
364
365       sep = strrchr(path, '\\');
366       if (!sep)
367         {
368           /*
369            * If current module path (current executable for static builds or
370            * current DLL library for shared build) cannot be determined then
371            * fallback to the current directory.
372            */
373           free(path);
374           pci_set_name_list_path(a, PCI_IDS, 0);
375         }
376       else
377         {
378           memcpy(sep+1, PCI_IDS, sizeof(PCI_IDS));
379           pci_set_name_list_path(a, path, 1);
380         }
381     }
382 }
383
384 #else
385
386 static void
387 pci_init_name_list_path(struct pci_access *a)
388 {
389   pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0);
390 }
391
392 #endif
393
394 struct pci_access *
395 pci_alloc(void)
396 {
397   struct pci_access *a = pci_malloc(NULL, sizeof(struct pci_access));
398   int i;
399
400   memset(a, 0, sizeof(*a));
401   pci_init_name_list_path(a);
402 #ifdef PCI_USE_DNS
403   pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
404   pci_define_param(a, "net.cache_name", "~/.pciids-cache", "Name of the ID cache file");
405   a->id_lookup_mode = PCI_LOOKUP_CACHE;
406 #endif
407 #ifdef PCI_HAVE_HWDB
408   pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero");
409 #endif
410   for (i=0; i<PCI_ACCESS_MAX; i++)
411     if (pci_methods[i] && pci_methods[i]->config)
412       pci_methods[i]->config(a);
413   return a;
414 }
415
416 void
417 pci_init_v35(struct pci_access *a)
418 {
419   if (!a->error)
420     a->error = pci_generic_error;
421   if (!a->warning)
422     a->warning = pci_generic_warn;
423   if (!a->debug)
424     a->debug = pci_generic_debug;
425   if (!a->debugging)
426     a->debug = pci_null_debug;
427
428   if (a->method)
429     {
430       if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
431         a->error("This access method is not supported.");
432       a->methods = pci_methods[a->method];
433     }
434   else
435     {
436       unsigned int i;
437       for (i=0; probe_sequence[i] >= 0; i++)
438         {
439           struct pci_methods *m = pci_methods[probe_sequence[i]];
440           if (!m)
441             continue;
442           a->debug("Trying method %s...", m->name);
443           if (m->detect(a))
444             {
445               a->debug("...OK\n");
446               a->methods = m;
447               a->method = probe_sequence[i];
448               break;
449             }
450           a->debug("...No.\n");
451         }
452       if (!a->methods)
453         a->error("Cannot find any working access method.");
454     }
455   a->debug("Decided to use %s\n", a->methods->name);
456   a->methods->init(a);
457 }
458
459 STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v35(a));
460 DEFINE_ALIAS(void pci_init_v30(struct pci_access *a), pci_init_v35);
461 SYMBOL_VERSION(pci_init_v30, pci_init@LIBPCI_3.0);
462 SYMBOL_VERSION(pci_init_v35, pci_init@@LIBPCI_3.5);
463
464 void
465 pci_cleanup(struct pci_access *a)
466 {
467   struct pci_dev *d, *e;
468
469   for (d=a->devices; d; d=e)
470     {
471       e = d->next;
472       pci_free_dev(d);
473     }
474   if (a->methods)
475     a->methods->cleanup(a);
476   pci_free_name_list(a);
477   pci_free_params(a);
478   pci_set_name_list_path(a, NULL, 0);
479   pci_mfree(a);
480 }