1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe (at) gmail.com> 5 * Copyright 2010-2011 LunarG, Inc. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 30 31 /** 32 * Functions for choosing and opening/loading device drivers. 33 */ 34 35 36 #include <assert.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 41 #include "eglstring.h" 42 #include "egldefines.h" 43 #include "egldisplay.h" 44 #include "egldriver.h" 45 #include "egllog.h" 46 #include "eglmutex.h" 47 48 #if defined(_EGL_OS_UNIX) 49 #include <dlfcn.h> 50 #include <sys/types.h> 51 #include <dirent.h> 52 #include <unistd.h> 53 #endif 54 55 56 typedef struct _egl_module { 57 char *Path; 58 _EGLMain_t BuiltIn; 59 void *Handle; 60 _EGLDriver *Driver; 61 } _EGLModule; 62 63 static _EGL_DECLARE_MUTEX(_eglModuleMutex); 64 static _EGLArray *_eglModules; 65 66 const struct { 67 const char *name; 68 _EGLMain_t main; 69 } _eglBuiltInDrivers[] = { 70 #ifdef _EGL_BUILT_IN_DRIVER_GALLIUM 71 { "egl_gallium", _eglBuiltInDriverGALLIUM }, 72 #endif 73 #ifdef _EGL_BUILT_IN_DRIVER_DRI2 74 { "egl_dri2", _eglBuiltInDriverDRI2 }, 75 #endif 76 #ifdef _EGL_BUILT_IN_DRIVER_GLX 77 { "egl_glx", _eglBuiltInDriverGLX }, 78 #endif 79 { NULL, NULL } 80 }; 81 82 /** 83 * Wrappers for dlopen/dlclose() 84 */ 85 #if defined(_EGL_OS_WINDOWS) 86 87 88 typedef HMODULE lib_handle; 89 90 static HMODULE 91 open_library(const char *filename) 92 { 93 return LoadLibrary(filename); 94 } 95 96 static void 97 close_library(HMODULE lib) 98 { 99 FreeLibrary(lib); 100 } 101 102 103 static const char * 104 library_suffix(void) 105 { 106 return ".dll"; 107 } 108 109 110 #elif defined(_EGL_OS_UNIX) 111 112 113 typedef void * lib_handle; 114 115 static void * 116 open_library(const char *filename) 117 { 118 return dlopen(filename, RTLD_LAZY); 119 } 120 121 static void 122 close_library(void *lib) 123 { 124 dlclose(lib); 125 } 126 127 128 static const char * 129 library_suffix(void) 130 { 131 return ".so"; 132 } 133 134 135 #endif 136 137 138 /** 139 * Open the named driver and find its bootstrap function: _eglMain(). 140 */ 141 static _EGLMain_t 142 _eglOpenLibrary(const char *driverPath, lib_handle *handle) 143 { 144 lib_handle lib; 145 _EGLMain_t mainFunc = NULL; 146 const char *error = "unknown error"; 147 148 assert(driverPath); 149 150 _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath); 151 lib = open_library(driverPath); 152 153 #if defined(_EGL_OS_WINDOWS) 154 /* XXX untested */ 155 if (lib) 156 mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); 157 #elif defined(_EGL_OS_UNIX) 158 if (lib) { 159 union { 160 _EGLMain_t func; 161 void *ptr; 162 } tmp = { NULL }; 163 /* direct cast gives a warning when compiled with -pedantic */ 164 tmp.ptr = dlsym(lib, "_eglMain"); 165 mainFunc = tmp.func; 166 if (!mainFunc) 167 error = dlerror(); 168 } 169 else { 170 error = dlerror(); 171 } 172 #endif 173 174 if (!lib) { 175 _eglLog(_EGL_WARNING, "Could not open driver %s (%s)", 176 driverPath, error); 177 return NULL; 178 } 179 180 if (!mainFunc) { 181 _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)", 182 driverPath, error); 183 if (lib) 184 close_library(lib); 185 return NULL; 186 } 187 188 *handle = lib; 189 return mainFunc; 190 } 191 192 193 /** 194 * Load a module and create the driver object. 195 */ 196 static EGLBoolean 197 _eglLoadModule(_EGLModule *mod) 198 { 199 _EGLMain_t mainFunc; 200 lib_handle lib; 201 _EGLDriver *drv; 202 203 if (mod->Driver) 204 return EGL_TRUE; 205 206 if (mod->BuiltIn) { 207 lib = (lib_handle) NULL; 208 mainFunc = mod->BuiltIn; 209 } 210 else { 211 mainFunc = _eglOpenLibrary(mod->Path, &lib); 212 if (!mainFunc) 213 return EGL_FALSE; 214 } 215 216 drv = mainFunc(NULL); 217 if (!drv) { 218 if (lib) 219 close_library(lib); 220 return EGL_FALSE; 221 } 222 223 if (!drv->Name) { 224 _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path); 225 drv->Name = "UNNAMED"; 226 } 227 228 mod->Handle = (void *) lib; 229 mod->Driver = drv; 230 231 return EGL_TRUE; 232 } 233 234 235 /** 236 * Unload a module. 237 */ 238 static void 239 _eglUnloadModule(_EGLModule *mod) 240 { 241 #if defined(_EGL_OS_UNIX) 242 /* destroy the driver */ 243 if (mod->Driver && mod->Driver->Unload) 244 mod->Driver->Unload(mod->Driver); 245 246 /* 247 * XXX At this point (atexit), the module might be the last reference to 248 * libEGL. Closing the module might unmap libEGL and give problems. 249 */ 250 #if 0 251 if (mod->Handle) 252 close_library(mod->Handle); 253 #endif 254 #elif defined(_EGL_OS_WINDOWS) 255 /* XXX Windows unloads DLLs before atexit */ 256 #endif 257 258 mod->Driver = NULL; 259 mod->Handle = NULL; 260 } 261 262 263 /** 264 * Add a module to the module array. 265 */ 266 static _EGLModule * 267 _eglAddModule(const char *path) 268 { 269 _EGLModule *mod; 270 EGLint i; 271 272 if (!_eglModules) { 273 _eglModules = _eglCreateArray("Module", 8); 274 if (!_eglModules) 275 return NULL; 276 } 277 278 /* find duplicates */ 279 for (i = 0; i < _eglModules->Size; i++) { 280 mod = _eglModules->Elements[i]; 281 if (strcmp(mod->Path, path) == 0) 282 return mod; 283 } 284 285 /* allocate a new one */ 286 mod = calloc(1, sizeof(*mod)); 287 if (mod) { 288 mod->Path = _eglstrdup(path); 289 if (!mod->Path) { 290 free(mod); 291 mod = NULL; 292 } 293 } 294 if (mod) { 295 _eglAppendArray(_eglModules, (void *) mod); 296 _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path); 297 } 298 299 return mod; 300 } 301 302 303 /** 304 * Free a module. 305 */ 306 static void 307 _eglFreeModule(void *module) 308 { 309 _EGLModule *mod = (_EGLModule *) module; 310 311 _eglUnloadModule(mod); 312 free(mod->Path); 313 free(mod); 314 } 315 316 317 /** 318 * A loader function for use with _eglPreloadForEach. The loader data is the 319 * filename of the driver. This function stops on the first valid driver. 320 */ 321 static EGLBoolean 322 _eglLoaderFile(const char *dir, size_t len, void *loader_data) 323 { 324 char path[1024]; 325 const char *filename = (const char *) loader_data; 326 size_t flen = strlen(filename); 327 328 /* make a full path */ 329 if (len + flen + 2 > sizeof(path)) 330 return EGL_TRUE; 331 if (len) { 332 memcpy(path, dir, len); 333 path[len++] = '/'; 334 } 335 memcpy(path + len, filename, flen); 336 len += flen; 337 path[len] = '\0'; 338 339 if (library_suffix()) { 340 const char *suffix = library_suffix(); 341 size_t slen = strlen(suffix); 342 const char *p; 343 EGLBoolean need_suffix; 344 345 p = filename + flen - slen; 346 need_suffix = (p < filename || strcmp(p, suffix) != 0); 347 if (need_suffix) { 348 /* overflow */ 349 if (len + slen + 1 > sizeof(path)) 350 return EGL_TRUE; 351 strcpy(path + len, suffix); 352 } 353 } 354 355 #if defined(_EGL_OS_UNIX) 356 /* check if the file exists */ 357 if (access(path, F_OK)) 358 return EGL_TRUE; 359 #endif 360 361 _eglAddModule(path); 362 363 return EGL_TRUE; 364 } 365 366 367 /** 368 * Run the callback function on each driver directory. 369 * 370 * The process may end prematurely if the callback function returns false. 371 */ 372 static void 373 _eglPreloadForEach(const char *search_path, 374 EGLBoolean (*loader)(const char *, size_t, void *), 375 void *loader_data) 376 { 377 const char *cur, *next; 378 size_t len; 379 380 cur = search_path; 381 while (cur) { 382 next = strchr(cur, ':'); 383 len = (next) ? next - cur : strlen(cur); 384 385 if (!loader(cur, len, loader_data)) 386 break; 387 388 cur = (next) ? next + 1 : NULL; 389 } 390 } 391 392 393 /** 394 * Return a list of colon-separated driver directories. 395 */ 396 static const char * 397 _eglGetSearchPath(void) 398 { 399 static char search_path[1024]; 400 401 #if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) 402 if (search_path[0] == '\0') { 403 char *buf = search_path; 404 size_t len = sizeof(search_path); 405 EGLBoolean use_env; 406 char dir_sep; 407 int ret; 408 409 #if defined(_EGL_OS_UNIX) 410 use_env = (geteuid() == getuid() && getegid() == getgid()); 411 dir_sep = '/'; 412 #else 413 use_env = EGL_TRUE; 414 dir_sep = '\\'; 415 #endif 416 417 if (use_env) { 418 char *p; 419 420 /* extract the dirname from EGL_DRIVER */ 421 p = getenv("EGL_DRIVER"); 422 if (p && strchr(p, dir_sep)) { 423 ret = _eglsnprintf(buf, len, "%s", p); 424 if (ret > 0 && ret < len) { 425 p = strrchr(buf, dir_sep); 426 *p++ = ':'; 427 428 len -= p - buf; 429 buf = p; 430 } 431 } 432 433 /* append EGL_DRIVERS_PATH */ 434 p = getenv("EGL_DRIVERS_PATH"); 435 if (p) { 436 ret = _eglsnprintf(buf, len, "%s:", p); 437 if (ret > 0 && ret < len) { 438 buf += ret; 439 len -= ret; 440 } 441 } 442 } 443 else { 444 _eglLog(_EGL_DEBUG, 445 "ignore EGL_DRIVERS_PATH for setuid/setgid binaries"); 446 } 447 448 ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR); 449 if (ret < 0 || ret >= len) 450 search_path[0] = '\0'; 451 452 _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path); 453 } 454 #endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */ 455 456 return search_path; 457 } 458 459 460 /** 461 * Add the user driver to the module array. 462 * 463 * The user driver is specified by EGL_DRIVER. 464 */ 465 static EGLBoolean 466 _eglAddUserDriver(void) 467 { 468 const char *search_path = _eglGetSearchPath(); 469 char *env; 470 size_t name_len = 0; 471 472 env = getenv("EGL_DRIVER"); 473 #if defined(_EGL_OS_UNIX) 474 if (env && strchr(env, '/')) { 475 search_path = ""; 476 if ((geteuid() != getuid() || getegid() != getgid())) { 477 _eglLog(_EGL_DEBUG, 478 "ignore EGL_DRIVER for setuid/setgid binaries"); 479 env = NULL; 480 } 481 } 482 else if (env) { 483 char *suffix = strchr(env, '.'); 484 name_len = (suffix) ? suffix - env : strlen(env); 485 } 486 #else 487 if (env) 488 name_len = strlen(env); 489 #endif /* _EGL_OS_UNIX */ 490 491 /* 492 * Try built-in drivers first if we know the driver name. This makes sure 493 * we do not load the outdated external driver that is still on the 494 * filesystem. 495 */ 496 if (name_len) { 497 _EGLModule *mod; 498 EGLint i; 499 500 for (i = 0; _eglBuiltInDrivers[i].name; i++) { 501 if (strlen(_eglBuiltInDrivers[i].name) == name_len && 502 !strncmp(_eglBuiltInDrivers[i].name, env, name_len)) { 503 mod = _eglAddModule(env); 504 if (mod) 505 mod->BuiltIn = _eglBuiltInDrivers[i].main; 506 507 return EGL_TRUE; 508 } 509 } 510 } 511 512 /* otherwise, treat env as a path */ 513 if (env) { 514 _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env); 515 516 return EGL_TRUE; 517 } 518 519 return EGL_FALSE; 520 } 521 522 523 /** 524 * Add egl_gallium to the module array. 525 */ 526 static void 527 _eglAddGalliumDriver(void) 528 { 529 #ifndef _EGL_BUILT_IN_DRIVER_GALLIUM 530 void *external = (void *) "egl_gallium"; 531 _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external); 532 #endif 533 } 534 535 536 /** 537 * Add built-in drivers to the module array. 538 */ 539 static void 540 _eglAddBuiltInDrivers(void) 541 { 542 _EGLModule *mod; 543 EGLint i; 544 545 for (i = 0; _eglBuiltInDrivers[i].name; i++) { 546 mod = _eglAddModule(_eglBuiltInDrivers[i].name); 547 if (mod) 548 mod->BuiltIn = _eglBuiltInDrivers[i].main; 549 } 550 } 551 552 553 /** 554 * Add drivers to the module array. Drivers will be loaded as they are matched 555 * to displays. 556 */ 557 static EGLBoolean 558 _eglAddDrivers(void) 559 { 560 if (_eglModules) 561 return EGL_TRUE; 562 563 if (!_eglAddUserDriver()) { 564 /* 565 * Add other drivers only when EGL_DRIVER is not set. The order here 566 * decides the priorities. 567 */ 568 _eglAddGalliumDriver(); 569 _eglAddBuiltInDrivers(); 570 } 571 572 return (_eglModules != NULL); 573 } 574 575 576 /** 577 * A helper function for _eglMatchDriver. It finds the first driver that can 578 * initialize the display and return. 579 */ 580 static _EGLDriver * 581 _eglMatchAndInitialize(_EGLDisplay *dpy) 582 { 583 _EGLDriver *drv = NULL; 584 EGLint i = 0; 585 586 if (!_eglAddDrivers()) { 587 _eglLog(_EGL_WARNING, "failed to find any driver"); 588 return NULL; 589 } 590 591 if (dpy->Driver) { 592 drv = dpy->Driver; 593 /* no re-matching? */ 594 if (!drv->API.Initialize(drv, dpy)) 595 drv = NULL; 596 return drv; 597 } 598 599 while (i < _eglModules->Size) { 600 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i]; 601 602 if (!_eglLoadModule(mod)) { 603 /* remove invalid modules */ 604 _eglEraseArray(_eglModules, i, _eglFreeModule); 605 continue; 606 } 607 608 if (mod->Driver->API.Initialize(mod->Driver, dpy)) { 609 drv = mod->Driver; 610 break; 611 } 612 else { 613 i++; 614 } 615 } 616 617 return drv; 618 } 619 620 621 /** 622 * Match a display to a driver. The display is initialized unless test_only is 623 * true. The matching is done by finding the first driver that can initialize 624 * the display. 625 */ 626 _EGLDriver * 627 _eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only) 628 { 629 _EGLDriver *best_drv; 630 631 assert(!dpy->Initialized); 632 633 _eglLockMutex(&_eglModuleMutex); 634 635 /* set options */ 636 dpy->Options.TestOnly = test_only; 637 dpy->Options.UseFallback = EGL_FALSE; 638 639 best_drv = _eglMatchAndInitialize(dpy); 640 if (!best_drv) { 641 dpy->Options.UseFallback = EGL_TRUE; 642 best_drv = _eglMatchAndInitialize(dpy); 643 } 644 645 _eglUnlockMutex(&_eglModuleMutex); 646 647 if (best_drv) { 648 _eglLog(_EGL_DEBUG, "the best driver is %s%s", 649 best_drv->Name, (test_only) ? " (test only) " : ""); 650 if (!test_only) { 651 dpy->Driver = best_drv; 652 dpy->Initialized = EGL_TRUE; 653 } 654 } 655 656 return best_drv; 657 } 658 659 660 __eglMustCastToProperFunctionPointerType 661 _eglGetDriverProc(const char *procname) 662 { 663 EGLint i; 664 _EGLProc proc = NULL; 665 666 if (!_eglModules) { 667 /* load the driver for the default display */ 668 EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 669 _EGLDisplay *dpy = _eglLookupDisplay(egldpy); 670 if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE)) 671 return NULL; 672 } 673 674 for (i = 0; i < _eglModules->Size; i++) { 675 _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i]; 676 677 if (!mod->Driver) 678 break; 679 proc = mod->Driver->API.GetProcAddress(mod->Driver, procname); 680 if (proc) 681 break; 682 } 683 684 return proc; 685 } 686 687 688 /** 689 * Unload all drivers. 690 */ 691 void 692 _eglUnloadDrivers(void) 693 { 694 /* this is called at atexit time */ 695 if (_eglModules) { 696 _eglDestroyArray(_eglModules, _eglFreeModule); 697 _eglModules = NULL; 698 } 699 } 700 701 702 /** 703 * Invoke a callback function on each EGL search path. 704 * 705 * The first argument of the callback function is the name of the search path. 706 * The second argument is the length of the name. 707 */ 708 void 709 _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *), 710 void *callback_data) 711 { 712 const char *search_path = _eglGetSearchPath(); 713 _eglPreloadForEach(search_path, callback, callback_data); 714 } 715