2644f820840627c40489606bb0fd4e266edcd904
[platform/core/uifw/libtbm.git] / src / tbm_module.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012-2021 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8          Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33
34 #include "tbm_bufmgr_int.h"
35 #include "tbm_bufmgr_backend.h"
36 #include "tbm_drm_helper.h"
37
38 #define PREFIX_LIB    "libtbm_"
39 #define SUFFIX_LIB    ".so"
40 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
41
42 /* values to indicate unspecified fields in XF86ModReqInfo. */
43 #define MAJOR_UNSPEC      0xFF
44 #define MINOR_UNSPEC      0xFF
45 #define PATCH_UNSPEC      0xFFFF
46 #define ABI_VERS_UNSPEC   0xFFFFFFFF
47
48 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
49                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
50 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
51 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
52 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
53
54 /* LCOV_EXCL_START */
55
56 static int
57 _tbm_backend_load_hal_tbm(tbm_module *module)
58 {
59         hal_tbm_backend *hal_backend = NULL;
60         hal_tbm_bufmgr *hal_bufmgr;
61         hal_tbm_error ret = HAL_TBM_ERROR_NONE;
62         hal_tbm_fd auth_drm_fd = -1;
63
64         hal_backend = hal_tbm_get_backend(&ret);
65         if (hal_backend == NULL || ret != HAL_TBM_ERROR_NONE) {
66                 TBM_ERR("get backend fail");
67                 return 0;
68         }
69
70         hal_bufmgr = hal_tbm_backend_get_bufmgr(hal_backend, &ret);
71         if (hal_bufmgr == NULL || ret != HAL_TBM_ERROR_NONE) {
72                 TBM_ERR("get hal_bufmgr fail");
73                 goto get_backend_fail;
74         }
75
76         if (hal_tbm_backend_has_drm_device(hal_backend, &ret)) {
77                 auth_drm_fd = hal_tbm_backend_get_master_drm_fd(hal_backend, &ret);
78                 if (auth_drm_fd < 0) {
79                         TBM_INFO("tbm_backend has no master drm_fd.");
80
81                         auth_drm_fd = tbm_drm_helper_get_master_fd();
82                         if (auth_drm_fd < 0) {
83                                 TBM_INFO("libtbm requests an authenticated drm_fd to a process(display server).");
84                                 if (!tbm_drm_helper_get_auth_info(&auth_drm_fd, NULL, NULL)) {
85                                         TBM_ERR("get auth drm_fd fail");
86                                         goto get_backend_fail;
87                                 }
88                         } else {
89                                 TBM_INFO("libtbm gets a master drm_fd from libtdm via tbm_drm_helper.");
90                         }
91
92                         TBM_INFO("libtbm sends a master drm_fd as an authentiated drm_fd to tbm_backend.");
93                         ret = hal_tbm_backend_set_authenticated_drm_fd(hal_backend, auth_drm_fd);
94                         if (ret != HAL_TBM_ERROR_NONE) {
95                                 TBM_ERR("hal_tbm_backend_set_authenticated_drm_fd failed.");
96                                 goto get_backend_fail;
97                         }
98                 } else {
99                         TBM_INFO("tbm_backend has a master drm_fd.");
100
101                         tbm_drm_helper_set_tbm_master_fd(auth_drm_fd);
102                 }
103                 tbm_drm_helper_set_fd(auth_drm_fd);
104         }
105
106         module->hal_backend = hal_backend;
107         module->hal_bufmgr = hal_bufmgr;
108
109         module->use_hal_tbm = 1;
110
111         TBM_INFO("use HAL-TBM_API");
112
113         return 1;
114
115 get_backend_fail:
116         if (auth_drm_fd >= 0)
117                 close(auth_drm_fd);
118         hal_tbm_put_backend(hal_backend);
119         return 0;
120 }
121
122 static int
123 _check_version(TBMModuleVersionInfo *data)
124 {
125         int backend_module_major, backend_module_minor;
126         int tbm_backend_major, tbm_backend_minor;
127
128         backend_module_major = GET_ABI_MAJOR(data->abiversion);
129         backend_module_minor = GET_ABI_MINOR(data->abiversion);
130
131         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
132             data->modname ? data->modname : "UNKNOWN!",
133             data->vendor ? data->vendor : "UNKNOWN!", backend_module_major, backend_module_minor);
134
135         tbm_backend_major = GET_ABI_MAJOR(TBM_ABI_VERSION);
136         tbm_backend_minor = GET_ABI_MINOR(TBM_ABI_VERSION);
137
138         TBM_DBG("TBM ABI version %d.%d\n",
139             tbm_backend_major, tbm_backend_minor);
140
141         if (backend_module_major != tbm_backend_major) {
142                 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
143                         backend_module_major, tbm_backend_major);
144                 return 0;
145         } else if (backend_module_minor > tbm_backend_minor) {
146                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
147                         backend_module_minor, tbm_backend_minor);
148                 return 0;
149         }
150
151         return 1;
152 }
153
154 static int
155 _tbm_backend_check_bufmgr_func(tbm_backend_bufmgr_func *bufmgr_func)
156 {
157         TBM_RETURN_VAL_IF_FAIL(bufmgr_func, 0); /* mandatory symbol */
158         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_capabilities, 0); /* mandatory symbol */
159         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_bind_native_display, 0); /* mandatory symbol */
160         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_supported_formats, 0); /* mandatory symbol */
161         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_plane_data, 0); /* mandatory symbol */
162         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_alloc_bo, 0); /* mandatory symbol */
163         if (!bufmgr_func->bufmgr_alloc_bo_with_format)
164                 TBM_DBG("No bufmgr_func->bufmgr_alloc_bo_with_format.");
165         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_import_fd, 0); /* mandatory symbol */
166         if (!bufmgr_func->bufmgr_import_key)
167                 TBM_DBG("No bufmgr_func->bo_export_key.");
168
169         return 1;
170 }
171
172 static int
173 _tbm_backend_check_bufmgr_bo(tbm_backend_bo_func *bo_func)
174 {
175         TBM_RETURN_VAL_IF_FAIL(bo_func, 0); /* mandatory symbol */
176         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_free, 0); /* mandatory symbol */
177         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_size, 0); /* mandatory symbol */
178         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_memory_types, 0); /* mandatory symbol */
179         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_handle, 0); /* mandatory symbol */
180         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_map, 0); /* mandatory symbol */
181         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_unmap, 0); /* mandatory symbol */
182         if (!bo_func->bo_lock)
183                 TBM_DBG("No bo_func->bo_lock.");
184         if (!bo_func->bo_unlock)
185                 TBM_DBG("No bo_func->bo_unlock.");
186         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_export_fd, 0); /* mandatory symbol */
187         if (!bo_func->bo_export_key)
188                 TBM_INFO("No bo_func->bo_export_key.");
189
190         return 1;
191 }
192
193 static int
194 _tbm_backend_load_module(tbm_module *module, const char *file)
195 {
196         char path[PATH_MAX] = {0, };
197         void *module_data = NULL;
198         tbm_backend_module *backend_module_data = NULL;
199         tbm_backend_bufmgr_data *bufmgr_data = NULL;
200         int backend_module_major, backend_module_minor;
201         int tbm_backend_major, tbm_backend_minor;
202         tbm_error_e error;
203
204         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
205
206         module_data = dlopen(path, RTLD_LAZY);
207         if (!module_data) {
208                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
209                 return 0;
210         }
211
212         backend_module_data = dlsym(module_data, "tbm_backend_module_data");
213         if (!backend_module_data) {
214                 TBM_ERR("Error: module does not have data object.\n");
215                 goto err;
216         }
217
218         tbm_backend_major = GET_ABI_MAJOR(TBM_BACKEND_ABI_LATEST_VERSION);
219         tbm_backend_minor = GET_ABI_MINOR(TBM_BACKEND_ABI_LATEST_VERSION);
220         TBM_INFO("TBM Backend ABI version %d.%d\n", tbm_backend_major, tbm_backend_minor);
221
222         backend_module_major = GET_ABI_MAJOR(backend_module_data->abi_version);
223         backend_module_minor = GET_ABI_MINOR(backend_module_data->abi_version);
224
225         TBM_INFO("TBM module %s: vendor=\"%s\" Backend ABI version=%d.%d\n",
226             backend_module_data->name ? backend_module_data->name : "UNKNOWN!",
227             backend_module_data->vendor ? backend_module_data->vendor : "UNKNOWN!",
228                 backend_module_major, backend_module_minor);
229
230         if (backend_module_major > tbm_backend_major) {
231                 TBM_ERR("TBM module ABI major ver(%d) is newer than the TBM's ver(%d)\n",
232                         backend_module_major, tbm_backend_major);
233                 goto err;
234         } else if (backend_module_minor > tbm_backend_minor) {
235                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
236                         backend_module_minor, tbm_backend_minor);
237                 goto err;
238         }
239
240         if (!backend_module_data->init) {
241                 TBM_ERR("Error: module does not supply init symbol.\n");
242                 goto err;
243         }
244
245         if (!backend_module_data->deinit)       {
246                 TBM_ERR("Error: module does not supply deinit symbol.\n");
247                 goto err;
248         }
249
250         bufmgr_data = backend_module_data->init((tbm_bufmgr)module, &error);
251         if (!bufmgr_data) {
252                 TBM_ERR("Fail to init module(%s)\n", file);
253                 goto err;
254         }
255
256         /* check the mandatory symbols of the backend module */
257         if (!_tbm_backend_check_bufmgr_func(module->bufmgr_func)) {
258                 TBM_ERR("Fail to check the bufmgr_func symboles.");
259                 goto err;
260         }
261
262         if (!_tbm_backend_check_bufmgr_bo(module->bo_func)) {
263                 TBM_ERR("Fail to check the bufmgr_bo symboles.");
264                 goto err;
265         }
266
267         module->module_data = module_data;
268         module->backend_module_data = backend_module_data;
269         module->bufmgr_data = bufmgr_data;
270
271         TBM_INFO("Success to load module(%s)\n", file);
272
273         return 1;
274
275 err:
276         if (bufmgr_data)
277                 module->backend_module_data->deinit(bufmgr_data);
278         if (module_data)
279                 dlclose(module_data);
280
281         return 0;
282 }
283
284 static int
285 _tbm_backend_load_bufmgr_module(tbm_module *module, int fd, const char *file)
286 {
287         char path[PATH_MAX] = {0, };
288         TBMModuleVersionInfo *vers;
289         TBMModuleData *initdata;
290         ModuleInitProc init;
291         void *module_data;
292
293         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
294
295         module_data = dlopen(path, RTLD_LAZY);
296         if (!module_data) {
297                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
298                 return 0;
299         }
300
301         initdata = dlsym(module_data, "tbmModuleData");
302         if (!initdata) {
303                 TBM_ERR("Error: module does not have data object.\n");
304                 goto err;
305         }
306
307         vers = initdata->vers;
308         if (!vers) {
309                 TBM_ERR("Error: module does not supply version information.\n");
310                 goto err;
311         }
312
313         init = initdata->init;
314         if (!init) {
315                 TBM_ERR("Error: module does not supply init symbol.\n");
316                 goto err;
317         }
318
319         if (!_check_version(vers)) {
320                 TBM_ERR("Fail to check version.\n");
321                 goto err;
322         }
323
324         if (!init((tbm_bufmgr)module, fd)) {
325                 TBM_ERR("Fail to init module(%s)\n", file);
326                 goto err;
327         }
328
329         if (!module->backend || !module->backend->priv) {
330                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
331                 goto err;
332         }
333
334         module->module_data = module_data;
335
336         TBM_DBG("Success to load module(%s)\n", file);
337
338         return 1;
339
340 err:
341         dlclose(module_data);
342         return 0;
343 }
344
345 /* LCOV_EXCL_STOP */
346
347 tbm_module *
348 tbm_module_load(tbm_bufmgr bufmgr, int fd)
349 {
350         tbm_module *module;
351         struct dirent **namelist;
352         int ret = 0, n;
353
354         module = calloc(1, sizeof(struct _tbm_module));
355         if (!module) {
356                 TBM_ERR("fail to allocate the memory");
357                 return NULL;
358         }
359         module->bufmgr = bufmgr;
360
361         /* try to load the hal-tbm backend module */
362         ret = _tbm_backend_load_hal_tbm(module);
363         if (ret) {
364                 module->type = TBM_MODULE_TYPE_HAL_TBM;
365                 goto done;
366         }
367
368         /* try to load the new backend module */
369         ret = _tbm_backend_load_module(module, DEFAULT_LIB);
370         if (ret) {
371                 module->type = TBM_MODULE_TYPE_TBM_BACKEND;
372                 goto done;
373         }
374
375         /* try to load the old(deprecated) backend mdoule */
376         ret = _tbm_backend_load_bufmgr_module(module, fd, DEFAULT_LIB);
377         if (ret) {
378                 module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
379                 return module;
380         }
381
382         /* load bufmgr priv from configured path */
383         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
384         if (n < 0) {
385                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
386                 tbm_module_unload(module);
387                 return NULL;
388         }
389
390         while (n--) {
391                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
392                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
393
394                         if (p && !strcmp(p, SUFFIX_LIB)) {
395                                 ret = _tbm_backend_load_module(module, namelist[n]->d_name);
396                                 if (ret)
397                                         module->type = TBM_MODULE_TYPE_TBM_BACKEND;
398                                 else {
399                                         ret = _tbm_backend_load_bufmgr_module(module, fd, namelist[n]->d_name);
400                                         module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
401                                 }
402                         }
403                 }
404
405                 free(namelist[n]);
406         }
407
408         free(namelist);
409
410         if (!ret) {
411                 free(module);
412                 module = NULL;
413         }
414
415 done:
416         return module;
417 }
418
419 void
420 tbm_module_unload(tbm_module *module)
421 {
422         switch (module->type) {
423         case TBM_MODULE_TYPE_HAL_TBM:
424                 if (module->auth_wl_socket_created) {
425                         tbm_drm_helper_wl_auth_server_deinit();
426                         close(module->auth_fd);
427                 }
428                 tbm_drm_helper_unset_tbm_master_fd();
429                 tbm_drm_helper_unset_fd();
430
431                 hal_tbm_put_backend(module->hal_backend);
432                 module->hal_backend = NULL;
433                 module->hal_bufmgr = NULL;
434                 module->use_hal_tbm = 0;
435                 break;
436         case TBM_MODULE_TYPE_TBM_BACKEND:
437                 module->backend_module_data->deinit(module->bufmgr_data);
438                 module->bo_func = NULL;
439                 module->bufmgr_func = NULL;
440                 module->bufmgr_data = NULL;
441                 module->backend_module_data = NULL;
442
443                 dlclose(module->module_data);
444                 break;
445         case TBM_MODULE_TYPE_BUFMGR_BACKEND:
446                 module->backend->bufmgr_deinit(module->backend->priv);
447                 module->backend->priv = NULL;
448                 tbm_backend_free(module->backend);
449                 module->backend = NULL;
450
451                 dlclose(module->module_data);
452                 break;
453         default:
454                 TBM_ERR("Wrong module type:%d", module->type);
455                 break;
456         }
457
458         module->bufmgr = NULL;
459
460         free(module);
461 }
462
463 int
464 tbm_module_bufmgr_get_capabilities(tbm_module *module)
465 {
466         tbm_error_e error = TBM_ERROR_NOT_SUPPORTED;
467         int capabilities = 0;
468
469         switch (module->type) {
470         case TBM_MODULE_TYPE_HAL_TBM:
471                 capabilities = hal_tbm_bufmgr_get_capabilities(module->hal_bufmgr, (hal_tbm_error *)&error);
472                 break;
473         case TBM_MODULE_TYPE_TBM_BACKEND:
474                 capabilities = module->bufmgr_func->bufmgr_get_capabilities(module->bufmgr_data, &error);
475                 break;
476         case TBM_MODULE_TYPE_BUFMGR_BACKEND:
477                 TBM_ERR("Do not support at tbm_bufmgr_backend.");
478                 break;
479         default:
480                 TBM_ERR("Wrong module type:%d", module->type);
481                 break;
482         }
483
484         if (error != TBM_ERROR_NONE) {
485                 TBM_ERR("fail to get capabilities of bufmgr");
486                 return 0;
487         }
488
489         return capabilities;
490 }