tbm_module: use module instead of bufmgr
[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 void
57 _tbm_module_copy_data_to_bufmgr(tbm_module *module, tbm_bufmgr bufmgr, int reset)
58 {
59         if (!reset) {
60                 bufmgr->module_data = module->module_data;
61                 bufmgr->backend = module->backend;
62
63                 bufmgr->backend_module_data = module->backend_module_data;
64                 bufmgr->bufmgr_data = module->bufmgr_data;
65                 bufmgr->bufmgr_func = module->bufmgr_func;
66                 bufmgr->bo_func = module->bo_func;
67
68                 bufmgr->use_hal_tbm = module->use_hal_tbm;
69                 bufmgr->auth_wl_socket_created = module->auth_wl_socket_created;
70                 bufmgr->auth_fd = module->auth_fd;
71                 bufmgr->hal_backend = module->hal_backend;
72                 bufmgr->hal_bufmgr = module->hal_bufmgr;
73         } else {
74                 bufmgr->module_data = NULL;
75                 bufmgr->backend = NULL;
76
77                 bufmgr->backend_module_data = NULL;
78                 bufmgr->bufmgr_data = NULL;
79                 bufmgr->bufmgr_func = NULL;
80                 bufmgr->bo_func = NULL;
81
82                 bufmgr->use_hal_tbm = 0;
83                 bufmgr->auth_wl_socket_created = 0;
84                 bufmgr->auth_fd = -1;
85                 bufmgr->hal_backend = NULL;
86                 bufmgr->hal_bufmgr = NULL;
87         }
88 }
89
90 static int
91 _tbm_backend_load_hal_tbm(tbm_module *module)
92 {
93         hal_tbm_backend *hal_backend = NULL;
94         hal_tbm_bufmgr_capability capability;
95         hal_tbm_bufmgr *hal_bufmgr;
96         hal_tbm_error ret = HAL_TBM_ERROR_NONE;
97         hal_tbm_fd auth_drm_fd = -1;
98
99         hal_backend = hal_tbm_get_backend(&ret);
100         if (hal_backend == NULL || ret != HAL_TBM_ERROR_NONE) {
101                 TBM_ERR("get backend fail");
102                 return 0;
103         }
104
105         hal_bufmgr = hal_tbm_backend_get_bufmgr(hal_backend, &ret);
106         if (hal_bufmgr == NULL || ret != HAL_TBM_ERROR_NONE) {
107                 TBM_ERR("get hal_bufmgr fail");
108                 goto get_backend_fail;
109         }
110
111         if (hal_tbm_backend_has_drm_device(hal_backend, &ret)) {
112                 auth_drm_fd = hal_tbm_backend_get_master_drm_fd(hal_backend, &ret);
113                 if (auth_drm_fd < 0) {
114                         TBM_INFO("tbm_backend has no master drm_fd.");
115
116                         auth_drm_fd = tbm_drm_helper_get_master_fd();
117                         if (auth_drm_fd < 0) {
118                                 TBM_INFO("libtbm requests an authenticated drm_fd to a process(display server).");
119                                 if (!tbm_drm_helper_get_auth_info(&auth_drm_fd, NULL, NULL)) {
120                                         TBM_ERR("get auth drm_fd fail");
121                                         goto get_backend_fail;
122                                 }
123                         } else {
124                                 TBM_INFO("libtbm gets a master drm_fd from libtdm via tbm_drm_helper.");
125                         }
126
127                         TBM_INFO("libtbm sends a master drm_fd as an authentiated drm_fd to tbm_backend.");
128                         ret = hal_tbm_backend_set_authenticated_drm_fd(hal_backend, auth_drm_fd);
129                         if (ret != HAL_TBM_ERROR_NONE) {
130                                 TBM_ERR("hal_tbm_backend_set_authenticated_drm_fd failed.");
131                                 goto get_backend_fail;
132                         }
133                 } else {
134                         TBM_INFO("tbm_backend has a master drm_fd.");
135
136                         tbm_drm_helper_set_tbm_master_fd(auth_drm_fd);
137                 }
138                 tbm_drm_helper_set_fd(auth_drm_fd);
139         }
140
141         capability = hal_tbm_bufmgr_get_capabilities(hal_bufmgr, &ret);
142         if (ret != HAL_TBM_ERROR_NONE) {
143                 TBM_ERR("hal_tbm_bufmgr_get_capabilities fail.");
144                 goto get_backend_fail;
145         }
146
147         if (capability == HAL_TBM_BUFMGR_CAPABILITY_NONE) {
148                 TBM_ERR("The capabilities of the backend module is TBM_BUFMGR_CAPABILITY_NONE.");
149                 TBM_ERR("TBM_BUFMGR_CAPABILITY_SHARE_FD is the essential capability.");
150                 goto get_backend_fail;
151         }
152         if (!(capability & HAL_TBM_BUFMGR_CAPABILITY_SHARE_FD)) {
153                 TBM_ERR("The capabilities of the backend module had no TBM_BUFMGR_CAPABILITY_SHARE_FD.");
154                 TBM_ERR("The tbm backend has to get TBM_BUFMGR_CAPABILITY_SHARE_FD. ");
155                 goto get_backend_fail;
156         }
157
158         module->bufmgr->capabilities = capability;
159
160         module->hal_backend = hal_backend;
161         module->hal_bufmgr = hal_bufmgr;
162
163         module->use_hal_tbm = 1;
164
165         TBM_INFO("use HAL-TBM_API");
166
167         return 1;
168
169 get_backend_fail:
170         if (auth_drm_fd >= 0)
171                 close(auth_drm_fd);
172         hal_tbm_put_backend(hal_backend);
173         return 0;
174 }
175
176 static int
177 _check_version(TBMModuleVersionInfo *data)
178 {
179         int backend_module_major, backend_module_minor;
180         int tbm_backend_major, tbm_backend_minor;
181
182         backend_module_major = GET_ABI_MAJOR(data->abiversion);
183         backend_module_minor = GET_ABI_MINOR(data->abiversion);
184
185         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
186             data->modname ? data->modname : "UNKNOWN!",
187             data->vendor ? data->vendor : "UNKNOWN!", backend_module_major, backend_module_minor);
188
189         tbm_backend_major = GET_ABI_MAJOR(TBM_ABI_VERSION);
190         tbm_backend_minor = GET_ABI_MINOR(TBM_ABI_VERSION);
191
192         TBM_DBG("TBM ABI version %d.%d\n",
193             tbm_backend_major, tbm_backend_minor);
194
195         if (backend_module_major != tbm_backend_major) {
196                 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
197                         backend_module_major, tbm_backend_major);
198                 return 0;
199         } else if (backend_module_minor > tbm_backend_minor) {
200                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
201                         backend_module_minor, tbm_backend_minor);
202                 return 0;
203         }
204
205         return 1;
206 }
207
208 static int
209 _tbm_backend_check_bufmgr_func(tbm_backend_bufmgr_func *bufmgr_func)
210 {
211         TBM_RETURN_VAL_IF_FAIL(bufmgr_func, 0); /* mandatory symbol */
212         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_capabilities, 0); /* mandatory symbol */
213         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_bind_native_display, 0); /* mandatory symbol */
214         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_supported_formats, 0); /* mandatory symbol */
215         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_plane_data, 0); /* mandatory symbol */
216         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_alloc_bo, 0); /* mandatory symbol */
217         if (!bufmgr_func->bufmgr_alloc_bo_with_format)
218                 TBM_DBG("No bufmgr_func->bufmgr_alloc_bo_with_format.");
219         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_import_fd, 0); /* mandatory symbol */
220         if (!bufmgr_func->bufmgr_import_key)
221                 TBM_DBG("No bufmgr_func->bo_export_key.");
222
223         return 1;
224 }
225
226 static int
227 _tbm_backend_check_bufmgr_bo(tbm_backend_bo_func *bo_func)
228 {
229         TBM_RETURN_VAL_IF_FAIL(bo_func, 0); /* mandatory symbol */
230         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_free, 0); /* mandatory symbol */
231         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_size, 0); /* mandatory symbol */
232         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_memory_types, 0); /* mandatory symbol */
233         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_handle, 0); /* mandatory symbol */
234         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_map, 0); /* mandatory symbol */
235         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_unmap, 0); /* mandatory symbol */
236         if (!bo_func->bo_lock)
237                 TBM_DBG("No bo_func->bo_lock.");
238         if (!bo_func->bo_unlock)
239                 TBM_DBG("No bo_func->bo_unlock.");
240         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_export_fd, 0); /* mandatory symbol */
241         if (!bo_func->bo_export_key)
242                 TBM_INFO("No bo_func->bo_export_key.");
243
244         return 1;
245 }
246
247 static int
248 _tbm_backend_load_module(tbm_module *module, const char *file)
249 {
250         char path[PATH_MAX] = {0, };
251         void *module_data = NULL;
252         tbm_backend_module *backend_module_data = NULL;
253         tbm_backend_bufmgr_data *bufmgr_data = NULL;
254         int backend_module_major, backend_module_minor;
255         int tbm_backend_major, tbm_backend_minor;
256         tbm_error_e error;
257
258         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
259
260         module_data = dlopen(path, RTLD_LAZY);
261         if (!module_data) {
262                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
263                 return 0;
264         }
265
266         backend_module_data = dlsym(module_data, "tbm_backend_module_data");
267         if (!backend_module_data) {
268                 TBM_ERR("Error: module does not have data object.\n");
269                 goto err;
270         }
271
272         tbm_backend_major = GET_ABI_MAJOR(TBM_BACKEND_ABI_LATEST_VERSION);
273         tbm_backend_minor = GET_ABI_MINOR(TBM_BACKEND_ABI_LATEST_VERSION);
274         TBM_INFO("TBM Backend ABI version %d.%d\n", tbm_backend_major, tbm_backend_minor);
275
276         backend_module_major = GET_ABI_MAJOR(backend_module_data->abi_version);
277         backend_module_minor = GET_ABI_MINOR(backend_module_data->abi_version);
278
279         TBM_INFO("TBM module %s: vendor=\"%s\" Backend ABI version=%d.%d\n",
280             backend_module_data->name ? backend_module_data->name : "UNKNOWN!",
281             backend_module_data->vendor ? backend_module_data->vendor : "UNKNOWN!",
282                 backend_module_major, backend_module_minor);
283
284         if (backend_module_major > tbm_backend_major) {
285                 TBM_ERR("TBM module ABI major ver(%d) is newer than the TBM's ver(%d)\n",
286                         backend_module_major, tbm_backend_major);
287                 goto err;
288         } else if (backend_module_minor > tbm_backend_minor) {
289                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
290                         backend_module_minor, tbm_backend_minor);
291                 goto err;
292         }
293
294         if (!backend_module_data->init) {
295                 TBM_ERR("Error: module does not supply init symbol.\n");
296                 goto err;
297         }
298
299         if (!backend_module_data->deinit)       {
300                 TBM_ERR("Error: module does not supply deinit symbol.\n");
301                 goto err;
302         }
303
304         bufmgr_data = backend_module_data->init((tbm_bufmgr)module, &error);
305         if (!bufmgr_data) {
306                 TBM_ERR("Fail to init module(%s)\n", file);
307                 goto err;
308         }
309
310         /* check the mandatory symbols of the backend module */
311         if (!_tbm_backend_check_bufmgr_func(module->bufmgr_func)) {
312                 TBM_ERR("Fail to check the bufmgr_func symboles.");
313                 goto err;
314         }
315
316         if (!_tbm_backend_check_bufmgr_bo(module->bo_func)) {
317                 TBM_ERR("Fail to check the bufmgr_bo symboles.");
318                 goto err;
319         }
320
321         /* get the capability */
322         module->bufmgr->capabilities = module->bufmgr->bufmgr_func->bufmgr_get_capabilities(bufmgr_data, &error);
323         if (module->bufmgr->capabilities == TBM_BUFMGR_CAPABILITY_NONE) {
324                 TBM_ERR("The capabilities of the backend module is TBM_BUFMGR_CAPABILITY_NONE.");
325                 TBM_ERR("TBM_BUFMGR_CAPABILITY_SHARE_FD is the essential capability.");
326                 goto err;
327         }
328
329         if (!(module->bufmgr->capabilities & TBM_BUFMGR_CAPABILITY_SHARE_FD)) {
330                 TBM_ERR("The capabilities of the backend module had no TBM_BUFMGR_CAPABILITY_SHARE_FD.");
331                 TBM_ERR("The tbm backend has to get TBM_BUFMGR_CAPABILITY_SHARE_FD. ");
332                 goto err;
333         }
334
335         module->module_data = module_data;
336         module->backend_module_data = backend_module_data;
337         module->bufmgr_data = bufmgr_data;
338
339         TBM_INFO("Success to load module(%s)\n", file);
340
341         return 1;
342
343 err:
344         if (bufmgr_data)
345                 module->backend_module_data->deinit(bufmgr_data);
346         if (module_data)
347                 dlclose(module_data);
348
349         return 0;
350 }
351
352 static int
353 _tbm_backend_load_bufmgr_module(tbm_module *module, int fd, const char *file)
354 {
355         char path[PATH_MAX] = {0, };
356         TBMModuleVersionInfo *vers;
357         TBMModuleData *initdata;
358         ModuleInitProc init;
359         void *module_data;
360
361         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
362
363         module_data = dlopen(path, RTLD_LAZY);
364         if (!module_data) {
365                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
366                 return 0;
367         }
368
369         initdata = dlsym(module_data, "tbmModuleData");
370         if (!initdata) {
371                 TBM_ERR("Error: module does not have data object.\n");
372                 goto err;
373         }
374
375         vers = initdata->vers;
376         if (!vers) {
377                 TBM_ERR("Error: module does not supply version information.\n");
378                 goto err;
379         }
380
381         init = initdata->init;
382         if (!init) {
383                 TBM_ERR("Error: module does not supply init symbol.\n");
384                 goto err;
385         }
386
387         if (!_check_version(vers)) {
388                 TBM_ERR("Fail to check version.\n");
389                 goto err;
390         }
391
392         if (!init((tbm_bufmgr)module, fd)) {
393                 TBM_ERR("Fail to init module(%s)\n", file);
394                 goto err;
395         }
396
397         if (!module->backend || !module->backend->priv) {
398                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
399                 goto err;
400         }
401
402         module->module_data = module_data;
403
404         TBM_DBG("Success to load module(%s)\n", file);
405
406         return 1;
407
408 err:
409         dlclose(module_data);
410         return 0;
411 }
412
413 /* LCOV_EXCL_STOP */
414
415 tbm_module *
416 tbm_module_load(tbm_bufmgr bufmgr, int fd)
417 {
418         tbm_module *module;
419         struct dirent **namelist;
420         int ret = 0, n;
421
422         module = calloc(1, sizeof(struct _tbm_module));
423         if (!module) {
424                 TBM_ERR("fail to allocate the memory");
425                 return NULL;
426         }
427         module->bufmgr = bufmgr;
428
429         /* try to load the hal-tbm backend module */
430         ret = _tbm_backend_load_hal_tbm(module);
431         if (ret) {
432                 module->type = TBM_MODULE_TYPE_HAL_TBM;
433                 goto done;
434         }
435
436         /* try to load the new backend module */
437         ret = _tbm_backend_load_module(module, DEFAULT_LIB);
438         if (ret) {
439                 module->type = TBM_MODULE_TYPE_TBM_BACKEND;
440                 goto done;
441         }
442
443         /* try to load the old(deprecated) backend mdoule */
444         ret = _tbm_backend_load_bufmgr_module(module, fd, DEFAULT_LIB);
445         if (ret) {
446                 module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
447                 return module;
448         }
449
450         /* load bufmgr priv from configured path */
451         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
452         if (n < 0) {
453                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
454                 tbm_module_unload(module);
455                 return NULL;
456         }
457
458         while (n--) {
459                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
460                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
461
462                         if (p && !strcmp(p, SUFFIX_LIB)) {
463                                 ret = _tbm_backend_load_module(module, namelist[n]->d_name);
464                                 if (ret)
465                                         module->type = TBM_MODULE_TYPE_TBM_BACKEND;
466                                 else {
467                                         ret = _tbm_backend_load_bufmgr_module(module, fd, namelist[n]->d_name);
468                                         module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
469                                 }
470                         }
471                 }
472
473                 free(namelist[n]);
474         }
475
476         free(namelist);
477
478         if (!ret) {
479                 free(module);
480                 module = NULL;
481         }
482
483 done:
484         if (module)
485                 _tbm_module_copy_data_to_bufmgr(module, module->bufmgr, 0);
486
487         return module;
488 }
489
490 void
491 tbm_module_unload(tbm_module *module)
492 {
493         if (module->use_hal_tbm) {
494                 if (module->auth_wl_socket_created) {
495                         tbm_drm_helper_wl_auth_server_deinit();
496                         close(module->auth_fd);
497                 }
498                 tbm_drm_helper_unset_tbm_master_fd();
499                 tbm_drm_helper_unset_fd();
500
501                 hal_tbm_put_backend(module->hal_backend);
502                 module->hal_backend = NULL;
503                 module->hal_bufmgr = NULL;
504                 module->use_hal_tbm = 0;
505         } else {
506                 if (module->backend_module_data) {
507                         module->backend_module_data->deinit(module->bufmgr_data);
508                         module->bo_func = NULL;
509                         module->bufmgr_func = NULL;
510                         module->bufmgr_data = NULL;
511                         module->backend_module_data = NULL;
512                 } else {
513                         module->backend->bufmgr_deinit(module->backend->priv);
514                         module->backend->priv = NULL;
515                         tbm_backend_free(module->backend);
516                         module->backend = NULL;
517                 }
518
519                 dlclose(module->module_data);
520         }
521
522         _tbm_module_copy_data_to_bufmgr(module, module->bufmgr, 1);
523         module->bufmgr = NULL;
524
525         free(module);
526 }
527