blob: 6dd80738e78f0b717ae294d4ebf267a8bb9fb384 [file] [log] [blame]
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +00001/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * This is a test meant to exercise the VGEM DRM kernel module's PRIME
6 * import/export functions. It will create a gem buffer object, mmap, write, and
7 * then verify it. Then the test will repeat that with the same gem buffer, but
8 * exported and then imported. Finally, a new gem buffer object is made in a
9 * different driver which exports into VGEM and the mmap, write, verify sequence
10 * is repeated on that.
11 */
12
13#define _GNU_SOURCE
14#include <assert.h>
15#include <fcntl.h>
16#include <stdbool.h>
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/mman.h>
22#include <sys/ioctl.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26#include <errno.h>
27#include <xf86drm.h>
28#include <linux/udmabuf.h>
29
30#include "bs_drm.h"
31
32#define HANDLE_EINTR_AND_EAGAIN(x) \
33 ({ \
34 int result; \
35 do { \
36 result = (x); \
37 } while (result != -1 && (errno == EINTR || errno == EAGAIN)); \
38 result; \
39 })
40
41#define fail_if(cond, ...) \
42 do { \
43 if (cond) { \
44 bs_debug_print("FAIL", __func__, __FILE__, __LINE__, __VA_ARGS__); \
45 exit(EXIT_FAILURE); \
46 } \
47 } while (0)
48
49const uint32_t g_bo_pattern = 0xdeadbeef;
50
51void *mmap_dumb_bo(int fd, int handle, size_t size)
52{
53 struct drm_mode_map_dumb mmap_arg;
54 void *ptr;
55 int ret;
56
57 memset(&mmap_arg, 0, sizeof(mmap_arg));
58
59 mmap_arg.handle = handle;
60
61 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg);
62 assert(ret == 0);
63 assert(mmap_arg.offset != 0);
64
65 ptr = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, mmap_arg.offset);
66
67 return ptr;
68}
69
70void write_pattern(uint32_t *bo_ptr, size_t bo_size)
71{
72 uint32_t *ptr;
73
74 for (ptr = bo_ptr; ptr < bo_ptr + (bo_size / sizeof(*bo_ptr)); ptr++) {
75 *ptr = g_bo_pattern;
76 }
77}
78
79bool verify_pattern(uint32_t *bo_ptr, size_t bo_size)
80{
81 uint32_t *ptr;
82
83 for (ptr = bo_ptr; ptr < bo_ptr + (bo_size / sizeof(*bo_ptr)); ptr++) {
84 fail_if(*ptr != g_bo_pattern, "buffer object verify");
85 }
86
87 return true;
88}
89
90int create_udmabuf(int fd, size_t length)
91{
92 int udmabuf_dev_fd = HANDLE_EINTR_AND_EAGAIN(open("/dev/udmabuf", O_RDWR));
93 fail_if(udmabuf_dev_fd < 0, "error opening /dev/udmabuf");
94
95 struct udmabuf_create create;
96 create.memfd = fd;
97 create.flags = UDMABUF_FLAGS_CLOEXEC;
98 create.offset = 0;
99 create.size = length;
100
101 int dmabuf_fd = HANDLE_EINTR_AND_EAGAIN(ioctl(udmabuf_dev_fd, UDMABUF_CREATE, &create));
102 fail_if(dmabuf_fd < 0, "error creating udmabuf");
103
104 close(udmabuf_dev_fd);
105 return dmabuf_fd;
106}
107
108int create_memfd(size_t length)
109{
110 int fd = memfd_create("test memfd", MFD_ALLOW_SEALING);
111 fail_if(fd == -1, "memfd_create() error: %s", strerror(errno));
112
113 int res = HANDLE_EINTR_AND_EAGAIN(ftruncate(fd, length));
114 fail_if(res == -1, "ftruncate() error: %s", strerror(errno));
115
116 // udmabuf_create requires that file descriptors be sealed with
117 // F_SEAL_SHRINK.
118 fail_if(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK) < 0,
119 "fcntl() error: %s", strerror(errno));
120
121 return fd;
122}
123
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000124void test_import_dma_buf(int native_fd)
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000125{
126 int width = 256;
127 int height = 256;
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000128 int bpp = 4;
129 int stride = width * bpp;
130 size_t size = stride * height;
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000131
132 int memfd_fd = create_memfd(size);
133 fail_if(memfd_fd == -1, "failed to create memfd");
134
135 uint32_t *memfd_map =
136 mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, memfd_fd, 0);
137 fail_if(memfd_map == MAP_FAILED, "failed to mmap memfd");
138
139 write_pattern(memfd_map, size);
140 fail_if(!verify_pattern(memfd_map, size), "failed to verify pattern");
141
142 fail_if(munmap(memfd_map, size) != 0, "munmap failed");
143
144 int udmabuf_fd = create_udmabuf(memfd_fd, size);
145 fail_if(udmabuf_fd == -1, "failed to create udmabuf");
146
147 fail_if(close(memfd_fd) != 0, "close memfd failed");
148
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000149 uint32_t foreign_imported_handle;
150 fail_if(drmPrimeFDToHandle(native_fd, udmabuf_fd, &foreign_imported_handle) != 0,
151 "drmPrimeFDToHandle failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000152
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000153 uint32_t *bo_ptr =
154 mmap_dumb_bo(native_fd, foreign_imported_handle, size);
155 fail_if(bo_ptr == MAP_FAILED,
156 "failed to map imported buffer object\n");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000157
158 fail_if(close(udmabuf_fd) != 0, "failed to close udmabuf_fd");
159
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000160 fail_if(!verify_pattern(bo_ptr, size), "pattern mismatch after map");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000161}
162
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000163void test_export_dma_buf(int native_fd)
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000164{
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000165 struct drm_mode_create_dumb create;
166 uint32_t *bo_ptr;
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000167
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000168 memset(&create, 0, sizeof(create));
169 create.width = 640;
170 create.height = 480;
171 create.bpp = 32;
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000172
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000173 fail_if(drmIoctl(native_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create) != 0,
174 "failed to create dumb buffer object");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000175
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000176 bo_ptr = mmap_dumb_bo(native_fd, create.handle, create.size);
177 fail_if(bo_ptr == MAP_FAILED, "failed to map dumb bo");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000178
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000179 write_pattern(bo_ptr, create.size);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000180
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000181 munmap(bo_ptr, create.size);
182
183 int dmabuf_fd;
184 fail_if(drmPrimeHandleToFD(native_fd, create.handle, DRM_CLOEXEC | DRM_RDWR, &dmabuf_fd) != 0,
185 "drmPrimeHandleToFD failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000186
187 uint32_t *dmabuf_map =
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000188 mmap(NULL, create.size, PROT_WRITE | PROT_READ, MAP_SHARED, dmabuf_fd, 0);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000189 fail_if(dmabuf_map == MAP_FAILED, "failed to mmap memfd");
190
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000191 fail_if(!verify_pattern(dmabuf_map, create.size),
192 "pattern mismatch after gbm_bo_map");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000193
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000194 fail_if(munmap(dmabuf_map, create.size) != 0, "munmap failed");
195
196 fail_if(close(dmabuf_fd) != 0, "failed to close dmabuf_fd");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000197}
198
199int main(int argc, char *argv[])
200{
201 int fd = bs_drm_open_for_display();
202 fail_if(fd == -1, "error opening dri card");
203
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000204 test_import_dma_buf(fd);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000205
Kristian H. Kristensendfa86ce2020-11-20 15:44:57 +0000206 test_export_dma_buf(fd);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000207
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000208 close(fd);
209
210 return EXIT_SUCCESS;
211}