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