[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] SVM patch to cleanup IOIO handling, do not use "real" mode but rather



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 632ad28f2fd7a6602b08a9d054dc1b44efaf93f3
# Parent  81ab21f76a6f11a7264d242f039c6c7b25cda650
SVM patch to cleanup IOIO handling, do not use "real" mode but rather
the correct "bitness".

Signed-off-by: Tom Woller <thomas.woller@xxxxxxx>
Signed-off-by: Mats Petersson <mats.petersson@xxxxxxx>
---
 xen/arch/x86/hvm/svm/svm.c |  193 +++++++++++++++++++++++++++------------------
 1 files changed, 120 insertions(+), 73 deletions(-)

diff -r 81ab21f76a6f -r 632ad28f2fd7 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed May 17 23:47:19 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed May 17 23:50:23 2006 +0100
@@ -1118,19 +1118,17 @@ static void svm_dr_access (struct vcpu *
 }
 
 
-static unsigned int check_for_null_selector(struct vmcb_struct *vmcb, 
-        unsigned int dir, unsigned long *base, unsigned int real)
-
+static void svm_get_prefix_info(struct vmcb_struct *vmcb, 
+               unsigned int dir, segment_selector_t **seg, unsigned int *asize)
 {
     unsigned char inst[MAX_INST_LEN];
-    segment_selector_t seg;
     int i;
 
     memset(inst, 0, MAX_INST_LEN);
     if (inst_copy_from_guest(inst, svm_rip2pointer(vmcb), sizeof(inst)) 
             != MAX_INST_LEN) 
     {
-        printk("check_for_null_selector: get guest instruction failed\n");
+        printk("%s: get guest instruction failed\n", __func__);
         domain_crash_synchronous();
     }
 
@@ -1142,7 +1140,6 @@ static unsigned int check_for_null_selec
         case 0xf2: /* REPNZ */
         case 0xf0: /* LOCK */
         case 0x66: /* data32 */
-        case 0x67: /* addr32 */
 #if __x86_64__
             /* REX prefixes */
         case 0x40:
@@ -1164,89 +1161,133 @@ static unsigned int check_for_null_selec
         case 0x4f:
 #endif
             continue;
+        case 0x67: /* addr32 */
+            *asize ^= 48;        /* Switch 16/32 bits */
+            continue;
         case 0x2e: /* CS */
-            seg = vmcb->cs;
+            *seg = &vmcb->cs;
+            continue;
+        case 0x36: /* SS */
+            *seg = &vmcb->ss;
+            continue;
+        case 0x26: /* ES */
+            *seg = &vmcb->es;
+            continue;
+        case 0x64: /* FS */
+            *seg = &vmcb->fs;
+            continue;
+        case 0x65: /* GS */
+            *seg = &vmcb->gs;
+            continue;
+        case 0x3e: /* DS */
+            *seg = &vmcb->ds;
+            continue;
+        default:
             break;
-        case 0x36: /* SS */
-            seg = vmcb->ss;
-            break;
-        case 0x26: /* ES */
-            seg = vmcb->es;
-            break;
-        case 0x64: /* FS */
-            seg = vmcb->fs;
-            break;
-        case 0x65: /* GS */
-            seg = vmcb->gs;
-            break;
-        case 0x3e: /* DS */
-            /* FALLTHROUGH */
-            seg = vmcb->ds;
-            break;
-        default:
-            if (dir == IOREQ_READ) /* IN/INS instruction? */
-                seg = vmcb->es;
-            else
-                seg = vmcb->ds;
-        }
-        
-        if (base)
-            *base = seg.base;
-
-        return seg.attributes.fields.p;
-    }
-
-    ASSERT(0);
-    return 0;
+        }
+        return;
+    }
 }
 
 
 /* Get the address of INS/OUTS instruction */
-static inline unsigned long svm_get_io_address(struct vmcb_struct *vmcb, 
-        struct cpu_user_regs *regs, unsigned int dir, unsigned int real)
-{
-    unsigned long addr = 0;
-    unsigned long base = 0;
-
-    check_for_null_selector(vmcb, dir, &base, real);
+static inline int svm_get_io_address(struct vmcb_struct *vmcb, 
+               struct cpu_user_regs *regs, unsigned int dir, 
+        unsigned long *count, unsigned long *addr)
+{
+    unsigned long        reg;
+    unsigned int         asize = 0;
+    unsigned int         isize;
+    int                  long_mode;
+    ioio_info_t          info;
+    segment_selector_t  *seg = NULL;
+
+    info.bytes = vmcb->exitinfo1;
+
+    /* If we're in long mode, we shouldn't check the segment presence and 
limit */
+    long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA;
+
+    /* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit. 
+     * l field combined with EFER_LMA -> longmode says whether it's 16 or 64 
bit. 
+     */
+    asize = (long_mode)?64:((vmcb->cs.attributes.fields.db)?32:16);
+
+
+    /* The ins/outs instructions are single byte, so if we have got more 
+     * than one byte (+ maybe rep-prefix), we have some prefix so we need 
+     * to figure out what it is...
+     */
+    isize = vmcb->exitinfo2 - vmcb->rip;
+
+    if (info.fields.rep)
+        isize --;
+
+    if (isize > 1) 
+    {
+        svm_get_prefix_info(vmcb, dir, &seg, &asize);
+    }
+
+    ASSERT(dir == IOREQ_READ || dir == IOREQ_WRITE);
 
     if (dir == IOREQ_WRITE)
     {
-        if (real)
-            addr = (regs->esi & 0xFFFF) + base;
-        else
-            addr = regs->esi + base;
+        reg = regs->esi;
+        if (!seg)               /* If no prefix, used DS. */
+            seg = &vmcb->ds;
     }
     else
     {
-        if (real)
-            addr = (regs->edi & 0xFFFF) + base;
-        else
-            addr = regs->edi + base;
-    }
-
-    return addr;
+        reg = regs->edi;
+        seg = &vmcb->es;        /* Note: This is ALWAYS ES. */
+    }
+
+    /* If the segment isn't present, give GP fault! */
+    if (!long_mode && !seg->attributes.fields.p) 
+    {
+        svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
+        return 0;
+    }
+
+    if (asize == 16) 
+    {
+        *addr = (reg & 0xFFFF);
+        *count = regs->ecx & 0xffff;
+    }
+    else
+    {
+        *addr = reg;
+        *count = regs->ecx;
+    }
+
+    if (!long_mode) {
+        if (*addr > seg->limit) 
+        {
+            svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
+            return 0;
+        } 
+        else 
+        {
+            *addr += seg->base;
+        }
+    }
+    
+
+    return 1;
 }
 
 
 static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs) 
 {
     struct mmio_op *mmio_opp;
-    unsigned long eip, cs, eflags, cr0;
-    unsigned long port;
-    unsigned int real, size, dir;
+    unsigned int port;
+    unsigned int size, dir;
     ioio_info_t info;
-
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
 
     ASSERT(vmcb);
     mmio_opp = &current->arch.hvm_vcpu.mmio_op;
     mmio_opp->instr = INSTR_PIO;
     mmio_opp->flags = 0;
-
-    eip = vmcb->rip;
-    cs =  vmcb->cs.sel;
-    eflags = vmcb->rflags;
 
     info.bytes = vmcb->exitinfo1;
 
@@ -1259,27 +1300,33 @@ static void svm_io_instruction(struct vc
     else 
         size = 1;
 
-    cr0 = vmcb->cr0;
-    real = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
-
     HVM_DBG_LOG(DBG_LEVEL_IO, 
-                "svm_io_instruction: port 0x%lx real %d, eip=%lx:%lx, "
+                "svm_io_instruction: port 0x%x eip=%lx:%lx, "
                 "exit_qualification = %lx",
-                (unsigned long) port, real, cs, eip, (unsigned 
long)info.bytes);
+                port, vmcb->cs.sel, vmcb->rip, (unsigned long)info.bytes);
     /* string instruction */
     if (info.fields.str)
     { 
-        unsigned long addr, count = 1;
+        unsigned long addr, count;
         int sign = regs->eflags & EF_DF ? -1 : 1;
 
-        /* Need the original rip, here. */
-        addr = svm_get_io_address(vmcb, regs, dir, real);
+        if (!svm_get_io_address(vmcb, regs, dir, &count, &addr)) 
+        {
+            /* We failed to get a valid address, so don't do the IO operation 
- 
+             * it would just get worse if we do! Hopefully the guest is handing
+             * gp-faults... 
+             */
+            return;
+        }
 
         /* "rep" prefix */
         if (info.fields.rep) 
         {
             mmio_opp->flags |= REPZ;
-            count = real ? regs->ecx & 0xFFFF : regs->ecx;
+        }
+        else 
+        {
+            count = 1;
         }
 
         /*

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.