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