diff options
author | Andy Lutomirski <luto@kernel.org> | 2018-03-14 01:03:11 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-03-14 04:21:01 -0400 |
commit | 78393fdde2a456cafa414b171c90f26a3df98b20 (patch) | |
tree | f46a9175e49de0f87b10994dd0c04c5dc758b2fa | |
parent | 327d53d005ca47b10eae940616ed11c569f75a9b (diff) |
selftests/x86/entry_from_vm86: Add test cases for POPF
POPF is currently broken -- add tests to catch the error. This
results in:
[RUN] POPF with VIP set and IF clear from vm86 mode
[INFO] Exited vm86 mode due to STI
[FAIL] Incorrect return reason (started at eip = 0xd, ended at eip = 0xf)
because POPF currently fails to check IF before reporting a pending
interrupt.
This patch also makes the FAIL message a bit more informative.
Reported-by: Bart Oldeman <bartoldeman@gmail.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stas Sergeev <stsp@list.ru>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/a16270b5cfe7832d6d00c479d0f871066cbdb52b.1521003603.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/testing/selftests/x86/entry_from_vm86.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 6e85f0d0498d..ade443a88421 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c | |||
@@ -95,6 +95,10 @@ asm ( | |||
95 | "int3\n\t" | 95 | "int3\n\t" |
96 | "vmcode_int80:\n\t" | 96 | "vmcode_int80:\n\t" |
97 | "int $0x80\n\t" | 97 | "int $0x80\n\t" |
98 | "vmcode_popf_hlt:\n\t" | ||
99 | "push %ax\n\t" | ||
100 | "popf\n\t" | ||
101 | "hlt\n\t" | ||
98 | "vmcode_umip:\n\t" | 102 | "vmcode_umip:\n\t" |
99 | /* addressing via displacements */ | 103 | /* addressing via displacements */ |
100 | "smsw (2052)\n\t" | 104 | "smsw (2052)\n\t" |
@@ -124,8 +128,8 @@ asm ( | |||
124 | 128 | ||
125 | extern unsigned char vmcode[], end_vmcode[]; | 129 | extern unsigned char vmcode[], end_vmcode[]; |
126 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], | 130 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], |
127 | vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], | 131 | vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[], |
128 | vmcode_umip_str[], vmcode_umip_sldt[]; | 132 | vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[]; |
129 | 133 | ||
130 | /* Returns false if the test was skipped. */ | 134 | /* Returns false if the test was skipped. */ |
131 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | 135 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, |
@@ -175,7 +179,7 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | |||
175 | (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { | 179 | (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { |
176 | printf("[OK]\tReturned correctly\n"); | 180 | printf("[OK]\tReturned correctly\n"); |
177 | } else { | 181 | } else { |
178 | printf("[FAIL]\tIncorrect return reason\n"); | 182 | printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip); |
179 | nerrs++; | 183 | nerrs++; |
180 | } | 184 | } |
181 | 185 | ||
@@ -264,6 +268,9 @@ int main(void) | |||
264 | v86.regs.ds = load_addr / 16; | 268 | v86.regs.ds = load_addr / 16; |
265 | v86.regs.es = load_addr / 16; | 269 | v86.regs.es = load_addr / 16; |
266 | 270 | ||
271 | /* Use the end of the page as our stack. */ | ||
272 | v86.regs.esp = 4096; | ||
273 | |||
267 | assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ | 274 | assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ |
268 | 275 | ||
269 | /* #BR -- should deliver SIG??? */ | 276 | /* #BR -- should deliver SIG??? */ |
@@ -295,6 +302,23 @@ int main(void) | |||
295 | v86.regs.eflags &= ~X86_EFLAGS_IF; | 302 | v86.regs.eflags &= ~X86_EFLAGS_IF; |
296 | do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); | 303 | do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); |
297 | 304 | ||
305 | /* POPF with VIP set but IF clear: should not trap */ | ||
306 | v86.regs.eflags = X86_EFLAGS_VIP; | ||
307 | v86.regs.eax = 0; | ||
308 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear"); | ||
309 | |||
310 | /* POPF with VIP set and IF set: should trap */ | ||
311 | v86.regs.eflags = X86_EFLAGS_VIP; | ||
312 | v86.regs.eax = X86_EFLAGS_IF; | ||
313 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set"); | ||
314 | |||
315 | /* POPF with VIP clear and IF set: should not trap */ | ||
316 | v86.regs.eflags = 0; | ||
317 | v86.regs.eax = X86_EFLAGS_IF; | ||
318 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set"); | ||
319 | |||
320 | v86.regs.eflags = 0; | ||
321 | |||
298 | /* INT3 -- should cause #BP */ | 322 | /* INT3 -- should cause #BP */ |
299 | do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); | 323 | do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); |
300 | 324 | ||