]> git.karo-electronics.de Git - linux-beck.git/commitdiff
KVM: Fix SS default ESP/EBP based addressing
authorAvi Kivity <avi@redhat.com>
Sun, 10 Jun 2012 14:15:39 +0000 (17:15 +0300)
committerAvi Kivity <avi@redhat.com>
Mon, 9 Jul 2012 11:19:02 +0000 (14:19 +0300)
We correctly default to SS when BP is used as a base in 16-bit address mode,
but we don't do that for 32-bit mode.

Fix by adjusting the default to SS when either ESP or EBP is used as the base
register.

Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/emulate.c

index 33ccd757cb1110f5f77bd65b1c2f87b0cfbf374b..7552c0ac6e7661e58b8c04056de12ce968c8ddd0 100644 (file)
@@ -974,6 +974,12 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
        op->orig_val = op->val;
 }
 
+static void adjust_modrm_seg(struct x86_emulate_ctxt *ctxt, int base_reg)
+{
+       if (base_reg == VCPU_REGS_RSP || base_reg == VCPU_REGS_RBP)
+               ctxt->modrm_seg = VCPU_SREG_SS;
+}
+
 static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                        struct operand *op)
 {
@@ -1077,15 +1083,20 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
 
                        if ((base_reg & 7) == 5 && ctxt->modrm_mod == 0)
                                modrm_ea += insn_fetch(s32, ctxt);
-                       else
+                       else {
                                modrm_ea += ctxt->regs[base_reg];
+                               adjust_modrm_seg(ctxt, base_reg);
+                       }
                        if (index_reg != 4)
                                modrm_ea += ctxt->regs[index_reg] << scale;
                } else if ((ctxt->modrm_rm & 7) == 5 && ctxt->modrm_mod == 0) {
                        if (ctxt->mode == X86EMUL_MODE_PROT64)
                                ctxt->rip_relative = 1;
-               } else
-                       modrm_ea += ctxt->regs[ctxt->modrm_rm];
+               } else {
+                       base_reg = ctxt->modrm_rm;
+                       modrm_ea += ctxt->regs[base_reg];
+                       adjust_modrm_seg(ctxt, base_reg);
+               }
                switch (ctxt->modrm_mod) {
                case 0:
                        if (ctxt->modrm_rm == 5)