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 #if defined(HAVE_DRI) || defined(HAVE_DRI2) || defined(HAVE_DRI3)
46 extern const struct gbm_backend gbm_dri_backend;
47 #endif
48
49 struct gbm_backend_desc {
50 const char *name;
51 const struct gbm_backend *backend;
52 void *lib;
53 };
54
55 static const struct gbm_backend_desc builtin_backends[] = {
56 #if defined(HAVE_DRI) || defined(HAVE_DRI2) || defined(HAVE_DRI3)
57 { "dri", &gbm_dri_backend },
58 #endif
59 };
60
61 #define BACKEND_LIB_SUFFIX "_gbm"
62 static const char *backend_search_path_vars[] = {
63 "GBM_BACKENDS_PATH",
64 NULL
65 };
66
67 static void
free_backend_desc(const struct gbm_backend_desc * backend_desc)68 free_backend_desc(const struct gbm_backend_desc *backend_desc)
69 {
70 assert(backend_desc->lib);
71
72 dlclose(backend_desc->lib);
73 free((void *)backend_desc->name);
74 free((void *)backend_desc);
75 }
76
77 static struct gbm_backend_desc *
create_backend_desc(const char * name,const struct gbm_backend * backend,void * lib)78 create_backend_desc(const char *name,
79 const struct gbm_backend *backend,
80 void *lib)
81 {
82 struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc));
83
84 if (!new_desc)
85 return NULL;
86
87 new_desc->name = strdup(name);
88
89 if (!new_desc->name) {
90 free(new_desc);
91 return NULL;
92 }
93
94 new_desc->backend = backend;
95 new_desc->lib = lib;
96
97 return new_desc;
98 }
99
100 static struct gbm_device *
backend_create_device(const struct gbm_backend_desc * bd,int fd)101 backend_create_device(const struct gbm_backend_desc *bd, int fd)
102 {
103 const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION,
104 bd->backend->v0.backend_version);
105 struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver);
106
107 if (dev) {
108 if (abi_ver != dev->v0.backend_version) {
109 _gbm_device_destroy(dev);
110 return NULL;
111 }
112 dev->v0.backend_desc = bd;
113 }
114
115 return dev;
116 }
117
118 static struct gbm_device *
load_backend(void * lib,int fd,const char * name)119 load_backend(void *lib, int fd, const char *name)
120 {
121 struct gbm_device *dev = NULL;
122 struct gbm_backend_desc *backend_desc;
123 const struct gbm_backend *gbm_backend;
124 GBM_GET_BACKEND_PROC_PTR get_backend;
125
126 get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME);
127
128 if (!get_backend)
129 goto fail;
130
131 gbm_backend = get_backend(&gbm_core);
132 backend_desc = create_backend_desc(name, gbm_backend, lib);
133
134 if (!backend_desc)
135 goto fail;
136
137 dev = backend_create_device(backend_desc, fd);
138
139 if (!dev)
140 free_backend_desc(backend_desc);
141
142 return dev;
143
144 fail:
145 dlclose(lib);
146 return NULL;
147 }
148
149 static struct gbm_device *
find_backend(const char * name,int fd)150 find_backend(const char *name, int fd)
151 {
152 struct gbm_device *dev = NULL;
153 const struct gbm_backend_desc *bd;
154 void *lib;
155 unsigned i;
156
157 for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) {
158 bd = &builtin_backends[i];
159
160 if (name && strcmp(bd->name, name))
161 continue;
162
163 dev = backend_create_device(bd, fd);
164
165 if (dev)
166 break;
167 }
168
169 if (name && !dev) {
170 lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX,
171 backend_search_path_vars,
172 DEFAULT_BACKENDS_PATH,
173 true);
174
175 if (lib)
176 dev = load_backend(lib, fd, name);
177 }
178
179 return dev;
180 }
181
182 static struct gbm_device *
override_backend(int fd)183 override_backend(int fd)
184 {
185 struct gbm_device *dev = NULL;
186 const char *b;
187
188 b = getenv("GBM_BACKEND");
189 if (b)
190 dev = find_backend(b, fd);
191
192 return dev;
193 }
194
195 static struct gbm_device *
backend_from_driver_name(int fd)196 backend_from_driver_name(int fd)
197 {
198 struct gbm_device *dev = NULL;
199 drmVersionPtr v = drmGetVersion(fd);
200 void *lib;
201
202 if (!v)
203 return NULL;
204
205 lib = loader_open_driver_lib(v->name, BACKEND_LIB_SUFFIX,
206 backend_search_path_vars,
207 DEFAULT_BACKENDS_PATH,
208 false);
209
210 if (lib)
211 dev = load_backend(lib, fd, v->name);
212
213 drmFreeVersion(v);
214
215 return dev;
216 }
217
218 struct gbm_device *
_gbm_create_device(int fd)219 _gbm_create_device(int fd)
220 {
221 struct gbm_device *dev;
222
223 dev = override_backend(fd);
224
225 if (!dev)
226 dev = backend_from_driver_name(fd);
227
228 if (!dev)
229 dev = find_backend(NULL, fd);
230
231 return dev;
232 }
233
234 void
_gbm_device_destroy(struct gbm_device * gbm)235 _gbm_device_destroy(struct gbm_device *gbm)
236 {
237 const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc;
238 gbm->v0.destroy(gbm);
239
240 if (backend_desc && backend_desc->lib)
241 free_backend_desc(backend_desc);
242 }
243