/* 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. */
--- /dev/null
+#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:
+ */
* 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)
{
/* 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();
}
}
.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");
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);
}