]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Extend the pv-iopl test to test VMASST_TYPE_architectural_iopl
authorAndrew Cooper <andrew.cooper3@citrix.com>
Sat, 19 Mar 2016 19:51:01 +0000 (19:51 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 26 Apr 2016 16:31:07 +0000 (17:31 +0100)
A varient of exec_user() is introduced which takes an IOPL parameter.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
include/xen/xen.h
include/xtf/hypercall.h
tests/pv-iopl/Makefile
tests/pv-iopl/asm.S [new file with mode: 0644]
tests/pv-iopl/main.c

index 7ae9de2e6f96f2d84290e2b4dba7ba9aff9389fd..e276e73213f994c57fa96fcd22361901db892446 100644 (file)
@@ -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.    */
index c48541d04e33d8edc1a875843b5fa1ef95aa6eba..edcd1486869a4e2cb967b5f240ae908be56bdf77 100644 (file)
@@ -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,
index 2458d0e1cacf3c24d5d85a89a0ace206164a787b..5b20f4a94c814fe7acd9084c9fc65e74b8dc37f4 100644 (file)
@@ -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 (file)
index 0000000..26e0767
--- /dev/null
@@ -0,0 +1,53 @@
+#include <arch/x86/processor.h>
+#include <arch/x86/segment.h>
+#include <xtf/asm_macros.h>
+
+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:
+ */
index d4e0a5b42c3d045d0b24a60933525c6df1d2d96b..91e4b6bedcb47f46502fa7c9617b437263406fd7 100644 (file)
  *    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 <xtf/lib.h>
 
 #include <arch/x86/processor.h>
 
+/**
+ * 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);
 }