]> xenbits.xensource.com Git - people/vhanquez/xen.git/commitdiff
SVM: handle page faults in emulated instruction fetches
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 17 Mar 2008 11:40:53 +0000 (11:40 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 17 Mar 2008 11:40:53 +0000 (11:40 +0000)
Deal with failures in hvm_copy_from_guest_virt when fetching
instructions in the various SVM emulation paths.  Since we know that
the instruction was fetchable by the hardware, we can usually just
return from the VMEXIT and try again; whatever caused us to fail will
cause the hardware to fail next time and we'll get the correct exit
code.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
xen-unstable changeset:   17202:8325f200e19414d998b7625f2e3cf786a6d3d3a3
xen-unstable date:        Mon Mar 17 11:39:50 2008 +0000

xen/arch/x86/hvm/svm/emulate.c
xen/arch/x86/hvm/svm/svm.c

index f22fd1cc17d0d6ee0033bb204fcf8cc1790a530b..e00ffbf377dfea880de0aa887079069b89ae7475 100644 (file)
@@ -435,7 +435,9 @@ int __get_instruction_length_from_list(struct vcpu *v,
     }
     else
     {
-        inst_copy_from_guest(buffer, svm_rip2pointer(v), MAX_INST_LEN);
+        if ( inst_copy_from_guest(buffer, svm_rip2pointer(v), MAX_INST_LEN)
+             != MAX_INST_LEN )
+            return 0;
         buf = buffer;
     }
 
index 285d3c31bcb72cacb48509f710304793bd8b34db..58b3c1bace5f44f79d9e9acf7423c8cccb296cda 100644 (file)
@@ -1128,7 +1128,7 @@ static void svm_dr_access(struct vcpu *v, struct cpu_user_regs *regs)
 }
 
 
-static void svm_get_prefix_info(struct vcpu *v, unsigned int dir, 
+static int svm_get_prefix_info(struct vcpu *v, unsigned int dir, 
                                 svm_segment_register_t **seg, 
                                 unsigned int *asize)
 {
@@ -1141,8 +1141,7 @@ static void svm_get_prefix_info(struct vcpu *v, unsigned int dir,
         != MAX_INST_LEN) 
     {
         gdprintk(XENLOG_ERR, "get guest instruction failed\n");
-        domain_crash(current->domain);
-        return;
+        return 0;
     }
 
     for (i = 0; i < MAX_INST_LEN; i++)
@@ -1200,8 +1199,9 @@ static void svm_get_prefix_info(struct vcpu *v, unsigned int dir,
         default:
             break;
         }
-        return;
+        break;
     }
+    return 1;
 }
 
 
@@ -1236,7 +1236,8 @@ static int svm_get_io_address(
         isize --;
 
     if (isize > 1) 
-        svm_get_prefix_info(v, info.fields.type, &seg, &asize);
+        if ( !svm_get_prefix_info(v, info.fields.type, &seg, &asize) )
+            return 0;
 
     if (info.fields.type == IOREQ_WRITE)
     {
@@ -1591,7 +1592,10 @@ static void svm_cr_access(
     enum instruction_index list_b[] = {INSTR_MOVCR2, INSTR_SMSW};
     enum instruction_index match;
 
-    inst_copy_from_guest(buffer, svm_rip2pointer(v), sizeof(buffer));
+    if ( inst_copy_from_guest(buffer, svm_rip2pointer(v), sizeof(buffer))
+         != sizeof buffer )
+        /* #PF will have been delivered if appropriate. */
+        return;
 
     /* get index to first actual instruction byte - as we will need to know 
        where the prefix lives later on */
@@ -1608,6 +1612,9 @@ static void svm_cr_access(
             v, list_b, ARRAY_SIZE(list_b), &buffer[index], &match);
     }
 
+    if ( inst_len == 0 )
+        return;
+
     inst_len += index;
 
     /* Check for REX prefix - it's ALWAYS the last byte of any prefix bytes */
@@ -1940,7 +1947,7 @@ void svm_handle_invlpg(const short invlpga, struct cpu_user_regs *regs)
     if ( inst_copy_from_guest(opcode, svm_rip2pointer(v), length) < length )
     {
         gdprintk(XENLOG_ERR, "Error reading memory %d bytes\n", length);
-        goto crash;
+        return;
     }
 
     if ( invlpga )
@@ -2055,6 +2062,8 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
             goto exit_and_crash;
         /* AMD Vol2, 15.11: INT3, INTO, BOUND intercepts do not update RIP. */
         inst_len = __get_instruction_length(v, INSTR_INT3, NULL);
+        if ( inst_len == 0 )
+            break;
         __update_guest_eip(regs, inst_len);
         domain_pause_for_debugger();
         break;
@@ -2131,6 +2140,8 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
 
     case VMEXIT_VMMCALL:
         inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL);
+        if ( inst_len == 0 ) 
+            break;
         HVMTRACE_1D(VMMCALL, v, regs->eax);
         rc = hvm_do_hypercall(regs);
         if ( rc != HVM_HCALL_preempted )