loader: Check if the kernel driver is i915 before loading iris
[mesa.git] / src / loader / loader.c
1 /*
2 * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
3 * Copyright (C) 2014-2016 Emil Velikov <emil.l.velikov@gmail.com>
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 <robclark@freedesktop.org>
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 <GL/internal/dri_interface.h>
49 #include "loader.h"
50
51 #ifdef HAVE_LIBDRM
52 #include <xf86drm.h>
53 #ifdef USE_DRICONF
54 #include "util/xmlconfig.h"
55 #include "util/xmlpool.h"
56 #endif
57 #endif
58
59 #include "util/macros.h"
60
61 #define __IS_LOADER
62 #include "pci_id_driver_map.h"
63
64 /* For systems like Hurd */
65 #ifndef PATH_MAX
66 #define PATH_MAX 4096
67 #endif
68
69 static void default_logger(int level, const char *fmt, ...)
70 {
71 if (level <= _LOADER_WARNING) {
72 va_list args;
73 va_start(args, fmt);
74 vfprintf(stderr, fmt, args);
75 va_end(args);
76 }
77 }
78
79 static loader_logger *log_ = default_logger;
80
81 int
82 loader_open_device(const char *device_name)
83 {
84 int fd;
85 #ifdef O_CLOEXEC
86 fd = open(device_name, O_RDWR | O_CLOEXEC);
87 if (fd == -1 && errno == EINVAL)
88 #endif
89 {
90 fd = open(device_name, O_RDWR);
91 if (fd != -1)
92 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
93 }
94 return fd;
95 }
96
97 static char *loader_get_kernel_driver_name(int fd)
98 {
99 #if HAVE_LIBDRM
100 char *driver;
101 drmVersionPtr version = drmGetVersion(fd);
102
103 if (!version) {
104 log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd);
105 return NULL;
106 }
107
108 driver = strndup(version->name, version->name_len);
109
110 drmFreeVersion(version);
111 return driver;
112 #else
113 return NULL;
114 #endif
115 }
116
117 bool
118 is_kernel_i915(int fd)
119 {
120 char *kernel_driver = loader_get_kernel_driver_name(fd);
121 return kernel_driver && strcmp(kernel_driver, "i915") == 0;
122 }
123
124 #if defined(HAVE_LIBDRM)
125 int
126 loader_open_render_node(const char *name)
127 {
128 drmDevicePtr *devices, device;
129 int err, render = -ENOENT, fd;
130 unsigned int num, i;
131
132 err = drmGetDevices2(0, NULL, 0);
133 if (err < 0)
134 return err;
135
136 num = err;
137
138 devices = calloc(num, sizeof(*devices));
139 if (!devices)
140 return -ENOMEM;
141
142 err = drmGetDevices2(0, devices, num);
143 if (err < 0) {
144 render = err;
145 goto free;
146 }
147
148 for (i = 0; i < num; i++) {
149 device = devices[i];
150
151 if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
152 (device->bustype == DRM_BUS_PLATFORM)) {
153 drmVersionPtr version;
154
155 fd = loader_open_device(device->nodes[DRM_NODE_RENDER]);
156 if (fd < 0)
157 continue;
158
159 version = drmGetVersion(fd);
160 if (!version) {
161 close(fd);
162 continue;
163 }
164
165 if (strcmp(version->name, name) != 0) {
166 drmFreeVersion(version);
167 close(fd);
168 continue;
169 }
170
171 drmFreeVersion(version);
172 render = fd;
173 break;
174 }
175 }
176
177 drmFreeDevices(devices, num);
178
179 free:
180 free(devices);
181 return render;
182 }
183
184 #ifdef USE_DRICONF
185 static const char __driConfigOptionsLoader[] =
186 DRI_CONF_BEGIN
187 DRI_CONF_SECTION_INITIALIZATION
188 DRI_CONF_DEVICE_ID_PATH_TAG()
189 DRI_CONF_DRI_DRIVER()
190 DRI_CONF_SECTION_END
191 DRI_CONF_END;
192
193 static char *loader_get_dri_config_driver(int fd)
194 {
195 driOptionCache defaultInitOptions;
196 driOptionCache userInitOptions;
197 char *dri_driver = NULL;
198 char *kernel_driver = loader_get_kernel_driver_name(fd);
199
200 driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader);
201 driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
202 "loader", kernel_driver, NULL, 0);
203 if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) {
204 char *opt = driQueryOptionstr(&userInitOptions, "dri_driver");
205 /* not an empty string */
206 if (*opt)
207 dri_driver = strdup(opt);
208 }
209 driDestroyOptionCache(&userInitOptions);
210 driDestroyOptionInfo(&defaultInitOptions);
211
212 free(kernel_driver);
213 return dri_driver;
214 }
215
216 static char *loader_get_dri_config_device_id(void)
217 {
218 driOptionCache defaultInitOptions;
219 driOptionCache userInitOptions;
220 char *prime = NULL;
221
222 driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader);
223 driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
224 "loader", NULL, NULL, 0);
225 if (driCheckOption(&userInitOptions, "device_id", DRI_STRING))
226 prime = strdup(driQueryOptionstr(&userInitOptions, "device_id"));
227 driDestroyOptionCache(&userInitOptions);
228 driDestroyOptionInfo(&defaultInitOptions);
229
230 return prime;
231 }
232 #endif
233
234 static char *drm_construct_id_path_tag(drmDevicePtr device)
235 {
236 char *tag = NULL;
237
238 if (device->bustype == DRM_BUS_PCI) {
239 if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u",
240 device->businfo.pci->domain,
241 device->businfo.pci->bus,
242 device->businfo.pci->dev,
243 device->businfo.pci->func) < 0) {
244 return NULL;
245 }
246 } else if (device->bustype == DRM_BUS_PLATFORM ||
247 device->bustype == DRM_BUS_HOST1X) {
248 char *fullname, *name, *address;
249
250 if (device->bustype == DRM_BUS_PLATFORM)
251 fullname = device->businfo.platform->fullname;
252 else
253 fullname = device->businfo.host1x->fullname;
254
255 name = strrchr(fullname, '/');
256 if (!name)
257 name = strdup(fullname);
258 else
259 name = strdup(name + 1);
260
261 address = strchr(name, '@');
262 if (address) {
263 *address++ = '\0';
264
265 if (asprintf(&tag, "platform-%s_%s", address, name) < 0)
266 tag = NULL;
267 } else {
268 if (asprintf(&tag, "platform-%s", name) < 0)
269 tag = NULL;
270 }
271
272 free(name);
273 }
274 return tag;
275 }
276
277 static bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag)
278 {
279 char *tag = drm_construct_id_path_tag(device);
280 int ret;
281
282 if (tag == NULL)
283 return false;
284
285 ret = strcmp(tag, prime_tag);
286
287 free(tag);
288 return ret == 0;
289 }
290
291 static char *drm_get_id_path_tag_for_fd(int fd)
292 {
293 drmDevicePtr device;
294 char *tag;
295
296 if (drmGetDevice2(fd, 0, &device) != 0)
297 return NULL;
298
299 tag = drm_construct_id_path_tag(device);
300 drmFreeDevice(&device);
301 return tag;
302 }
303
304 int loader_get_user_preferred_fd(int default_fd, bool *different_device)
305 {
306 /* Arbitrary "maximum" value of drm devices. */
307 #define MAX_DRM_DEVICES 32
308 const char *dri_prime = getenv("DRI_PRIME");
309 char *default_tag, *prime = NULL;
310 drmDevicePtr devices[MAX_DRM_DEVICES];
311 int i, num_devices, fd;
312 bool found = false;
313
314 if (dri_prime)
315 prime = strdup(dri_prime);
316 #ifdef USE_DRICONF
317 else
318 prime = loader_get_dri_config_device_id();
319 #endif
320
321 if (prime == NULL) {
322 *different_device = false;
323 return default_fd;
324 }
325
326 default_tag = drm_get_id_path_tag_for_fd(default_fd);
327 if (default_tag == NULL)
328 goto err;
329
330 num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
331 if (num_devices < 0)
332 goto err;
333
334 /* two format are supported:
335 * "1": choose any other card than the card used by default.
336 * id_path_tag: (for example "pci-0000_02_00_0") choose the card
337 * with this id_path_tag.
338 */
339 if (!strcmp(prime,"1")) {
340 /* Hmm... detection for 2-7 seems to be broken. Oh well ...
341 * Pick the first render device that is not our own.
342 */
343 for (i = 0; i < num_devices; i++) {
344 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
345 !drm_device_matches_tag(devices[i], default_tag)) {
346
347 found = true;
348 break;
349 }
350 }
351 } else {
352 for (i = 0; i < num_devices; i++) {
353 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
354 drm_device_matches_tag(devices[i], prime)) {
355
356 found = true;
357 break;
358 }
359 }
360 }
361
362 if (!found) {
363 drmFreeDevices(devices, num_devices);
364 goto err;
365 }
366
367 fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]);
368 drmFreeDevices(devices, num_devices);
369 if (fd < 0)
370 goto err;
371
372 close(default_fd);
373
374 *different_device = !!strcmp(default_tag, prime);
375
376 free(default_tag);
377 free(prime);
378 return fd;
379
380 err:
381 *different_device = false;
382
383 free(default_tag);
384 free(prime);
385 return default_fd;
386 }
387 #else
388 int
389 loader_open_render_node(const char *name)
390 {
391 return -1;
392 }
393
394 int loader_get_user_preferred_fd(int default_fd, bool *different_device)
395 {
396 *different_device = false;
397 return default_fd;
398 }
399 #endif
400
401 #if defined(HAVE_LIBDRM)
402
403 static bool
404 drm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
405 {
406 drmDevicePtr device;
407 bool ret;
408
409 if (drmGetDevice2(fd, 0, &device) == 0) {
410 if (device->bustype == DRM_BUS_PCI) {
411 *vendor_id = device->deviceinfo.pci->vendor_id;
412 *chip_id = device->deviceinfo.pci->device_id;
413 ret = true;
414 }
415 else {
416 log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n");
417 ret = false;
418 }
419 drmFreeDevice(&device);
420 }
421 else {
422 log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n");
423 ret = false;
424 }
425
426 return ret;
427 }
428 #endif
429
430
431 bool
432 loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
433 {
434 #if HAVE_LIBDRM
435 return drm_get_pci_id_for_fd(fd, vendor_id, chip_id);
436 #endif
437 return false;
438 }
439
440 char *
441 loader_get_device_name_for_fd(int fd)
442 {
443 char *result = NULL;
444
445 #if HAVE_LIBDRM
446 result = drmGetDeviceNameFromFd2(fd);
447 #endif
448
449 return result;
450 }
451
452 char *
453 loader_get_driver_for_fd(int fd)
454 {
455 int vendor_id, chip_id, i, j;
456 char *driver = NULL;
457
458 /* Allow an environment variable to force choosing a different driver
459 * binary. If that driver binary can't survive on this FD, that's the
460 * user's problem, but this allows vc4 simulator to run on an i965 host,
461 * and may be useful for some touch testing of i915 on an i965 host.
462 */
463 if (geteuid() == getuid()) {
464 driver = getenv("MESA_LOADER_DRIVER_OVERRIDE");
465 if (driver)
466 return strdup(driver);
467 }
468
469 #if defined(HAVE_LIBDRM) && defined(USE_DRICONF)
470 driver = loader_get_dri_config_driver(fd);
471 if (driver)
472 return driver;
473 #endif
474
475 if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
476 driver = loader_get_kernel_driver_name(fd);
477 if (driver)
478 log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd);
479 return driver;
480 }
481
482 for (i = 0; i < ARRAY_SIZE(driver_map); i++) {
483 if (vendor_id != driver_map[i].vendor_id)
484 continue;
485
486 if (driver_map[i].predicate && !driver_map[i].predicate(fd))
487 continue;
488
489 if (driver_map[i].num_chips_ids == -1) {
490 driver = strdup(driver_map[i].driver);
491 goto out;
492 }
493
494 for (j = 0; j < driver_map[i].num_chips_ids; j++)
495 if (driver_map[i].chip_ids[j] == chip_id) {
496 driver = strdup(driver_map[i].driver);
497 goto out;
498 }
499 }
500
501 out:
502 log_(driver ? _LOADER_DEBUG : _LOADER_WARNING,
503 "pci id for fd %d: %04x:%04x, driver %s\n",
504 fd, vendor_id, chip_id, driver);
505 return driver;
506 }
507
508 void
509 loader_set_logger(loader_logger *logger)
510 {
511 log_ = logger;
512 }
513
514 char *
515 loader_get_extensions_name(const char *driver_name)
516 {
517 char *name = NULL;
518
519 if (asprintf(&name, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS, driver_name) < 0)
520 return NULL;
521
522 const size_t len = strlen(name);
523 for (size_t i = 0; i < len; i++) {
524 if (name[i] == '-')
525 name[i] = '_';
526 }
527
528 return name;
529 }
530
531 /**
532 * Opens a DRI driver using its driver name, returning the __DRIextension
533 * entrypoints.
534 *
535 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
536 * \param out_driver - Address where the dlopen() return value will be stored.
537 * \param search_path_vars - NULL-terminated list of env vars that can be used
538 * to override the DEFAULT_DRIVER_DIR search path.
539 */
540 const struct __DRIextensionRec **
541 loader_open_driver(const char *driver_name,
542 void **out_driver_handle,
543 const char **search_path_vars)
544 {
545 char path[PATH_MAX], *search_paths, *next, *end;
546 char *get_extensions_name;
547 const struct __DRIextensionRec **extensions = NULL;
548 const struct __DRIextensionRec **(*get_extensions)(void);
549
550 search_paths = NULL;
551 if (geteuid() == getuid() && search_path_vars) {
552 for (int i = 0; search_path_vars[i] != NULL; i++) {
553 search_paths = getenv(search_path_vars[i]);
554 if (search_paths)
555 break;
556 }
557 }
558 if (search_paths == NULL)
559 search_paths = DEFAULT_DRIVER_DIR;
560
561 void *driver = NULL;
562 end = search_paths + strlen(search_paths);
563 for (char *p = search_paths; p < end; p = next + 1) {
564 int len;
565 next = strchr(p, ':');
566 if (next == NULL)
567 next = end;
568
569 len = next - p;
570 #if USE_ELF_TLS
571 snprintf(path, sizeof(path), "%.*s/tls/%s_dri.so", len, p, driver_name);
572 driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
573 #endif
574 if (driver == NULL) {
575 snprintf(path, sizeof(path), "%.*s/%s_dri.so", len, p, driver_name);
576 driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
577 if (driver == NULL)
578 log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n",
579 path, dlerror());
580 }
581 /* not need continue to loop all paths once the driver is found */
582 if (driver != NULL)
583 break;
584 }
585
586 if (driver == NULL) {
587 log_(_LOADER_WARNING, "MESA-LOADER: failed to open %s (search paths %s)\n",
588 driver_name, search_paths);
589 *out_driver_handle = NULL;
590 return NULL;
591 }
592
593 log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path);
594
595 get_extensions_name = loader_get_extensions_name(driver_name);
596 if (get_extensions_name) {
597 get_extensions = dlsym(driver, get_extensions_name);
598 if (get_extensions) {
599 extensions = get_extensions();
600 } else {
601 log_(_LOADER_DEBUG, "MESA-LOADER: driver does not expose %s(): %s\n",
602 get_extensions_name, dlerror());
603 }
604 free(get_extensions_name);
605 }
606
607 if (!extensions)
608 extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS);
609 if (extensions == NULL) {
610 log_(_LOADER_WARNING,
611 "MESA-LOADER: driver exports no extensions (%s)\n", dlerror());
612 dlclose(driver);
613 }
614
615 *out_driver_handle = driver;
616 return extensions;
617 }