]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Choose a hypercall instruction in run-time
authorValentine Sinitsyn <valentine.sinitsyn@gmail.com>
Mon, 1 Sep 2014 16:54:48 +0000 (22:54 +0600)
committerJan Kiszka <jan.kiszka@siemens.com>
Sat, 1 Nov 2014 19:10:01 +0000 (20:10 +0100)
VMX and SVM use different instructions to make a hypercall (vmcall and
vmmcall, respectively). Jailhouse abstracts hypercall instructions with
inlined functions in jailhouse_hypercall.h, and these need to be able to
differentiate between VMX and SVM. For this reason, jailhouse_use_vmcall
global variable was introduced that is stored and filled by the driver.
Inmates will require similar initialization. This is left out as inmates
do not make use of hypercalls at this point.

As jailhouse_call_*() functions are never called on a CPU without VM
extensions (the driver checks if Jailhouse is enabled before issuing a
hypercall, and inmates do not run outside cells), it is safe to assume
that the CPU without VMX support is an SVM one.

Signed-off-by: Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
[Jan: dropped inmate initialization,
      switched to bool for jailhouse_use_vmcall,
      refactored init_use_vmcall_flag to init_hypercall]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
driver.c
hypervisor/arch/x86/include/asm/jailhouse_hypercall.h
hypervisor/arch/x86/include/asm/processor.h
hypervisor/arch/x86/vcpu.c

index 52789263c557303b89728568ab5a87d04012b26e..ed270e6422e3dddef35ada93cb60a88462cfb8dc 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -124,6 +124,19 @@ static struct kobject *cells_dir;
 
 #define MIN(a, b)      ((a) < (b) ? (a) : (b))
 
+#ifdef CONFIG_X86
+bool jailhouse_use_vmcall;
+
+static void init_hypercall(void)
+{
+       jailhouse_use_vmcall = boot_cpu_has(X86_FEATURE_VMX);
+}
+#else /* !CONFIG_X86 */
+static void init_hypercall(void)
+{
+}
+#endif
+
 struct jailhouse_cpu_stats_attr {
        struct kobj_attribute kattr;
        unsigned int code;
@@ -1039,6 +1052,8 @@ static int __init jailhouse_init(void)
 
        register_reboot_notifier(&jailhouse_shutdown_nb);
 
+       init_hypercall();
+
        return 0;
 
 remove_cells_dir:
index 1efe8d27dce081abfd9e0701fa17c3ded72bfb45..7b03f39574126f642c1280aae64e5d826ebe8d3c 100644 (file)
 
 #define JAILHOUSE_BASE         0xfffffffff0000000
 
-#define JAILHOUSE_CALL_INS     "vmcall"
+/*
+ * As this is never called on a CPU without VM extensions,
+ * we assume that where VMCALL isn't available, VMMCALL is.
+ */
+#define JAILHOUSE_CALL_CODE    \
+       "cmp $0x01, %1\n\t"\
+       "jnz 1f\n\t"\
+       "vmcall\n\t"\
+       "jmp 2f\n\t"\
+       "1: vmmcall\n\t"\
+       "2:"
+
 #define JAILHOUSE_CALL_RESULT  "=a" (result)
+#define JAILHOUSE_USE_VMCALL   "m" (jailhouse_use_vmcall)
 #define JAILHOUSE_CALL_NUM     "a" (num)
 #define JAILHOUSE_CALL_ARG1    "D" (arg1)
 #define JAILHOUSE_CALL_ARG2    "S" (arg2)
 
 #ifndef __ASSEMBLY__
 
+/**
+ * @defgroup Hypercalls
+ *
+ * The hypercall subsystem provides an interface for cells
+ * to call into Jailhouse.
+ *
+ * @{
+ */
+
+/**
+ * This variable selects the x86 hypercall instruction to be used by
+ * jailhouse_call(), jailhouse_call_arg1(), and jailhouse_call_arg2().
+ * A caller should define and initialize the variable before calling
+ * any of these functions.
+ *
+ * @li @c false Use AMD's VMMCALL.
+ * @li @c true Use Intel's VMCALL.
+ */
+extern bool jailhouse_use_vmcall;
+
 struct jailhouse_comm_region {
        COMM_REGION_GENERIC_HEADER;
 
@@ -40,9 +72,9 @@ static inline __u32 jailhouse_call(__u32 num)
 {
        __u32 result;
 
-       asm volatile(JAILHOUSE_CALL_INS
+       asm volatile(JAILHOUSE_CALL_CODE
                : JAILHOUSE_CALL_RESULT
-               : JAILHOUSE_CALL_NUM
+               : JAILHOUSE_USE_VMCALL, JAILHOUSE_CALL_NUM
                : "memory");
        return result;
 }
@@ -51,9 +83,10 @@ static inline __u32 jailhouse_call_arg1(__u32 num, unsigned long arg1)
 {
        __u32 result;
 
-       asm volatile(JAILHOUSE_CALL_INS
+       asm volatile(JAILHOUSE_CALL_CODE
                : JAILHOUSE_CALL_RESULT
-               : JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1
+               : JAILHOUSE_USE_VMCALL,
+                 JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1
                : "memory");
        return result;
 }
@@ -63,9 +96,10 @@ static inline __u32 jailhouse_call_arg2(__u32 num, unsigned long arg1,
 {
        __u32 result;
 
-       asm volatile(JAILHOUSE_CALL_INS
+       asm volatile(JAILHOUSE_CALL_CODE
                : JAILHOUSE_CALL_RESULT
-               : JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1, JAILHOUSE_CALL_ARG2
+               : JAILHOUSE_USE_VMCALL,
+                 JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1, JAILHOUSE_CALL_ARG2
                : "memory");
        return result;
 }
@@ -90,4 +124,6 @@ jailhouse_send_reply_from_cell(struct jailhouse_comm_region *comm_region,
        comm_region->reply_from_cell = reply;
 }
 
+/** @} **/
+
 #endif /* !__ASSEMBLY__ */
index 320245286327e9ec88ba7f37ebe74691afdc00fd..ec20a6ac8bdc4b402c9d44225193288d53fbb5af 100644 (file)
@@ -73,7 +73,8 @@
 #define X86_INST_LEN_CPUID                             2
 #define X86_INST_LEN_RDMSR                             2
 #define X86_INST_LEN_WRMSR                             2
-#define X86_INST_LEN_VMCALL                            3
+/* This covers both VMCALL and VMMCALL */
+#define X86_INST_LEN_HYPERCALL                         3
 #define X86_INST_LEN_MOV_TO_CR                         3
 #define X86_INST_LEN_XSETBV                            3
 
index a73af1f3556f70c2f313de61e9340ab37f6fdf52..24da80e6f1f0f909a4816e294f8c3c9d1826d575 100644 (file)
@@ -141,7 +141,7 @@ void vcpu_handle_hypercall(struct registers *guest_regs,
        struct per_cpu *cpu_data = this_cpu_data();
        unsigned long code = guest_regs->rax;
 
-       vcpu_skip_emulated_instruction(X86_INST_LEN_VMCALL);
+       vcpu_skip_emulated_instruction(X86_INST_LEN_HYPERCALL);
 
        if ((!long_mode && (x_state->rflags & X86_RFLAGS_VM)) ||
            (x_state->cs & 3) != 0) {
@@ -152,9 +152,9 @@ void vcpu_handle_hypercall(struct registers *guest_regs,
        guest_regs->rax = hypercall(code, guest_regs->rdi & arg_mask,
                                    guest_regs->rsi & arg_mask);
        if (guest_regs->rax == -ENOSYS)
-               printk("CPU %d: Unknown vmcall %d, RIP: %p\n",
+               printk("CPU %d: Unknown hypercall %d, RIP: %p\n",
                       cpu_data->cpu_id, code,
-                      x_state->rip - X86_INST_LEN_VMCALL);
+                      x_state->rip - X86_INST_LEN_HYPERCALL);
 
        if (code == JAILHOUSE_HC_DISABLE && guest_regs->rax == 0)
                vcpu_deactivate_vmm(guest_regs);