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

[Xen-devel] [PATCH] x86emul: suppress memory writes after faulting FPU insns



FPU insns writing to memory must not touch memory if they latch #MF (to
be delivered on the next waiting FPU insn). Note that inspecting FSW.ES
needs to be avoided for all FNST* insns, as they don't raise exceptions
themselves, but may instead be invoked with the bit already set.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
While #MF and memory access faults are all listed in the same priority
group, it is not entirely clear how FPU insns reading memory operate
when an exception to be delivered doesn't depend on the memory operand
(which would namely be FPU register stack overflows). It is therefore
possible that memory reads would need to be suppressed in some
situations, too. Of course this only matters for reads which have side
effects. Otoh SNaN operand detection and stack overflow/underflow are
listed as having the same priority, so the memory read may well be
performed unconditionally.

Furthermore I think we have another issue with writes: If the write
faults, the FSW (or MXCSR, albeit there only for instructions we don't
emulate yet) register may have been updated already, so we'd need to
undo that update. For MXCSR that will be possible by saving the initial
value and re-loading it in case ->write() fails (and iirc there's
exactly one affected insn - VCVTPS2PH). There's no suitable way to load
FSW, though - all existing mechanisms have further effects we don't
really want (albeit arguably the side effects of going through a
{F,}XSAVE/{F,}XRSTOR cycle could occur at any time as a scheduling side
effect).

--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -457,6 +457,9 @@ typedef union {
 #define EFLG_MBS  (1<<1)
 #define EFLG_CF   (1<<0)
 
+/* Floating point status word definitions. */
+#define FSW_ES    (1U << 7)
+
 /* MXCSR bit definitions. */
 #define MXCSR_MM  (1U << 17)
 
@@ -868,6 +871,15 @@ do {
                           (_fic)->exn_raised);                  \
 } while (0)
 
+static inline bool fpu_check_write(void)
+{
+    uint16_t fsw;
+
+    asm ( "fnstsw %0" : "=am" (fsw) );
+
+    return !(fsw & FSW_ES);
+}
+
 #define emulate_fpu_insn(_op)                           \
     asm volatile (                                      \
         "movb $2f-1f,%0 \n"                             \
@@ -3723,6 +3735,8 @@ x86_emulate(
             default:
                 generate_exception(EXC_UD);
             }
+            if ( dst.type == OP_MEM && dst.bytes == 4 && !fpu_check_write() )
+                dst.type = OP_NONE;
         }
         put_fpu(&fic);
         break;
@@ -3835,7 +3849,8 @@ x86_emulate(
             case 7: /* fstp m80fp */
                 fail_if(!ops->write);
                 emulate_fpu_insn_memdst("fstpt", *mmvalp);
-                if ( (rc = ops->write(ea.mem.seg, ea.mem.off, mmvalp,
+                if ( fpu_check_write() &&
+                     (rc = ops->write(ea.mem.seg, ea.mem.off, mmvalp,
                                       10, ctxt)) != X86EMUL_OKAY )
                     goto done;
                 dst.type = OP_NONE;
@@ -3843,6 +3858,8 @@ x86_emulate(
             default:
                 generate_exception(EXC_UD);
             }
+            if ( dst.type == OP_MEM && !fpu_check_write() )
+                dst.type = OP_NONE;
         }
         put_fpu(&fic);
         break;
@@ -3946,6 +3963,8 @@ x86_emulate(
             default:
                 generate_exception(EXC_UD);
             }
+            if ( dst.type == OP_MEM && dst.bytes == 8 && !fpu_check_write() )
+                dst.type = OP_NONE;
         }
         put_fpu(&fic);
         break;
@@ -4063,7 +4082,8 @@ x86_emulate(
             case 6: /* fbstp packed bcd */
                 fail_if(!ops->write);
                 emulate_fpu_insn_memdst("fbstp", *mmvalp);
-                if ( (rc = ops->write(ea.mem.seg, ea.mem.off, mmvalp,
+                if ( fpu_check_write() &&
+                     (rc = ops->write(ea.mem.seg, ea.mem.off, mmvalp,
                                       10, ctxt)) != X86EMUL_OKAY )
                     goto done;
                 dst.type = OP_NONE;
@@ -4073,6 +4093,8 @@ x86_emulate(
                 dst.bytes = 8;
                 break;
             }
+            if ( dst.type == OP_MEM && !fpu_check_write() )
+                dst.type = OP_NONE;
         }
         put_fpu(&fic);
         break;


Attachment: x86emul-FPU-suppress-write.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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