From: Andrew Cooper Date: Sat, 19 Mar 2016 19:51:01 +0000 (+0000) Subject: Extend the pv-iopl test to test VMASST_TYPE_architectural_iopl X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=164a450117b9c057d25c039b48400b8e45a978e9;p=people%2Froyger%2Fxen-test-framework.git Extend the pv-iopl test to test VMASST_TYPE_architectural_iopl A varient of exec_user() is introduced which takes an IOPL parameter. Signed-off-by: Andrew Cooper --- diff --git a/include/xen/xen.h b/include/xen/xen.h index 7ae9de2..e276e73 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -71,6 +71,21 @@ typedef uint16_t domid_t; /* Commands to HYPERVISOR_console_io */ #define CONSOLEIO_write 0 +/* + * Commands to HYPERVISOR_vm_assist(). + */ +#define VMASST_CMD_enable 0 +#define VMASST_CMD_disable 1 + +/* + * x86 guests: Sane behaviour for virtual iopl + * - virtual iopl updated from do_iret() hypercalls. + * - virtual iopl reported in bounce frames. + * - guest kernels assumed to be level 0 for the purpose of iopl checks. + */ +#define VMASST_TYPE_architectural_iopl 4 + + #ifndef __ASSEMBLY__ struct start_info { /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h index c48541d..edcd148 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -71,6 +71,11 @@ static inline long hypercall_update_va_mapping(void *va, uint64_t npte, #endif } +static inline long hypercall_vm_assist(unsigned int cmd, unsigned int type) +{ + return HYPERCALL2(long, __HYPERVISOR_vm_assist, cmd, type); +} + static inline long hypercall_mmuext_op(const mmuext_op_t ops[], unsigned int count, unsigned int *done, diff --git a/tests/pv-iopl/Makefile b/tests/pv-iopl/Makefile index 2458d0e..5b20f4a 100644 --- a/tests/pv-iopl/Makefile +++ b/tests/pv-iopl/Makefile @@ -7,6 +7,6 @@ NAME := pv-iopl CATEGORY := functional TEST-ENVS := $(PV_ENVIRONMENTS) -obj-perenv += main.o +obj-perenv += main.o asm.o include $(ROOT)/build/gen.mk diff --git a/tests/pv-iopl/asm.S b/tests/pv-iopl/asm.S new file mode 100644 index 0000000..26e0767 --- /dev/null +++ b/tests/pv-iopl/asm.S @@ -0,0 +1,53 @@ +#include +#include +#include + +ENTRY(exec_user_with_iopl) /* void (*fn)(void), unsigned int iopl */ + + push $__USER_DS /* SS */ +#ifdef __i386__ + push %esp + addl $4, (%esp) /* ESP */ +#else + push %rsp + addq $8, (%rsp) +#endif + pushf /* EFLAGS */ + + /* PV guests see the real interrupt flag. Clobber it. */ +#ifdef __i386__ + andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_IF), (%esp) + mov 5*4(%esp), %eax + shl $12, %eax + or %eax, (%esp) +#else + andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_IF), (%rsp) + shl $12, %esi + or %esi, (%rsp) +#endif + + push $__USER_CS /* CS */ + push $1f /* EIP */ + +#ifdef __x86_64__ + push $0 +#endif + jmp HYPERCALL_iret /* Drop to user privilege. */ +1: +#ifdef __i386__ + call *4(%esp) /* fn() */ +#else + call *%rdi +#endif + + int $0x20 /* Return to kernel privilege. */ + ret + +ENDFUNC(exec_user_with_iopl) + +/* + * Local variables: + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/pv-iopl/main.c b/tests/pv-iopl/main.c index d4e0a5b..91e4b6b 100644 --- a/tests/pv-iopl/main.c +++ b/tests/pv-iopl/main.c @@ -28,12 +28,26 @@ * kernel will suffer faults from IO accesses until it sets an IOPL of 1. * A guest may set the current IOPL, but cannot query the value. * + * 2. VMASST_TYPE_architectural_iopl + * + * This is a change to the ABI, introduced in Xen 4.7 (following XSA-171) + * to make IOPL handling easier for the guest kernel. A guest must opt in + * to the new ABI by enabling the VMASSIT. This ABI considers a guest + * kernel to have an cpl of 0, and the shadowed IOPL will be updated from + * the contents of iret frame during an iret hypercall. + * * @sa tests/pv-iopl/main.c */ #include #include +/** + * Execute @p fn at user privilege on the current stack, folding @p iopl into + * the iret frame. + */ +void exec_user_with_iopl(void (*fn)(void), unsigned int iopl); + /** Stub CLI instruction with @#GP fixup. */ static void stub_cli(void) { @@ -149,7 +163,7 @@ static void run_test(const struct test *t) /* Run insn in userspace. */ expect(seq->name, 1, t->should_fault(1, iopl)); - exec_user(seq->fn); + exec_user_with_iopl(seq->fn, iopl); check(); } } @@ -192,6 +206,38 @@ static const struct test hypercall = .should_fault = hypercall_should_fault, }; +static void nop(void){} +static void vmassist_set_iopl(unsigned int iopl) +{ + /* + * All that needs to happen to set iopl is to execute an iret hypercall + * with the appropriate iopl set. Reuse the exec_user infrastructure to + * issue the iret, and execute nothing interesting in user context. + */ + exec_user_with_iopl(nop, iopl); +} + +static bool vmassist_should_fault(bool user, unsigned int iopl) +{ + /* + * Kernel has vCPL 0, userspace has vCPL 3. + * + * Kenrel should never fault, while userspace should only not fault at + * iopl 3. + */ + if ( !user ) + return false; + + return iopl != 3; +} + +/** VMASSIT based IOPL interface. */ +static const struct test vmassist = +{ + .set_iopl = vmassist_set_iopl, + .should_fault = vmassist_should_fault, +}; + void test_main(void) { printk("PV IOPL emulation\n"); @@ -201,6 +247,13 @@ void test_main(void) printk("Test: PHYSDEVOP_set_iopl\n"); run_test(&hypercall); + if ( hypercall_vm_assist(VMASST_CMD_enable, + VMASST_TYPE_architectural_iopl) ) + return xtf_skip("VMASST_TYPE_architectural_iopl not detected\n"); + + printk("Test: VMASST_TYPE_architectural_iopl\n"); + run_test(&vmassist); + xtf_exlog_stop(); xtf_success(NULL); }