vmm: Handle mov with zero-extend
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 22 Dec 2017 17:06:24 +0000 (12:06 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 22 Dec 2017 17:06:24 +0000 (12:06 -0500)
I noticed that if you dropped the apic=debug command line argument to the
guest, then they would crash.

The root cause was our EPT handler, which emulates access to the low 4K of
physical memory, wasn't handling movzwl correctly.  We were not
zero-extending.  That led to junk in registers that the compiler didn't
expect.  And that led Linux to get a false positive for get_bios_ebda(),
which lead to dereferencing garbage.

The apic=debug turned on a printk, which was enough to change the registers
so that the junk was not present.  Similarly, some basic tracing that moved
registers or changed "don't care" values before the call to get_bios_ebda()
was enough to make the code work.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/vmm/decode.c

index bf3c9ab..f12765d 100644 (file)
@@ -311,5 +311,16 @@ int decode(struct guest_thread *vm_thread, uint64_t *gpa, uint8_t *destreg,
                *regp = &vm_tf->tf_r15;
                break;
        }
+       /* Handle movz{b,w}X.  Zero the destination. */
+       if ((rip_gpa[0] == 0x0f) && (rip_gpa[1] == 0xb6)) {
+               /* movzb.
+                * TODO: figure out if the destination size is 16 or 32 bits.  Linux
+                * doesn't call this yet, so it's not urgent. */
+               return -1;
+       }
+       if ((rip_gpa[0] == 0x0f) && (rip_gpa[1] == 0xb7)) {
+               /* movzwl.  Destination is 32 bits, unless we had the rex prefix */
+               **regp &= ~((1ULL << 32) - 1);
+       }
        return 0;
 }