From: Andrew Cooper Date: Fri, 15 Jul 2016 16:02:56 +0000 (+0000) Subject: Introduce xtf_set_idte() to allow tests to add extra IDT entries X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=a8616f4d2e79bdcd11291c7e5bcd249441276ad9;p=xtf.git Introduce xtf_set_idte() to allow tests to add extra IDT entries Add an extra entry to the selftests. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/hvm/traps.c b/arch/x86/hvm/traps.c index f1f78c7..792a596 100644 --- a/arch/x86/hvm/traps.c +++ b/arch/x86/hvm/traps.c @@ -82,6 +82,17 @@ static void setup_gate(unsigned int entry, void *addr, unsigned int dpl) #endif } +int xtf_set_idte(unsigned int vector, struct xtf_idte *idte) +{ +#if defined(__i386__) + pack_gate32(&idt[vector], 14, idte->addr, idte->dpl, idte->cs); +#elif defined(__x86_64__) + pack_gate64(&idt[vector], 14, idte->addr, idte->dpl, 0, idte->cs); +#endif + + return 0; +} + void arch_init_traps(void) { setup_gate(X86_EXC_DE, &entry_DE, 0); diff --git a/arch/x86/pv/traps.c b/arch/x86/pv/traps.c index 6c2405c..625f2dd 100644 --- a/arch/x86/pv/traps.c +++ b/arch/x86/pv/traps.c @@ -59,6 +59,17 @@ struct xen_trap_info pv_default_trap_info[] = { 0, 0, 0, 0 }, /* Sentinel. */ }; +int xtf_set_idte(unsigned int vector, struct xtf_idte *idte) +{ + struct xen_trap_info ti[2] = + { + { vector, idte->dpl | 4, idte->cs, idte->addr }, + { 0, 0, 0, 0 }, /* Sentinel. */ + }; + + return hypercall_set_trap_table(ti); +} + #ifdef __i386__ static bool __used ex_pf_user(struct cpu_regs *regs, const struct extable_entry *ex) diff --git a/include/arch/x86/idt.h b/include/arch/x86/idt.h index 5c7399d..453d75d 100644 --- a/include/arch/x86/idt.h +++ b/include/arch/x86/idt.h @@ -14,6 +14,36 @@ */ #define X86_VEC_RET2KERN 0x20 +/** + * Available for test use. + */ +#define X86_VEC_AVAIL 0x21 + + +#ifndef __ASSEMBLY__ + +/** A guest agnostic represention of IDT information. */ +struct xtf_idte +{ + unsigned long addr; + unsigned int cs, dpl; +}; + +/** + * Set up an IDT Entry, in a guest agnostic way. + * + * Construct an IDT Entry at the specified @p vector, using configuration + * provided in @p idte. + * + * @param vector Vector to set up. + * @param idte Details to set up. + * @returns 0 for HVM guests, hypercall result for PV guests. + */ +int xtf_set_idte(unsigned int vector, + struct xtf_idte *idte); + +#endif /* __ASSEMBLY__ */ + #endif /* XTF_X86_IDT_H */ /* diff --git a/tests/selftest/main.c b/tests/selftest/main.c index 72b4045..5ff2467 100644 --- a/tests/selftest/main.c +++ b/tests/selftest/main.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -245,6 +246,52 @@ static void test_extable_handler(void) xtf_failure("Fail: Custom handler didn't run\n"); } +void test_idte_handler(void); +asm ("test_idte_handler:;" +#if defined (CONFIG_PV) && defined (CONFIG_64BIT) + "pop %rcx; pop %r11;" +#endif + "mov $0x1e51c0de, %eax;" +#if defined (CONFIG_HVM) +#ifdef __x86_64__ + "rex64 " +#endif + "iret;" +#else /* CONFIG_HVM */ +#ifdef __x86_64__ + "push $0;" +#endif + "jmp HYPERCALL_iret;" +#endif + ); + +static void test_custom_idte(void) +{ + struct xtf_idte idte = + { + .addr = (unsigned long)test_idte_handler, + /* PV guests need DPL1, HVM need DPL0. */ + .dpl = IS_DEFINED(CONFIG_PV) ? 1 : 0, + .cs = __KERN_CS, + }; + + printk("Test: Custom IDT entry\n"); + + int rc = xtf_set_idte(X86_VEC_AVAIL, &idte); + + if ( rc ) + return xtf_failure("Fail: xtf_set_idte() returned %d\n", rc); + + unsigned int res; + asm volatile ("int $%c[vec]" + : "=a" (res) + : "0" (0), + [vec] "i" (X86_VEC_AVAIL)); + + if ( res != 0x1e51c0de ) + xtf_failure("Fail: Unexpected result %#x\n", res); +}; + void test_main(void) { printk("XTF Selftests\n"); @@ -257,6 +304,7 @@ void test_main(void) test_NULL_unmapped(); test_unhandled_exception_hook(); test_extable_handler(); + test_custom_idte(); xtf_success(NULL); }