• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018 Broadcom
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file
26  *
27  * Implements wrappers of libc functions to fake having a DRM device that
28  * isn't actually present in the kernel.
29  */
30 
31 /* Prevent glibc from defining open64 when we want to alias it. */
32 #undef _FILE_OFFSET_BITS
33 #define _LARGEFILE64_SOURCE
34 
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/ioctl.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <sys/sysmacros.h>
44 #include <stdarg.h>
45 #include <fcntl.h>
46 #include <dlfcn.h>
47 #include <dirent.h>
48 #include <c11/threads.h>
49 #include <drm-uapi/drm.h>
50 
51 #include "util/set.h"
52 #include "util/u_debug.h"
53 #include "drm_shim.h"
54 
55 #define REAL_FUNCTION_POINTER(x) __typeof__(x) *real_##x
56 
57 static mtx_t shim_lock = _MTX_INITIALIZER_NP;
58 struct set *opendir_set;
59 bool drm_shim_debug;
60 
61 /* If /dev/dri doesn't exist, we'll need an arbitrary pointer that wouldn't be
62  * returned by any other opendir() call so we can return just our fake node.
63  */
64 DIR *fake_dev_dri = (void *)&opendir_set;
65 
66 REAL_FUNCTION_POINTER(close);
67 REAL_FUNCTION_POINTER(closedir);
68 REAL_FUNCTION_POINTER(dup);
69 REAL_FUNCTION_POINTER(fcntl);
70 REAL_FUNCTION_POINTER(fopen);
71 REAL_FUNCTION_POINTER(ioctl);
72 REAL_FUNCTION_POINTER(mmap);
73 REAL_FUNCTION_POINTER(mmap64);
74 REAL_FUNCTION_POINTER(open);
75 REAL_FUNCTION_POINTER(opendir);
76 REAL_FUNCTION_POINTER(readdir);
77 REAL_FUNCTION_POINTER(readdir64);
78 REAL_FUNCTION_POINTER(readlink);
79 REAL_FUNCTION_POINTER(realpath);
80 
81 #define HAS_XSTAT __GLIBC__ == 2 && __GLIBC_MINOR__ < 33
82 
83 #if HAS_XSTAT
84 REAL_FUNCTION_POINTER(__xstat);
85 REAL_FUNCTION_POINTER(__xstat64);
86 REAL_FUNCTION_POINTER(__fxstat);
87 REAL_FUNCTION_POINTER(__fxstat64);
88 #else
89 REAL_FUNCTION_POINTER(stat);
90 REAL_FUNCTION_POINTER(stat64);
91 REAL_FUNCTION_POINTER(fstat);
92 REAL_FUNCTION_POINTER(fstat64);
93 #endif
94 
95 /* Full path of /dev/dri/renderD* */
96 static char *render_node_path;
97 /* renderD* */
98 static char *render_node_dirent_name;
99 /* /sys/dev/char/major:minor/device */
100 static char *device_path;
101 /* /sys/dev/char/major:minor/device/subsystem */
102 static char *subsystem_path;
103 int render_node_minor = -1;
104 
105 struct file_override {
106    const char *path;
107    char *contents;
108 };
109 static struct file_override file_overrides[10];
110 static int file_overrides_count;
111 extern bool drm_shim_driver_prefers_first_render_node;
112 
113 #define nfasprintf(...)                         \
114    {                                            \
115       UNUSED int __ret = asprintf(__VA_ARGS__); \
116       assert(__ret >= 0);                       \
117    }
118 #define nfvasprintf(...)                         \
119    {                                             \
120       UNUSED int __ret = vasprintf(__VA_ARGS__); \
121       assert(__ret >= 0);                        \
122    }
123 
124 /* Pick the minor and filename for our shimmed render node.  This can be
125  * either a new one that didn't exist on the system, or if the driver wants,
126  * it can replace the first render node.
127  */
128 static void
get_dri_render_node_minor(void)129 get_dri_render_node_minor(void)
130 {
131    for (int i = 0; i < 10; i++) {
132       UNUSED int minor = 128 + i;
133       nfasprintf(&render_node_dirent_name, "renderD%d", minor);
134       nfasprintf(&render_node_path, "/dev/dri/%s",
135                  render_node_dirent_name);
136       struct stat st;
137       if (drm_shim_driver_prefers_first_render_node ||
138           stat(render_node_path, &st) == -1) {
139 
140          render_node_minor = minor;
141          return;
142       }
143    }
144 
145    fprintf(stderr, "Couldn't find a spare render node slot\n");
146 }
147 
get_function_pointer(const char * name)148 static void *get_function_pointer(const char *name)
149 {
150    void *func = dlsym(RTLD_NEXT, name);
151    if (!func) {
152       fprintf(stderr, "Failed to resolve %s\n", name);
153       abort();
154    }
155    return func;
156 }
157 
158 #define GET_FUNCTION_POINTER(x) real_##x = get_function_pointer(#x)
159 
160 void
drm_shim_override_file(const char * contents,const char * path_format,...)161 drm_shim_override_file(const char *contents, const char *path_format, ...)
162 {
163    assert(file_overrides_count < ARRAY_SIZE(file_overrides));
164 
165    char *path;
166    va_list ap;
167    va_start(ap, path_format);
168    nfvasprintf(&path, path_format, ap);
169    va_end(ap);
170 
171    struct file_override *override = &file_overrides[file_overrides_count++];
172    override->path = path;
173    override->contents = strdup(contents);
174 }
175 
176 static void
destroy_shim(void)177 destroy_shim(void)
178 {
179    _mesa_set_destroy(opendir_set, NULL);
180    free(render_node_path);
181    free(render_node_dirent_name);
182    free(subsystem_path);
183 }
184 
185 /* Initialization, which will be called from the first general library call
186  * that might need to be wrapped with the shim.
187  */
188 static void
init_shim(void)189 init_shim(void)
190 {
191    static bool inited = false;
192    drm_shim_debug = debug_get_bool_option("DRM_SHIM_DEBUG", false);
193 
194    /* We can't lock this, because we recurse during initialization. */
195    if (inited)
196       return;
197 
198    /* This comes first (and we're locked), to make sure we don't recurse
199     * during initialization.
200     */
201    inited = true;
202 
203    opendir_set = _mesa_set_create(NULL,
204                                   _mesa_hash_string,
205                                   _mesa_key_string_equal);
206 
207    GET_FUNCTION_POINTER(close);
208    GET_FUNCTION_POINTER(closedir);
209    GET_FUNCTION_POINTER(dup);
210    GET_FUNCTION_POINTER(fcntl);
211    GET_FUNCTION_POINTER(fopen);
212    GET_FUNCTION_POINTER(ioctl);
213    GET_FUNCTION_POINTER(mmap);
214    GET_FUNCTION_POINTER(mmap64);
215    GET_FUNCTION_POINTER(open);
216    GET_FUNCTION_POINTER(opendir);
217    GET_FUNCTION_POINTER(readdir);
218    GET_FUNCTION_POINTER(readdir64);
219    GET_FUNCTION_POINTER(readlink);
220    GET_FUNCTION_POINTER(realpath);
221 
222 #if HAS_XSTAT
223    GET_FUNCTION_POINTER(__xstat);
224    GET_FUNCTION_POINTER(__xstat64);
225    GET_FUNCTION_POINTER(__fxstat);
226    GET_FUNCTION_POINTER(__fxstat64);
227 #else
228    GET_FUNCTION_POINTER(stat);
229    GET_FUNCTION_POINTER(stat64);
230    GET_FUNCTION_POINTER(fstat);
231    GET_FUNCTION_POINTER(fstat64);
232 #endif
233 
234    get_dri_render_node_minor();
235 
236    if (drm_shim_debug) {
237       fprintf(stderr, "Initializing DRM shim on %s\n",
238               render_node_path);
239    }
240 
241    nfasprintf(&device_path,
242               "/sys/dev/char/%d:%d/device",
243               DRM_MAJOR, render_node_minor);
244 
245    nfasprintf(&subsystem_path,
246               "/sys/dev/char/%d:%d/device/subsystem",
247               DRM_MAJOR, render_node_minor);
248 
249    drm_shim_device_init();
250 
251    atexit(destroy_shim);
252 }
253 
254 /* Override libdrm's reading of various sysfs files for device enumeration. */
fopen(const char * path,const char * mode)255 PUBLIC FILE *fopen(const char *path, const char *mode)
256 {
257    init_shim();
258 
259    for (int i = 0; i < file_overrides_count; i++) {
260       if (strcmp(file_overrides[i].path, path) == 0) {
261          int fds[2];
262          pipe(fds);
263          write(fds[1], file_overrides[i].contents,
264                strlen(file_overrides[i].contents));
265          close(fds[1]);
266          return fdopen(fds[0], "r");
267       }
268    }
269 
270    return real_fopen(path, mode);
271 }
272 PUBLIC FILE *fopen64(const char *path, const char *mode)
273    __attribute__((alias("fopen")));
274 
275 /* Intercepts open(render_node_path) to redirect it to the simulator. */
open(const char * path,int flags,...)276 PUBLIC int open(const char *path, int flags, ...)
277 {
278    init_shim();
279 
280    va_list ap;
281    va_start(ap, flags);
282    mode_t mode = va_arg(ap, mode_t);
283    va_end(ap);
284 
285    if (strcmp(path, render_node_path) != 0)
286       return real_open(path, flags, mode);
287 
288    int fd = real_open("/dev/null", O_RDWR, 0);
289 
290    drm_shim_fd_register(fd, NULL);
291 
292    return fd;
293 }
294 PUBLIC int open64(const char*, int, ...) __attribute__((alias("open")));
295 
close(int fd)296 PUBLIC int close(int fd)
297 {
298    init_shim();
299 
300    drm_shim_fd_unregister(fd);
301 
302    return real_close(fd);
303 }
304 
305 #if HAS_XSTAT
306 /* Fakes stat to return character device stuff for our fake render node. */
__xstat(int ver,const char * path,struct stat * st)307 PUBLIC int __xstat(int ver, const char *path, struct stat *st)
308 {
309    init_shim();
310 
311    /* Note: call real stat if we're in the process of probing for a free
312     * render node!
313     */
314    if (render_node_minor == -1)
315       return real___xstat(ver, path, st);
316 
317    /* Fool libdrm's probe of whether the /sys dir for this char dev is
318     * there.
319     */
320    char *sys_dev_drm_dir;
321    nfasprintf(&sys_dev_drm_dir,
322               "/sys/dev/char/%d:%d/device/drm",
323               DRM_MAJOR, render_node_minor);
324    if (strcmp(path, sys_dev_drm_dir) == 0) {
325       free(sys_dev_drm_dir);
326       return 0;
327    }
328    free(sys_dev_drm_dir);
329 
330    if (strcmp(path, render_node_path) != 0)
331       return real___xstat(ver, path, st);
332 
333    memset(st, 0, sizeof(*st));
334    st->st_rdev = makedev(DRM_MAJOR, render_node_minor);
335    st->st_mode = S_IFCHR;
336 
337    return 0;
338 }
339 
340 /* Fakes stat to return character device stuff for our fake render node. */
__xstat64(int ver,const char * path,struct stat64 * st)341 PUBLIC int __xstat64(int ver, const char *path, struct stat64 *st)
342 {
343    init_shim();
344 
345    /* Note: call real stat if we're in the process of probing for a free
346     * render node!
347     */
348    if (render_node_minor == -1)
349       return real___xstat64(ver, path, st);
350 
351    /* Fool libdrm's probe of whether the /sys dir for this char dev is
352     * there.
353     */
354    char *sys_dev_drm_dir;
355    nfasprintf(&sys_dev_drm_dir,
356               "/sys/dev/char/%d:%d/device/drm",
357               DRM_MAJOR, render_node_minor);
358    if (strcmp(path, sys_dev_drm_dir) == 0) {
359       free(sys_dev_drm_dir);
360       return 0;
361    }
362    free(sys_dev_drm_dir);
363 
364    if (strcmp(path, render_node_path) != 0)
365       return real___xstat64(ver, path, st);
366 
367    memset(st, 0, sizeof(*st));
368    st->st_rdev = makedev(DRM_MAJOR, render_node_minor);
369    st->st_mode = S_IFCHR;
370 
371    return 0;
372 }
373 
374 /* Fakes fstat to return character device stuff for our fake render node. */
__fxstat(int ver,int fd,struct stat * st)375 PUBLIC int __fxstat(int ver, int fd, struct stat *st)
376 {
377    init_shim();
378 
379    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
380 
381    if (!shim_fd)
382       return real___fxstat(ver, fd, st);
383 
384    memset(st, 0, sizeof(*st));
385    st->st_rdev = makedev(DRM_MAJOR, render_node_minor);
386    st->st_mode = S_IFCHR;
387 
388    return 0;
389 }
390 
__fxstat64(int ver,int fd,struct stat64 * st)391 PUBLIC int __fxstat64(int ver, int fd, struct stat64 *st)
392 {
393    init_shim();
394 
395    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
396 
397    if (!shim_fd)
398       return real___fxstat64(ver, fd, st);
399 
400    memset(st, 0, sizeof(*st));
401    st->st_rdev = makedev(DRM_MAJOR, render_node_minor);
402    st->st_mode = S_IFCHR;
403 
404    return 0;
405 }
406 
407 #else
408 
stat(const char * path,struct stat * stat_buf)409 PUBLIC int stat(const char* path, struct stat* stat_buf)
410 {
411    init_shim();
412 
413    /* Note: call real stat if we're in the process of probing for a free
414     * render node!
415     */
416    if (render_node_minor == -1)
417       return real_stat(path, stat_buf);
418 
419    /* Fool libdrm's probe of whether the /sys dir for this char dev is
420     * there.
421     */
422    char *sys_dev_drm_dir;
423    nfasprintf(&sys_dev_drm_dir,
424               "/sys/dev/char/%d:%d/device/drm",
425               DRM_MAJOR, render_node_minor);
426    if (strcmp(path, sys_dev_drm_dir) == 0) {
427       free(sys_dev_drm_dir);
428       return 0;
429    }
430    free(sys_dev_drm_dir);
431 
432    if (strcmp(path, render_node_path) != 0)
433       return real_stat(path, stat_buf);
434 
435    memset(stat_buf, 0, sizeof(*stat_buf));
436    stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
437    stat_buf->st_mode = S_IFCHR;
438 
439    return 0;
440 }
441 
stat64(const char * path,struct stat64 * stat_buf)442 PUBLIC int stat64(const char* path, struct stat64* stat_buf)
443 {
444    init_shim();
445 
446    /* Note: call real stat if we're in the process of probing for a free
447     * render node!
448     */
449    if (render_node_minor == -1)
450       return real_stat64(path, stat_buf);
451 
452    /* Fool libdrm's probe of whether the /sys dir for this char dev is
453     * there.
454     */
455    char *sys_dev_drm_dir;
456    nfasprintf(&sys_dev_drm_dir,
457               "/sys/dev/char/%d:%d/device/drm",
458               DRM_MAJOR, render_node_minor);
459    if (strcmp(path, sys_dev_drm_dir) == 0) {
460       free(sys_dev_drm_dir);
461       return 0;
462    }
463    free(sys_dev_drm_dir);
464 
465    if (strcmp(path, render_node_path) != 0)
466       return real_stat64(path, stat_buf);
467 
468    memset(stat_buf, 0, sizeof(*stat_buf));
469    stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
470    stat_buf->st_mode = S_IFCHR;
471 
472    return 0;
473 }
474 
fstat(int fd,struct stat * stat_buf)475 PUBLIC int fstat(int fd, struct stat* stat_buf)
476 {
477    init_shim();
478 
479    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
480 
481    if (!shim_fd)
482       return real_fstat(fd, stat_buf);
483 
484    memset(stat_buf, 0, sizeof(*stat_buf));
485    stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
486    stat_buf->st_mode = S_IFCHR;
487 
488    return 0;
489 }
490 
fstat64(int fd,struct stat64 * stat_buf)491 PUBLIC int fstat64(int fd, struct stat64* stat_buf)
492 {
493    init_shim();
494 
495    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
496 
497    if (!shim_fd)
498       return real_fstat64(fd, stat_buf);
499 
500    memset(stat_buf, 0, sizeof(*stat_buf));
501    stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
502    stat_buf->st_mode = S_IFCHR;
503 
504    return 0;
505 }
506 #endif
507 
508 /* Tracks if the opendir was on /dev/dri. */
509 PUBLIC DIR *
opendir(const char * name)510 opendir(const char *name)
511 {
512    init_shim();
513 
514    DIR *dir = real_opendir(name);
515    if (strcmp(name, "/dev/dri") == 0) {
516       if (!dir) {
517          /* If /dev/dri didn't exist, we still want to be able to return our
518           * fake /dev/dri/render* even though we probably can't
519           * mkdir("/dev/dri").  Return a fake DIR pointer for that.
520           */
521          dir = fake_dev_dri;
522       }
523 
524       mtx_lock(&shim_lock);
525       _mesa_set_add(opendir_set, dir);
526       mtx_unlock(&shim_lock);
527    }
528 
529    return dir;
530 }
531 
532 /* If we're looking at /dev/dri, add our render node to the list
533  * before the real entries in the directory.
534  */
535 PUBLIC struct dirent *
readdir(DIR * dir)536 readdir(DIR *dir)
537 {
538    init_shim();
539 
540    struct dirent *ent = NULL;
541 
542    static struct dirent render_node_dirent = { 0 };
543 
544    mtx_lock(&shim_lock);
545    if (_mesa_set_search(opendir_set, dir)) {
546       strcpy(render_node_dirent.d_name,
547              render_node_dirent_name);
548       ent = &render_node_dirent;
549       _mesa_set_remove_key(opendir_set, dir);
550    }
551    mtx_unlock(&shim_lock);
552 
553    if (!ent && dir != fake_dev_dri)
554       ent = real_readdir(dir);
555 
556    return ent;
557 }
558 
559 /* If we're looking at /dev/dri, add our render node to the list
560  * before the real entries in the directory.
561  */
562 PUBLIC struct dirent64 *
readdir64(DIR * dir)563 readdir64(DIR *dir)
564 {
565    init_shim();
566 
567    struct dirent64 *ent = NULL;
568 
569    static struct dirent64 render_node_dirent = { 0 };
570 
571    mtx_lock(&shim_lock);
572    if (_mesa_set_search(opendir_set, dir)) {
573       strcpy(render_node_dirent.d_name,
574              render_node_dirent_name);
575       ent = &render_node_dirent;
576       _mesa_set_remove_key(opendir_set, dir);
577    }
578    mtx_unlock(&shim_lock);
579 
580    if (!ent && dir != fake_dev_dri)
581       ent = real_readdir64(dir);
582 
583    return ent;
584 }
585 
586 /* Cleans up tracking of opendir("/dev/dri") */
587 PUBLIC int
closedir(DIR * dir)588 closedir(DIR *dir)
589 {
590    init_shim();
591 
592    mtx_lock(&shim_lock);
593    _mesa_set_remove_key(opendir_set, dir);
594    mtx_unlock(&shim_lock);
595 
596    if (dir != fake_dev_dri)
597       return real_closedir(dir);
598    else
599       return 0;
600 }
601 
602 /* Handles libdrm's readlink to figure out what kind of device we have. */
603 PUBLIC ssize_t
readlink(const char * path,char * buf,size_t size)604 readlink(const char *path, char *buf, size_t size)
605 {
606    init_shim();
607 
608    if (strcmp(path, subsystem_path) != 0)
609       return real_readlink(path, buf, size);
610 
611    static const struct {
612       const char *name;
613       int bus_type;
614    } bus_types[] = {
615       { "/pci", DRM_BUS_PCI },
616       { "/usb", DRM_BUS_USB },
617       { "/platform", DRM_BUS_PLATFORM },
618       { "/spi", DRM_BUS_PLATFORM },
619       { "/host1x", DRM_BUS_HOST1X },
620    };
621 
622    for (uint32_t i = 0; i < ARRAY_SIZE(bus_types); i++) {
623       if (bus_types[i].bus_type != shim_device.bus_type)
624          continue;
625 
626       strncpy(buf, bus_types[i].name, size);
627       buf[size - 1] = 0;
628       break;
629    }
630 
631    return strlen(buf) + 1;
632 }
633 
634 /* Handles libdrm's realpath to figure out what kind of device we have. */
635 PUBLIC char *
realpath(const char * path,char * resolved_path)636 realpath(const char *path, char *resolved_path)
637 {
638    init_shim();
639 
640    if (strcmp(path, device_path) != 0)
641       return real_realpath(path, resolved_path);
642 
643    strcpy(resolved_path, path);
644 
645    return resolved_path;
646 }
647 
648 /* Main entrypoint to DRM drivers: the ioctl syscall.  We send all ioctls on
649  * our DRM fd to drm_shim_ioctl().
650  */
651 PUBLIC int
ioctl(int fd,unsigned long request,...)652 ioctl(int fd, unsigned long request, ...)
653 {
654    init_shim();
655 
656    va_list ap;
657    va_start(ap, request);
658    void *arg = va_arg(ap, void *);
659    va_end(ap);
660 
661    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
662    if (!shim_fd)
663       return real_ioctl(fd, request, arg);
664 
665    return drm_shim_ioctl(fd, request, arg);
666 }
667 
668 /* Gallium uses this to dup the incoming fd on gbm screen creation */
669 PUBLIC int
fcntl(int fd,int cmd,...)670 fcntl(int fd, int cmd, ...)
671 {
672    init_shim();
673 
674    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
675 
676    va_list ap;
677    va_start(ap, cmd);
678    void *arg = va_arg(ap, void *);
679    va_end(ap);
680 
681    int ret = real_fcntl(fd, cmd, arg);
682 
683    if (shim_fd && (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC))
684       drm_shim_fd_register(ret, shim_fd);
685 
686    return ret;
687 }
688 PUBLIC int fcntl64(int, int, ...)
689    __attribute__((alias("fcntl")));
690 
691 /* I wrote this when trying to fix gallium screen creation, leaving it around
692  * since it's probably good to have.
693  */
694 PUBLIC int
dup(int fd)695 dup(int fd)
696 {
697    init_shim();
698 
699    int ret = real_dup(fd);
700 
701    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
702    if (shim_fd && ret >= 0)
703       drm_shim_fd_register(ret, shim_fd);
704 
705    return ret;
706 }
707 
708 PUBLIC void *
mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)709 mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
710 {
711    init_shim();
712 
713    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
714    if (shim_fd)
715       return drm_shim_mmap(shim_fd, length, prot, flags, fd, offset);
716 
717    return real_mmap(addr, length, prot, flags, fd, offset);
718 }
719 
720 PUBLIC void *
mmap64(void * addr,size_t length,int prot,int flags,int fd,off64_t offset)721 mmap64(void* addr, size_t length, int prot, int flags, int fd, off64_t offset)
722 {
723    init_shim();
724 
725    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
726    if (shim_fd)
727       return drm_shim_mmap(shim_fd, length, prot, flags, fd, offset);
728 
729    return real_mmap64(addr, length, prot, flags, fd, offset);
730 }
731