1 /*
2 * Copyright © 2014-2015 Intel Corporation
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 DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Damien Lespiau <damien.lespiau@intel.com>
25 * Daniel Stone <daniels@collabora.com>
26 */
27
28 #include "igt.h"
29 #include <errno.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <string.h>
33
34 IGT_TEST_DESCRIPTION("Tests behaviour of mass-data 'blob' properties.");
35
36 static const struct drm_mode_modeinfo test_mode_valid = {
37 .clock = 1234,
38 .hdisplay = 640,
39 .hsync_start = 641,
40 .hsync_end = 642,
41 .htotal = 643,
42 .hskew = 0,
43 .vdisplay = 480,
44 .vsync_start = 481,
45 .vsync_end = 482,
46 .vtotal = 483,
47 .vscan = 0,
48 .vrefresh = 60000,
49 .flags = 0,
50 .type = 0,
51 .name = "FROMUSER",
52 };
53
54
55 #define ioctl_or_ret_errno(fd, ioc, ioc_data) { \
56 if (drmIoctl(fd, ioc, ioc_data) != 0) \
57 return errno; \
58 }
59
igt_require_propblob(int fd)60 static void igt_require_propblob(int fd)
61 {
62 struct drm_mode_create_blob c;
63 struct drm_mode_destroy_blob d;
64 uint32_t blob_data;
65 c.data = (uintptr_t) &blob_data;
66 c.length = sizeof(blob_data);
67
68 igt_require(drmIoctl(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &c) == 0);
69 d.blob_id = c.blob_id;
70 igt_require(drmIoctl(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &d) == 0);
71 }
72
73 static int
validate_prop(int fd,uint32_t prop_id)74 validate_prop(int fd, uint32_t prop_id)
75 {
76 struct drm_mode_get_blob get;
77 struct drm_mode_modeinfo ret_mode;
78
79 get.blob_id = prop_id;
80 get.length = 0;
81 get.data = (uintptr_t) 0;
82 ioctl_or_ret_errno(fd, DRM_IOCTL_MODE_GETPROPBLOB, &get);
83
84 if (get.length != sizeof(test_mode_valid))
85 return ENOMEM;
86
87 get.data = (uintptr_t) &ret_mode;
88 ioctl_or_ret_errno(fd, DRM_IOCTL_MODE_GETPROPBLOB, &get);
89
90 if (memcmp(&ret_mode, &test_mode_valid, sizeof(test_mode_valid)) != 0)
91 return EINVAL;
92
93 return 0;
94 }
95
96 static uint32_t
create_prop(int fd)97 create_prop(int fd)
98 {
99 struct drm_mode_create_blob create;
100
101 create.length = sizeof(test_mode_valid);
102 create.data = (uintptr_t) &test_mode_valid;
103
104 do_ioctl(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create);
105 igt_assert_neq_u32(create.blob_id, 0);
106
107 return create.blob_id;
108 }
109
110 static int
destroy_prop(int fd,uint32_t prop_id)111 destroy_prop(int fd, uint32_t prop_id)
112 {
113 struct drm_mode_destroy_blob destroy;
114
115 destroy.blob_id = prop_id;
116 ioctl_or_ret_errno(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy);
117
118 return 0;
119 }
120
121 static void
test_validate(int fd)122 test_validate(int fd)
123 {
124 struct drm_mode_create_blob create;
125 struct drm_mode_get_blob get;
126 char too_small[32];
127 uint32_t prop_id;
128
129 memset(too_small, 0, sizeof(too_small));
130
131 /* Outlandish size. */
132 create.length = 0x10000;
133 create.data = (uintptr_t) &too_small;
134 do_ioctl_err(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create, EFAULT);
135
136 /* Outlandish address. */
137 create.length = sizeof(test_mode_valid);
138 create.data = (uintptr_t) 0xdeadbeee;
139 do_ioctl_err(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create, EFAULT);
140
141 /* When we pass an incorrect size, the kernel should correct us. */
142 prop_id = create_prop(fd);
143 get.blob_id = prop_id;
144 get.length = sizeof(too_small);
145 get.data = (uintptr_t) too_small;
146 do_ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &get);
147 igt_assert_eq_u32(get.length, sizeof(test_mode_valid));
148
149 get.blob_id = prop_id;
150 get.data = (uintptr_t) 0xdeadbeee;
151 do_ioctl_err(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create, EFAULT);
152 }
153
154 static void
test_lifetime(int fd)155 test_lifetime(int fd)
156 {
157 int fd2;
158 uint32_t prop_id, prop_id2;
159
160 fd2 = drm_open_driver(DRIVER_ANY);
161 igt_assert_fd(fd2);
162
163 /* Ensure clients can see properties created by other clients. */
164 prop_id = create_prop(fd);
165 igt_assert_eq(validate_prop(fd, prop_id), 0);
166 igt_assert_eq(validate_prop(fd2, prop_id), 0);
167
168 /* ... but can't destroy them. */
169 igt_assert_eq(destroy_prop(fd2, prop_id), EPERM);
170
171 /* Make sure properties can't be accessed once explicitly destroyed. */
172 prop_id2 = create_prop(fd2);
173 igt_assert_eq(validate_prop(fd2, prop_id2), 0);
174 igt_assert_eq(destroy_prop(fd2, prop_id2), 0);
175 igt_assert_eq(validate_prop(fd2, prop_id2), ENOENT);
176 igt_assert_eq(validate_prop(fd, prop_id2), ENOENT);
177
178 /* Make sure properties are cleaned up on client exit. */
179 prop_id2 = create_prop(fd2);
180 igt_assert_eq(validate_prop(fd, prop_id2), 0);
181 igt_assert_eq(close(fd2), 0);
182 igt_assert_eq(validate_prop(fd, prop_id2), ENOENT);
183
184 igt_assert_eq(validate_prop(fd, prop_id), 0);
185 igt_assert_eq(destroy_prop(fd, prop_id), 0);
186 igt_assert_eq(validate_prop(fd, prop_id), ENOENT);
187 }
188
189 static void
test_multiple(int fd)190 test_multiple(int fd)
191 {
192 uint32_t prop_ids[5];
193 int fd2;
194 int i;
195
196 fd2 = drm_open_driver(DRIVER_ANY);
197 igt_assert_fd(fd2);
198
199 /* Ensure destroying multiple properties explicitly works as needed. */
200 for (i = 0; i < ARRAY_SIZE(prop_ids); i++) {
201 prop_ids[i] = create_prop(fd2);
202 igt_assert_eq(validate_prop(fd, prop_ids[i]), 0);
203 igt_assert_eq(validate_prop(fd2, prop_ids[i]), 0);
204 }
205 for (i = 0; i < ARRAY_SIZE(prop_ids); i++) {
206 igt_assert_eq(destroy_prop(fd2, prop_ids[i]), 0);
207 igt_assert_eq(validate_prop(fd2, prop_ids[i]), ENOENT);
208 }
209 igt_assert_eq(close(fd2), 0);
210
211 fd2 = drm_open_driver(DRIVER_ANY);
212 igt_assert_fd(fd2);
213
214 /* Ensure that multiple properties get cleaned up on fd close. */
215 for (i = 0; i < ARRAY_SIZE(prop_ids); i++) {
216 prop_ids[i] = create_prop(fd2);
217 igt_assert_eq(validate_prop(fd, prop_ids[i]), 0);
218 igt_assert_eq(validate_prop(fd2, prop_ids[i]), 0);
219 }
220 igt_assert_eq(close(fd2), 0);
221
222 for (i = 0; i < ARRAY_SIZE(prop_ids); i++)
223 igt_assert_eq(validate_prop(fd, prop_ids[i]), ENOENT);
224 }
225
226 static void
test_core(int fd)227 test_core(int fd)
228 {
229 uint32_t prop_id;
230
231 /* The first hurdle. */
232 prop_id = create_prop(fd);
233 igt_assert_eq(validate_prop(fd, prop_id), 0);
234 igt_assert_eq(destroy_prop(fd, prop_id), 0);
235
236 /* Look up some invalid property IDs. They should fail. */
237 igt_assert_eq(validate_prop(fd, 0xffffffff), ENOENT);
238 igt_assert_eq(validate_prop(fd, 0), ENOENT);
239 }
240
241 static void
test_basic(int fd)242 test_basic(int fd)
243 {
244 uint32_t prop_id;
245
246 /* A very simple gating test to ensure property support exists. */
247 prop_id = create_prop(fd);
248 igt_assert_eq(destroy_prop(fd, prop_id), 0);
249 }
250
prop_tests(int fd)251 static void prop_tests(int fd)
252 {
253 struct drm_mode_obj_get_properties get_props = {};
254 struct drm_mode_obj_set_property set_prop = {};
255 uint64_t prop, prop_val, blob_id;
256
257 igt_fixture
258 blob_id = create_prop(fd);
259
260 get_props.props_ptr = (uintptr_t) ∝
261 get_props.prop_values_ptr = (uintptr_t) &prop_val;
262 get_props.count_props = 1;
263 get_props.obj_id = blob_id;
264
265 igt_subtest("invalid-get-prop-any") {
266 get_props.obj_type = 0; /* DRM_MODE_OBJECT_ANY */
267
268 igt_assert(drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES,
269 &get_props) == -1 && errno == EINVAL);
270 }
271
272 igt_subtest("invalid-get-prop") {
273 get_props.obj_type = DRM_MODE_OBJECT_BLOB;
274
275 igt_assert(drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES,
276 &get_props) == -1 && errno == EINVAL);
277 }
278
279 set_prop.value = 0;
280 set_prop.prop_id = 1;
281 set_prop.obj_id = blob_id;
282
283 igt_subtest("invalid-set-prop-any") {
284 set_prop.obj_type = 0; /* DRM_MODE_OBJECT_ANY */
285
286 igt_assert(drmIoctl(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY,
287 &set_prop) == -1 && errno == EINVAL);
288 }
289
290 igt_subtest("invalid-set-prop") {
291 set_prop.obj_type = DRM_MODE_OBJECT_BLOB;
292
293 igt_assert(drmIoctl(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY,
294 &set_prop) == -1 && errno == EINVAL);
295 }
296
297 igt_fixture
298 destroy_prop(fd, blob_id);
299 }
300
301 igt_main
302 {
303 int fd;
304
305 igt_fixture {
306 fd = drm_open_driver(DRIVER_ANY);
307 igt_require(fd >= 0);
308 igt_require_propblob(fd);
309 }
310
311 igt_subtest("basic")
312 test_basic(fd);
313
314 igt_subtest("blob-prop-core")
315 test_core(fd);
316
317 igt_subtest("blob-prop-validate")
318 test_validate(fd);
319
320 igt_subtest("blob-prop-lifetime")
321 test_lifetime(fd);
322
323 igt_subtest("blob-multiple")
324 test_multiple(fd);
325
326 prop_tests(fd);
327
328 igt_fixture
329 close(fd);
330 }
331