• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) &prop;
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