1af69d88dSmrg/* 2af69d88dSmrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 301e04c3fSmrg * Copyright (C) 2014-2016 Emil Velikov <emil.l.velikov@gmail.com> 401e04c3fSmrg * Copyright (C) 2016 Intel Corporation 5af69d88dSmrg * 6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 8af69d88dSmrg * to deal in the Software without restriction, including without limitation 9af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 11af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 12af69d88dSmrg * 13af69d88dSmrg * The above copyright notice and this permission notice (including the next 14af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 15af69d88dSmrg * Software. 16af69d88dSmrg * 17af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23af69d88dSmrg * SOFTWARE. 24af69d88dSmrg * 25af69d88dSmrg * Authors: 26af69d88dSmrg * Rob Clark <robclark@freedesktop.org> 27af69d88dSmrg */ 28af69d88dSmrg 299f464c52Smaya#include <dlfcn.h> 3001e04c3fSmrg#include <errno.h> 3101e04c3fSmrg#include <fcntl.h> 3201e04c3fSmrg#include <sys/stat.h> 33af69d88dSmrg#include <stdarg.h> 34af69d88dSmrg#include <stdio.h> 3501e04c3fSmrg#include <stdbool.h> 36af69d88dSmrg#include <string.h> 37af69d88dSmrg#include <unistd.h> 38af69d88dSmrg#include <stdlib.h> 391463c08dSmrg#include <limits.h> 409f464c52Smaya#include <sys/param.h> 4101e04c3fSmrg#ifdef MAJOR_IN_MKDEV 4201e04c3fSmrg#include <sys/mkdev.h> 43af69d88dSmrg#endif 4401e04c3fSmrg#ifdef MAJOR_IN_SYSMACROS 4501e04c3fSmrg#include <sys/sysmacros.h> 46af69d88dSmrg#endif 479f464c52Smaya#include <GL/gl.h> 489f464c52Smaya#include <GL/internal/dri_interface.h> 49af69d88dSmrg#include "loader.h" 50af69d88dSmrg 5101e04c3fSmrg#ifdef HAVE_LIBDRM 52af69d88dSmrg#include <xf86drm.h> 531463c08dSmrg#define MAX_DRM_DEVICES 64 5401e04c3fSmrg#ifdef USE_DRICONF 5501e04c3fSmrg#include "util/xmlconfig.h" 561463c08dSmrg#include "util/driconf.h" 5701e04c3fSmrg#endif 58af69d88dSmrg#endif 59af69d88dSmrg 601463c08dSmrg#include "util/macros.h" 611463c08dSmrg 62af69d88dSmrg#define __IS_LOADER 63af69d88dSmrg#include "pci_id_driver_map.h" 64af69d88dSmrg 651463c08dSmrg/* For systems like Hurd */ 661463c08dSmrg#ifndef PATH_MAX 671463c08dSmrg#define PATH_MAX 4096 681463c08dSmrg#endif 691463c08dSmrg 70af69d88dSmrgstatic void default_logger(int level, const char *fmt, ...) 71af69d88dSmrg{ 72af69d88dSmrg if (level <= _LOADER_WARNING) { 73af69d88dSmrg va_list args; 74af69d88dSmrg va_start(args, fmt); 75af69d88dSmrg vfprintf(stderr, fmt, args); 76af69d88dSmrg va_end(args); 77af69d88dSmrg } 78af69d88dSmrg} 79af69d88dSmrg 809f464c52Smayastatic loader_logger *log_ = default_logger; 81af69d88dSmrg 8201e04c3fSmrgint 8301e04c3fSmrgloader_open_device(const char *device_name) 84af69d88dSmrg{ 8501e04c3fSmrg int fd; 8601e04c3fSmrg#ifdef O_CLOEXEC 8701e04c3fSmrg fd = open(device_name, O_RDWR | O_CLOEXEC); 8801e04c3fSmrg if (fd == -1 && errno == EINVAL) 8901e04c3fSmrg#endif 9001e04c3fSmrg { 9101e04c3fSmrg fd = open(device_name, O_RDWR); 9201e04c3fSmrg if (fd != -1) 9301e04c3fSmrg fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 94af69d88dSmrg } 951463c08dSmrg if (fd == -1 && errno == EACCES) { 961463c08dSmrg log_(_LOADER_WARNING, "failed to open %s: %s\n", 971463c08dSmrg device_name, strerror(errno)); 981463c08dSmrg } 9901e04c3fSmrg return fd; 100af69d88dSmrg} 101af69d88dSmrg 10201e04c3fSmrgstatic char *loader_get_kernel_driver_name(int fd) 103af69d88dSmrg{ 10401e04c3fSmrg#if HAVE_LIBDRM 10501e04c3fSmrg char *driver; 10601e04c3fSmrg drmVersionPtr version = drmGetVersion(fd); 10701e04c3fSmrg 10801e04c3fSmrg if (!version) { 10901e04c3fSmrg log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd); 11001e04c3fSmrg return NULL; 11101e04c3fSmrg } 112af69d88dSmrg 11301e04c3fSmrg driver = strndup(version->name, version->name_len); 1141463c08dSmrg log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, "using driver %s for %d\n", 1151463c08dSmrg driver, fd); 116af69d88dSmrg 11701e04c3fSmrg drmFreeVersion(version); 11801e04c3fSmrg return driver; 11901e04c3fSmrg#else 12001e04c3fSmrg return NULL; 12101e04c3fSmrg#endif 12201e04c3fSmrg} 123af69d88dSmrg 1241463c08dSmrgbool 1251463c08dSmrgis_kernel_i915(int fd) 1261463c08dSmrg{ 1271463c08dSmrg char *kernel_driver = loader_get_kernel_driver_name(fd); 1281463c08dSmrg bool is_i915 = kernel_driver && strcmp(kernel_driver, "i915") == 0; 1291463c08dSmrg 1301463c08dSmrg free(kernel_driver); 1311463c08dSmrg return is_i915; 1321463c08dSmrg} 1331463c08dSmrg 13401e04c3fSmrg#if defined(HAVE_LIBDRM) 13501e04c3fSmrgint 13601e04c3fSmrgloader_open_render_node(const char *name) 137af69d88dSmrg{ 1381463c08dSmrg drmDevicePtr devices[MAX_DRM_DEVICES], device; 1391463c08dSmrg int i, num_devices, fd = -1; 14001e04c3fSmrg 1411463c08dSmrg num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 1421463c08dSmrg if (num_devices <= 0) 1431463c08dSmrg return -ENOENT; 144af69d88dSmrg 1451463c08dSmrg for (i = 0; i < num_devices; i++) { 14601e04c3fSmrg device = devices[i]; 14701e04c3fSmrg 14801e04c3fSmrg if ((device->available_nodes & (1 << DRM_NODE_RENDER)) && 14901e04c3fSmrg (device->bustype == DRM_BUS_PLATFORM)) { 15001e04c3fSmrg drmVersionPtr version; 15101e04c3fSmrg 1529f464c52Smaya fd = loader_open_device(device->nodes[DRM_NODE_RENDER]); 15301e04c3fSmrg if (fd < 0) 15401e04c3fSmrg continue; 15501e04c3fSmrg 15601e04c3fSmrg version = drmGetVersion(fd); 15701e04c3fSmrg if (!version) { 15801e04c3fSmrg close(fd); 15901e04c3fSmrg continue; 16001e04c3fSmrg } 16101e04c3fSmrg 16201e04c3fSmrg if (strcmp(version->name, name) != 0) { 16301e04c3fSmrg drmFreeVersion(version); 16401e04c3fSmrg close(fd); 16501e04c3fSmrg continue; 16601e04c3fSmrg } 16701e04c3fSmrg 16801e04c3fSmrg drmFreeVersion(version); 16901e04c3fSmrg break; 17001e04c3fSmrg } 171af69d88dSmrg } 1721463c08dSmrg drmFreeDevices(devices, num_devices); 173af69d88dSmrg 1741463c08dSmrg if (i == num_devices) 1751463c08dSmrg return -ENOENT; 17601e04c3fSmrg 1771463c08dSmrg return fd; 178af69d88dSmrg} 179af69d88dSmrg 18001e04c3fSmrg#ifdef USE_DRICONF 1811463c08dSmrgstatic const driOptionDescription __driConfigOptionsLoader[] = { 18201e04c3fSmrg DRI_CONF_SECTION_INITIALIZATION 18301e04c3fSmrg DRI_CONF_DEVICE_ID_PATH_TAG() 18401e04c3fSmrg DRI_CONF_DRI_DRIVER() 18501e04c3fSmrg DRI_CONF_SECTION_END 1861463c08dSmrg}; 18701e04c3fSmrg 18801e04c3fSmrgstatic char *loader_get_dri_config_driver(int fd) 189af69d88dSmrg{ 19001e04c3fSmrg driOptionCache defaultInitOptions; 19101e04c3fSmrg driOptionCache userInitOptions; 19201e04c3fSmrg char *dri_driver = NULL; 19301e04c3fSmrg char *kernel_driver = loader_get_kernel_driver_name(fd); 19401e04c3fSmrg 1951463c08dSmrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader, 1961463c08dSmrg ARRAY_SIZE(__driConfigOptionsLoader)); 19701e04c3fSmrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, 1981463c08dSmrg "loader", kernel_driver, NULL, NULL, 0, NULL, 0); 19901e04c3fSmrg if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) { 20001e04c3fSmrg char *opt = driQueryOptionstr(&userInitOptions, "dri_driver"); 20101e04c3fSmrg /* not an empty string */ 20201e04c3fSmrg if (*opt) 20301e04c3fSmrg dri_driver = strdup(opt); 204af69d88dSmrg } 20501e04c3fSmrg driDestroyOptionCache(&userInitOptions); 20601e04c3fSmrg driDestroyOptionInfo(&defaultInitOptions); 207af69d88dSmrg 20801e04c3fSmrg free(kernel_driver); 20901e04c3fSmrg return dri_driver; 21001e04c3fSmrg} 211af69d88dSmrg 21201e04c3fSmrgstatic char *loader_get_dri_config_device_id(void) 21301e04c3fSmrg{ 21401e04c3fSmrg driOptionCache defaultInitOptions; 21501e04c3fSmrg driOptionCache userInitOptions; 21601e04c3fSmrg char *prime = NULL; 217af69d88dSmrg 2181463c08dSmrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader, 2191463c08dSmrg ARRAY_SIZE(__driConfigOptionsLoader)); 2201463c08dSmrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, 2211463c08dSmrg "loader", NULL, NULL, NULL, 0, NULL, 0); 22201e04c3fSmrg if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) 22301e04c3fSmrg prime = strdup(driQueryOptionstr(&userInitOptions, "device_id")); 22401e04c3fSmrg driDestroyOptionCache(&userInitOptions); 22501e04c3fSmrg driDestroyOptionInfo(&defaultInitOptions); 22601e04c3fSmrg 22701e04c3fSmrg return prime; 228af69d88dSmrg} 22901e04c3fSmrg#endif 230af69d88dSmrg 23101e04c3fSmrgstatic char *drm_construct_id_path_tag(drmDevicePtr device) 232af69d88dSmrg{ 23301e04c3fSmrg char *tag = NULL; 23401e04c3fSmrg 23501e04c3fSmrg if (device->bustype == DRM_BUS_PCI) { 23601e04c3fSmrg if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u", 23701e04c3fSmrg device->businfo.pci->domain, 23801e04c3fSmrg device->businfo.pci->bus, 23901e04c3fSmrg device->businfo.pci->dev, 24001e04c3fSmrg device->businfo.pci->func) < 0) { 24101e04c3fSmrg return NULL; 242af69d88dSmrg } 24301e04c3fSmrg } else if (device->bustype == DRM_BUS_PLATFORM || 24401e04c3fSmrg device->bustype == DRM_BUS_HOST1X) { 24501e04c3fSmrg char *fullname, *name, *address; 24601e04c3fSmrg 24701e04c3fSmrg if (device->bustype == DRM_BUS_PLATFORM) 24801e04c3fSmrg fullname = device->businfo.platform->fullname; 24901e04c3fSmrg else 25001e04c3fSmrg fullname = device->businfo.host1x->fullname; 251af69d88dSmrg 25201e04c3fSmrg name = strrchr(fullname, '/'); 25301e04c3fSmrg if (!name) 25401e04c3fSmrg name = strdup(fullname); 25501e04c3fSmrg else 25601e04c3fSmrg name = strdup(name + 1); 25701e04c3fSmrg 25801e04c3fSmrg address = strchr(name, '@'); 25901e04c3fSmrg if (address) { 26001e04c3fSmrg *address++ = '\0'; 26101e04c3fSmrg 26201e04c3fSmrg if (asprintf(&tag, "platform-%s_%s", address, name) < 0) 26301e04c3fSmrg tag = NULL; 26401e04c3fSmrg } else { 26501e04c3fSmrg if (asprintf(&tag, "platform-%s", name) < 0) 26601e04c3fSmrg tag = NULL; 26701e04c3fSmrg } 26801e04c3fSmrg 26901e04c3fSmrg free(name); 270af69d88dSmrg } 27101e04c3fSmrg return tag; 272af69d88dSmrg} 273af69d88dSmrg 27401e04c3fSmrgstatic bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag) 275af69d88dSmrg{ 27601e04c3fSmrg char *tag = drm_construct_id_path_tag(device); 27701e04c3fSmrg int ret; 278af69d88dSmrg 27901e04c3fSmrg if (tag == NULL) 28001e04c3fSmrg return false; 281af69d88dSmrg 28201e04c3fSmrg ret = strcmp(tag, prime_tag); 283af69d88dSmrg 28401e04c3fSmrg free(tag); 28501e04c3fSmrg return ret == 0; 286af69d88dSmrg} 287af69d88dSmrg 28801e04c3fSmrgstatic char *drm_get_id_path_tag_for_fd(int fd) 289af69d88dSmrg{ 29001e04c3fSmrg drmDevicePtr device; 29101e04c3fSmrg char *tag; 292af69d88dSmrg 29301e04c3fSmrg if (drmGetDevice2(fd, 0, &device) != 0) 29401e04c3fSmrg return NULL; 29501e04c3fSmrg 29601e04c3fSmrg tag = drm_construct_id_path_tag(device); 29701e04c3fSmrg drmFreeDevice(&device); 29801e04c3fSmrg return tag; 29901e04c3fSmrg} 300af69d88dSmrg 30101e04c3fSmrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 302af69d88dSmrg{ 303af69d88dSmrg const char *dri_prime = getenv("DRI_PRIME"); 30401e04c3fSmrg char *default_tag, *prime = NULL; 30501e04c3fSmrg drmDevicePtr devices[MAX_DRM_DEVICES]; 3061463c08dSmrg int i, num_devices, fd = -1; 307af69d88dSmrg 308af69d88dSmrg if (dri_prime) 309af69d88dSmrg prime = strdup(dri_prime); 310af69d88dSmrg#ifdef USE_DRICONF 31101e04c3fSmrg else 31201e04c3fSmrg prime = loader_get_dri_config_device_id(); 313af69d88dSmrg#endif 314af69d88dSmrg 315af69d88dSmrg if (prime == NULL) { 31601e04c3fSmrg *different_device = false; 317af69d88dSmrg return default_fd; 318af69d88dSmrg } 319af69d88dSmrg 32001e04c3fSmrg default_tag = drm_get_id_path_tag_for_fd(default_fd); 32101e04c3fSmrg if (default_tag == NULL) 32201e04c3fSmrg goto err; 323af69d88dSmrg 32401e04c3fSmrg num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 3251463c08dSmrg if (num_devices <= 0) 32601e04c3fSmrg goto err; 327af69d88dSmrg 3281463c08dSmrg for (i = 0; i < num_devices; i++) { 3291463c08dSmrg if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER)) 3301463c08dSmrg continue; 33101e04c3fSmrg 3321463c08dSmrg /* two formats of DRI_PRIME are supported: 3331463c08dSmrg * "1": choose any other card than the card used by default. 3341463c08dSmrg * id_path_tag: (for example "pci-0000_02_00_0") choose the card 3351463c08dSmrg * with this id_path_tag. 3361463c08dSmrg */ 3371463c08dSmrg if (!strcmp(prime,"1")) { 3381463c08dSmrg if (drm_device_matches_tag(devices[i], default_tag)) 3391463c08dSmrg continue; 3401463c08dSmrg } else { 3411463c08dSmrg if (!drm_device_matches_tag(devices[i], prime)) 3421463c08dSmrg continue; 34301e04c3fSmrg } 34401e04c3fSmrg 3451463c08dSmrg fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]); 3461463c08dSmrg break; 347af69d88dSmrg } 3481463c08dSmrg drmFreeDevices(devices, num_devices); 349af69d88dSmrg 3501463c08dSmrg if (i == num_devices) 35101e04c3fSmrg goto err; 352af69d88dSmrg 35301e04c3fSmrg if (fd < 0) 35401e04c3fSmrg goto err; 355af69d88dSmrg 35601e04c3fSmrg close(default_fd); 357af69d88dSmrg 35801e04c3fSmrg *different_device = !!strcmp(default_tag, prime); 359af69d88dSmrg 36001e04c3fSmrg free(default_tag); 36101e04c3fSmrg free(prime); 36201e04c3fSmrg return fd; 363af69d88dSmrg 36401e04c3fSmrg err: 36501e04c3fSmrg *different_device = false; 366af69d88dSmrg 36701e04c3fSmrg free(default_tag); 36801e04c3fSmrg free(prime); 36901e04c3fSmrg return default_fd; 370af69d88dSmrg} 37101e04c3fSmrg#else 37201e04c3fSmrgint 37301e04c3fSmrgloader_open_render_node(const char *name) 374af69d88dSmrg{ 37501e04c3fSmrg return -1; 37601e04c3fSmrg} 377af69d88dSmrg 37801e04c3fSmrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 37901e04c3fSmrg{ 38001e04c3fSmrg *different_device = false; 38101e04c3fSmrg return default_fd; 382af69d88dSmrg} 383af69d88dSmrg#endif 384af69d88dSmrg 38501e04c3fSmrg#if defined(HAVE_LIBDRM) 386af69d88dSmrg 3871463c08dSmrgstatic bool 388af69d88dSmrgdrm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 389af69d88dSmrg{ 39001e04c3fSmrg drmDevicePtr device; 39101e04c3fSmrg 3921463c08dSmrg if (drmGetDevice2(fd, 0, &device) != 0) { 39301e04c3fSmrg log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n"); 3941463c08dSmrg return false; 3951463c08dSmrg } 3961463c08dSmrg 3971463c08dSmrg if (device->bustype != DRM_BUS_PCI) { 3981463c08dSmrg drmFreeDevice(&device); 3991463c08dSmrg log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n"); 4001463c08dSmrg return false; 401af69d88dSmrg } 402af69d88dSmrg 4031463c08dSmrg *vendor_id = device->deviceinfo.pci->vendor_id; 4041463c08dSmrg *chip_id = device->deviceinfo.pci->device_id; 4051463c08dSmrg drmFreeDevice(&device); 4061463c08dSmrg return true; 407af69d88dSmrg} 408af69d88dSmrg#endif 409af69d88dSmrg 410af69d88dSmrg 4111463c08dSmrgbool 412af69d88dSmrgloader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 413af69d88dSmrg{ 41401e04c3fSmrg#if HAVE_LIBDRM 4151463c08dSmrg return drm_get_pci_id_for_fd(fd, vendor_id, chip_id); 416af69d88dSmrg#endif 4171463c08dSmrg return false; 418af69d88dSmrg} 419af69d88dSmrg 420af69d88dSmrgchar * 421af69d88dSmrgloader_get_device_name_for_fd(int fd) 422af69d88dSmrg{ 423af69d88dSmrg char *result = NULL; 424af69d88dSmrg 42501e04c3fSmrg#if HAVE_LIBDRM 42601e04c3fSmrg result = drmGetDeviceNameFromFd2(fd); 427af69d88dSmrg#endif 42801e04c3fSmrg 429af69d88dSmrg return result; 430af69d88dSmrg} 431af69d88dSmrg 4321463c08dSmrgstatic char * 4331463c08dSmrgloader_get_pci_driver(int fd) 434af69d88dSmrg{ 435af69d88dSmrg int vendor_id, chip_id, i, j; 436af69d88dSmrg char *driver = NULL; 437af69d88dSmrg 4381463c08dSmrg if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) 4391463c08dSmrg return NULL; 440af69d88dSmrg 4411463c08dSmrg for (i = 0; i < ARRAY_SIZE(driver_map); i++) { 442af69d88dSmrg if (vendor_id != driver_map[i].vendor_id) 443af69d88dSmrg continue; 444af69d88dSmrg 445af69d88dSmrg if (driver_map[i].predicate && !driver_map[i].predicate(fd)) 446af69d88dSmrg continue; 447af69d88dSmrg 448af69d88dSmrg if (driver_map[i].num_chips_ids == -1) { 449af69d88dSmrg driver = strdup(driver_map[i].driver); 450af69d88dSmrg goto out; 451af69d88dSmrg } 452af69d88dSmrg 453af69d88dSmrg for (j = 0; j < driver_map[i].num_chips_ids; j++) 454af69d88dSmrg if (driver_map[i].chip_ids[j] == chip_id) { 455af69d88dSmrg driver = strdup(driver_map[i].driver); 456af69d88dSmrg goto out; 457af69d88dSmrg } 458af69d88dSmrg } 459af69d88dSmrg 460af69d88dSmrgout: 461af69d88dSmrg log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, 462af69d88dSmrg "pci id for fd %d: %04x:%04x, driver %s\n", 463af69d88dSmrg fd, vendor_id, chip_id, driver); 464af69d88dSmrg return driver; 465af69d88dSmrg} 466af69d88dSmrg 4671463c08dSmrgchar * 4681463c08dSmrgloader_get_driver_for_fd(int fd) 4691463c08dSmrg{ 4701463c08dSmrg char *driver; 4711463c08dSmrg 4721463c08dSmrg /* Allow an environment variable to force choosing a different driver 4731463c08dSmrg * binary. If that driver binary can't survive on this FD, that's the 4741463c08dSmrg * user's problem, but this allows vc4 simulator to run on an i965 host, 4751463c08dSmrg * and may be useful for some touch testing of i915 on an i965 host. 4761463c08dSmrg */ 4771463c08dSmrg if (geteuid() == getuid()) { 4781463c08dSmrg driver = getenv("MESA_LOADER_DRIVER_OVERRIDE"); 4791463c08dSmrg if (driver) 4801463c08dSmrg return strdup(driver); 4811463c08dSmrg } 4821463c08dSmrg 4831463c08dSmrg#if defined(HAVE_LIBDRM) && defined(USE_DRICONF) 4841463c08dSmrg driver = loader_get_dri_config_driver(fd); 4851463c08dSmrg if (driver) 4861463c08dSmrg return driver; 4871463c08dSmrg#endif 4881463c08dSmrg 4891463c08dSmrg driver = loader_get_pci_driver(fd); 4901463c08dSmrg if (!driver) 4911463c08dSmrg driver = loader_get_kernel_driver_name(fd); 4921463c08dSmrg 4931463c08dSmrg return driver; 4941463c08dSmrg} 4951463c08dSmrg 496af69d88dSmrgvoid 4979f464c52Smayaloader_set_logger(loader_logger *logger) 498af69d88dSmrg{ 499af69d88dSmrg log_ = logger; 500af69d88dSmrg} 50101e04c3fSmrg 50201e04c3fSmrgchar * 50301e04c3fSmrgloader_get_extensions_name(const char *driver_name) 50401e04c3fSmrg{ 50501e04c3fSmrg char *name = NULL; 50601e04c3fSmrg 50701e04c3fSmrg if (asprintf(&name, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS, driver_name) < 0) 50801e04c3fSmrg return NULL; 50901e04c3fSmrg 51001e04c3fSmrg const size_t len = strlen(name); 51101e04c3fSmrg for (size_t i = 0; i < len; i++) { 51201e04c3fSmrg if (name[i] == '-') 51301e04c3fSmrg name[i] = '_'; 51401e04c3fSmrg } 51501e04c3fSmrg 51601e04c3fSmrg return name; 51701e04c3fSmrg} 5189f464c52Smaya 5199f464c52Smaya/** 5201463c08dSmrg * Opens a driver or backend using its name, returning the library handle. 5219f464c52Smaya * 5229f464c52Smaya * \param driverName - a name like "i965", "radeon", "nouveau", etc. 5231463c08dSmrg * \param lib_suffix - a suffix to append to the driver name to generate the 5241463c08dSmrg * full library name. 5259f464c52Smaya * \param search_path_vars - NULL-terminated list of env vars that can be used 5261463c08dSmrg * \param default_search_path - a colon-separted list of directories used if 5271463c08dSmrg * search_path_vars is NULL or none of the vars are set in the environment. 5281463c08dSmrg * \param warn_on_fail - Log a warning if the driver is not found. 5299f464c52Smaya */ 5301463c08dSmrgvoid * 5311463c08dSmrgloader_open_driver_lib(const char *driver_name, 5321463c08dSmrg const char *lib_suffix, 5331463c08dSmrg const char **search_path_vars, 5341463c08dSmrg const char *default_search_path, 5351463c08dSmrg bool warn_on_fail) 5369f464c52Smaya{ 5371463c08dSmrg char path[PATH_MAX]; 5381463c08dSmrg const char *search_paths, *next, *end; 5399f464c52Smaya 5409f464c52Smaya search_paths = NULL; 541757f638fSmaya if (!issetugid() && search_path_vars) { 5429f464c52Smaya for (int i = 0; search_path_vars[i] != NULL; i++) { 5439f464c52Smaya search_paths = getenv(search_path_vars[i]); 5449f464c52Smaya if (search_paths) 5459f464c52Smaya break; 5469f464c52Smaya } 5479f464c52Smaya } 5489f464c52Smaya if (search_paths == NULL) 5491463c08dSmrg search_paths = default_search_path; 5509f464c52Smaya 5519f464c52Smaya void *driver = NULL; 5521463c08dSmrg const char *dl_error = NULL; 5539f464c52Smaya end = search_paths + strlen(search_paths); 5541463c08dSmrg for (const char *p = search_paths; p < end; p = next + 1) { 5559f464c52Smaya int len; 5569f464c52Smaya next = strchr(p, ':'); 5579f464c52Smaya if (next == NULL) 5589f464c52Smaya next = end; 5599f464c52Smaya 5609f464c52Smaya len = next - p; 5611463c08dSmrg#if USE_ELF_TLS 5621463c08dSmrg snprintf(path, sizeof(path), "%.*s/tls/%s%s.so", len, 5631463c08dSmrg p, driver_name, lib_suffix); 5649f464c52Smaya driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 5659f464c52Smaya#endif 5669f464c52Smaya if (driver == NULL) { 5671463c08dSmrg snprintf(path, sizeof(path), "%.*s/%s%s.so", len, 5681463c08dSmrg p, driver_name, lib_suffix); 5699f464c52Smaya driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 5701463c08dSmrg if (driver == NULL) { 5711463c08dSmrg dl_error = dlerror(); 5729f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n", 5731463c08dSmrg path, dl_error); 5741463c08dSmrg } 5759f464c52Smaya } 5769f464c52Smaya /* not need continue to loop all paths once the driver is found */ 5779f464c52Smaya if (driver != NULL) 5789f464c52Smaya break; 5799f464c52Smaya } 5809f464c52Smaya 5819f464c52Smaya if (driver == NULL) { 5821463c08dSmrg if (warn_on_fail) { 5831463c08dSmrg log_(_LOADER_WARNING, 5841463c08dSmrg "MESA-LOADER: failed to open %s: %s (search paths %s, suffix %s)\n", 5851463c08dSmrg driver_name, dl_error, search_paths, lib_suffix); 5861463c08dSmrg } 5879f464c52Smaya return NULL; 5889f464c52Smaya } 5899f464c52Smaya 5909f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path); 5919f464c52Smaya 5921463c08dSmrg return driver; 5931463c08dSmrg} 5941463c08dSmrg 5951463c08dSmrg/** 5961463c08dSmrg * Opens a DRI driver using its driver name, returning the __DRIextension 5971463c08dSmrg * entrypoints. 5981463c08dSmrg * 5991463c08dSmrg * \param driverName - a name like "i965", "radeon", "nouveau", etc. 6001463c08dSmrg * \param out_driver - Address where the dlopen() return value will be stored. 6011463c08dSmrg * \param search_path_vars - NULL-terminated list of env vars that can be used 6021463c08dSmrg * to override the DEFAULT_DRIVER_DIR search path. 6031463c08dSmrg */ 6041463c08dSmrgconst struct __DRIextensionRec ** 6051463c08dSmrgloader_open_driver(const char *driver_name, 6061463c08dSmrg void **out_driver_handle, 6071463c08dSmrg const char **search_path_vars) 6081463c08dSmrg{ 6091463c08dSmrg char *get_extensions_name; 6101463c08dSmrg const struct __DRIextensionRec **extensions = NULL; 6111463c08dSmrg const struct __DRIextensionRec **(*get_extensions)(void); 6121463c08dSmrg void *driver = loader_open_driver_lib(driver_name, "_dri", search_path_vars, 6131463c08dSmrg DEFAULT_DRIVER_DIR, true); 6141463c08dSmrg 6151463c08dSmrg if (!driver) 6161463c08dSmrg goto failed; 6171463c08dSmrg 6189f464c52Smaya get_extensions_name = loader_get_extensions_name(driver_name); 6199f464c52Smaya if (get_extensions_name) { 6209f464c52Smaya get_extensions = dlsym(driver, get_extensions_name); 6219f464c52Smaya if (get_extensions) { 6229f464c52Smaya extensions = get_extensions(); 6239f464c52Smaya } else { 6249f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: driver does not expose %s(): %s\n", 6259f464c52Smaya get_extensions_name, dlerror()); 6269f464c52Smaya } 6279f464c52Smaya free(get_extensions_name); 6289f464c52Smaya } 6299f464c52Smaya 6309f464c52Smaya if (!extensions) 6319f464c52Smaya extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS); 6329f464c52Smaya if (extensions == NULL) { 6339f464c52Smaya log_(_LOADER_WARNING, 6349f464c52Smaya "MESA-LOADER: driver exports no extensions (%s)\n", dlerror()); 6359f464c52Smaya dlclose(driver); 6361463c08dSmrg driver = NULL; 6379f464c52Smaya } 6389f464c52Smaya 6391463c08dSmrgfailed: 6409f464c52Smaya *out_driver_handle = driver; 6419f464c52Smaya return extensions; 6429f464c52Smaya} 643