1 /*
2 * Copyright (C) 2013 Rob Clark <[email protected]>
3 * Copyright (C) 2014-2016 Emil Velikov <[email protected]>
4 * Copyright (C) 2016 Intel Corporation
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 * Rob Clark <[email protected]>
27 */
28
29 #include <dlfcn.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <sys/stat.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdbool.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <limits.h>
40 #include <sys/param.h>
41 #ifdef MAJOR_IN_MKDEV
42 #include <sys/mkdev.h>
43 #endif
44 #ifdef MAJOR_IN_SYSMACROS
45 #include <sys/sysmacros.h>
46 #endif
47 #include <GL/gl.h>
48 #include "mesa_interface.h"
49 #include "loader.h"
50 #include "util/libdrm.h"
51 #include "util/os_file.h"
52 #include "util/os_misc.h"
53 #include "util/u_debug.h"
54 #include "git_sha1.h"
55
56 #include "drm-uapi/nouveau_drm.h"
57
58 #define MAX_DRM_DEVICES 64
59
60 #ifdef USE_DRICONF
61 #include "util/xmlconfig.h"
62 #include "util/driconf.h"
63 #endif
64
65 #include "util/macros.h"
66
67 #define __IS_LOADER
68 #include "pci_id_driver_map.h"
69
70 /* For systems like Hurd */
71 #ifndef PATH_MAX
72 #define PATH_MAX 4096
73 #endif
74
default_logger(int level,const char * fmt,...)75 static void default_logger(int level, const char *fmt, ...)
76 {
77 if (level <= _LOADER_WARNING) {
78 va_list args;
79 va_start(args, fmt);
80 vfprintf(stderr, fmt, args);
81 va_end(args);
82 }
83 }
84
85 static loader_logger *log_ = default_logger;
86
87 int
loader_open_device(const char * device_name)88 loader_open_device(const char *device_name)
89 {
90 int fd;
91 #ifdef O_CLOEXEC
92 fd = open(device_name, O_RDWR | O_CLOEXEC);
93 if (fd == -1 && errno == EINVAL)
94 #endif
95 {
96 fd = open(device_name, O_RDWR);
97 if (fd != -1)
98 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
99 }
100 if (fd == -1 && errno == EACCES) {
101 log_(_LOADER_WARNING, "failed to open %s: %s\n",
102 device_name, strerror(errno));
103 }
104 return fd;
105 }
106
107 char *
loader_get_kernel_driver_name(int fd)108 loader_get_kernel_driver_name(int fd)
109 {
110 char *driver;
111 drmVersionPtr version = drmGetVersion(fd);
112
113 if (!version) {
114 log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd);
115 return NULL;
116 }
117
118 driver = strndup(version->name, version->name_len);
119 log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, "using driver %s for %d\n",
120 driver, fd);
121
122 drmFreeVersion(version);
123 return driver;
124 }
125
126 bool
iris_predicate(int fd,const char * driver)127 iris_predicate(int fd, const char *driver)
128 {
129 char *kernel_driver = loader_get_kernel_driver_name(fd);
130 bool ret = kernel_driver && (strcmp(kernel_driver, "i915") == 0 ||
131 strcmp(kernel_driver, "xe") == 0);
132
133 free(kernel_driver);
134 return ret;
135 }
136
137 /* choose zink or nouveau GL */
138 bool
nouveau_zink_predicate(int fd,const char * driver)139 nouveau_zink_predicate(int fd, const char *driver)
140 {
141 #if !defined(HAVE_NVK) || !defined(HAVE_ZINK)
142 if (!strcmp(driver, "zink"))
143 return false;
144 return true;
145 #else
146
147 bool prefer_zink = false;
148
149 /* enable this once zink is up to speed.
150 * struct drm_nouveau_getparam r = { .param = NOUVEAU_GETPARAM_CHIPSET_ID };
151 * int ret = drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r));
152 * if (ret == 0 && (r.value & ~0xf) >= 0x160)
153 * prefer_zink = true;
154 */
155
156 prefer_zink = debug_get_bool_option("NOUVEAU_USE_ZINK", prefer_zink);
157
158 if (prefer_zink && !strcmp(driver, "zink"))
159 return true;
160
161 if (!prefer_zink && !strcmp(driver, "nouveau"))
162 return true;
163 return false;
164 #endif
165 }
166
167
168 /**
169 * Goes through all the platform devices whose driver is on the given list and
170 * try to open their render node. It returns the fd of the first device that
171 * it can open.
172 */
173 int
loader_open_render_node_platform_device(const char * const drivers[],unsigned int n_drivers)174 loader_open_render_node_platform_device(const char * const drivers[],
175 unsigned int n_drivers)
176 {
177 drmDevicePtr devices[MAX_DRM_DEVICES], device;
178 int num_devices, fd = -1;
179 int i, j;
180 bool found = false;
181
182 num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
183 if (num_devices <= 0)
184 return -ENOENT;
185
186 for (i = 0; i < num_devices; i++) {
187 device = devices[i];
188
189 if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
190 (device->bustype == DRM_BUS_PLATFORM)) {
191 drmVersionPtr version;
192
193 fd = loader_open_device(device->nodes[DRM_NODE_RENDER]);
194 if (fd < 0)
195 continue;
196
197 version = drmGetVersion(fd);
198 if (!version) {
199 close(fd);
200 continue;
201 }
202
203 for (j = 0; j < n_drivers; j++) {
204 if (strcmp(version->name, drivers[j]) == 0) {
205 found = true;
206 break;
207 }
208 }
209 if (!found) {
210 drmFreeVersion(version);
211 close(fd);
212 continue;
213 }
214
215 drmFreeVersion(version);
216 break;
217 }
218 }
219 drmFreeDevices(devices, num_devices);
220
221 if (i == num_devices)
222 return -ENOENT;
223
224 return fd;
225 }
226
227 bool
loader_is_device_render_capable(int fd)228 loader_is_device_render_capable(int fd)
229 {
230 drmDevicePtr dev_ptr;
231 bool ret;
232
233 if (drmGetDevice2(fd, 0, &dev_ptr) != 0)
234 return false;
235
236 ret = (dev_ptr->available_nodes & (1 << DRM_NODE_RENDER));
237
238 drmFreeDevice(&dev_ptr);
239
240 return ret;
241 }
242
243 char *
loader_get_render_node(dev_t device)244 loader_get_render_node(dev_t device)
245 {
246 char *render_node = NULL;
247 drmDevicePtr dev_ptr;
248
249 if (drmGetDeviceFromDevId(device, 0, &dev_ptr) < 0)
250 return NULL;
251
252 if (dev_ptr->available_nodes & (1 << DRM_NODE_RENDER)) {
253 render_node = strdup(dev_ptr->nodes[DRM_NODE_RENDER]);
254 if (!render_node)
255 log_(_LOADER_DEBUG, "MESA-LOADER: failed to allocate memory for render node\n");
256 }
257
258 drmFreeDevice(&dev_ptr);
259
260 return render_node;
261 }
262
263 #ifdef USE_DRICONF
264 static const driOptionDescription __driConfigOptionsLoader[] = {
265 DRI_CONF_SECTION_INITIALIZATION
266 DRI_CONF_DEVICE_ID_PATH_TAG()
267 DRI_CONF_DRI_DRIVER()
268 DRI_CONF_SECTION_END
269 };
270
loader_get_dri_config_driver(int fd)271 static char *loader_get_dri_config_driver(int fd)
272 {
273 driOptionCache defaultInitOptions;
274 driOptionCache userInitOptions;
275 char *dri_driver = NULL;
276 char *kernel_driver = loader_get_kernel_driver_name(fd);
277
278 driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader,
279 ARRAY_SIZE(__driConfigOptionsLoader));
280 driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
281 "loader", kernel_driver, NULL, NULL, 0, NULL, 0);
282 if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) {
283 char *opt = driQueryOptionstr(&userInitOptions, "dri_driver");
284 /* not an empty string */
285 if (*opt)
286 dri_driver = strdup(opt);
287 }
288 driDestroyOptionCache(&userInitOptions);
289 driDestroyOptionInfo(&defaultInitOptions);
290
291 free(kernel_driver);
292 return dri_driver;
293 }
294
loader_get_dri_config_device_id(void)295 static char *loader_get_dri_config_device_id(void)
296 {
297 driOptionCache defaultInitOptions;
298 driOptionCache userInitOptions;
299 char *prime = NULL;
300
301 driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader,
302 ARRAY_SIZE(__driConfigOptionsLoader));
303 driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
304 "loader", NULL, NULL, NULL, 0, NULL, 0);
305 if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) {
306 char *opt = driQueryOptionstr(&userInitOptions, "device_id");
307 if (*opt)
308 prime = strdup(opt);
309 }
310 driDestroyOptionCache(&userInitOptions);
311 driDestroyOptionInfo(&defaultInitOptions);
312
313 return prime;
314 }
315 #endif
316
drm_construct_id_path_tag(drmDevicePtr device)317 static char *drm_construct_id_path_tag(drmDevicePtr device)
318 {
319 char *tag = NULL;
320
321 if (device->bustype == DRM_BUS_PCI) {
322 if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u",
323 device->businfo.pci->domain,
324 device->businfo.pci->bus,
325 device->businfo.pci->dev,
326 device->businfo.pci->func) < 0) {
327 return NULL;
328 }
329 } else if (device->bustype == DRM_BUS_PLATFORM ||
330 device->bustype == DRM_BUS_HOST1X) {
331 char *fullname, *name, *address;
332
333 if (device->bustype == DRM_BUS_PLATFORM)
334 fullname = device->businfo.platform->fullname;
335 else
336 fullname = device->businfo.host1x->fullname;
337
338 name = strrchr(fullname, '/');
339 if (!name)
340 name = strdup(fullname);
341 else
342 name = strdup(name + 1);
343
344 address = strchr(name, '@');
345 if (address) {
346 *address++ = '\0';
347
348 if (asprintf(&tag, "platform-%s_%s", address, name) < 0)
349 tag = NULL;
350 } else {
351 if (asprintf(&tag, "platform-%s", name) < 0)
352 tag = NULL;
353 }
354
355 free(name);
356 }
357 return tag;
358 }
359
drm_device_matches_tag(drmDevicePtr device,const char * prime_tag)360 static bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag)
361 {
362 char *tag = drm_construct_id_path_tag(device);
363 int ret;
364
365 if (tag == NULL)
366 return false;
367
368 ret = strcmp(tag, prime_tag);
369
370 free(tag);
371 return ret == 0;
372 }
373
drm_get_id_path_tag_for_fd(int fd)374 static char *drm_get_id_path_tag_for_fd(int fd)
375 {
376 drmDevicePtr device;
377 char *tag;
378
379 if (drmGetDevice2(fd, 0, &device) != 0)
380 return NULL;
381
382 tag = drm_construct_id_path_tag(device);
383 drmFreeDevice(&device);
384 return tag;
385 }
386
loader_get_user_preferred_fd(int * fd_render_gpu,int * original_fd)387 bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
388 {
389 const char *dri_prime = getenv("DRI_PRIME");
390 bool debug = debug_get_bool_option("DRI_PRIME_DEBUG", false);
391 char *default_tag = NULL;
392 drmDevicePtr devices[MAX_DRM_DEVICES];
393 int i, num_devices, fd = -1;
394 struct {
395 enum {
396 PRIME_IS_INTEGER,
397 PRIME_IS_VID_DID,
398 PRIME_IS_PCI_TAG
399 } semantics;
400 union {
401 int as_integer;
402 struct {
403 uint16_t v, d;
404 } as_vendor_device_ids;
405 } v;
406 char *str;
407 } prime = {};
408 prime.str = NULL;
409
410 if (dri_prime)
411 prime.str = strdup(dri_prime);
412 #ifdef USE_DRICONF
413 else
414 prime.str = loader_get_dri_config_device_id();
415 #endif
416
417 if (prime.str == NULL) {
418 goto no_prime_gpu_offloading;
419 } else {
420 uint16_t vendor_id, device_id;
421 if (sscanf(prime.str, "%hx:%hx", &vendor_id, &device_id) == 2) {
422 prime.semantics = PRIME_IS_VID_DID;
423 prime.v.as_vendor_device_ids.v = vendor_id;
424 prime.v.as_vendor_device_ids.d = device_id;
425 } else {
426 int i = atoi(prime.str);
427 if (i < 0 || strcmp(prime.str, "0") == 0) {
428 printf("Invalid value (%d) for DRI_PRIME. Should be > 0\n", i);
429 goto err;
430 } else if (i == 0) {
431 prime.semantics = PRIME_IS_PCI_TAG;
432 } else {
433 prime.semantics = PRIME_IS_INTEGER;
434 prime.v.as_integer = i;
435 }
436 }
437 }
438
439 default_tag = drm_get_id_path_tag_for_fd(*fd_render_gpu);
440 if (default_tag == NULL)
441 goto err;
442
443 num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
444 if (num_devices <= 0)
445 goto err;
446
447 if (debug) {
448 log_(_LOADER_WARNING, "DRI_PRIME: %d devices\n", num_devices);
449 for (i = 0; i < num_devices; i++) {
450 log_(_LOADER_WARNING, " %d:", i);
451 if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER)) {
452 log_(_LOADER_WARNING, "not a render node -> not usable\n");
453 continue;
454 }
455 char *tag = drm_construct_id_path_tag(devices[i]);
456 if (tag) {
457 log_(_LOADER_WARNING, " %s", tag);
458 free(tag);
459 }
460 if (devices[i]->bustype == DRM_BUS_PCI) {
461 log_(_LOADER_WARNING, " %4x:%4x",
462 devices[i]->deviceinfo.pci->vendor_id,
463 devices[i]->deviceinfo.pci->device_id);
464 }
465 log_(_LOADER_WARNING, " %s", devices[i]->nodes[DRM_NODE_RENDER]);
466
467 if (drm_device_matches_tag(devices[i], default_tag)) {
468 log_(_LOADER_WARNING, " [default]");
469 }
470 log_(_LOADER_WARNING, "\n");
471 }
472 }
473
474 if (prime.semantics == PRIME_IS_INTEGER &&
475 prime.v.as_integer >= num_devices) {
476 printf("Inconsistent value (%d) for DRI_PRIME. Should be < %d "
477 "(GPU devices count). Using: %d\n",
478 prime.v.as_integer, num_devices, num_devices - 1);
479 prime.v.as_integer = num_devices - 1;
480 }
481
482 for (i = 0; i < num_devices; i++) {
483 if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
484 continue;
485
486 log_(debug ? _LOADER_WARNING : _LOADER_INFO, "DRI_PRIME: device %d ", i);
487
488 /* three formats of DRI_PRIME are supported:
489 * "N": a >= 1 integer value. Select the Nth GPU, skipping the
490 * default one.
491 * id_path_tag: (for example "pci-0000_02_00_0") choose the card
492 * with this id_path_tag.
493 * vendor_id:device_id
494 */
495 switch (prime.semantics) {
496 case PRIME_IS_INTEGER: {
497 /* Skip the default device */
498 if (drm_device_matches_tag(devices[i], default_tag)) {
499 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
500 "skipped (default device)\n");
501 continue;
502 }
503 prime.v.as_integer--;
504
505 /* Skip more GPUs? */
506 if (prime.v.as_integer) {
507 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
508 "skipped (%d more to skip)\n", prime.v.as_integer - 1);
509 continue;
510 }
511 log_(debug ? _LOADER_WARNING : _LOADER_INFO, " -> ");
512 break;
513 }
514 case PRIME_IS_VID_DID: {
515 if (devices[i]->bustype == DRM_BUS_PCI &&
516 devices[i]->deviceinfo.pci->vendor_id == prime.v.as_vendor_device_ids.v &&
517 devices[i]->deviceinfo.pci->device_id == prime.v.as_vendor_device_ids.d) {
518 /* Update prime for the "different_device"
519 * determination below. */
520 free(prime.str);
521 prime.str = drm_construct_id_path_tag(devices[i]);
522 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
523 " - vid:did match -> ");
524 break;
525 } else {
526 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
527 "skipped (vid:did didn't match)\n");
528 }
529 continue;
530 }
531 case PRIME_IS_PCI_TAG: {
532 if (!drm_device_matches_tag(devices[i], prime.str)) {
533 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
534 "skipped (pci id tag didn't match)\n");
535 continue;
536 }
537 log_(debug ? _LOADER_WARNING : _LOADER_INFO, " - pci tag match -> ");
538 break;
539 }
540 }
541
542 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
543 "selected (%s)\n", devices[i]->nodes[DRM_NODE_RENDER]);
544 fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]);
545 break;
546 }
547 drmFreeDevices(devices, num_devices);
548
549 if (i == num_devices)
550 goto err;
551
552 if (fd < 0) {
553 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
554 "DRI_PRIME: failed to open '%s'\n",
555 devices[i]->nodes[DRM_NODE_RENDER]);
556
557 goto err;
558 }
559
560 bool is_render_and_display_gpu_diff = !!strcmp(default_tag, prime.str);
561 if (original_fd) {
562 if (is_render_and_display_gpu_diff) {
563 *original_fd = *fd_render_gpu;
564 *fd_render_gpu = fd;
565 } else {
566 *original_fd = *fd_render_gpu;
567 close(fd);
568 }
569 } else {
570 close(*fd_render_gpu);
571 *fd_render_gpu = fd;
572 }
573
574 free(default_tag);
575 free(prime.str);
576 return is_render_and_display_gpu_diff;
577 err:
578 log_(debug ? _LOADER_WARNING : _LOADER_INFO,
579 "DRI_PRIME: error. Using the default GPU\n");
580 free(default_tag);
581 free(prime.str);
582 no_prime_gpu_offloading:
583 if (original_fd)
584 *original_fd = *fd_render_gpu;
585 return false;
586 }
587
588 static bool
drm_get_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)589 drm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
590 {
591 drmDevicePtr device;
592
593 if (drmGetDevice2(fd, 0, &device) != 0) {
594 log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n");
595 return false;
596 }
597
598 if (device->bustype != DRM_BUS_PCI) {
599 drmFreeDevice(&device);
600 log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n");
601 return false;
602 }
603
604 *vendor_id = device->deviceinfo.pci->vendor_id;
605 *chip_id = device->deviceinfo.pci->device_id;
606 drmFreeDevice(&device);
607 return true;
608 }
609
610 #ifdef __linux__
loader_get_linux_pci_field(int maj,int min,const char * field)611 static int loader_get_linux_pci_field(int maj, int min, const char *field)
612 {
613 char path[PATH_MAX + 1];
614 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/%s", maj, min, field);
615
616 char *field_str = os_read_file(path, NULL);
617 if (!field_str) {
618 /* Probably non-PCI device. */
619 return 0;
620 }
621
622 int value = (int)strtoll(field_str, NULL, 16);
623 free(field_str);
624
625 return value;
626 }
627
628 static bool
loader_get_linux_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)629 loader_get_linux_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
630 {
631 struct stat sbuf;
632 if (fstat(fd, &sbuf) != 0) {
633 log_(_LOADER_DEBUG, "MESA-LOADER: failed to fstat fd\n");
634 return false;
635 }
636
637 int maj = major(sbuf.st_rdev);
638 int min = minor(sbuf.st_rdev);
639
640 *vendor_id = loader_get_linux_pci_field(maj, min, "vendor");
641 *chip_id = loader_get_linux_pci_field(maj, min, "device");
642
643 return *vendor_id && *chip_id;
644 }
645 #endif /* __linux__ */
646
647 bool
loader_get_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)648 loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
649 {
650 #ifdef __linux__
651 /* Implementation without causing full enumeration of DRM devices. */
652 if (loader_get_linux_pci_id_for_fd(fd, vendor_id, chip_id))
653 return true;
654 #endif
655
656 return drm_get_pci_id_for_fd(fd, vendor_id, chip_id);
657 }
658
659 char *
loader_get_device_name_for_fd(int fd)660 loader_get_device_name_for_fd(int fd)
661 {
662 return drmGetDeviceNameFromFd2(fd);
663 }
664
665 static char *
loader_get_pci_driver(int fd)666 loader_get_pci_driver(int fd)
667 {
668 int vendor_id, chip_id, i, j;
669 char *driver = NULL;
670
671 if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id))
672 return NULL;
673
674 for (i = 0; i < ARRAY_SIZE(driver_map); i++) {
675 if (vendor_id != driver_map[i].vendor_id)
676 continue;
677
678 if (driver_map[i].predicate && !driver_map[i].predicate(fd, driver_map[i].driver))
679 continue;
680
681 if (driver_map[i].num_chips_ids == -1) {
682 driver = strdup(driver_map[i].driver);
683 goto out;
684 }
685
686 for (j = 0; j < driver_map[i].num_chips_ids; j++)
687 if (driver_map[i].chip_ids[j] == chip_id) {
688 driver = strdup(driver_map[i].driver);
689 goto out;
690 }
691 }
692
693 out:
694 log_(driver ? _LOADER_DEBUG : _LOADER_WARNING,
695 "pci id for fd %d: %04x:%04x, driver %s\n",
696 fd, vendor_id, chip_id, driver);
697 return driver;
698 }
699
700 char *
loader_get_driver_for_fd(int fd)701 loader_get_driver_for_fd(int fd)
702 {
703 char *driver;
704
705 /* Allow an environment variable to force choosing a different driver
706 * binary. If that driver binary can't survive on this FD, that's the
707 * user's problem, but this allows vc4 simulator to run on an i965 host,
708 * and may be useful for some touch testing of i915 on an i965 host.
709 */
710 if (__normal_user()) {
711 const char *override = os_get_option("MESA_LOADER_DRIVER_OVERRIDE");
712 if (override)
713 return strdup(override);
714 }
715
716 #if defined(USE_DRICONF)
717 driver = loader_get_dri_config_driver(fd);
718 if (driver)
719 return driver;
720 #endif
721
722 driver = loader_get_pci_driver(fd);
723 if (!driver)
724 driver = loader_get_kernel_driver_name(fd);
725
726 return driver;
727 }
728
729 void
loader_set_logger(loader_logger * logger)730 loader_set_logger(loader_logger *logger)
731 {
732 log_ = logger;
733 }
734
735 bool
loader_bind_extensions(void * data,const struct dri_extension_match * matches,size_t num_matches,const __DRIextension ** extensions)736 loader_bind_extensions(void *data,
737 const struct dri_extension_match *matches, size_t num_matches,
738 const __DRIextension **extensions)
739 {
740 bool ret = true;
741
742 for (size_t j = 0; j < num_matches; j++) {
743 const struct dri_extension_match *match = &matches[j];
744 const __DRIextension **field = (const __DRIextension **)((char *)data + matches[j].offset);
745 for (size_t i = 0; extensions[i]; i++) {
746 if (strcmp(extensions[i]->name, match->name) == 0 &&
747 extensions[i]->version >= match->version) {
748 *field = extensions[i];
749 break;
750 }
751 }
752
753 if (!*field) {
754 log_(match->optional ? _LOADER_DEBUG : _LOADER_FATAL, "did not find extension %s version %d\n",
755 match->name, match->version);
756 if (!match->optional)
757 ret = false;
758 continue;
759 }
760
761 /* The loaders rely on the loaded DRI drivers being from the same Mesa
762 * build so that we can reference the same structs on both sides.
763 */
764 if (strcmp(match->name, __DRI_MESA) == 0) {
765 const __DRImesaCoreExtension *mesa = (const __DRImesaCoreExtension *)*field;
766 if (strcmp(mesa->version_string, MESA_INTERFACE_VERSION_STRING) != 0) {
767 log_(_LOADER_FATAL, "DRI driver not from this Mesa build ('%s' vs '%s')\n",
768 mesa->version_string, MESA_INTERFACE_VERSION_STRING);
769 ret = false;
770 }
771 }
772 }
773
774 return ret;
775 }
776 /**
777 * Opens a driver or backend using its name, returning the library handle.
778 *
779 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
780 * \param lib_suffix - a suffix to append to the driver name to generate the
781 * full library name.
782 * \param search_path_vars - NULL-terminated list of env vars that can be used
783 * \param default_search_path - a colon-separted list of directories used if
784 * search_path_vars is NULL or none of the vars are set in the environment.
785 * \param warn_on_fail - Log a warning if the driver is not found.
786 */
787 void *
loader_open_driver_lib(const char * driver_name,const char * lib_suffix,const char ** search_path_vars,const char * default_search_path,bool warn_on_fail)788 loader_open_driver_lib(const char *driver_name,
789 const char *lib_suffix,
790 const char **search_path_vars,
791 const char *default_search_path,
792 bool warn_on_fail)
793 {
794 char path[PATH_MAX];
795 const char *search_paths, *next, *end;
796
797 search_paths = NULL;
798 if (__normal_user() && search_path_vars) {
799 for (int i = 0; search_path_vars[i] != NULL; i++) {
800 search_paths = os_get_option(search_path_vars[i]);
801 if (search_paths)
802 break;
803 }
804 }
805 if (search_paths == NULL)
806 search_paths = default_search_path;
807
808 void *driver = NULL;
809 const char *dl_error = NULL;
810 end = search_paths + strlen(search_paths);
811 for (const char *p = search_paths; p < end; p = next + 1) {
812 int len;
813 next = strchr(p, ':');
814 if (next == NULL)
815 next = end;
816
817 len = next - p;
818 snprintf(path, sizeof(path), "%.*s/tls/%s%s.so", len,
819 p, driver_name, lib_suffix);
820 driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
821 if (driver == NULL) {
822 snprintf(path, sizeof(path), "%.*s/%s%s.so", len,
823 p, driver_name, lib_suffix);
824 driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
825 if (driver == NULL) {
826 dl_error = dlerror();
827 log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n",
828 path, dl_error);
829 }
830 }
831 /* not need continue to loop all paths once the driver is found */
832 if (driver != NULL)
833 break;
834 }
835
836 if (driver == NULL) {
837 if (warn_on_fail) {
838 log_(_LOADER_WARNING,
839 "MESA-LOADER: failed to open %s: %s (search paths %s, suffix %s)\n",
840 driver_name, dl_error, search_paths, lib_suffix);
841 }
842 return NULL;
843 }
844
845 log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path);
846
847 return driver;
848 }
849