1 /*
2  * Copyright © 2011 Intel Corporation
3  * Copyright © 2021 NVIDIA Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * 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
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
27  *    James Jones <jajones@nvidia.com>
28  */
29 
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <assert.h>
36 #include <dlfcn.h>
37 #include <xf86drm.h>
38 
39 #include "loader.h"
40 #include "backend.h"
41 
42 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
43 #define VER_MIN(a, b) ((a) < (b) ? (a) : (b))
44 
45 extern const struct gbm_backend gbm_dri_backend;
46 
47 struct gbm_backend_desc {
48    const char *name;
49    const struct gbm_backend *backend;
50    void *lib;
51 };
52 
53 static const struct gbm_backend_desc builtin_backends[] = {
54    { "dri", &gbm_dri_backend },
55 };
56 
57 #define BACKEND_LIB_SUFFIX "_gbm"
58 static const char *backend_search_path_vars[] = {
59    "GBM_BACKENDS_PATH",
60    NULL
61 };
62 
63 static void
free_backend_desc(const struct gbm_backend_desc * backend_desc)64 free_backend_desc(const struct gbm_backend_desc *backend_desc)
65 {
66    assert(backend_desc->lib);
67 
68    dlclose(backend_desc->lib);
69    free((void *)backend_desc->name);
70    free((void *)backend_desc);
71 }
72 
73 static struct gbm_backend_desc *
create_backend_desc(const char * name,const struct gbm_backend * backend,void * lib)74 create_backend_desc(const char *name,
75                     const struct gbm_backend *backend,
76                     void *lib)
77 {
78    struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc));
79 
80    if (!new_desc)
81       return NULL;
82 
83    new_desc->name = strdup(name);
84 
85    if (!new_desc->name) {
86       free(new_desc);
87       return NULL;
88    }
89 
90    new_desc->backend = backend;
91    new_desc->lib = lib;
92 
93    return new_desc;
94 }
95 
96 static struct gbm_device *
backend_create_device(const struct gbm_backend_desc * bd,int fd)97 backend_create_device(const struct gbm_backend_desc *bd, int fd)
98 {
99    const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION,
100                                     bd->backend->v0.backend_version);
101    struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver);
102 
103    if (dev) {
104       if (abi_ver != dev->v0.backend_version) {
105          _gbm_device_destroy(dev);
106          return NULL;
107       }
108       dev->v0.backend_desc = bd;
109    }
110 
111    return dev;
112 }
113 
114 static struct gbm_device *
load_backend(void * lib,int fd,const char * name)115 load_backend(void *lib, int fd, const char *name)
116 {
117    struct gbm_device *dev = NULL;
118    struct gbm_backend_desc *backend_desc;
119    const struct gbm_backend *gbm_backend;
120    GBM_GET_BACKEND_PROC_PTR get_backend;
121 
122    get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME);
123 
124    if (!get_backend)
125       goto fail;
126 
127    gbm_backend = get_backend(&gbm_core);
128    backend_desc = create_backend_desc(name, gbm_backend, lib);
129 
130    if (!backend_desc)
131       goto fail;
132 
133    dev = backend_create_device(backend_desc, fd);
134 
135    if (!dev)
136       free_backend_desc(backend_desc);
137 
138    return dev;
139 
140 fail:
141    dlclose(lib);
142    return NULL;
143 }
144 
145 static struct gbm_device *
find_backend(const char * name,int fd)146 find_backend(const char *name, int fd)
147 {
148    struct gbm_device *dev = NULL;
149    const struct gbm_backend_desc *bd;
150    void *lib;
151    unsigned i;
152 
153    for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) {
154       bd = &builtin_backends[i];
155 
156       if (name && strcmp(bd->name, name))
157          continue;
158 
159       dev = backend_create_device(bd, fd);
160 
161       if (dev)
162          break;
163    }
164 
165    if (name && !dev) {
166       lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX,
167                                    backend_search_path_vars,
168                                    DEFAULT_BACKENDS_PATH,
169                                    true);
170 
171       if (lib)
172          dev = load_backend(lib, fd, name);
173    }
174 
175    return dev;
176 }
177 
178 static struct gbm_device *
override_backend(int fd)179 override_backend(int fd)
180 {
181    struct gbm_device *dev = NULL;
182    const char *b;
183 
184    b = getenv("GBM_BACKEND");
185    if (b)
186       dev = find_backend(b, fd);
187 
188    return dev;
189 }
190 
191 static struct gbm_device *
backend_from_driver_name(int fd)192 backend_from_driver_name(int fd)
193 {
194    struct gbm_device *dev = NULL;
195    drmVersionPtr v = drmGetVersion(fd);
196    void *lib;
197 
198    if (!v)
199       return NULL;
200 
201    lib = loader_open_driver_lib(v->name, BACKEND_LIB_SUFFIX,
202                                 backend_search_path_vars,
203                                 DEFAULT_BACKENDS_PATH,
204                                 false);
205 
206    if (lib)
207       dev = load_backend(lib, fd, v->name);
208 
209    drmFreeVersion(v);
210 
211    return dev;
212 }
213 
214 struct gbm_device *
_gbm_create_device(int fd)215 _gbm_create_device(int fd)
216 {
217    struct gbm_device *dev;
218 
219    dev = override_backend(fd);
220 
221    if (!dev)
222       dev = backend_from_driver_name(fd);
223 
224    if (!dev)
225       dev = find_backend(NULL, fd);
226 
227    return dev;
228 }
229 
230 void
_gbm_device_destroy(struct gbm_device * gbm)231 _gbm_device_destroy(struct gbm_device *gbm)
232 {
233    const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc;
234    gbm->v0.destroy(gbm);
235 
236    if (backend_desc && backend_desc->lib)
237       free_backend_desc(backend_desc);
238 }
239