]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
Test Long Mode #TS
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 12 Oct 2021 22:47:49 +0000 (23:47 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 2 Oct 2023 15:30:28 +0000 (16:30 +0100)
Introduce TSS_SEL and clean up nmi-taskswitch-priv to use it.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/include/arch/segment.h
docs/all-tests.dox
tests/lm-ts/Makefile [new file with mode: 0644]
tests/lm-ts/main.c [new file with mode: 0644]
tests/nmi-taskswitch-priv/main.c

index d915e978d272d084f3b9638bf958e07ffb77ec41..f28085af8d0eb5889ca764b71cc73cf1880a84cb 100644 (file)
@@ -74,6 +74,8 @@
 
 #endif /* __x86_64__ */
 
+#define TSS_SEL     (GDTE_TSS * 8)
+
 #endif /* CONFIG_HVM */
 
 /*
index 7282b36aab7043df9020d70a203dd21a7c41031a..3a63da499ae8def0bc294bb3ee23f250f8a0e94d 100644 (file)
@@ -26,6 +26,8 @@ and functionality.
 
 @subpage test-livepatch-priv-check - Live Patch Privilege Check.
 
+@subpage test-lm-ts - Long Mode @#TS exception.
+
 @subpage test-memop-seg - Memory operand and segment interaction test.
 
 @subpage test-nmi-taskswitch-priv - Task Gate handling of interrupts.
diff --git a/tests/lm-ts/Makefile b/tests/lm-ts/Makefile
new file mode 100644 (file)
index 0000000..6b5f345
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := lm-ts
+CATEGORY  := functional
+TEST-ENVS := hvm32 hvm64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/lm-ts/main.c b/tests/lm-ts/main.c
new file mode 100644 (file)
index 0000000..e8efa2f
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * @file tests/lm-ts/main.c
+ * @ref test-lm-ts
+ *
+ * @page test-lm-ts Long Mode @#TS exception
+ *
+ * Task Switches are removed from the AMD64 spec, but contrary to popular
+ * belief, these are not the only source of @#TS exceptions.  This is a
+ * demonstration of #TS occurring in 64bit mode (and 32bit to show that the
+ * behaviour is consistent.)
+ *
+ * @#TS can occur because of a limit violation accessing @%tr.  Construct a
+ * scenario where the TSS limit includes {e,r}sp0 (so we can handle exceptions
+ * from lower privileges), but excludes {e,r}sp1 (so we can trigger @#TS).
+ *
+ * @see tests/lm-ts/main.c
+ */
+#include <xtf.h>
+
+const char test_title[] = "Test Long Mode #TS";
+
+#ifdef __i386__
+# define COND(_32, _64) _32
+#else
+# define COND(_32, _64) _64
+#endif
+
+static bool check_ts(struct cpu_regs *regs, const struct extable_entry *ex)
+{
+    exinfo_t got = EXINFO(regs->entry_vector, regs->error_code);
+    exinfo_t exp = EXINFO_SYM(TS, SEL_EC_SYM(TSS_SEL, GDT));
+
+    if ( got == exp )
+    {
+        printk("  Got %pe as expected\n", _p(got));
+        regs->ip = ex->fixup;
+        return true;
+    }
+
+    return false;
+}
+
+static void __user_text user(void)
+{
+    asm volatile ("1: int $"STR(X86_VEC_AVAIL)";"
+                  "2:"
+                  _ASM_EXTABLE_HANDLER(1b, 2b, %P[check])
+                  :
+                  : [check] "p" (check_ts)
+                  : "memory");
+}
+
+void test_main(void)
+{
+    /*
+     * Edit the TSS descriptor in place.  Reset Busy to Available, and reduce
+     * limit to exclude the Ring1 stack.
+     */
+    gdt[GDTE_TSS].type = 0x9;
+    gdt[GDTE_TSS].limit0 = offsetof(env_tss, COND(esp1, rsp1)) - 1;
+
+    /* Reload %tr */
+    ltr(TSS_SEL);
+
+#ifdef __i386__
+    tss.ss1 = __KERN_CS;
+#endif
+
+    /* Ring1 code segment. */
+    gdt[GDTE_AVAIL0] = GDTE_SYM(0, 0xfffff, COMMON, DPL1, CODE, COND(D, L));
+
+    /*
+     * DPL3 RPL1 gate to allow userspace to invoke Ring 1.  It will fault as
+     * %tr->{e,r}sp1 can't be accessed.
+     */
+    pack_intr_gate(&idt[X86_VEC_AVAIL], (GDTE_AVAIL0 * 8) | 1, 0, 3, 0);
+
+    exec_user_void(user);
+
+    xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 942cd5985f54e3d72abb2fb36d54946ced475f64..1bc275651cb7258b4391a591813568033682773b 100644 (file)
@@ -138,9 +138,9 @@ void test_main(void)
     printk("First self-nmi, from supervisor mode\n");
     apic_mmio_icr_write(APIC_DEST_SELF | APIC_DM_NMI);
 
-    if ( (curr_ts = str()) != (GDTE_TSS * 8) )
+    if ( (curr_ts = str()) != TSS_SEL )
         xtf_failure("Fail: Running main task with unexpected %%tr\n"
-                    "  Expected %04x, got %04x\n", (GDTE_TSS * 8), curr_ts);
+                    "  Expected %04x, got %04x\n", TSS_SEL, curr_ts);
 
     /*
      * Send an NMI from user mode, and again check that we are in the expected
@@ -149,9 +149,9 @@ void test_main(void)
     printk("Second self-nmi, from user mode\n");
     exec_user_void(user_inject_nmi);
 
-    if ( (curr_ts = str()) != (GDTE_TSS * 8) )
+    if ( (curr_ts = str()) != TSS_SEL )
         xtf_failure("Fail: Running main task with unexpected %%tr\n"
-                    "  Expected %04x, got %04x\n", (GDTE_TSS * 8), curr_ts);
+                    "  Expected %04x, got %04x\n", TSS_SEL, curr_ts);
 
     /*
      * If Xen is still alive, it handled the user=>supervisor task switch