From: Andrew Cooper Date: Tue, 12 Oct 2021 22:47:49 +0000 (+0100) Subject: Test Long Mode #TS X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=3c0b315d79eb67846d99060e51989ff62bb33464;p=people%2Fandrewcoop%2Fxen-test-framework.git Test Long Mode #TS Introduce TSS_SEL and clean up nmi-taskswitch-priv to use it. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/include/arch/segment.h b/arch/x86/include/arch/segment.h index d915e97..f28085a 100644 --- a/arch/x86/include/arch/segment.h +++ b/arch/x86/include/arch/segment.h @@ -74,6 +74,8 @@ #endif /* __x86_64__ */ +#define TSS_SEL (GDTE_TSS * 8) + #endif /* CONFIG_HVM */ /* diff --git a/docs/all-tests.dox b/docs/all-tests.dox index 7282b36..3a63da4 100644 --- a/docs/all-tests.dox +++ b/docs/all-tests.dox @@ -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 index 0000000..6b5f345 --- /dev/null +++ b/tests/lm-ts/Makefile @@ -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 index 0000000..e8efa2f --- /dev/null +++ b/tests/lm-ts/main.c @@ -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 + +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: + */ diff --git a/tests/nmi-taskswitch-priv/main.c b/tests/nmi-taskswitch-priv/main.c index 942cd59..1bc2756 100644 --- a/tests/nmi-taskswitch-priv/main.c +++ b/tests/nmi-taskswitch-priv/main.c @@ -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