VMM: Fix MSR emulation (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 28 Apr 2016 19:39:21 +0000 (15:39 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 May 2016 21:11:15 +0000 (17:11 -0400)
emsr_ok() was busted.

First, it was swapping rax and rdx.  The functions take rdx first, but
rdmsr takes rax first.  This was the proximate cause of a bug where if you
ran a guest pcore that did Linux initialization on the same pcore that had
a previous VM do the same, then the kernel would GPF on wrmsr 0x1c9 <-
0x300000003.  Good times.

The rdmsr() macro also wasn't zeroing the upper part of rax.  So we'd have
old stuff floating around.  That would be okay if you only ever use it with
u32s, but since it's a macro, we didn't know that from its signature.
Great.

Finally, we were passing the upper 32 of rax through to write_msr or-ed
with rdx.  That's not supposed to happen either.

Reinstall your kernel header if you care.  Though that crappy macro
shouldn't be in a kernel header...

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

index 30924af..40fade9 100644 (file)
@@ -641,8 +641,15 @@ struct vmcs {
 
 typedef uint64_t gpa_t;
 typedef uint64_t gva_t;
+/* TODO: remove these nasty macros */
 #define rdmsrl(msr, val) (val) = read_msr((msr))
-#define rdmsr(msr, low, high) do {uint64_t m = read_msr(msr); low = m; high = m>>32;} while (0)
+#define rdmsr(msr, low, high)                                                  \
+do {                                                                           \
+       uint64_t m = read_msr(msr);                                                \
+                                                                                  \
+       low = m & 0xffffffff;                                                      \
+       high = m >> 32;                                                            \
+} while (0)
 
 struct vmx_capability {
        uint32_t ept;
index 0287ad4..818e26c 100644 (file)
@@ -398,10 +398,14 @@ bool emsr_fakewrite(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
 bool emsr_ok(struct emmsr *msr, uint64_t *rcx, uint64_t *rdx,
              uint64_t *rax, uint32_t opcode)
 {
+       uint32_t eax, edx;
+
        if (opcode == VMM_MSR_EMU_READ) {
-               rdmsr(msr->reg, *rdx, *rax);
+               rdmsr(msr->reg, eax, edx);
+               *rax = eax;
+               *rdx = edx;
        } else {
-               uint64_t val = (uint64_t) *rdx << 32 | *rax;
+               uint64_t val = (*rdx << 32) | (*rax & 0xffffffff);
 
                write_msr(msr->reg, val);
        }