#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;
register_reboot_notifier(&jailhouse_shutdown_nb);
+ init_hypercall();
+
return 0;
remove_cells_dir:
#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;
{
__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;
}
{
__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;
}
{
__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;
}
comm_region->reply_from_cell = reply;
}
+/** @} **/
+
#endif /* !__ASSEMBLY__ */
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) {
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);