1 /*
2  * Copyright © 2014 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  *    Chris Wilson <chris@chris-wilson.co.uk>
25  *
26  */
27 
28 #include "igt.h"
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <inttypes.h>
35 #include <errno.h>
36 #include <setjmp.h>
37 #include <signal.h>
38 
39 #include "drm.h"
40 
41 IGT_TEST_DESCRIPTION("Checks that the kernel reports EFAULT when trying to use"
42 		     " purged bo.");
43 
44 #define OBJECT_SIZE (1024*1024)
45 
46 /* Testcase: checks that the kernel reports EFAULT when trying to use purged bo
47  *
48  */
49 
50 static jmp_buf jmp;
51 
sigtrap(int sig)52 static void __attribute__((noreturn)) sigtrap(int sig)
53 {
54 	longjmp(jmp, sig);
55 }
56 
57 static void
dontneed_before_mmap(void)58 dontneed_before_mmap(void)
59 {
60 	int fd = drm_open_driver(DRIVER_INTEL);
61 	uint32_t handle;
62 	char *ptr;
63 
64 	handle = gem_create(fd, OBJECT_SIZE);
65 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
66 	ptr = gem_mmap__gtt(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
67 	close(fd);
68 
69 	signal(SIGSEGV, sigtrap);
70 	signal(SIGBUS, sigtrap);
71 	switch (setjmp(jmp)) {
72 	case SIGBUS:
73 		break;
74 	case 0:
75 		*ptr = 0;
76 	default:
77 		igt_assert(!"reached");
78 		break;
79 	}
80 	munmap(ptr, OBJECT_SIZE);
81 	signal(SIGBUS, SIG_DFL);
82 	signal(SIGSEGV, SIG_DFL);
83 }
84 
85 static void
dontneed_after_mmap(void)86 dontneed_after_mmap(void)
87 {
88 	int fd = drm_open_driver(DRIVER_INTEL);
89 	uint32_t handle;
90 	char *ptr;
91 
92 	handle = gem_create(fd, OBJECT_SIZE);
93 	ptr = gem_mmap__gtt(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
94 	igt_assert(ptr);
95 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
96 	close(fd);
97 
98 	signal(SIGBUS, sigtrap);
99 	switch (setjmp(jmp)) {
100 	case SIGBUS:
101 		break;
102 	case 0:
103 		*ptr = 0;
104 	default:
105 		igt_assert(!"reached");
106 		break;
107 	}
108 	munmap(ptr, OBJECT_SIZE);
109 	signal(SIGBUS, SIG_DFL);
110 }
111 
112 static void
dontneed_before_pwrite(void)113 dontneed_before_pwrite(void)
114 {
115 	int fd = drm_open_driver(DRIVER_INTEL);
116 	uint32_t bbe = MI_BATCH_BUFFER_END;
117 	uint32_t handle;
118 
119 	handle = gem_create(fd, OBJECT_SIZE);
120 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
121 
122 	igt_assert_eq(__gem_write(fd, handle, 0, &bbe, sizeof(bbe)), -EFAULT);
123 
124 	close(fd);
125 }
126 
127 static void
dontneed_before_exec(void)128 dontneed_before_exec(void)
129 {
130 	int fd = drm_open_driver(DRIVER_INTEL);
131 	struct drm_i915_gem_execbuffer2 execbuf;
132 	struct drm_i915_gem_exec_object2 exec;
133 	uint32_t buf[] = { MI_BATCH_BUFFER_END, 0 };
134 
135 	memset(&execbuf, 0, sizeof(execbuf));
136 	memset(&exec, 0, sizeof(exec));
137 
138 	exec.handle = gem_create(fd, OBJECT_SIZE);
139 	gem_write(fd, exec.handle, 0, buf, sizeof(buf));
140 	gem_madvise(fd, exec.handle, I915_MADV_DONTNEED);
141 
142 	execbuf.buffers_ptr = to_user_pointer(&exec);
143 	execbuf.buffer_count = 1;
144 	execbuf.batch_len = sizeof(buf);
145 	igt_assert_eq(__gem_execbuf(fd, &execbuf), -EFAULT);
146 
147 	close(fd);
148 }
149 
150 igt_main
151 {
152 	igt_skip_on_simulation();
153 
154 	igt_subtest("dontneed-before-mmap")
155 		dontneed_before_mmap();
156 
157 	igt_subtest("dontneed-after-mmap")
158 		dontneed_after_mmap();
159 
160 	igt_subtest("dontneed-before-pwrite")
161 		dontneed_before_pwrite();
162 
163 	igt_subtest("dontneed-before-exec")
164 		dontneed_before_exec();
165 }
166