xref: /aosp_15_r20/external/mesa3d/src/loader/loader.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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