summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-10-10 21:48:59 +0000
committerneel <neel@FreeBSD.org>2014-10-10 21:48:59 +0000
commitae1ff84ece91e97a57c3b53f820787e1e59f26a4 (patch)
treef148690323fb6d774bf09d7608499eaec76d18a6 /sys/amd64/vmm
parent16cbb8793a45363cd459773925c4c4862981337f (diff)
downloadFreeBSD-src-ae1ff84ece91e97a57c3b53f820787e1e59f26a4.zip
FreeBSD-src-ae1ff84ece91e97a57c3b53f820787e1e59f26a4.tar.gz
Fix bhyvectl so it works correctly on AMD/SVM hosts. Also, add command line
options to display some key VMCB fields. The set of valid options that can be passed to bhyvectl now depends on the processor type. AMD-specific options are identified by a "--vmcb" or "--avic" in the option name. Intel-specific options are identified by a "--vmcs" in the option name. Submitted by: Anish Gupta (akgupt3@gmail.com)
Diffstat (limited to 'sys/amd64/vmm')
-rw-r--r--sys/amd64/vmm/amd/vmcb.c48
-rw-r--r--sys/amd64/vmm/amd/vmcb.h40
2 files changed, 88 insertions, 0 deletions
diff --git a/sys/amd64/vmm/amd/vmcb.c b/sys/amd64/vmm/amd/vmcb.c
index b16eb44..8be2308 100644
--- a/sys/amd64/vmm/amd/vmcb.c
+++ b/sys/amd64/vmm/amd/vmcb.c
@@ -111,6 +111,48 @@ vmcb_segptr(struct vmcb *vmcb, int type)
return (seg);
}
+static int
+vmcb_access(struct svm_softc *softc, int vcpu, int write, int ident,
+ uint64_t *val)
+{
+ struct vmcb *vmcb;
+ int off, bytes;
+ char *ptr;
+
+ vmcb = svm_get_vmcb(softc, vcpu);
+ off = VMCB_ACCESS_OFFSET(ident);
+ bytes = VMCB_ACCESS_BYTES(ident);
+
+ if ((off + bytes) >= sizeof (struct vmcb))
+ return (EINVAL);
+
+ ptr = (char *)vmcb;
+
+ if (!write)
+ *val = 0;
+
+ switch (bytes) {
+ case 8:
+ case 4:
+ case 2:
+ if (write)
+ memcpy(ptr + off, val, bytes);
+ else
+ memcpy(val, ptr + off, bytes);
+ break;
+ default:
+ VCPU_CTR1(softc->vm, vcpu,
+ "Invalid size %d for VMCB access: %d", bytes);
+ return (EINVAL);
+ }
+
+ /* Invalidate all VMCB state cached by h/w. */
+ if (write)
+ svm_set_dirty(softc, vcpu, 0xffffffff);
+
+ return (0);
+}
+
/*
* Read from segment selector, control and general purpose register of VMCB.
*/
@@ -126,6 +168,9 @@ vmcb_read(struct svm_softc *sc, int vcpu, int ident, uint64_t *retval)
state = &vmcb->state;
err = 0;
+ if (VMCB_ACCESS_OK(ident))
+ return (vmcb_access(sc, vcpu, 0, ident, retval));
+
switch (ident) {
case VM_REG_GUEST_CR0:
*retval = state->cr0;
@@ -210,6 +255,9 @@ vmcb_write(struct svm_softc *sc, int vcpu, int ident, uint64_t val)
dirtyseg = 0;
err = 0;
+ if (VMCB_ACCESS_OK(ident))
+ return (vmcb_access(sc, vcpu, 1, ident, &val));
+
switch (ident) {
case VM_REG_GUEST_CR0:
state->cr0 = val;
diff --git a/sys/amd64/vmm/amd/vmcb.h b/sys/amd64/vmm/amd/vmcb.h
index 82e1ceb..e8fa91c 100644
--- a/sys/amd64/vmm/amd/vmcb.h
+++ b/sys/amd64/vmm/amd/vmcb.h
@@ -164,6 +164,45 @@ struct svm_softc;
#define VMCB_EXITINTINFO_VALID(x) (((x) & BIT(31)) ? 1 : 0)
#define VMCB_EXITINTINFO_EC(x) (((x) >> 32) & 0xFFFFFFFF)
+/* Offset of various VMCB fields. */
+#define VMCB_OFF_CTRL(x) (x)
+#define VMCB_OFF_STATE(x) ((x) + 0x400)
+
+#define VMCB_OFF_CR_INTERCEPT VMCB_OFF_CTRL(0x0)
+#define VMCB_OFF_DR_INTERCEPT VMCB_OFF_CTRL(0x4)
+#define VMCB_OFF_EXC_INTERCEPT VMCB_OFF_CTRL(0x8)
+#define VMCB_OFF_INST1_INTERCEPT VMCB_OFF_CTRL(0xC)
+#define VMCB_OFF_INST2_INTERCEPT VMCB_OFF_CTRL(0x10)
+#define VMCB_OFF_IO_PERM VMCB_OFF_CTRL(0x40)
+#define VMCB_OFF_MSR_PERM VMCB_OFF_CTRL(0x48)
+#define VMCB_OFF_TSC_OFFSET VMCB_OFF_CTRL(0x50)
+#define VMCB_OFF_ASID VMCB_OFF_CTRL(0x58)
+#define VMCB_OFF_TLB_CTRL VMCB_OFF_CTRL(0x5C)
+#define VMCB_OFF_VIRQ VMCB_OFF_CTRL(0x60)
+#define VMCB_OFF_EXIT_REASON VMCB_OFF_CTRL(0x70)
+#define VMCB_OFF_EXITINFO1 VMCB_OFF_CTRL(0x78)
+#define VMCB_OFF_EXITINFO2 VMCB_OFF_CTRL(0x80)
+#define VMCB_OFF_EXITINTINFO VMCB_OFF_CTRL(0x88)
+#define VMCB_OFF_AVIC_BAR VMCB_OFF_CTRL(0x98)
+#define VMCB_OFF_NPT_BASE VMCB_OFF_CTRL(0xB0)
+#define VMCB_OFF_AVIC_PAGE VMCB_OFF_CTRL(0xE0)
+#define VMCB_OFF_AVIC_LT VMCB_OFF_CTRL(0xF0)
+#define VMCB_OFF_AVIC_PT VMCB_OFF_CTRL(0xF8)
+#define VMCB_OFF_SYSENTER_CS VMCB_OFF_STATE(0x228)
+#define VMCB_OFF_SYSENTER_ESP VMCB_OFF_STATE(0x230)
+#define VMCB_OFF_SYSENTER_EIP VMCB_OFF_STATE(0x238)
+#define VMCB_OFF_GUEST_PAT VMCB_OFF_STATE(0x268)
+
+/*
+ * Encode the VMCB offset and bytes that we want to read from VMCB.
+ */
+#define VMCB_ACCESS(o, w) (0x80000000 | (((w) & 0xF) << 16) | \
+ ((o) & 0xFFF))
+#define VMCB_ACCESS_OK(v) ((v) & 0x80000000 )
+#define VMCB_ACCESS_BYTES(v) (((v) >> 16) & 0xF)
+#define VMCB_ACCESS_OFFSET(v) ((v) & 0xFFF)
+
+#ifdef _KERNEL
/* VMCB save state area segment format */
struct vmcb_segment {
uint16_t selector;
@@ -287,4 +326,5 @@ int vmcb_setdesc(void *arg, int vcpu, int ident, struct seg_desc *desc);
int vmcb_getdesc(void *arg, int vcpu, int ident, struct seg_desc *desc);
int vmcb_seg(struct vmcb *vmcb, int ident, struct vmcb_segment *seg);
+#endif /* _KERNEL */
#endif /* _VMCB_H_ */
OpenPOWER on IntegriCloud