aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/testing/selftests/x86/sigreturn.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
index 246145b84a12..2559e2c01793 100644
--- a/tools/testing/selftests/x86/sigreturn.c
+++ b/tools/testing/selftests/x86/sigreturn.c
@@ -612,19 +612,38 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss)
612 greg_t req = requested_regs[i], res = resulting_regs[i]; 612 greg_t req = requested_regs[i], res = resulting_regs[i];
613 if (i == REG_TRAPNO || i == REG_IP) 613 if (i == REG_TRAPNO || i == REG_IP)
614 continue; /* don't care */ 614 continue; /* don't care */
615 if (i == REG_SP) {
616 printf("\tSP: %llx -> %llx\n", (unsigned long long)req,
617 (unsigned long long)res);
618 615
616 if (i == REG_SP) {
619 /* 617 /*
620 * In many circumstances, the high 32 bits of rsp 618 * If we were using a 16-bit stack segment, then
621 * are zeroed. For example, we could be a real 619 * the kernel is a bit stuck: IRET only restores
622 * 32-bit program, or we could hit any of a number 620 * the low 16 bits of ESP/RSP if SS is 16-bit.
623 * of poorly-documented IRET or segmented ESP 621 * The kernel uses a hack to restore bits 31:16,
624 * oddities. If this happens, it's okay. 622 * but that hack doesn't help with bits 63:32.
623 * On Intel CPUs, bits 63:32 end up zeroed, and, on
624 * AMD CPUs, they leak the high bits of the kernel
625 * espfix64 stack pointer. There's very little that
626 * the kernel can do about it.
627 *
628 * Similarly, if we are returning to a 32-bit context,
629 * the CPU will often lose the high 32 bits of RSP.
625 */ 630 */
626 if (res == (req & 0xFFFFFFFF)) 631
627 continue; /* OK; not expected to work */ 632 if (res == req)
633 continue;
634
635 if (cs_bits != 64 && ((res ^ req) & 0xFFFFFFFF) == 0) {
636 printf("[NOTE]\tSP: %llx -> %llx\n",
637 (unsigned long long)req,
638 (unsigned long long)res);
639 continue;
640 }
641
642 printf("[FAIL]\tSP mismatch: requested 0x%llx; got 0x%llx\n",
643 (unsigned long long)requested_regs[i],
644 (unsigned long long)resulting_regs[i]);
645 nerrs++;
646 continue;
628 } 647 }
629 648
630 bool ignore_reg = false; 649 bool ignore_reg = false;
@@ -663,13 +682,6 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss)
663 } 682 }
664 683
665 if (requested_regs[i] != resulting_regs[i] && !ignore_reg) { 684 if (requested_regs[i] != resulting_regs[i] && !ignore_reg) {
666 /*
667 * SP is particularly interesting here. The
668 * usual cause of failures is that we hit the
669 * nasty IRET case of returning to a 16-bit SS,
670 * in which case bits 16:31 of the *kernel*
671 * stack pointer persist in ESP.
672 */
673 printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n", 685 printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
674 i, (unsigned long long)requested_regs[i], 686 i, (unsigned long long)requested_regs[i],
675 (unsigned long long)resulting_regs[i]); 687 (unsigned long long)resulting_regs[i]);