VMM: Move MSR emulation to vmm.c [4/4]
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 1 Feb 2016 16:33:09 +0000 (11:33 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 2 Feb 2016 22:43:52 +0000 (17:43 -0500)
It's now vendor independent, so we can move it out of vmx.c.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/vmm/intel/vmx.c
kern/arch/x86/vmm/vmm.c

index 95ebf97..317f68e 100644 (file)
@@ -1158,240 +1158,6 @@ static void dumpmsrs(void) {
        printk("core id %d\n", core_id());
 }
 
-/* emulated msr. For now, an msr value and a pointer to a helper that
- * performs the requested operation.
- */
-struct emmsr {
-       uint32_t reg;
-       char *name;
-       bool (*f)(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                 uint64_t *rax, uint32_t opcode);
-       bool written;
-       uint32_t edx, eax;
-};
-
-bool emsr_miscenable(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                     uint64_t *rax, uint32_t opcode);
-bool emsr_mustmatch(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                    uint64_t *rax, uint32_t opcode);
-bool emsr_readonly(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                   uint64_t *rax, uint32_t opcode);
-bool emsr_readzero(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                   uint64_t *rax, uint32_t opcode);
-bool emsr_fakewrite(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                    uint64_t *rax, uint32_t opcode);
-bool emsr_ok(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-             uint64_t *rax, uint32_t opcode);
-bool emsr_fake_apicbase(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                        uint64_t *rax, uint32_t opcode);
-
-struct emmsr emmsrs[] = {
-       {MSR_IA32_MISC_ENABLE, "MSR_IA32_MISC_ENABLE", emsr_miscenable},
-       {MSR_IA32_SYSENTER_CS, "MSR_IA32_SYSENTER_CS", emsr_ok},
-       {MSR_IA32_SYSENTER_EIP, "MSR_IA32_SYSENTER_EIP", emsr_ok},
-       {MSR_IA32_SYSENTER_ESP, "MSR_IA32_SYSENTER_ESP", emsr_ok},
-       {MSR_IA32_UCODE_REV, "MSR_IA32_UCODE_REV", emsr_fakewrite},
-       {MSR_CSTAR, "MSR_CSTAR", emsr_fakewrite},
-       {MSR_IA32_VMX_BASIC_MSR, "MSR_IA32_VMX_BASIC_MSR", emsr_fakewrite},
-       {MSR_IA32_VMX_PINBASED_CTLS_MSR, "MSR_IA32_VMX_PINBASED_CTLS_MSR",
-        emsr_fakewrite},
-       {MSR_IA32_VMX_PROCBASED_CTLS_MSR, "MSR_IA32_VMX_PROCBASED_CTLS_MSR",
-        emsr_fakewrite},
-       {MSR_IA32_VMX_PROCBASED_CTLS2, "MSR_IA32_VMX_PROCBASED_CTLS2",
-        emsr_fakewrite},
-       {MSR_IA32_VMX_EXIT_CTLS_MSR, "MSR_IA32_VMX_EXIT_CTLS_MSR",
-        emsr_fakewrite},
-       {MSR_IA32_VMX_ENTRY_CTLS_MSR, "MSR_IA32_VMX_ENTRY_CTLS_MSR",
-        emsr_fakewrite},
-       {MSR_IA32_ENERGY_PERF_BIAS, "MSR_IA32_ENERGY_PERF_BIAS",
-        emsr_fakewrite},
-       {MSR_LBR_SELECT, "MSR_LBR_SELECT", emsr_ok},
-       {MSR_LBR_TOS, "MSR_LBR_TOS", emsr_ok},
-       {MSR_LBR_NHM_FROM, "MSR_LBR_NHM_FROM", emsr_ok},
-       {MSR_LBR_NHM_TO, "MSR_LBR_NHM_TO", emsr_ok},
-       {MSR_LBR_CORE_FROM, "MSR_LBR_CORE_FROM", emsr_ok},
-       {MSR_LBR_CORE_TO, "MSR_LBR_CORE_TO", emsr_ok},
-
-       // grumble.
-       {MSR_OFFCORE_RSP_0, "MSR_OFFCORE_RSP_0", emsr_ok},
-       {MSR_OFFCORE_RSP_1, "MSR_OFFCORE_RSP_1", emsr_ok},
-       // louder.
-       {MSR_PEBS_LD_LAT_THRESHOLD, "MSR_PEBS_LD_LAT_THRESHOLD", emsr_ok},
-       // aaaaaahhhhhhhhhhhhhhhhhhhhh
-       {MSR_ARCH_PERFMON_EVENTSEL0, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
-       {MSR_ARCH_PERFMON_EVENTSEL1, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
-       {MSR_IA32_PERF_CAPABILITIES, "MSR_IA32_PERF_CAPABILITIES", emsr_ok},
-       // unsafe.
-       {MSR_IA32_APICBASE, "MSR_IA32_APICBASE", emsr_fake_apicbase},
-
-       // mostly harmless.
-       {MSR_TSC_AUX, "MSR_TSC_AUX", emsr_fakewrite},
-       {MSR_RAPL_POWER_UNIT, "MSR_RAPL_POWER_UNIT", emsr_readzero},
-
-       // TBD
-       {MSR_IA32_TSC_DEADLINE, "MSR_IA32_TSC_DEADLINE", emsr_fakewrite},
-};
-
-/* this may be the only register that needs special handling.
- * If there others then we might want to extend teh emmsr struct.
- */
-bool emsr_miscenable(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                     uint64_t *rax, uint32_t opcode)
-{
-       uint32_t eax, edx;
-
-       rdmsr(msr->reg, eax, edx);
-       /* we just let them read the misc msr for now. */
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = eax;
-               *rax |= MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
-               *rdx = edx;
-               return TRUE;
-       } else {
-               /* if they are writing what is already written, that's ok. */
-               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
-                       return TRUE;
-       }
-       printk
-               ("%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
-                msr->name, (uint32_t) *rdx, (uint32_t) *rax, edx, eax);
-       return FALSE;
-}
-
-/* TODO: this looks like a copy-paste for the read side.  What's the purpose of
- * mustmatch?  No one even uses it. */
-bool emsr_mustmatch(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                    uint64_t *rax, uint32_t opcode)
-{
-       uint32_t eax, edx;
-
-       rdmsr(msr->reg, eax, edx);
-       /* we just let them read the misc msr for now. */
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = eax;
-               *rdx = edx;
-               return TRUE;
-       } else {
-               /* if they are writing what is already written, that's ok. */
-               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
-                       return TRUE;
-       }
-       printk
-               ("%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
-                msr->name, (uint32_t) *rdx, (uint32_t) *rax, edx, eax);
-       return FALSE;
-}
-
-bool emsr_readonly(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                   uint64_t *rax, uint32_t opcode)
-{
-       uint32_t eax, edx;
-
-       rdmsr((uint32_t) *rcx, eax, edx);
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = eax;
-               *rdx = edx;
-               return TRUE;
-       }
-
-       printk("%s: Tried to write a readonly register\n", msr->name);
-       return FALSE;
-}
-
-bool emsr_readzero(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                   uint64_t *rax, uint32_t opcode)
-{
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = 0;
-               *rdx = 0;
-               return TRUE;
-       }
-
-       printk("%s: Tried to write a readonly register\n", msr->name);
-       return FALSE;
-}
-
-/* pretend to write it, but don't write it. */
-bool emsr_fakewrite(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                    uint64_t *rax, uint32_t opcode)
-{
-       uint32_t eax, edx;
-       if (!msr->written) {
-               rdmsr(msr->reg, eax, edx);
-       } else {
-               edx = msr->edx;
-               eax = msr->eax;
-       }
-       /* we just let them read the misc msr for now. */
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = eax;
-               *rdx = edx;
-               return TRUE;
-       } else {
-               /* if they are writing what is already written, that's ok. */
-               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
-                       return TRUE;
-               msr->edx = *rdx;
-               msr->eax = *rax;
-               msr->written = TRUE;
-       }
-       return TRUE;
-}
-
-bool emsr_ok(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-             uint64_t *rax, uint32_t opcode)
-{
-       if (opcode == VMM_MSR_EMU_READ) {
-               rdmsr(msr->reg, *rdx, *rax);
-       } else {
-               uint64_t val = (uint64_t) *rdx << 32 | *rax;
-               write_msr(msr->reg, val);
-       }
-       return TRUE;
-}
-
-/* pretend to write it, but don't write it. */
-bool emsr_fake_apicbase(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
-                        uint64_t *rax, uint32_t opcode)
-{
-       uint32_t eax, edx;
-
-       if (!msr->written) {
-               //rdmsr(msr->reg, eax, edx);
-               /* TODO: tightly coupled to the addr in vmrunkernel.  We want this func
-                * to return the val that vmrunkernel put into the VMCS. */
-               eax = 0xfee00900;
-               edx = 0;
-       } else {
-               edx = msr->edx;
-               eax = msr->eax;
-       }
-       /* we just let them read the misc msr for now. */
-       if (opcode == VMM_MSR_EMU_READ) {
-               *rax = eax;
-               *rdx = edx;
-               return TRUE;
-       } else {
-               /* if they are writing what is already written, that's ok. */
-               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
-                       return 0;
-               msr->edx = *rdx;
-               msr->eax = *rax;
-               msr->written = TRUE;
-       }
-       return TRUE;
-}
-
-bool vmm_emulate_msr(uint64_t *rcx, uint64_t *rdx, uint64_t *rax, int op)
-{
-       for (int i = 0; i < ARRAY_SIZE(emmsrs); i++) {
-               if (emmsrs[i].reg != *rcx)
-                       continue;
-               return emmsrs[i].f(&emmsrs[i], rcx, rdx, rax, op);
-       }
-       return FALSE;
-}
-
 static int
 msrio(struct vmx_vcpu *vcpu, uint32_t opcode, uint32_t qual) {
        int i;
index 0cd1b71..d5fc6f8 100644 (file)
@@ -210,3 +210,239 @@ void unload_guest_pcore(struct proc *p, int guest_pcoreid)
        spin_unlock(&p->vmm.lock);
        pcpui->guest_pcoreid = -1;
 }
+
+/* emulated msr. For now, an msr value and a pointer to a helper that
+ * performs the requested operation.
+ */
+struct emmsr {
+       uint32_t reg;
+       char *name;
+       bool (*f)(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                 uint64_t *rax, uint32_t opcode);
+       bool written;
+       uint32_t edx, eax;
+};
+
+static bool emsr_miscenable(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                            uint64_t *rax, uint32_t opcode);
+static bool emsr_mustmatch(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                           uint64_t *rax, uint32_t opcode);
+static bool emsr_readonly(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                          uint64_t *rax, uint32_t opcode);
+static bool emsr_readzero(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                          uint64_t *rax, uint32_t opcode);
+static bool emsr_fakewrite(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                           uint64_t *rax, uint32_t opcode);
+static bool emsr_ok(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                    uint64_t *rax, uint32_t opcode);
+static bool emsr_fake_apicbase(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                               uint64_t *rax, uint32_t opcode);
+
+struct emmsr emmsrs[] = {
+       {MSR_IA32_MISC_ENABLE, "MSR_IA32_MISC_ENABLE", emsr_miscenable},
+       {MSR_IA32_SYSENTER_CS, "MSR_IA32_SYSENTER_CS", emsr_ok},
+       {MSR_IA32_SYSENTER_EIP, "MSR_IA32_SYSENTER_EIP", emsr_ok},
+       {MSR_IA32_SYSENTER_ESP, "MSR_IA32_SYSENTER_ESP", emsr_ok},
+       {MSR_IA32_UCODE_REV, "MSR_IA32_UCODE_REV", emsr_fakewrite},
+       {MSR_CSTAR, "MSR_CSTAR", emsr_fakewrite},
+       {MSR_IA32_VMX_BASIC_MSR, "MSR_IA32_VMX_BASIC_MSR", emsr_fakewrite},
+       {MSR_IA32_VMX_PINBASED_CTLS_MSR, "MSR_IA32_VMX_PINBASED_CTLS_MSR",
+        emsr_fakewrite},
+       {MSR_IA32_VMX_PROCBASED_CTLS_MSR, "MSR_IA32_VMX_PROCBASED_CTLS_MSR",
+        emsr_fakewrite},
+       {MSR_IA32_VMX_PROCBASED_CTLS2, "MSR_IA32_VMX_PROCBASED_CTLS2",
+        emsr_fakewrite},
+       {MSR_IA32_VMX_EXIT_CTLS_MSR, "MSR_IA32_VMX_EXIT_CTLS_MSR",
+        emsr_fakewrite},
+       {MSR_IA32_VMX_ENTRY_CTLS_MSR, "MSR_IA32_VMX_ENTRY_CTLS_MSR",
+        emsr_fakewrite},
+       {MSR_IA32_ENERGY_PERF_BIAS, "MSR_IA32_ENERGY_PERF_BIAS",
+        emsr_fakewrite},
+       {MSR_LBR_SELECT, "MSR_LBR_SELECT", emsr_ok},
+       {MSR_LBR_TOS, "MSR_LBR_TOS", emsr_ok},
+       {MSR_LBR_NHM_FROM, "MSR_LBR_NHM_FROM", emsr_ok},
+       {MSR_LBR_NHM_TO, "MSR_LBR_NHM_TO", emsr_ok},
+       {MSR_LBR_CORE_FROM, "MSR_LBR_CORE_FROM", emsr_ok},
+       {MSR_LBR_CORE_TO, "MSR_LBR_CORE_TO", emsr_ok},
+
+       // grumble.
+       {MSR_OFFCORE_RSP_0, "MSR_OFFCORE_RSP_0", emsr_ok},
+       {MSR_OFFCORE_RSP_1, "MSR_OFFCORE_RSP_1", emsr_ok},
+       // louder.
+       {MSR_PEBS_LD_LAT_THRESHOLD, "MSR_PEBS_LD_LAT_THRESHOLD", emsr_ok},
+       // aaaaaahhhhhhhhhhhhhhhhhhhhh
+       {MSR_ARCH_PERFMON_EVENTSEL0, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
+       {MSR_ARCH_PERFMON_EVENTSEL1, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
+       {MSR_IA32_PERF_CAPABILITIES, "MSR_IA32_PERF_CAPABILITIES", emsr_ok},
+       // unsafe.
+       {MSR_IA32_APICBASE, "MSR_IA32_APICBASE", emsr_fake_apicbase},
+
+       // mostly harmless.
+       {MSR_TSC_AUX, "MSR_TSC_AUX", emsr_fakewrite},
+       {MSR_RAPL_POWER_UNIT, "MSR_RAPL_POWER_UNIT", emsr_readzero},
+
+       // TBD
+       {MSR_IA32_TSC_DEADLINE, "MSR_IA32_TSC_DEADLINE", emsr_fakewrite},
+};
+
+/* this may be the only register that needs special handling.
+ * If there others then we might want to extend the emmsr struct.
+ */
+bool emsr_miscenable(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                     uint64_t *rax, uint32_t opcode)
+{
+       uint32_t eax, edx;
+
+       rdmsr(msr->reg, eax, edx);
+       /* we just let them read the misc msr for now. */
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = eax;
+               *rax |= MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
+               *rdx = edx;
+               return TRUE;
+       } else {
+               /* if they are writing what is already written, that's ok. */
+               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
+                       return TRUE;
+       }
+       printk
+               ("%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
+                msr->name, (uint32_t) *rdx, (uint32_t) *rax, edx, eax);
+       return FALSE;
+}
+
+/* TODO: this looks like a copy-paste for the read side.  What's the purpose of
+ * mustmatch?  No one even uses it. */
+bool emsr_mustmatch(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                    uint64_t *rax, uint32_t opcode)
+{
+       uint32_t eax, edx;
+
+       rdmsr(msr->reg, eax, edx);
+       /* we just let them read the misc msr for now. */
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = eax;
+               *rdx = edx;
+               return TRUE;
+       } else {
+               /* if they are writing what is already written, that's ok. */
+               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
+                       return TRUE;
+       }
+       printk
+               ("%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
+                msr->name, (uint32_t) *rdx, (uint32_t) *rax, edx, eax);
+       return FALSE;
+}
+
+bool emsr_readonly(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                   uint64_t *rax, uint32_t opcode)
+{
+       uint32_t eax, edx;
+
+       rdmsr((uint32_t) *rcx, eax, edx);
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = eax;
+               *rdx = edx;
+               return TRUE;
+       }
+
+       printk("%s: Tried to write a readonly register\n", msr->name);
+       return FALSE;
+}
+
+bool emsr_readzero(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                   uint64_t *rax, uint32_t opcode)
+{
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = 0;
+               *rdx = 0;
+               return TRUE;
+       }
+
+       printk("%s: Tried to write a readonly register\n", msr->name);
+       return FALSE;
+}
+
+/* pretend to write it, but don't write it. */
+bool emsr_fakewrite(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                    uint64_t *rax, uint32_t opcode)
+{
+       uint32_t eax, edx;
+
+       if (!msr->written) {
+               rdmsr(msr->reg, eax, edx);
+       } else {
+               edx = msr->edx;
+               eax = msr->eax;
+       }
+       /* we just let them read the misc msr for now. */
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = eax;
+               *rdx = edx;
+               return TRUE;
+       } else {
+               /* if they are writing what is already written, that's ok. */
+               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
+                       return TRUE;
+               msr->edx = *rdx;
+               msr->eax = *rax;
+               msr->written = TRUE;
+       }
+       return TRUE;
+}
+
+bool emsr_ok(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+             uint64_t *rax, uint32_t opcode)
+{
+       if (opcode == VMM_MSR_EMU_READ) {
+               rdmsr(msr->reg, *rdx, *rax);
+       } else {
+               uint64_t val = (uint64_t) *rdx << 32 | *rax;
+
+               write_msr(msr->reg, val);
+       }
+       return TRUE;
+}
+
+/* pretend to write it, but don't write it. */
+bool emsr_fake_apicbase(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
+                        uint64_t *rax, uint32_t opcode)
+{
+       uint32_t eax, edx;
+
+       if (!msr->written) {
+               //rdmsr(msr->reg, eax, edx);
+               /* TODO: tightly coupled to the addr in vmrunkernel.  We want this func
+                * to return the val that vmrunkernel put into the VMCS. */
+               eax = 0xfee00900;
+               edx = 0;
+       } else {
+               edx = msr->edx;
+               eax = msr->eax;
+       }
+       /* we just let them read the misc msr for now. */
+       if (opcode == VMM_MSR_EMU_READ) {
+               *rax = eax;
+               *rdx = edx;
+               return TRUE;
+       } else {
+               /* if they are writing what is already written, that's ok. */
+               if (((uint32_t) *rax == eax) && ((uint32_t) *rdx == edx))
+                       return 0;
+               msr->edx = *rdx;
+               msr->eax = *rax;
+               msr->written = TRUE;
+       }
+       return TRUE;
+}
+
+bool vmm_emulate_msr(uint64_t *rcx, uint64_t *rdx, uint64_t *rax, int op)
+{
+       for (int i = 0; i < ARRAY_SIZE(emmsrs); i++) {
+               if (emmsrs[i].reg != *rcx)
+                       continue;
+               return emmsrs[i].f(&emmsrs[i], rcx, rdx, rax, op);
+       }
+       return FALSE;
+}