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