blob: fc8fc9dcf322a3d30854bfca529528a9f86dec8c [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. Kristensen032a9552020-11-25 19:07:31 +0000124void test_import_dma_buf(struct gbm_device *gbm)
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000125{
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000126 int width = 64;
127 int height = 64;
128 size_t size = width * height * 4;
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000129
130 int memfd_fd = create_memfd(size);
131 fail_if(memfd_fd == -1, "failed to create memfd");
132
133 uint32_t *memfd_map =
134 mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, memfd_fd, 0);
135 fail_if(memfd_map == MAP_FAILED, "failed to mmap memfd");
136
137 write_pattern(memfd_map, size);
138 fail_if(!verify_pattern(memfd_map, size), "failed to verify pattern");
139
140 fail_if(munmap(memfd_map, size) != 0, "munmap failed");
141
142 int udmabuf_fd = create_udmabuf(memfd_fd, size);
143 fail_if(udmabuf_fd == -1, "failed to create udmabuf");
144
145 fail_if(close(memfd_fd) != 0, "close memfd failed");
146
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000147 struct gbm_import_fd_modifier_data gbm_import_data = {
148 .width = width,
149 .height = height,
150 .format = GBM_FORMAT_ARGB8888,
151 .num_fds = 1,
152 .fds[0] = udmabuf_fd,
153 .strides[0] = width * 4,
154 .offsets[0] = 0,
155 .modifier = DRM_FORMAT_MOD_LINEAR,
156 };
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000157
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000158 struct gbm_bo *bo =
159 gbm_bo_import(gbm, GBM_BO_IMPORT_FD_MODIFIER,
160 &gbm_import_data, GBM_BO_USE_RENDERING);
161 fail_if(bo == NULL, "failed to import bo");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000162
163 fail_if(close(udmabuf_fd) != 0, "failed to close udmabuf_fd");
164
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000165 uint32_t stride;
166 void *map_data;
167 void *bo_map = gbm_bo_map(bo,0, 0, width, height,
168 GBM_BO_TRANSFER_READ, &stride, &map_data);
169
170 fail_if(bo_map == MAP_FAILED, "gbm_bo_map failed");
171
172 fail_if(!verify_pattern(bo_map, size), "pattern mismatch after gbm_bo_map");
173
174 gbm_bo_unmap(bo, map_data);
175
176 gbm_bo_destroy(bo);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000177}
178
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000179void test_export_dma_buf(struct gbm_device *gbm)
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000180{
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000181 int width = 64;
182 int height = 64;
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000183
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000184 struct gbm_bo *bo = gbm_bo_create(gbm, width, height,
185 GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR);
186 fail_if(bo == NULL, "create bo failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000187
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000188 uint32_t stride;
189 void *map_data;
190 void *bo_map = gbm_bo_map(bo,0, 0, width, height,
191 GBM_BO_TRANSFER_WRITE, &stride, &map_data);
192 fail_if(bo_map == MAP_FAILED, "gbm_bo_map failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000193
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000194 fail_if(stride != gbm_bo_get_stride(bo),
195 "mapped buffer stride doesn't match bo stride");
196 uint32_t size = stride * height;
197 write_pattern(bo_map, size);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000198
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000199 gbm_bo_unmap(bo, map_data);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000200
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000201 int dmabuf_fd = gbm_bo_get_fd(bo);
202 fail_if(dmabuf_fd == -1, "dma-buf export failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000203
204 uint32_t *dmabuf_map =
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000205 mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, dmabuf_fd, 0);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000206 fail_if(dmabuf_map == MAP_FAILED, "failed to mmap memfd");
207
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000208 fail_if(!verify_pattern(dmabuf_map, size), "pattern mismatch after gbm_bo_map");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000209
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000210 fail_if(munmap(dmabuf_map, size) != 0, "munmap failed");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000211}
212
213int main(int argc, char *argv[])
214{
215 int fd = bs_drm_open_for_display();
216 fail_if(fd == -1, "error opening dri card");
217
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000218 struct gbm_device* gbm = gbm_create_device(fd);
219 fail_if(gbm == NULL, "failed to create gbm device");
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000220
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000221 test_import_dma_buf(gbm);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000222
Kristian H. Kristensen032a9552020-11-25 19:07:31 +0000223 test_export_dma_buf(gbm);
224
225 gbm_device_destroy(gbm);
Kristian H. Kristensenee5a5572020-09-03 07:47:01 +0000226 close(fd);
227
228 return EXIT_SUCCESS;
229}