xref: /OK3568_Linux_fs/external/libmali/hook/hook.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  *  Copyright (c) 2020, Rockchip Electronics Co., Ltd
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  */
14 
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE 1
17 #endif
18 
19 #include <dlfcn.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <xf86drm.h>
27 #include <sys/mman.h>
28 
29 #ifdef HAS_GBM
30 #include <gbm.h>
31 #endif
32 
33 #ifdef HAS_EGL
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36 #endif
37 
38 #ifdef HAS_X11
39 #include <pthread.h>
40 
41 #include <X11/Xlib.h>
42 #include <X11/Xlibint.h>
43 #endif
44 
45 #ifndef ARRAY_SIZE
46 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
47 #endif
48 
49 #ifndef DRM_FORMAT_MOD_LINEAR
50 #define DRM_FORMAT_MOD_LINEAR 0
51 #endif
52 
53 #ifndef DRM_FORMAT_MOD_INVALID
54 #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
55 #endif
56 
57 /* A stub symbol to ensure that the hook library would not be removed as unused */
58 int mali_injected = 0;
59 
60 /* Override libmali symbols */
61 
62 #ifdef HAS_GBM
63 static struct gbm_surface * (* _gbm_surface_create)(struct gbm_device *, uint32_t, uint32_t, uint32_t, uint32_t) = NULL;
64 static struct gbm_bo * (* _gbm_bo_create) (struct gbm_device *, uint32_t, uint32_t, uint32_t, uint32_t) = NULL;
65 #ifdef HAS_gbm_bo_get_modifier
66 static uint64_t (* _gbm_bo_get_modifier) (struct gbm_bo *bo) = NULL;
67 #endif
68 #endif
69 
70 #ifdef HAS_EGL
71 static PFNEGLGETDISPLAYPROC _eglGetDisplay = NULL;
72 
73 #ifdef HAS_X11
74 static PFNEGLGETPROCADDRESSPROC _eglGetProcAddress = NULL;
75 static PFNEGLGETPLATFORMDISPLAYPROC _eglGetPlatformDisplay = NULL;
76 static PFNEGLGETPLATFORMDISPLAYEXTPROC _eglGetPlatformDisplayEXT = NULL;
77 #endif
78 #endif
79 
80 #define MALI_SYMBOL(func) { #func, (void **)(&_ ## func), }
81 static struct {
82    const char *func;
83    void **symbol;
84 } mali_symbols[] = {
85 #ifdef HAS_GBM
86    MALI_SYMBOL(gbm_surface_create),
87    MALI_SYMBOL(gbm_bo_create),
88 #ifdef HAS_gbm_bo_get_modifier
89    MALI_SYMBOL(gbm_bo_get_modifier),
90 #endif
91 #endif
92 #ifdef HAS_EGL
93    MALI_SYMBOL(eglGetDisplay),
94 #ifdef HAS_X11
95    MALI_SYMBOL(eglGetProcAddress),
96 #endif
97 #endif
98 };
99 
100 __attribute__((constructor)) static void
load_mali_symbols(void)101 load_mali_symbols(void)
102 {
103    void *handle, *symbol;
104    int i;
105 
106    /* The libmali should be already loaded */
107    handle = dlopen(LIBMALI_SO, RTLD_LAZY | RTLD_NOLOAD);
108    if (!handle) {
109       /* Should not reach here */
110       fprintf(stderr, "FATAL: dlopen(" LIBMALI_SO ") failed(%s)\n", dlerror());
111       exit(-1);
112    }
113 
114    for (i = 0; i < ARRAY_SIZE(mali_symbols); i++) {
115       const char *func = mali_symbols[i].func;
116 
117       /* Clear error */
118       dlerror();
119 
120       symbol = dlsym(handle, func);
121       if (!symbol) {
122          /* Should not reach here */
123          fprintf(stderr, "FATAL: " LIBMALI_SO " dlsym(%s) failed(%s)\n",
124                  func, dlerror());
125          exit(-1);
126       }
127 
128       *mali_symbols[i].symbol = symbol;
129    }
130 
131    dlclose(handle);
132 
133 #ifdef HAS_EGL
134 #ifdef HAS_X11
135    _eglGetPlatformDisplay =
136       (PFNEGLGETPLATFORMDISPLAYPROC)_eglGetProcAddress("eglGetPlatformDisplay");
137    _eglGetPlatformDisplayEXT =
138       (PFNEGLGETPLATFORMDISPLAYEXTPROC)_eglGetProcAddress("eglGetPlatformDisplayEXT");
139 #endif
140 #endif
141 }
142 
143 #ifdef HAS_GBM
144 
145 /* Implement new GBM APIs */
146 
147 __attribute__((unused)) static inline bool
can_ignore_modifiers(const uint64_t * modifiers,const unsigned int count)148 can_ignore_modifiers(const uint64_t *modifiers,
149                      const unsigned int count)
150 {
151    for (int i = 0; i < count; i++) {
152       /* linear or invalid */
153       if (!modifiers[i] || modifiers[i] == DRM_FORMAT_MOD_INVALID) {
154          return true;
155       }
156    }
157 
158    return !count;
159 }
160 
161 #ifndef HAS_gbm_bo_get_offset
162 uint32_t
gbm_bo_get_offset(struct gbm_bo * bo,int plane)163 gbm_bo_get_offset(struct gbm_bo *bo, int plane)
164 {
165    return 0;
166 }
167 #endif
168 
169 #ifndef HAS_gbm_bo_get_plane_count
170 int
gbm_bo_get_plane_count(struct gbm_bo * bo)171 gbm_bo_get_plane_count(struct gbm_bo *bo)
172 {
173    return 1;
174 }
175 #endif
176 
177 #ifndef HAS_gbm_bo_get_stride_for_plane
178 uint32_t
gbm_bo_get_stride_for_plane(struct gbm_bo * bo,int plane)179 gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane)
180 {
181    if (plane)
182       return 0;
183 
184    return gbm_bo_get_stride(bo);
185 }
186 #endif
187 
188 #ifndef HAS_gbm_bo_get_fd_for_plane
189 int
gbm_bo_get_fd_for_plane(struct gbm_bo * bo,int plane)190 gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane)
191 {
192    if (plane)
193       return -1;
194 
195    return gbm_bo_get_fd(bo);
196 }
197 #endif
198 
199 #ifndef HAS_gbm_bo_get_handle_for_plane
200 union gbm_bo_handle
gbm_bo_get_handle_for_plane(struct gbm_bo * bo,int plane)201 gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane)
202 {
203    union gbm_bo_handle ret;
204    ret.s32 = -1;
205 
206    if (plane)
207       return ret;
208 
209    return gbm_bo_get_handle(bo);
210 }
211 #endif
212 
213 #ifndef HAS_gbm_device_get_format_modifier_plane_count
214 int
gbm_device_get_format_modifier_plane_count(struct gbm_device * gbm,uint32_t format,uint64_t modifier)215 gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm,
216                                            uint32_t format,
217                                            uint64_t modifier)
218 {
219    return can_ignore_modifiers(&modifier, 1) ? 1 : 0;
220 }
221 #endif
222 
223 #ifndef HAS_gbm_bo_create_with_modifiers
224 struct gbm_bo *
gbm_bo_create_with_modifiers(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,const uint64_t * modifiers,const unsigned int count)225 gbm_bo_create_with_modifiers(struct gbm_device *gbm,
226                              uint32_t width, uint32_t height,
227                              uint32_t format,
228                              const uint64_t *modifiers,
229                              const unsigned int count)
230 {
231    if (!can_ignore_modifiers(modifiers, count))
232       return NULL;
233 
234    return gbm_bo_create(gbm, width, height, format, GBM_BO_USE_LINEAR);
235 }
236 #endif
237 
238 #ifndef HAS_gbm_surface_create_with_modifiers
239 struct gbm_surface *
gbm_surface_create_with_modifiers(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,const uint64_t * modifiers,const unsigned int count)240 gbm_surface_create_with_modifiers(struct gbm_device *gbm,
241                                   uint32_t width, uint32_t height,
242                                   uint32_t format,
243                                   const uint64_t *modifiers,
244                                   const unsigned int count)
245 {
246    if (!can_ignore_modifiers(modifiers, count))
247       return NULL;
248 
249    return gbm_surface_create(gbm, width, height, format, 0);
250 }
251 #endif
252 
253 #ifndef HAS_gbm_bo_map
254 void *
gbm_bo_map(struct gbm_bo * bo,uint32_t x,uint32_t y,uint32_t width,uint32_t height,uint32_t flags,uint32_t * stride,void ** map_data)255 gbm_bo_map(struct gbm_bo *bo,
256            uint32_t x, uint32_t y, uint32_t width, uint32_t height,
257            uint32_t flags, uint32_t *stride, void **map_data)
258 {
259    struct drm_mode_map_dumb arg;
260    struct gbm_device *gbm_dev;
261    void *map;
262    int fd, ret;
263 
264    if (!bo || !map_data || width <= 0 || width > gbm_bo_get_width(bo) ||
265        height <= 0 || height > gbm_bo_get_height(bo)) {
266       errno = EINVAL;
267       return MAP_FAILED;
268    }
269 
270    gbm_dev = gbm_bo_get_device(bo);
271    if (!gbm_dev)
272       return MAP_FAILED;
273 
274    fd = gbm_device_get_fd(gbm_dev);
275    if (fd < 0)
276       return MAP_FAILED;
277 
278    memset(&arg, 0, sizeof(arg));
279    arg.handle = gbm_bo_get_handle(bo).u32;
280    ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
281    if (ret)
282       return MAP_FAILED;
283 
284    map = mmap(NULL, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo),
285               PROT_READ | PROT_WRITE, MAP_SHARED, fd, arg.offset);
286    if (map == MAP_FAILED)
287       return map;
288 
289    *map_data = map;
290 
291    if (stride)
292       *stride = gbm_bo_get_stride(bo);
293 
294    return map + y * gbm_bo_get_stride(bo) + x * (gbm_bo_get_bpp(bo) >> 3);
295 }
296 #endif
297 
298 #ifndef HAS_gbm_bo_unmap
299 void
gbm_bo_unmap(struct gbm_bo * bo,void * map_data)300 gbm_bo_unmap(struct gbm_bo *bo, void *map_data)
301 {
302    if (map_data)
303       munmap(map_data, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo));
304 }
305 #endif
306 
307 /* From mesa3d 20.1.5 : src/gbm/main/gbm.c */
308 #ifndef HAS_gbm_bo_get_bpp
309 uint32_t
gbm_bo_get_bpp(struct gbm_bo * bo)310 gbm_bo_get_bpp(struct gbm_bo *bo)
311 {
312    switch (gbm_bo_get_format(bo)) {
313    default:
314       return 0;
315    case GBM_FORMAT_C8:
316    case GBM_FORMAT_R8:
317    case GBM_FORMAT_RGB332:
318    case GBM_FORMAT_BGR233:
319       return 8;
320    case GBM_FORMAT_GR88:
321    case GBM_FORMAT_XRGB4444:
322    case GBM_FORMAT_XBGR4444:
323    case GBM_FORMAT_RGBX4444:
324    case GBM_FORMAT_BGRX4444:
325    case GBM_FORMAT_ARGB4444:
326    case GBM_FORMAT_ABGR4444:
327    case GBM_FORMAT_RGBA4444:
328    case GBM_FORMAT_BGRA4444:
329    case GBM_FORMAT_XRGB1555:
330    case GBM_FORMAT_XBGR1555:
331    case GBM_FORMAT_RGBX5551:
332    case GBM_FORMAT_BGRX5551:
333    case GBM_FORMAT_ARGB1555:
334    case GBM_FORMAT_ABGR1555:
335    case GBM_FORMAT_RGBA5551:
336    case GBM_FORMAT_BGRA5551:
337    case GBM_FORMAT_RGB565:
338    case GBM_FORMAT_BGR565:
339       return 16;
340    case GBM_FORMAT_RGB888:
341    case GBM_FORMAT_BGR888:
342       return 24;
343    case GBM_FORMAT_XRGB8888:
344    case GBM_FORMAT_XBGR8888:
345    case GBM_FORMAT_RGBX8888:
346    case GBM_FORMAT_BGRX8888:
347    case GBM_FORMAT_ARGB8888:
348    case GBM_FORMAT_ABGR8888:
349    case GBM_FORMAT_RGBA8888:
350    case GBM_FORMAT_BGRA8888:
351    case GBM_FORMAT_XRGB2101010:
352    case GBM_FORMAT_XBGR2101010:
353    case GBM_FORMAT_RGBX1010102:
354    case GBM_FORMAT_BGRX1010102:
355    case GBM_FORMAT_ARGB2101010:
356    case GBM_FORMAT_ABGR2101010:
357    case GBM_FORMAT_RGBA1010102:
358    case GBM_FORMAT_BGRA1010102:
359       return 32;
360    case GBM_FORMAT_XBGR16161616F:
361    case GBM_FORMAT_ABGR16161616F:
362       return 64;
363    }
364 }
365 #endif
366 
367 /* From mesa3d 20.1.5 : src/gbm/main/gbm.c */
368 #ifndef HAS_gbm_format_get_name
369 static uint32_t
gbm_format_canonicalize(uint32_t gbm_format)370 gbm_format_canonicalize(uint32_t gbm_format)
371 {
372    switch (gbm_format) {
373    case GBM_BO_FORMAT_XRGB8888:
374       return GBM_FORMAT_XRGB8888;
375    case GBM_BO_FORMAT_ARGB8888:
376       return GBM_FORMAT_ARGB8888;
377    default:
378       return gbm_format;
379    }
380 }
381 
382 char *
gbm_format_get_name(uint32_t gbm_format,struct gbm_format_name_desc * desc)383 gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc)
384 {
385    gbm_format = gbm_format_canonicalize(gbm_format);
386 
387    desc->name[0] = gbm_format;
388    desc->name[1] = gbm_format >> 8;
389    desc->name[2] = gbm_format >> 16;
390    desc->name[3] = gbm_format >> 24;
391    desc->name[4] = 0;
392 
393    return desc->name;
394 }
395 #endif
396 
397 /* Wrappers for invalid modifier */
398 
399 uint64_t
gbm_bo_get_modifier(struct gbm_bo * bo)400 gbm_bo_get_modifier(struct gbm_bo *bo)
401 {
402 #ifdef HAS_gbm_bo_get_modifier
403    uint64_t modifier = _gbm_bo_get_modifier(bo);
404    if (modifier != DRM_FORMAT_MOD_INVALID)
405       return modifier;
406 #endif
407    return DRM_FORMAT_MOD_LINEAR;
408 }
409 
410 /* Wrappers for unsupported flags */
411 
412 struct gbm_surface *
gbm_surface_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)413 gbm_surface_create(struct gbm_device *gbm,
414                    uint32_t width, uint32_t height,
415                    uint32_t format, uint32_t flags)
416 {
417    struct gbm_surface *surface;
418 
419    surface = _gbm_surface_create(gbm, width, height, format, flags);
420    if (surface)
421       return surface;
422 
423    flags &= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
424    return _gbm_surface_create(gbm, width, height, format, flags);
425 }
426 
427 struct gbm_bo *
gbm_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)428 gbm_bo_create(struct gbm_device *gbm,
429               uint32_t width, uint32_t height,
430               uint32_t format, uint32_t flags)
431 {
432    struct gbm_bo *bo;
433 
434    bo = _gbm_bo_create(gbm, width, height, format, flags);
435    if (bo)
436       return bo;
437 
438    flags &= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING |
439       GBM_BO_USE_WRITE | GBM_BO_USE_CURSOR_64X64;
440    return _gbm_bo_create(gbm, width, height, format, flags);
441 }
442 
443 #endif // HAS_GBM
444 
445 #ifdef HAS_EGL
446 #ifdef HAS_X11
447 
448 /* Hacked displays (should not be much) */
449 #define MAX_X11_DISPLAY 32
450 static Display *_x11_displays[MAX_X11_DISPLAY] = { NULL, };
451 
452 static pthread_mutex_t _x11_mutex = PTHREAD_MUTEX_INITIALIZER;
453 
454 static inline int
force_x11_threads(void)455 force_x11_threads(void)
456 {
457    return !getenv("MALI_X11_NO_FORCE_THREADS");
458 }
459 
460 __attribute__((constructor)) static void
init_x11_threads(void)461 init_x11_threads(void)
462 {
463    if (force_x11_threads())
464       XInitThreads();
465 }
466 
467 __attribute__((destructor)) static void
cleanup_x11_display(void)468 cleanup_x11_display(void)
469 {
470    int i;
471 
472    for (i = 0; i < MAX_X11_DISPLAY; i++) {
473       Display *display = _x11_displays[i];
474       if (display)
475          XCloseDisplay(display);
476    }
477 }
478 
479 static Display *
fixup_x11_display(Display * display)480 fixup_x11_display(Display *display)
481 {
482    int i;
483 
484    if (!force_x11_threads())
485       return display;
486 
487    if (!display || display->lock_fns)
488       return display;
489 
490    pthread_mutex_lock(&_x11_mutex);
491    /* Create a new threaded display */
492    display = XOpenDisplay(DisplayString(display));
493 
494    for (i = 0; i < MAX_X11_DISPLAY; i++) {
495       if (!_x11_displays[i]) {
496          _x11_displays[i] = display;
497          break;
498       }
499    }
500    pthread_mutex_unlock(&_x11_mutex);
501 
502    return display;
503 }
504 
505 /* Override EGL symbols */
506 
507 EGLAPI EGLDisplay EGLAPIENTRY
eglGetPlatformDisplay(EGLenum platform,void * native_display,const EGLAttrib * attrib_list)508 eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list)
509 {
510    if (!_eglGetPlatformDisplay)
511       return EGL_NO_DISPLAY;
512 
513    if (platform == EGL_PLATFORM_X11_KHR && native_display) {
514       native_display = (void *)fixup_x11_display(native_display);
515       if (!native_display)
516          return EGL_NO_DISPLAY;
517    }
518 
519    return _eglGetPlatformDisplay(platform, native_display, attrib_list);
520 }
521 
522 EGLAPI EGLDisplay EGLAPIENTRY
eglGetPlatformDisplayEXT(EGLenum platform,void * native_display,const EGLint * attrib_list)523 eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list)
524 {
525    if (!_eglGetPlatformDisplayEXT)
526       return EGL_NO_DISPLAY;
527 
528    if (platform == EGL_PLATFORM_X11_KHR && native_display) {
529       native_display = (void *)fixup_x11_display(native_display);
530       if (!native_display)
531          return EGL_NO_DISPLAY;
532    }
533 
534    return _eglGetPlatformDisplayEXT(platform, native_display, attrib_list);
535 }
536 
537 EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
eglGetProcAddress(const char * procname)538 eglGetProcAddress(const char *procname)
539 {
540    if (!procname)
541       return NULL;
542 
543    if (!strcmp(procname, __func__))
544       return (__eglMustCastToProperFunctionPointerType)eglGetProcAddress;
545 
546    if (!strcmp(procname, "eglGetDisplay"))
547       return (__eglMustCastToProperFunctionPointerType)eglGetDisplay;
548 
549    if (!strcmp(procname, "eglGetPlatformDisplay")) {
550       if (!_eglGetPlatformDisplay)
551          return NULL;
552       return (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplay;
553    }
554 
555    if (!strcmp(procname, "eglGetPlatformDisplayEXT")) {
556       if (!_eglGetPlatformDisplayEXT)
557          return NULL;
558       return (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplayEXT;
559    }
560 
561    return _eglGetProcAddress(procname);
562 }
563 
564 #endif // HAS_X11
565 
566 EGLAPI EGLDisplay EGLAPIENTRY
eglGetDisplay(EGLNativeDisplayType display_id)567 eglGetDisplay (EGLNativeDisplayType display_id)
568 {
569     const char *type = getenv("MALI_DEFAULT_WINSYS");
570 
571     static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
572     if (!get_platform_display)
573         get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
574             eglGetProcAddress("eglGetPlatformDisplayEXT");
575     if (!get_platform_display)
576         goto bail;
577 
578 #ifdef HAS_GBM
579     if (type && !strcmp(type, "gbm"))
580         return get_platform_display(EGL_PLATFORM_GBM_KHR, display_id, NULL);
581 #endif
582 
583 #ifdef HAS_WAYLAND
584     if (type && !strcmp(type, "wayland"))
585         return get_platform_display(EGL_PLATFORM_WAYLAND_EXT, display_id, NULL);
586 #endif
587 
588 #ifdef HAS_X11
589     /* Use X11 by default when avaiable */
590     return get_platform_display(EGL_PLATFORM_X11_KHR, display_id, NULL);
591 #endif
592 
593 bail:
594     return _eglGetDisplay(display_id);
595 }
596 
597 #endif // HAS_EGL
598