targets/egl: Fix crashes from loading invalid modules.
[mesa.git] / src / gallium / targets / egl / egl.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the 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
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include "util/u_debug.h"
30 #include "util/u_string.h"
31 #include "util/u_memory.h"
32 #include "util/u_dl.h"
33 #include "egldriver.h"
34 #include "egllog.h"
35
36 #include "state_tracker/st_api.h"
37 #include "state_tracker/drm_driver.h"
38 #include "common/egl_g3d_loader.h"
39
40 #include "egl.h"
41
42 struct egl_g3d_loader egl_g3d_loader;
43
44 static struct st_module {
45 boolean initialized;
46 char *name;
47 struct util_dl_library *lib;
48 struct st_api *stapi;
49 } st_modules[ST_API_COUNT];
50
51 static struct pipe_module {
52 boolean initialized;
53 char *name;
54 struct util_dl_library *lib;
55 const struct drm_driver_descriptor *drmdd;
56 struct pipe_screen *(*swrast_create_screen)(struct sw_winsys *);
57 } pipe_modules[16];
58
59 static char *
60 loader_strdup(const char *s)
61 {
62 size_t len = (s) ? strlen(s) : 0;
63 char *t = MALLOC(len + 1);
64 if (t) {
65 memcpy(t, s, len);
66 t[len] = '\0';
67 }
68 return t;
69 }
70
71 static EGLBoolean
72 dlopen_st_module_cb(const char *dir, size_t len, void *callback_data)
73 {
74 struct st_module *stmod =
75 (struct st_module *) callback_data;
76 char path[1024];
77 int ret;
78
79 if (len) {
80 ret = util_snprintf(path, sizeof(path),
81 "%.*s/" ST_PREFIX "%s" UTIL_DL_EXT, len, dir, stmod->name);
82 }
83 else {
84 ret = util_snprintf(path, sizeof(path),
85 ST_PREFIX "%s" UTIL_DL_EXT, stmod->name);
86 }
87
88 if (ret > 0 && ret < sizeof(path)) {
89 stmod->lib = util_dl_open(path);
90 if (stmod->lib)
91 _eglLog(_EGL_DEBUG, "loaded %s", path);
92 }
93
94 return !(stmod->lib);
95 }
96
97 static boolean
98 load_st_module(struct st_module *stmod,
99 const char *name, const char *procname)
100 {
101 struct st_api *(*create_api)(void);
102
103 _eglLog(_EGL_DEBUG, "searching for st module %s", name);
104
105 stmod->name = loader_strdup(name);
106 if (stmod->name)
107 _eglSearchPathForEach(dlopen_st_module_cb, (void *) stmod);
108 else
109 stmod->lib = util_dl_open(NULL);
110
111 if (stmod->lib) {
112 create_api = (struct st_api *(*)(void))
113 util_dl_get_proc_address(stmod->lib, procname);
114 if (create_api)
115 stmod->stapi = create_api();
116
117 if (!stmod->stapi) {
118 util_dl_close(stmod->lib);
119 stmod->lib = NULL;
120 }
121 }
122
123 if (!stmod->stapi) {
124 FREE(stmod->name);
125 stmod->name = NULL;
126 }
127
128 return (stmod->stapi != NULL);
129 }
130
131 static EGLBoolean
132 dlopen_pipe_module_cb(const char *dir, size_t len, void *callback_data)
133 {
134 struct pipe_module *pmod = (struct pipe_module *) callback_data;
135 char path[1024];
136 int ret;
137
138 if (len) {
139 ret = util_snprintf(path, sizeof(path),
140 "%.*s/" PIPE_PREFIX "%s" UTIL_DL_EXT, len, dir, pmod->name);
141 }
142 else {
143 ret = util_snprintf(path, sizeof(path),
144 PIPE_PREFIX "%s" UTIL_DL_EXT, pmod->name);
145 }
146 if (ret > 0 && ret < sizeof(path)) {
147 pmod->lib = util_dl_open(path);
148 if (pmod->lib)
149 _eglLog(_EGL_DEBUG, "loaded %s", path);
150 }
151
152 return !(pmod->lib);
153 }
154
155 static boolean
156 load_pipe_module(struct pipe_module *pmod, const char *name)
157 {
158 pmod->name = loader_strdup(name);
159 if (!pmod->name)
160 return FALSE;
161
162 _eglLog(_EGL_DEBUG, "searching for pipe module %s", pmod->name);
163 _eglSearchPathForEach(dlopen_pipe_module_cb, (void *) pmod);
164 if (pmod->lib) {
165 pmod->drmdd = (const struct drm_driver_descriptor *)
166 util_dl_get_proc_address(pmod->lib, "driver_descriptor");
167
168 /* sanity check on the name */
169 if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0)
170 pmod->drmdd = NULL;
171
172 /* swrast */
173 if (pmod->drmdd && !pmod->drmdd->driver_name) {
174 pmod->swrast_create_screen =
175 (struct pipe_screen *(*)(struct sw_winsys *))
176 util_dl_get_proc_address(pmod->lib, "swrast_create_screen");
177 if (!pmod->swrast_create_screen)
178 pmod->drmdd = NULL;
179 }
180
181 if (!pmod->drmdd) {
182 util_dl_close(pmod->lib);
183 pmod->lib = NULL;
184 }
185 }
186
187 return (pmod->drmdd != NULL);
188 }
189
190 static struct st_api *
191 get_st_api_full(enum st_api_type api, enum st_profile_type profile)
192 {
193 struct st_module *stmod = &st_modules[api];
194 const char *names[8], *symbol;
195 int i, count = 0;
196
197 if (stmod->initialized)
198 return stmod->stapi;
199
200 switch (api) {
201 case ST_API_OPENGL:
202 symbol = ST_CREATE_OPENGL_SYMBOL;
203 switch (profile) {
204 case ST_PROFILE_OPENGL_ES1:
205 names[count++] = "GLESv1_CM";
206 names[count++] = "GL";
207 break;
208 case ST_PROFILE_OPENGL_ES2:
209 names[count++] = "GLESv2";
210 names[count++] = "GL";
211 break;
212 default:
213 names[count++] = "GL";
214 break;
215 }
216 break;
217 case ST_API_OPENVG:
218 symbol = ST_CREATE_OPENVG_SYMBOL;
219 names[count++] = "OpenVG";
220 break;
221 default:
222 symbol = NULL;
223 assert(!"Unknown API Type\n");
224 break;
225 }
226
227 /* NULL means the process itself */
228 names[count++] = NULL;
229
230 for (i = 0; i < count; i++) {
231 if (load_st_module(stmod, names[i], symbol))
232 break;
233 }
234
235 if (!stmod->stapi) {
236 EGLint level = (egl_g3d_loader.profile_masks[api]) ?
237 _EGL_WARNING : _EGL_DEBUG;
238 _eglLog(level, "unable to load " ST_PREFIX "%s" UTIL_DL_EXT, names[0]);
239 }
240
241 stmod->initialized = TRUE;
242
243 return stmod->stapi;
244 }
245
246 static struct st_api *
247 get_st_api(enum st_api_type api)
248 {
249 enum st_profile_type profile = ST_PROFILE_DEFAULT;
250
251 /* determine the profile from the linked libraries */
252 if (api == ST_API_OPENGL) {
253 struct util_dl_library *self;
254
255 self = util_dl_open(NULL);
256 if (self) {
257 if (util_dl_get_proc_address(self, "glColor4x"))
258 profile = ST_PROFILE_OPENGL_ES1;
259 else if (util_dl_get_proc_address(self, "glShaderBinary"))
260 profile = ST_PROFILE_OPENGL_ES2;
261 util_dl_close(self);
262 }
263 }
264
265 return get_st_api_full(api, profile);
266 }
267
268 static struct st_api *
269 guess_gl_api(enum st_profile_type profile)
270 {
271 return get_st_api_full(ST_API_OPENGL, profile);
272 }
273
274 static struct pipe_module *
275 get_pipe_module(const char *name)
276 {
277 struct pipe_module *pmod = NULL;
278 int i;
279
280 if (!name)
281 return NULL;
282
283 for (i = 0; i < Elements(pipe_modules); i++) {
284 if (!pipe_modules[i].initialized ||
285 strcmp(pipe_modules[i].name, name) == 0) {
286 pmod = &pipe_modules[i];
287 break;
288 }
289 }
290 if (!pmod)
291 return NULL;
292
293 if (!pmod->initialized) {
294 load_pipe_module(pmod, name);
295 pmod->initialized = TRUE;
296 }
297
298 return pmod;
299 }
300
301 static struct pipe_screen *
302 create_drm_screen(const char *name, int fd)
303 {
304 struct pipe_module *pmod = get_pipe_module(name);
305 return (pmod && pmod->drmdd && pmod->drmdd->create_screen) ?
306 pmod->drmdd->create_screen(fd) : NULL;
307 }
308
309 static struct pipe_screen *
310 create_sw_screen(struct sw_winsys *ws)
311 {
312 struct pipe_module *pmod = get_pipe_module("swrast");
313 return (pmod && pmod->swrast_create_screen) ?
314 pmod->swrast_create_screen(ws) : NULL;
315 }
316
317 static const struct egl_g3d_loader *
318 loader_init(void)
319 {
320 /* TODO detect at runtime? */
321 #if FEATURE_GL
322 egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_DEFAULT_MASK;
323 #endif
324 #if FEATURE_ES1
325 egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_OPENGL_ES1_MASK;
326 #endif
327 #if FEATURE_ES2
328 egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_OPENGL_ES2_MASK;
329 #endif
330 #if FEATURE_VG
331 egl_g3d_loader.profile_masks[ST_API_OPENVG] |= ST_PROFILE_DEFAULT_MASK;
332 #endif
333
334 egl_g3d_loader.get_st_api = get_st_api;
335 egl_g3d_loader.guess_gl_api = guess_gl_api;
336 egl_g3d_loader.create_drm_screen = create_drm_screen;
337 egl_g3d_loader.create_sw_screen = create_sw_screen;
338
339 return &egl_g3d_loader;
340 }
341
342 static void
343 loader_fini(void)
344 {
345 int i;
346
347 for (i = 0; i < ST_API_COUNT; i++) {
348 struct st_module *stmod = &st_modules[i];
349
350 if (stmod->stapi) {
351 stmod->stapi->destroy(stmod->stapi);
352 stmod->stapi = NULL;
353 }
354 if (stmod->lib) {
355 util_dl_close(stmod->lib);
356 stmod->lib = NULL;
357 }
358 if (stmod->name) {
359 FREE(stmod->name);
360 stmod->name = NULL;
361 }
362 stmod->initialized = FALSE;
363 }
364 for (i = 0; i < Elements(pipe_modules); i++) {
365 struct pipe_module *pmod = &pipe_modules[i];
366
367 if (!pmod->initialized)
368 break;
369
370 pmod->drmdd = NULL;
371 pmod->swrast_create_screen = NULL;
372 if (pmod->lib) {
373 util_dl_close(pmod->lib);
374 pmod->lib = NULL;
375 }
376 if (pmod->name) {
377 FREE(pmod->name);
378 pmod->name = NULL;
379 }
380 pmod->initialized = FALSE;
381 }
382 }
383
384 static void
385 egl_g3d_unload(_EGLDriver *drv)
386 {
387 egl_g3d_destroy_driver(drv);
388 loader_fini();
389 }
390
391 _EGLDriver *
392 _eglMain(const char *args)
393 {
394 const struct egl_g3d_loader *loader;
395 _EGLDriver *drv;
396
397 loader = loader_init();
398 drv = egl_g3d_create_driver(loader);
399 if (!drv) {
400 loader_fini();
401 return NULL;
402 }
403
404 drv->Name = "Gallium";
405 drv->Unload = egl_g3d_unload;
406
407 return drv;
408 }