svm.c uses x86_decode_prefix() instead of io_address() and io_get_override().

*** WARNING: the SVM part has not been tested because I don't have any AMD
system. ***

Signed-off-by: Laurent Vivier <[EMAIL PROTECTED]>
-- 
------------- [EMAIL PROTECTED]  --------------
          "Software is hard" - Donald Knuth
Index: kvm/drivers/kvm/svm.c
===================================================================
--- kvm.orig/drivers/kvm/svm.c  2007-08-01 10:10:24.000000000 +0200
+++ kvm/drivers/kvm/svm.c       2007-08-01 10:37:30.000000000 +0200
@@ -98,20 +98,6 @@
        return svm_features & feat;
 }
 
-static unsigned get_addr_size(struct vcpu_svm *svm)
-{
-       struct vmcb_save_area *sa = &svm->vmcb->save;
-       u16 cs_attrib;
-
-       if (!(sa->cr0 & X86_CR0_PE) || (sa->rflags & X86_EFLAGS_VM))
-               return 2;
-
-       cs_attrib = sa->cs.attrib;
-
-       return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
-                               (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
-}
-
 static inline u8 pop_irq(struct kvm_vcpu *vcpu)
 {
        int word_index = __ffs(vcpu->irq_summary);
@@ -996,112 +982,6 @@
        return 0;
 }
 
-static int io_get_override(struct vcpu_svm *svm,
-                         struct vmcb_seg **seg,
-                         int *addr_override)
-{
-       u8 inst[MAX_INST_SIZE];
-       unsigned ins_length;
-       gva_t rip;
-       int i;
-
-       rip =  svm->vmcb->save.rip;
-       ins_length = svm->next_rip - rip;
-       rip += svm->vmcb->save.cs.base;
-
-       if (ins_length > MAX_INST_SIZE)
-               printk(KERN_DEBUG
-                      "%s: inst length err, cs base 0x%llx rip 0x%llx "
-                      "next rip 0x%llx ins_length %u\n",
-                      __FUNCTION__,
-                      svm->vmcb->save.cs.base,
-                      svm->vmcb->save.rip,
-                      svm->vmcb->control.exit_info_2,
-                      ins_length);
-
-       if (emulator_read_std(rip, inst, ins_length, &svm->vcpu)
-           != X86EMUL_CONTINUE)
-               /* #PF */
-               return 0;
-
-       *addr_override = 0;
-       *seg = NULL;
-       for (i = 0; i < ins_length; i++)
-               switch (inst[i]) {
-               case 0xf0:
-               case 0xf2:
-               case 0xf3:
-               case 0x66:
-                       continue;
-               case 0x67:
-                       *addr_override = 1;
-                       continue;
-               case 0x2e:
-                       *seg = &svm->vmcb->save.cs;
-                       continue;
-               case 0x36:
-                       *seg = &svm->vmcb->save.ss;
-                       continue;
-               case 0x3e:
-                       *seg = &svm->vmcb->save.ds;
-                       continue;
-               case 0x26:
-                       *seg = &svm->vmcb->save.es;
-                       continue;
-               case 0x64:
-                       *seg = &svm->vmcb->save.fs;
-                       continue;
-               case 0x65:
-                       *seg = &svm->vmcb->save.gs;
-                       continue;
-               default:
-                       return 1;
-               }
-       printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
-       return 0;
-}
-
-static unsigned long io_address(struct vcpu_svm *svm, int ins, gva_t *address)
-{
-       unsigned long addr_mask;
-       unsigned long *reg;
-       struct vmcb_seg *seg;
-       int addr_override;
-       struct vmcb_save_area *save_area = &svm->vmcb->save;
-       u16 cs_attrib = save_area->cs.attrib;
-       unsigned addr_size = get_addr_size(svm);
-
-       if (!io_get_override(svm, &seg, &addr_override))
-               return 0;
-
-       if (addr_override)
-               addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
-
-       if (ins) {
-               reg = &svm->vcpu.regs[VCPU_REGS_RDI];
-               seg = &svm->vmcb->save.es;
-       } else {
-               reg = &svm->vcpu.regs[VCPU_REGS_RSI];
-               seg = (seg) ? seg : &svm->vmcb->save.ds;
-       }
-
-       addr_mask = ~0ULL >> (64 - (addr_size * 8));
-
-       if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
-           !(svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
-               *address = (*reg & addr_mask);
-               return addr_mask;
-       }
-
-       if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
-               svm_inject_gp(&svm->vcpu, 0);
-               return 0;
-       }
-
-       *address = (*reg & addr_mask) + seg->base;
-       return addr_mask;
-}
-
 static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
        u32 io_info = svm->vmcb->control.exit_info_1; //address size bug?
@@ -1109,6 +989,7 @@
        unsigned port;
        unsigned long count;
        gva_t address = 0;
+       struct vmcb_save_area *sa = &svm->vmcb->save;
 
        ++svm->vcpu.stat.io_exits;
 
@@ -1120,21 +1001,96 @@
        string = (io_info & SVM_IOIO_STR_MASK) != 0;
        rep = (io_info & SVM_IOIO_REP_MASK) != 0;
        count = 1;
-       down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
+       down = (sa->rflags & X86_EFLAGS_DF) != 0;
 
        if (string) {
-               unsigned addr_mask;
+               int mode;
+               u8 inst[MAX_INST_SIZE];
+               unsigned ins_length;
+               gva_t rip;
+               struct x86_prefix prefix;
+               u16 cs_ar = sa->cs.attrib;
+               unsigned long addr_mask;
+
+               mode = (!(sa->cr0 & X86_CR0_PE) ||
+                       (sa->rflags & X86_EFLAGS_VM)) ?
+                       X86EMUL_MODE_REAL :  (cs_ar & SVM_SELECTOR_L_MASK)
+                       ? X86EMUL_MODE_PROT64 : (cs_ar & SVM_SELECTOR_DB_MASK)
+                       ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+
+               rip =  svm->vmcb->save.rip;
+               ins_length = svm->vmcb->save.rip - rip;
+               if (mode != X86EMUL_MODE_PROT64)
+                       rip += svm->vmcb->save.cs.base;
+
+               if (ins_length > MAX_INST_SIZE)
+                       printk(KERN_DEBUG
+                              "%s: inst length err, cs base 0x%llx rip 0x%llx "
+                              "next rip 0x%llx ins_length %u\n",
+                              __FUNCTION__,
+                              svm->vmcb->save.cs.base,
+                              svm->vmcb->save.rip,
+                              svm->vmcb->control.exit_info_2,
+                              ins_length);
 
-               addr_mask = io_address(svm, in, &address);
-               if (!addr_mask) {
-                       printk(KERN_DEBUG "%s: get io address failed\n",
-                              __FUNCTION__);
+               if (emulator_read_std(rip, inst, ins_length, &svm->vcpu)
+                                       != X86EMUL_CONTINUE)
+                       return 1;
+
+               prefix.override_base = -1;
+               if (x86_decode_prefix(mode, (u8*)&inst, &prefix) == -1)
                        return 1;
-               }
 
+               addr_mask = (~0ULL >> (64 - (prefix.ad_bytes <<3)));
                if (rep)
                        count = svm->vcpu.regs[VCPU_REGS_RCX] & addr_mask;
+
+               if (in)
+                       address = svm->vcpu.regs[VCPU_REGS_RDI];
+               else
+                       address = svm->vcpu.regs[VCPU_REGS_RSI];
+
+               address &= addr_mask;
+
+               if (mode != X86EMUL_MODE_PROT64) {
+                       struct vmcb_seg *seg;
+
+                       if (in)
+                               seg = &svm->vmcb->save.es;
+                       else switch(prefix.override_base) {
+                               case -1:
+                               case X86EMUL_BASE_DS:
+                                       seg = &svm->vmcb->save.ds;
+                                       break;
+                               case X86EMUL_BASE_CS:
+                                       seg = &svm->vmcb->save.cs;
+                                       break;
+                               case X86EMUL_BASE_ES:
+                                       seg = &svm->vmcb->save.es;
+                                       break;
+                               case X86EMUL_BASE_GS:
+                                       seg = &svm->vmcb->save.gs;
+                                       break;
+                               case X86EMUL_BASE_SS:
+                                       seg = &svm->vmcb->save.ss;
+                                       break;
+                               default:
+                                       printk(KERN_DEBUG "%s: unexpected\n",
+                                               __FUNCTION__);
+                                       return 1;
+                       }
+
+                       if (seg->attrib & SVM_SELECTOR_P_SHIFT) {
+                               svm_inject_gp(&svm->vcpu, 0);
+                               printk(KERN_DEBUG "%s: get io address failed\n",
+                                       __FUNCTION__);
+                               return 1;
+                       }
+
+                       address += seg->base;
+               }
        }
+
        return kvm_setup_pio(&svm->vcpu, kvm_run, in, size, count, string,
                             down, address, rep, port);
 }
Index: kvm/drivers/kvm/.svm.c.swp
===================================================================
Binary files kvm.orig/drivers/kvm/.svm.c.swp    2007-08-01 10:12:34.000000000 
+0200 and /dev/null       1970-01-01 00:00:00.000000000 +0000 differ

Attachment: signature.asc
Description: OpenPGP digital signature

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to