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

[Xen-changelog] [xen-unstable] x86, hvm: Observe EFLAGS.DF when performing segmentation checks and



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1219157839 -3600
# Node ID a3fe573a0e1eb98246e09db98f12e13de117a52b
# Parent  6e3c97f43f9c79506c834fe0661b4ceb7ba21a99
x86, hvm: Observe EFLAGS.DF when performing segmentation checks and
address translations on multi-iteration string instructions.

Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/hvm/emulate.c |   93 ++++++++++++++++++++++++++++++---------------
 1 files changed, 63 insertions(+), 30 deletions(-)

diff -r 6e3c97f43f9c -r a3fe573a0e1e xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c        Tue Aug 19 15:56:31 2008 +0100
+++ b/xen/arch/x86/hvm/emulate.c        Tue Aug 19 15:57:19 2008 +0100
@@ -208,6 +208,7 @@ static int hvmemul_linear_to_phys(
 {
     struct vcpu *curr = current;
     unsigned long pfn, npfn, done, todo, i;
+    int reverse;
 
     /* Clip repetitions to a sensible maximum. */
     *reps = min_t(unsigned long, *reps, 4096);
@@ -221,41 +222,53 @@ static int hvmemul_linear_to_phys(
 
     *paddr = addr & ~PAGE_MASK;
 
-    /* Get the first PFN in the range. */
-    if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
+    /* Reverse mode if this is a backwards multi-iteration string operation. */
+    reverse = (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1);
+
+    if ( reverse && ((-addr & ~PAGE_MASK) < bytes_per_rep) )
+    {
+        /* Do page-straddling first iteration forwards via recursion. */
+        unsigned long _paddr, one_rep = 1;
+        int rc = hvmemul_linear_to_phys(
+            addr, &_paddr, bytes_per_rep, &one_rep, pfec, hvmemul_ctxt);
+        if ( rc != X86EMUL_OKAY )
+            return rc;
+        pfn = _paddr >> PAGE_SHIFT;
+    }
+    else if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
     {
         hvm_inject_exception(TRAP_page_fault, pfec, addr);
         return X86EMUL_EXCEPTION;
     }
 
     /* If the range does not straddle a page boundary then we're done. */
-    done = PAGE_SIZE - (addr & ~PAGE_MASK);
+    done = reverse ? bytes_per_rep + (addr & ~PAGE_MASK) : -addr & ~PAGE_MASK;
     todo = *reps * bytes_per_rep;
     if ( done >= todo )
         goto done;
 
-    addr += done;
     for ( i = 1; done < todo; i++ )
     {
         /* Get the next PFN in the range. */
+        addr += reverse ? -PAGE_SIZE : PAGE_SIZE;
         npfn = paging_gva_to_gfn(curr, addr, &pfec);
 
         /* Is it contiguous with the preceding PFNs? If not then we're done. */
-        if ( (npfn == INVALID_GFN) || (npfn != (pfn + i)) )
+        if ( (npfn == INVALID_GFN) || (npfn != (pfn + (reverse ? -i : i))) )
         {
             done /= bytes_per_rep;
             if ( done == 0 )
             {
+                ASSERT(!reverse);
                 if ( npfn != INVALID_GFN )
                     return X86EMUL_UNHANDLEABLE;
-                hvm_inject_exception(TRAP_page_fault, pfec, addr);
+                hvm_inject_exception(TRAP_page_fault, pfec, addr & PAGE_MASK);
                 return X86EMUL_EXCEPTION;
             }
             *reps = done;
             break;
         }
 
-        addr += PAGE_SIZE;
         done += PAGE_SIZE;
     }
 
@@ -268,7 +281,8 @@ static int hvmemul_virtual_to_linear(
 static int hvmemul_virtual_to_linear(
     enum x86_segment seg,
     unsigned long offset,
-    unsigned int bytes,
+    unsigned int bytes_per_rep,
+    unsigned long *reps,
     enum hvm_access_type access_type,
     struct hvm_emulate_ctxt *hvmemul_ctxt,
     unsigned long *paddr)
@@ -282,21 +296,40 @@ static int hvmemul_virtual_to_linear(
         return X86EMUL_OKAY;
     }
 
+    *reps = min_t(unsigned long, *reps, 4096);
     reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
-    okay = hvm_virtual_to_linear_addr(
-        seg, reg, offset, bytes, access_type,
-        hvmemul_ctxt->ctxt.addr_size, paddr);
-
-    if ( !okay )
-    {
-        hvmemul_ctxt->exn_pending = 1;
-        hvmemul_ctxt->exn_vector = TRAP_gp_fault;
-        hvmemul_ctxt->exn_error_code = 0;
-        hvmemul_ctxt->exn_insn_len = 0;
-        return X86EMUL_EXCEPTION;
-    }
-
-    return X86EMUL_OKAY;
+
+    if ( (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1) )
+    {
+        ASSERT(offset >= ((*reps - 1) * bytes_per_rep));
+        okay = hvm_virtual_to_linear_addr(
+            seg, reg, offset - (*reps - 1) * bytes_per_rep,
+            *reps * bytes_per_rep, access_type,
+            hvmemul_ctxt->ctxt.addr_size, paddr);
+        *paddr += (*reps - 1) * bytes_per_rep;
+        if ( hvmemul_ctxt->ctxt.addr_size != 64 )
+            *paddr = (uint32_t)*paddr;
+    }
+    else
+    {
+        okay = hvm_virtual_to_linear_addr(
+            seg, reg, offset, *reps * bytes_per_rep, access_type,
+            hvmemul_ctxt->ctxt.addr_size, paddr);
+    }
+
+    if ( okay )
+        return X86EMUL_OKAY;
+
+    /* If this is a string operation, emulate each iteration separately. */
+    if ( *reps != 1 )
+        return X86EMUL_UNHANDLEABLE;
+
+    /* This is a singleton operation: fail it with an exception. */
+    hvmemul_ctxt->exn_pending = 1;
+    hvmemul_ctxt->exn_vector = TRAP_gp_fault;
+    hvmemul_ctxt->exn_error_code = 0;
+    hvmemul_ctxt->exn_insn_len = 0;
+    return X86EMUL_EXCEPTION;
 }
 
 static int __hvmemul_read(
@@ -314,7 +347,7 @@ static int __hvmemul_read(
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        seg, offset, bytes, access_type, hvmemul_ctxt, &addr);
+        seg, offset, bytes, &reps, access_type, hvmemul_ctxt, &addr);
     if ( rc != X86EMUL_OKAY )
         return rc;
 
@@ -406,7 +439,7 @@ static int hvmemul_write(
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        seg, offset, bytes, hvm_access_write, hvmemul_ctxt, &addr);
+        seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt, &addr);
     if ( rc != X86EMUL_OKAY )
         return rc;
 
@@ -470,7 +503,7 @@ static int hvmemul_rep_ins(
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        dst_seg, dst_offset, *reps * bytes_per_rep, hvm_access_write,
+        dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
         hvmemul_ctxt, &addr);
     if ( rc != X86EMUL_OKAY )
         return rc;
@@ -503,7 +536,7 @@ static int hvmemul_rep_outs(
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        src_seg, src_offset, *reps * bytes_per_rep, hvm_access_read,
+        src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
         hvmemul_ctxt, &addr);
     if ( rc != X86EMUL_OKAY )
         return rc;
@@ -538,13 +571,13 @@ static int hvmemul_rep_movs(
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        src_seg, src_offset, *reps * bytes_per_rep, hvm_access_read,
+        src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
         hvmemul_ctxt, &saddr);
     if ( rc != X86EMUL_OKAY )
         return rc;
 
     rc = hvmemul_virtual_to_linear(
-        dst_seg, dst_offset, *reps * bytes_per_rep, hvm_access_write,
+        dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
         hvmemul_ctxt, &daddr);
     if ( rc != X86EMUL_OKAY )
         return rc;
@@ -792,11 +825,11 @@ static int hvmemul_invlpg(
 {
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
-    unsigned long addr;
+    unsigned long addr, reps = 1;
     int rc;
 
     rc = hvmemul_virtual_to_linear(
-        seg, offset, 1, hvm_access_none, hvmemul_ctxt, &addr);
+        seg, offset, 1, &reps, hvm_access_none, hvmemul_ctxt, &addr);
 
     if ( rc == X86EMUL_OKAY )
         hvm_funcs.invlpg_intercept(addr);

_______________________________________________
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®.