aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/x86/syscall_arg_fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/x86/syscall_arg_fault.c')
-rw-r--r--tools/testing/selftests/x86/syscall_arg_fault.c112
1 files changed, 107 insertions, 5 deletions
diff --git a/tools/testing/selftests/x86/syscall_arg_fault.c b/tools/testing/selftests/x86/syscall_arg_fault.c
index 4e25d38c8bbd..bc0ecc2e862e 100644
--- a/tools/testing/selftests/x86/syscall_arg_fault.c
+++ b/tools/testing/selftests/x86/syscall_arg_fault.c
@@ -15,9 +15,30 @@
15#include <setjmp.h> 15#include <setjmp.h>
16#include <errno.h> 16#include <errno.h>
17 17
18#ifdef __x86_64__
19# define WIDTH "q"
20#else
21# define WIDTH "l"
22#endif
23
18/* Our sigaltstack scratch space. */ 24/* Our sigaltstack scratch space. */
19static unsigned char altstack_data[SIGSTKSZ]; 25static unsigned char altstack_data[SIGSTKSZ];
20 26
27static unsigned long get_eflags(void)
28{
29 unsigned long eflags;
30 asm volatile ("pushf" WIDTH "\n\tpop" WIDTH " %0" : "=rm" (eflags));
31 return eflags;
32}
33
34static void set_eflags(unsigned long eflags)
35{
36 asm volatile ("push" WIDTH " %0\n\tpopf" WIDTH
37 : : "rm" (eflags) : "flags");
38}
39
40#define X86_EFLAGS_TF (1UL << 8)
41
21static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 42static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
22 int flags) 43 int flags)
23{ 44{
@@ -35,13 +56,22 @@ static sigjmp_buf jmpbuf;
35 56
36static volatile sig_atomic_t n_errs; 57static volatile sig_atomic_t n_errs;
37 58
59#ifdef __x86_64__
60#define REG_AX REG_RAX
61#define REG_IP REG_RIP
62#else
63#define REG_AX REG_EAX
64#define REG_IP REG_EIP
65#endif
66
38static void sigsegv_or_sigbus(int sig, siginfo_t *info, void *ctx_void) 67static void sigsegv_or_sigbus(int sig, siginfo_t *info, void *ctx_void)
39{ 68{
40 ucontext_t *ctx = (ucontext_t*)ctx_void; 69 ucontext_t *ctx = (ucontext_t*)ctx_void;
70 long ax = (long)ctx->uc_mcontext.gregs[REG_AX];
41 71
42 if (ctx->uc_mcontext.gregs[REG_EAX] != -EFAULT) { 72 if (ax != -EFAULT && ax != -ENOSYS) {
43 printf("[FAIL]\tAX had the wrong value: 0x%x\n", 73 printf("[FAIL]\tAX had the wrong value: 0x%lx\n",
44 ctx->uc_mcontext.gregs[REG_EAX]); 74 (unsigned long)ax);
45 n_errs++; 75 n_errs++;
46 } else { 76 } else {
47 printf("[OK]\tSeems okay\n"); 77 printf("[OK]\tSeems okay\n");
@@ -50,9 +80,42 @@ static void sigsegv_or_sigbus(int sig, siginfo_t *info, void *ctx_void)
50 siglongjmp(jmpbuf, 1); 80 siglongjmp(jmpbuf, 1);
51} 81}
52 82
83static volatile sig_atomic_t sigtrap_consecutive_syscalls;
84
85static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
86{
87 /*
88 * KVM has some bugs that can cause us to stop making progress.
89 * detect them and complain, but don't infinite loop or fail the
90 * test.
91 */
92
93 ucontext_t *ctx = (ucontext_t*)ctx_void;
94 unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
95
96 if (*ip == 0x340f || *ip == 0x050f) {
97 /* The trap was on SYSCALL or SYSENTER */
98 sigtrap_consecutive_syscalls++;
99 if (sigtrap_consecutive_syscalls > 3) {
100 printf("[WARN]\tGot stuck single-stepping -- you probably have a KVM bug\n");
101 siglongjmp(jmpbuf, 1);
102 }
103 } else {
104 sigtrap_consecutive_syscalls = 0;
105 }
106}
107
53static void sigill(int sig, siginfo_t *info, void *ctx_void) 108static void sigill(int sig, siginfo_t *info, void *ctx_void)
54{ 109{
55 printf("[SKIP]\tIllegal instruction\n"); 110 ucontext_t *ctx = (ucontext_t*)ctx_void;
111 unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
112
113 if (*ip == 0x0b0f) {
114 /* one of the ud2 instructions faulted */
115 printf("[OK]\tSYSCALL returned normally\n");
116 } else {
117 printf("[SKIP]\tIllegal instruction\n");
118 }
56 siglongjmp(jmpbuf, 1); 119 siglongjmp(jmpbuf, 1);
57} 120}
58 121
@@ -120,9 +183,48 @@ int main()
120 "movl $-1, %%ebp\n\t" 183 "movl $-1, %%ebp\n\t"
121 "movl $-1, %%esp\n\t" 184 "movl $-1, %%esp\n\t"
122 "syscall\n\t" 185 "syscall\n\t"
123 "pushl $0" /* make sure we segfault cleanly */ 186 "ud2" /* make sure we recover cleanly */
187 : : : "memory", "flags");
188 }
189
190 printf("[RUN]\tSYSENTER with TF and invalid state\n");
191 sethandler(SIGTRAP, sigtrap, SA_ONSTACK);
192
193 if (sigsetjmp(jmpbuf, 1) == 0) {
194 sigtrap_consecutive_syscalls = 0;
195 set_eflags(get_eflags() | X86_EFLAGS_TF);
196 asm volatile (
197 "movl $-1, %%eax\n\t"
198 "movl $-1, %%ebx\n\t"
199 "movl $-1, %%ecx\n\t"
200 "movl $-1, %%edx\n\t"
201 "movl $-1, %%esi\n\t"
202 "movl $-1, %%edi\n\t"
203 "movl $-1, %%ebp\n\t"
204 "movl $-1, %%esp\n\t"
205 "sysenter"
206 : : : "memory", "flags");
207 }
208 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
209
210 printf("[RUN]\tSYSCALL with TF and invalid state\n");
211 if (sigsetjmp(jmpbuf, 1) == 0) {
212 sigtrap_consecutive_syscalls = 0;
213 set_eflags(get_eflags() | X86_EFLAGS_TF);
214 asm volatile (
215 "movl $-1, %%eax\n\t"
216 "movl $-1, %%ebx\n\t"
217 "movl $-1, %%ecx\n\t"
218 "movl $-1, %%edx\n\t"
219 "movl $-1, %%esi\n\t"
220 "movl $-1, %%edi\n\t"
221 "movl $-1, %%ebp\n\t"
222 "movl $-1, %%esp\n\t"
223 "syscall\n\t"
224 "ud2" /* make sure we recover cleanly */
124 : : : "memory", "flags"); 225 : : : "memory", "flags");
125 } 226 }
227 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
126 228
127 return 0; 229 return 0;
128} 230}