Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168009433
D8100.id20978.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D8100.id20978.diff
View Options
Index: sys/amd64/include/bhyve_hypercall.h
===================================================================
--- /dev/null
+++ sys/amd64/include/bhyve_hypercall.h
@@ -0,0 +1,383 @@
+/*-
+ * Copyright (c) 2016 Domagoj Stolfa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_HYPERCALL_H_
+#define _MACHINE_HYPERCALL_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <x86/x86_var.h>
+#include <x86/cputypes.h>
+
+#define HYPERCALL_RET_NOT_IMPL -2
+#define HYPERCALL_RET_ERROR -1
+#define HYPERCALL_RET_SUCCESS 0
+
+#define VMCALL ".byte 0x0f,0x01,0xc1\n"
+#define VMMCALL ".byte 0x0f,0x01,0xd9\n"
+
+typedef struct hypercall_arg {
+ __uint64_t len;
+ __uint64_t val;
+} hc_arg_t;
+
+/*
+ * Used to create additional known hypercalls. The name
+ * of each of the defines should correspond to the function
+ * being called once the hypercall is initiated.
+ * Keep the defines in order.
+ *
+ * Keep in sync with ring_plevel.
+ */
+#define HYPERCALL_COMPAT_RESERVED1 0
+#define HYPERCALL_COMPAT_RESERVED2 1
+#define HYPERCALL_COMPAT_RESERVED3 2
+#define HYPERCALL_COMPAT_RESERVED4 3
+#define HYPERCALL_COMPAT_RESERVED5 4
+#define HYPERCALL_COMPAT_RESERVED6 5
+#define HYPERCALL_COMPAT_RESERVED7 6
+#define HYPERCALL_COMPAT_RESERVED8 7
+#define HYPERCALL_COMPAT_RESERVED9 8
+#define HYPERCALL_COMPAT_RESERVED10 9
+#define HYPERCALL_COMPAT_RESERVED11 10
+#define HYPERCALL_COMPAT_RESERVED12 11
+#define HYPERCALL_COMPAT_RESERVED13 12
+#define HYPERCALL_COMPAT_RESERVED14 13
+#define HYPERCALL_COMPAT_RESERVED15 14
+#define HYPERCALL_COMPAT_RESERVED16 15
+#define HYPERCALL_COMPAT_RESERVED17 16
+#define HYPERCALL_COMPAT_RESERVED18 17
+#define HYPERCALL_COMPAT_RESERVED19 18
+#define HYPERCALL_COMPAT_RESERVED20 19
+#define HYPERCALL_COMPAT_RESERVED21 20
+#define HYPERCALL_COMPAT_RESERVED22 21
+#define HYPERCALL_COMPAT_RESERVED23 22
+#define HYPERCALL_COMPAT_RESERVED24 23
+#define HYPERCALL_COMPAT_RESERVED25 24
+#define HYPERCALL_COMPAT_RESERVED26 25
+#define HYPERCALL_COMPAT_RESERVED27 26
+#define HYPERCALL_COMPAT_RESERVED28 27
+#define HYPERCALL_COMPAT_RESERVED29 28
+#define HYPERCALL_COMPAT_RESERVED30 29
+#define HYPERCALL_COMPAT_RESERVED31 30
+#define HYPERCALL_COMPAT_RESERVED32 31
+#define HYPERCALL_COMPAT_RESERVED33 32
+#define HYPERCALL_COMPAT_RESERVED34 33
+#define HYPERCALL_COMPAT_RESERVED35 34
+#define HYPERCALL_COMPAT_RESERVED36 35
+#define HYPERCALL_COMPAT_RESERVED37 36
+#define HYPERCALL_COMPAT_RESERVED38 37
+#define HYPERCALL_COMPAT_RESERVED39 38
+#define HYPERCALL_COMPAT_RESERVED40 39
+#define HYPERCALL_COMPAT_RESERVED41 40
+#define HYPERCALL_COMPAT_RESERVED42 41
+#define HYPERCALL_COMPAT_RESERVED43 42
+#define HYPERCALL_COMPAT_RESERVED44 43
+#define HYPERCALL_COMPAT_RESERVED45 44
+#define HYPERCALL_COMPAT_RESERVED46 45
+#define HYPERCALL_COMPAT_RESERVED47 46
+#define HYPERCALL_COMPAT_RESERVED48 47
+#define HYPERCALL_COMPAT_RESERVED49 48
+#define HYPERCALL_COMPAT_RESERVED50 49
+#define HYPERCALL_COMPAT_RESERVED51 50
+#define HYPERCALL_COMPAT_RESERVED52 51
+#define HYPERCALL_COMPAT_RESERVED53 52
+#define HYPERCALL_COMPAT_RESERVED54 53
+#define HYPERCALL_COMPAT_RESERVED55 54
+#define HYPERCALL_COMPAT_RESERVED56 55
+#define HYPERCALL_COMPAT_RESERVED57 56
+#define HYPERCALL_COMPAT_RESERVED58 57
+#define HYPERCALL_COMPAT_RESERVED59 58
+#define HYPERCALL_COMPAT_RESERVED60 59
+#define HYPERCALL_COMPAT_RESERVED61 60
+#define HYPERCALL_COMPAT_RESERVED62 61
+#define HYPERCALL_COMPAT_RESERVED63 62
+#define HYPERCALL_COMPAT_RESERVED64 63
+#define HYPERCALL_COMPAT_RESERVED65 64
+#define HYPERCALL_COMPAT_RESERVED66 65
+#define HYPERCALL_COMPAT_RESERVED67 66
+#define HYPERCALL_COMPAT_RESERVED68 67
+#define HYPERCALL_COMPAT_RESERVED69 68
+#define HYPERCALL_COMPAT_RESERVED70 69
+#define HYPERCALL_COMPAT_RESERVED71 70
+#define HYPERCALL_COMPAT_RESERVED72 71
+#define HYPERCALL_COMPAT_RESERVED73 72
+#define HYPERCALL_COMPAT_RESERVED74 73
+#define HYPERCALL_COMPAT_RESERVED75 74
+#define HYPERCALL_COMPAT_RESERVED76 75
+#define HYPERCALL_COMPAT_RESERVED77 76
+#define HYPERCALL_COMPAT_RESERVED78 77
+#define HYPERCALL_COMPAT_RESERVED79 78
+#define HYPERCALL_COMPAT_RESERVED80 79
+#define HYPERCALL_DTRACE_PROBE_CREATE 81
+#define HYPERCALL_DTRACE_PROBE 82
+#define HYPERCALL_DTRACE_RESERVED1 83
+#define HYPERCALL_DTRACE_RESERVED2 84
+#define HYPERCALL_DTRACE_RESERVED3 85
+#define HYPERCALL_DTRACE_RESERVED4 86
+#define HYPERCALL_DTRACE_RESERVED5 87
+
+#define HYPERCALL_INDEX_MAX 88
+
+/*
+ * The following functions perform hypercalls towards
+ * the host OS. Each of the functions uses registers
+ * RAX and RBX in order to pass in information to the
+ * host OS. The registers used for argument passing
+ * are RCX, RDX, RSI, RDI and the 8 new registers on
+ * amd64 architecture, R8-R15.
+ */
+
+static __inline __int64_t
+hypercall0(__uint64_t c)
+{
+ const __uint64_t nargs = 0;
+ __int64_t ret;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs)
+ : "memory", "rsp");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs)
+ : "memory", "rsp");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall1(__uint64_t c, hc_arg_t *arg0)
+{
+ const __uint64_t nargs = 1;
+ __int64_t ret;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val)
+ : "rax", "rbx", "rcx", "rdx");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val)
+ : "rax", "rbx", "rcx", "rdx");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall2(__uint64_t c, hc_arg_t *arg0,
+ hc_arg_t *arg1)
+{
+ const __uint64_t nargs = 2;
+ __int64_t ret;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall3(__uint64_t c, hc_arg_t *arg0,
+ hc_arg_t *arg1, hc_arg_t *arg2)
+{
+ const __uint64_t nargs = 3;
+ __int64_t ret;
+ register __uint64_t arg2_len __asm("r8") = arg2->len;
+ register __uint64_t arg2_val __asm("r9") = arg2->val;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall4(__uint64_t c, hc_arg_t *arg0,
+ hc_arg_t *arg1, hc_arg_t *arg2,
+ hc_arg_t *arg3)
+{
+ const __uint64_t nargs = 4;
+ __int64_t ret;
+ register __uint64_t arg2_len __asm("r8") = arg2->len;
+ register __uint64_t arg2_val __asm("r9") = arg2->val;
+ register __uint64_t arg3_len __asm("r10") = arg3->len;
+ register __uint64_t arg3_val __asm("r11") = arg3->val;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall5(__uint64_t c, hc_arg_t *arg0,
+ hc_arg_t *arg1, hc_arg_t *arg2,
+ hc_arg_t *arg3, hc_arg_t *arg4)
+{
+ const __uint64_t nargs = 5;
+ __int64_t ret;
+ register __uint64_t arg2_len __asm("r8") = arg2->len;
+ register __uint64_t arg2_val __asm("r9") = arg2->val;
+ register __uint64_t arg3_len __asm("r10") = arg3->len;
+ register __uint64_t arg3_val __asm("r11") = arg3->val;
+ register __uint64_t arg4_len __asm("r12") = arg4->len;
+ register __uint64_t arg4_val __asm("r13") = arg4->val;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val),
+ "r"(arg4_len), "r"(arg4_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val),
+ "r"(arg4_len), "r"(arg4_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13");
+ }
+ return (ret);
+}
+
+static __inline __int64_t
+hypercall6(__uint64_t c, hc_arg_t *arg0,
+ hc_arg_t *arg1, hc_arg_t *arg2,
+ hc_arg_t *arg3, hc_arg_t *arg4,
+ hc_arg_t *arg5)
+{
+ const __uint64_t nargs = 6;
+ __int64_t ret;
+ register __uint64_t arg2_len __asm("r8") = arg2->len;
+ register __uint64_t arg2_val __asm("r9") = arg2->val;
+ register __uint64_t arg3_len __asm("r10") = arg3->len;
+ register __uint64_t arg3_val __asm("r11") = arg3->val;
+ register __uint64_t arg4_len __asm("r12") = arg4->len;
+ register __uint64_t arg4_val __asm("r13") = arg4->val;
+ register __uint64_t arg5_len __asm("r14") = arg5->len;
+ register __uint64_t arg5_val __asm("r15") = arg5->val;
+ if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ __asm __volatile(
+ VMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val),
+ "r"(arg4_len), "r"(arg4_val),
+ "r"(arg5_len), "r"(arg5_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15");
+ } else {
+ __asm __volatile(
+ VMMCALL
+ : "=a"(ret)
+ : "a"(c), "b"(nargs),
+ "c"(arg0->len), "d"(arg0->val),
+ "S"(arg1->len), "D"(arg1->val),
+ "r"(arg2_len), "r"(arg2_val),
+ "r"(arg3_len), "r"(arg3_val),
+ "r"(arg4_len), "r"(arg4_val),
+ "r"(arg5_len), "r"(arg5_val)
+ : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15");
+ }
+ return (ret);
+}
+
+#endif /* _MACHINE_HYPERCALL_H_ */
Index: sys/amd64/include/vmm.h
===================================================================
--- sys/amd64/include/vmm.h
+++ sys/amd64/include/vmm.h
@@ -104,6 +104,14 @@
#ifdef _KERNEL
+/*
+ * The maximum amount of arguments currently supproted
+ * through the hypercall functionality in the VMM.
+ * Everything higher than HYPERCALL_MAX_ARGS will be
+ * discarded.
+ */
+#define HYPERCALL_MAX_ARGS 6
+
#define VM_MAX_NAMELEN 32
struct vm;
@@ -167,8 +175,9 @@
vmi_vlapic_cleanup vlapic_cleanup;
};
-extern struct vmm_ops vmm_ops_intel;
-extern struct vmm_ops vmm_ops_amd;
+extern struct vmm_ops vmm_ops_intel;
+extern struct vmm_ops vmm_ops_amd;
+extern int hypercalls_enabled;
int vm_create(const char *name, struct vm **retvm);
void vm_destroy(struct vm *vm);
@@ -533,6 +542,7 @@
VM_EXITCODE_MWAIT,
VM_EXITCODE_SVM,
VM_EXITCODE_REQIDLE,
+ VM_EXITCODE_HYPERCALL,
VM_EXITCODE_MAX
};
@@ -573,6 +583,10 @@
struct vm_guest_paging paging;
};
+struct vm_hypercall {
+ struct vm_guest_paging paging;
+};
+
struct vm_exit {
enum vm_exitcode exitcode;
int inst_length; /* 0 means unknown */
@@ -636,7 +650,8 @@
struct {
enum vm_suspend_how how;
} suspended;
- struct vm_task_switch task_switch;
+ struct vm_task_switch task_switch;
+ struct vm_hypercall hypercall;
} u;
};
Index: sys/amd64/vmm/amd/svm.c
===================================================================
--- sys/amd64/vmm/amd/svm.c
+++ sys/amd64/vmm/amd/svm.c
@@ -158,7 +158,6 @@
static int
svm_cleanup(void)
{
-
smp_rendezvous(NULL, svm_disable, NULL, NULL);
return (0);
}
@@ -469,6 +468,9 @@
svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_MONITOR);
svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_MWAIT);
+ /* Enable VMMCALL to be used for DTrace probes */
+ svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_VMMCALL);
+
/*
* From section "Canonicalization and Consistency Checks" in APMv2
* the VMRUN intercept bit must be set to pass the consistency check.
@@ -849,6 +851,29 @@
vie_init(&vmexit->u.inst_emul.vie, inst_bytes, inst_len);
}
+static void
+svm_handle_hypercall(struct svm_softc *svm_sc, int vcpu, struct vmcb *vmcb, struct vm_exit *vmexit)
+{
+ struct vm_guest_paging *paging;
+ struct vmcb_segment seg;
+ uint64_t rsp;
+ int error;
+
+ paging = &vmexit->u.hypercall.paging;
+ vmexit->exitcode = VM_EXITCODE_HYPERCALL;
+
+ error = vmcb_read(svm_sc, vcpu, VM_REG_GUEST_RSP,
+ &rsp);
+ KASSERT(error == 0, ("%s: error %d getting RSP",
+ __func__, error));
+
+ error = vmcb_seg(vmcb, VM_REG_GUEST_SS, &seg);
+ KASSERT(error == 0, ("%s: error %d getting segment SS",
+ __func__, error));
+
+ svm_paging_info(vmcb, paging);
+}
+
#ifdef KTR
static const char *
intrtype_to_str(int intr_type)
@@ -1243,6 +1268,12 @@
return ("monitor");
case VMCB_EXIT_MWAIT:
return ("mwait");
+ case VMCB_EXIT_VMMCALL:
+ return ("vmmcall");
+ case VMCB_EXIT_VMLOAD:
+ return ("vmload");
+ case VMCB_EXIT_VMSAVE:
+ return ("vmsave");
default:
snprintf(reasonbuf, sizeof(reasonbuf), "%#lx", reason);
return (reasonbuf);
@@ -1344,6 +1375,13 @@
case VMCB_EXIT_NMI: /* external NMI */
handled = 1;
break;
+ case VMCB_EXIT_VMMCALL:
+ if (hypercalls_enabled) {
+ svm_handle_hypercall(svm_sc, vcpu, vmcb, vmexit);
+ } else {
+ handled = 1;
+ }
+ break;
case 0x40 ... 0x5F:
vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_EXCEPTION, 1);
reflect = 1;
Index: sys/amd64/vmm/amd/vmcb.h
===================================================================
--- sys/amd64/vmm/amd/vmcb.h
+++ sys/amd64/vmm/amd/vmcb.h
@@ -139,6 +139,8 @@
#define VMCB_EXIT_IO 0x7B
#define VMCB_EXIT_MSR 0x7C
#define VMCB_EXIT_SHUTDOWN 0x7F
+#define VMCB_EXIT_VMMCALL 0x81
+#define VMCB_EXIT_VMLOAD 0x82
#define VMCB_EXIT_VMSAVE 0x83
#define VMCB_EXIT_MONITOR 0x8A
#define VMCB_EXIT_MWAIT 0x8B
Index: sys/amd64/vmm/intel/vmx.c
===================================================================
--- sys/amd64/vmm/intel/vmx.c
+++ sys/amd64/vmm/intel/vmx.c
@@ -2474,6 +2474,14 @@
case EXIT_REASON_MWAIT:
vmexit->exitcode = VM_EXITCODE_MWAIT;
break;
+ case EXIT_REASON_VMCALL:
+ if (hypercalls_enabled) {
+ vmexit->exitcode = VM_EXITCODE_HYPERCALL;
+ vmx_paging_info(&vmexit->u.hypercall.paging);
+ } else {
+ handled = HANDLED;
+ }
+ break;
default:
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_UNKNOWN, 1);
break;
Index: sys/amd64/vmm/vmm.c
===================================================================
--- sys/amd64/vmm/vmm.c
+++ sys/amd64/vmm/vmm.c
@@ -55,6 +55,7 @@
#include <machine/cpu.h>
#include <machine/pcb.h>
#include <machine/smp.h>
+#include <machine/bhyve_hypercall.h>
#include <x86/psl.h>
#include <x86/apicreg.h>
@@ -224,6 +225,103 @@
&trace_guest_exceptions, 0,
"Trap into hypervisor on all guest exceptions and reflect them back");
+int hypercalls_enabled = 0;
+SYSCTL_INT(_hw_vmm, OID_AUTO, hypercalls_enabled, CTLFLAG_RWTUN,
+ &hypercalls_enabled, 0,
+ "Enable handling of hypercalls inside the VMM");
+
+
+static int8_t ring_plevel[HYPERCALL_INDEX_MAX] = {
+ [HYPERCALL_COMPAT_RESERVED1] = 0,
+ [HYPERCALL_COMPAT_RESERVED2] = 0,
+ [HYPERCALL_COMPAT_RESERVED3] = 0,
+ [HYPERCALL_COMPAT_RESERVED4] = 0,
+ [HYPERCALL_COMPAT_RESERVED5] = 0,
+ [HYPERCALL_COMPAT_RESERVED6] = 0,
+ [HYPERCALL_COMPAT_RESERVED7] = 0,
+ [HYPERCALL_COMPAT_RESERVED8] = 0,
+ [HYPERCALL_COMPAT_RESERVED9] = 0,
+ [HYPERCALL_COMPAT_RESERVED10] = 0,
+ [HYPERCALL_COMPAT_RESERVED11] = 0,
+ [HYPERCALL_COMPAT_RESERVED12] = 0,
+ [HYPERCALL_COMPAT_RESERVED13] = 0,
+ [HYPERCALL_COMPAT_RESERVED14] = 0,
+ [HYPERCALL_COMPAT_RESERVED15] = 0,
+ [HYPERCALL_COMPAT_RESERVED16] = 0,
+ [HYPERCALL_COMPAT_RESERVED17] = 0,
+ [HYPERCALL_COMPAT_RESERVED18] = 0,
+ [HYPERCALL_COMPAT_RESERVED19] = 0,
+ [HYPERCALL_COMPAT_RESERVED20] = 0,
+ [HYPERCALL_COMPAT_RESERVED21] = 0,
+ [HYPERCALL_COMPAT_RESERVED22] = 0,
+ [HYPERCALL_COMPAT_RESERVED23] = 0,
+ [HYPERCALL_COMPAT_RESERVED24] = 0,
+ [HYPERCALL_COMPAT_RESERVED25] = 0,
+ [HYPERCALL_COMPAT_RESERVED26] = 0,
+ [HYPERCALL_COMPAT_RESERVED27] = 0,
+ [HYPERCALL_COMPAT_RESERVED28] = 0,
+ [HYPERCALL_COMPAT_RESERVED29] = 0,
+ [HYPERCALL_COMPAT_RESERVED30] = 0,
+ [HYPERCALL_COMPAT_RESERVED31] = 0,
+ [HYPERCALL_COMPAT_RESERVED32] = 0,
+ [HYPERCALL_COMPAT_RESERVED33] = 0,
+ [HYPERCALL_COMPAT_RESERVED34] = 0,
+ [HYPERCALL_COMPAT_RESERVED35] = 0,
+ [HYPERCALL_COMPAT_RESERVED36] = 0,
+ [HYPERCALL_COMPAT_RESERVED37] = 0,
+ [HYPERCALL_COMPAT_RESERVED38] = 0,
+ [HYPERCALL_COMPAT_RESERVED39] = 0,
+ [HYPERCALL_COMPAT_RESERVED40] = 0,
+ [HYPERCALL_COMPAT_RESERVED41] = 0,
+ [HYPERCALL_COMPAT_RESERVED42] = 0,
+ [HYPERCALL_COMPAT_RESERVED43] = 0,
+ [HYPERCALL_COMPAT_RESERVED44] = 0,
+ [HYPERCALL_COMPAT_RESERVED45] = 0,
+ [HYPERCALL_COMPAT_RESERVED46] = 0,
+ [HYPERCALL_COMPAT_RESERVED47] = 0,
+ [HYPERCALL_COMPAT_RESERVED48] = 0,
+ [HYPERCALL_COMPAT_RESERVED49] = 0,
+ [HYPERCALL_COMPAT_RESERVED50] = 0,
+ [HYPERCALL_COMPAT_RESERVED51] = 0,
+ [HYPERCALL_COMPAT_RESERVED52] = 0,
+ [HYPERCALL_COMPAT_RESERVED53] = 0,
+ [HYPERCALL_COMPAT_RESERVED54] = 0,
+ [HYPERCALL_COMPAT_RESERVED55] = 0,
+ [HYPERCALL_COMPAT_RESERVED56] = 0,
+ [HYPERCALL_COMPAT_RESERVED57] = 0,
+ [HYPERCALL_COMPAT_RESERVED58] = 0,
+ [HYPERCALL_COMPAT_RESERVED59] = 0,
+ [HYPERCALL_COMPAT_RESERVED60] = 0,
+ [HYPERCALL_COMPAT_RESERVED61] = 0,
+ [HYPERCALL_COMPAT_RESERVED62] = 0,
+ [HYPERCALL_COMPAT_RESERVED63] = 0,
+ [HYPERCALL_COMPAT_RESERVED64] = 0,
+ [HYPERCALL_COMPAT_RESERVED65] = 0,
+ [HYPERCALL_COMPAT_RESERVED66] = 0,
+ [HYPERCALL_COMPAT_RESERVED67] = 0,
+ [HYPERCALL_COMPAT_RESERVED68] = 0,
+ [HYPERCALL_COMPAT_RESERVED69] = 0,
+ [HYPERCALL_COMPAT_RESERVED70] = 0,
+ [HYPERCALL_COMPAT_RESERVED71] = 0,
+ [HYPERCALL_COMPAT_RESERVED72] = 0,
+ [HYPERCALL_COMPAT_RESERVED73] = 0,
+ [HYPERCALL_COMPAT_RESERVED74] = 0,
+ [HYPERCALL_COMPAT_RESERVED75] = 0,
+ [HYPERCALL_COMPAT_RESERVED76] = 0,
+ [HYPERCALL_COMPAT_RESERVED77] = 0,
+ [HYPERCALL_COMPAT_RESERVED78] = 0,
+ [HYPERCALL_COMPAT_RESERVED79] = 0,
+ [HYPERCALL_COMPAT_RESERVED80] = 0,
+ [HYPERCALL_DTRACE_PROBE_CREATE] = 0,
+ [HYPERCALL_DTRACE_PROBE] = 0,
+ [HYPERCALL_DTRACE_RESERVED1] = 3, /* Reserved for DTrace */
+ [HYPERCALL_DTRACE_RESERVED2] = 0, /* Reserved for DTrace */
+ [HYPERCALL_DTRACE_RESERVED3] = 0, /* Reserved for DTrace */
+ [HYPERCALL_DTRACE_RESERVED4] = 0, /* Reserved for DTrace */
+ [HYPERCALL_DTRACE_RESERVED5] = 0, /* Reserved for DTrace */
+};
+
+
static void vm_free_memmap(struct vm *vm, int ident);
static bool sysmem_mapping(struct vm *vm, struct mem_map *mm);
static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr);
@@ -538,8 +636,9 @@
if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL)
return (ENOMEM);
- else
+ else {
return (0);
+ }
}
int
@@ -1507,6 +1606,166 @@
return (0);
}
+static int
+hypercall_copy_arg(struct vm *vm, int vcpuid, uint64_t ds_base,
+ struct hypercall_arg *arg, struct vm_guest_paging *paging, void *dst)
+{
+ struct vm_copyinfo copyinfo[2];
+ uint64_t gla;
+ int error, fault;
+
+ gla = ds_base + arg->val;
+ error = vm_copy_setup(vm, vcpuid, paging, gla, arg->len,
+ PROT_READ, copyinfo, nitems(copyinfo), &fault);
+ if (error || fault) {
+ return (error);
+ }
+
+ vm_copyin(vm, vcpuid, copyinfo, dst, arg->len);
+ vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));
+
+ return (0);
+}
+
+static int
+vm_handle_hypercall(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu)
+{
+ struct vm_guest_paging *paging;
+ struct hypercall_arg args[HYPERCALL_MAX_ARGS] = { {0} };
+ /*
+ * This struct sets the requirement of the following registers being used:
+ *
+ * arg0->len = RCX
+ * arg0->val = RDX
+ *
+ * arg1->len = RSI
+ * arg1->val = RDI
+ *
+ * arg2->len = R8
+ * arg2->val = R9
+ *
+ * arg3->len = R10
+ * arg3->val = R11
+ *
+ * arg4->len = R12
+ * arg4->val = R13
+ *
+ * arg5->len = R14
+ * arg5->val = R15
+ *
+ * Using any different order while passing arguments in from the guest
+ * OS will result in the wrong values at wrong places inside this
+ * function.
+ */
+ struct hypercall_arg regs[] = {
+ [0] = {
+ .len = VM_REG_GUEST_RCX,
+ .val = VM_REG_GUEST_RDX
+ },
+ [1] = {
+ .len = VM_REG_GUEST_RSI,
+ .val = VM_REG_GUEST_RDI
+ },
+ [2] = {
+ .len = VM_REG_GUEST_R8,
+ .val = VM_REG_GUEST_R9
+ },
+ [3] = {
+ .len = VM_REG_GUEST_R10,
+ .val = VM_REG_GUEST_R11
+ },
+ [4] = {
+ .len = VM_REG_GUEST_R12,
+ .val = VM_REG_GUEST_R13
+ },
+ [5] = {
+ .len = VM_REG_GUEST_R14,
+ .val = VM_REG_GUEST_R15
+ },
+ };
+ struct seg_desc cs_desc;
+ uint64_t hcid, nargs, i;
+ int error, handled;
+
+ error = vm_get_register(vm, vcpuid, VM_REG_GUEST_RAX, &hcid);
+ KASSERT(error == 0, ("%s: error %d getting RAX",
+ __func__, error));
+ /*
+ * Ensure that the hypercall called by the guest never exceed
+ * the maximum number of hypercalls defined.
+ */
+ if (hcid >= HYPERCALL_INDEX_MAX) {
+ error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, HYPERCALL_RET_ERROR);
+ KASSERT(error == 0, ("%s: error %d setting RAX",
+ __func__, error));
+ return (0);
+ }
+
+ error = vm_get_seg_desc(vm, vcpuid, VM_REG_GUEST_CS, &cs_desc);
+ KASSERT(error == 0, ("%s: error %d getting CS descriptor",
+ __func__, error));
+
+ /*
+ * The check ensures that each of the hypercalls that is called
+ * from the guest is called from the correct protection ring.
+ */
+ if (SEG_DESC_DPL(cs_desc.access) != ring_plevel[hcid]) {
+ error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, HYPERCALL_RET_ERROR);
+ KASSERT(error == 0, ("%s: error %d setting RAX",
+ __func__, error));
+ return (0);
+ }
+
+ error = vm_get_register(vm, vcpuid, VM_REG_GUEST_RBX, &nargs);
+ KASSERT(error == 0, ("%s: error %d getting RBX",
+ __func__, error));
+
+ if (nargs > HYPERCALL_MAX_ARGS) {
+ error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, HYPERCALL_RET_ERROR);
+ KASSERT(error == 0, ("%s: error %d setting RAX",
+ __func__, error));
+ return (0);
+ }
+
+ handled = 0;
+ paging = &vmexit->u.hypercall.paging;
+
+ for (i = 0; i < nargs; i++) {
+ error = vm_get_register(vm, vcpuid, regs[i].len, &args[i].len);
+ KASSERT(error == 0, ("%s: error %d copying at index %lu",
+ __func__, error, i));
+ error = vm_get_register(vm, vcpuid, regs[i].val, &args[i].val);
+ KASSERT(error == 0, ("%s: error %d copying at index %lu",
+ __func__, error, i));
+ }
+
+ /*
+ * From this point on, all the arguments passed in from the
+ * guest are contained in the args array.
+ */
+
+ switch (hcid) {
+ case HYPERCALL_DTRACE_PROBE_CREATE:
+ case HYPERCALL_DTRACE_PROBE:
+ case HYPERCALL_DTRACE_RESERVED1:
+ case HYPERCALL_DTRACE_RESERVED2:
+ case HYPERCALL_DTRACE_RESERVED3:
+ case HYPERCALL_DTRACE_RESERVED4:
+ case HYPERCALL_DTRACE_RESERVED5:
+ error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, HYPERCALL_RET_NOT_IMPL);
+ KASSERT(error == 0, ("%s: error %d setting RAX",
+ __func__, error));
+ break;
+ default:
+ error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, HYPERCALL_RET_NOT_IMPL);
+ KASSERT(error == 0, ("%s: error %d setting RAX",
+ __func__, error));
+ break;
+ }
+
+ return (0);
+}
+
int
vm_suspend(struct vm *vm, enum vm_suspend_how how)
{
@@ -1675,6 +1934,9 @@
case VM_EXITCODE_MWAIT:
vm_inject_ud(vm, vcpuid);
break;
+ case VM_EXITCODE_HYPERCALL:
+ error = vm_handle_hypercall(vm, vcpuid, vme, &retu);
+ break;
default:
retu = true; /* handled in userland */
break;
@@ -1855,6 +2117,7 @@
/* Handle exceptions serially */
*retinfo = info2;
}
+
return (1);
}
Index: sys/amd64/vmm/x86.h
===================================================================
--- sys/amd64/vmm/x86.h
+++ sys/amd64/vmm/x86.h
@@ -47,6 +47,8 @@
#define CPUID_8000_0006 (0x80000006)
#define CPUID_8000_0007 (0x80000007)
#define CPUID_8000_0008 (0x80000008)
+#define CPUID_4000_0000 (0x40000000)
+#define CPUID_4000_0001 (0x40000001)
/*
* CPUID instruction Fn0000_0001:
Index: sys/amd64/vmm/x86.c
===================================================================
--- sys/amd64/vmm/x86.c
+++ sys/amd64/vmm/x86.c
@@ -50,7 +50,7 @@
SYSCTL_DECL(_hw_vmm);
static SYSCTL_NODE(_hw_vmm, OID_AUTO, topology, CTLFLAG_RD, 0, NULL);
-#define CPUID_VM_HIGH 0x40000000
+#define CPUID_VM_HIGH 0x40000001
static const char bhyve_id[12] = "bhyve bhyve ";
@@ -463,12 +463,18 @@
}
break;
- case 0x40000000:
+ case CPUID_4000_0000:
regs[0] = CPUID_VM_HIGH;
bcopy(bhyve_id, ®s[1], 4);
bcopy(bhyve_id + 4, ®s[2], 4);
bcopy(bhyve_id + 8, ®s[3], 4);
break;
+ case CPUID_4000_0001:
+ regs[0] = hypercalls_enabled;
+ regs[1] = HYPERCALL_MAX_ARGS;
+ regs[2] = 0;
+ regs[3] = 0;
+ break;
default:
/*
Index: sys/kern/subr_param.c
===================================================================
--- sys/kern/subr_param.c
+++ sys/kern/subr_param.c
@@ -149,6 +149,7 @@
"hv",
"vmware",
"kvm",
+ "bhyve",
NULL
};
CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST);
Index: sys/sys/systm.h
===================================================================
--- sys/sys/systm.h
+++ sys/sys/systm.h
@@ -74,7 +74,7 @@
* Keep in sync with vm_guest_sysctl_names[].
*/
enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV,
- VM_GUEST_VMWARE, VM_GUEST_KVM, VM_LAST };
+ VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_LAST };
#if defined(WITNESS) || defined(INVARIANT_SUPPORT)
void kassert_panic(const char *fmt, ...) __printflike(1, 2);
Index: sys/x86/x86/identcpu.c
===================================================================
--- sys/x86/x86/identcpu.c
+++ sys/x86/x86/identcpu.c
@@ -1288,6 +1288,8 @@
vm_guest = VM_GUEST_HV;
else if (strcmp(hv_vendor, "KVMKVMKVM") == 0)
vm_guest = VM_GUEST_KVM;
+ else if (strcmp(hv_vendor, "bhyve bhyve ") == 0)
+ vm_guest = VM_GUEST_BHYVE;
}
return;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Aug 26, 9:41 PM (10 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37330078
Default Alt Text
D8100.id20978.diff (28 KB)
Attached To
Mode
D8100: Bhyve hypercall implementation
Attached
Detach File
Event Timeline
Log In to Comment