From patchwork Thu Sep 14 15:21:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9953375 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A5155602C9 for ; Thu, 14 Sep 2017 15:23:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 963E720683 for ; Thu, 14 Sep 2017 15:23:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8AF4B290F3; Thu, 14 Sep 2017 15:23:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 81DD720683 for ; Thu, 14 Sep 2017 15:23:27 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dsVxD-0004ok-Pb; Thu, 14 Sep 2017 15:21:23 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dsVxD-0004oR-62 for xen-devel@lists.xenproject.org; Thu, 14 Sep 2017 15:21:23 +0000 Received: from [85.158.143.35] by server-1.bemta-6.messagelabs.com id D7/4E-03414-27E9AB95; Thu, 14 Sep 2017 15:21:22 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrHIsWRWlGSWpSXmKPExsXS6fjDS7dg3q5 Ig7mT1C2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ozv6xIKnsxgrDg02aWB8UlQFyMnh5BAnsTi OzeZQWxeATuJhr3zWUBsCQFDidMLb4LZLAKqEks3PGIHsdkE1CXanm1n7WLk4BARMJA4dzQJx GQWiJe4us4epEJYwE3ibctTVojpRRK3O2cygticAvYSnfOngXXyCghK/N0hDBJmFtCSePjrFg uErS2xbOFrZoiJ0hLL/3FMYOSbhdAwC0nDLCQNsxAaFjCyrGLUKE4tKkst0jW00EsqykzPKMl NzMzRNTQw08tNLS5OTE/NSUwq1kvOz93ECAw7BiDYwXhzY8AhRkkOJiVR3r26OyOF+JLyUyoz Eosz4otKc1KLDzHKcHAoSfCmzt0VKSRYlJqeWpGWmQOMAJi0BAePkghvH0iat7ggMbc4Mx0id YpRl6Pj5t0/TEIsefl5qVLivG4gRQIgRRmleXAjYNF4iVFWSpiXEegoIZ6C1KLczBJU+VeM4h yMSsK80iBTeDLzSuA2vQI6ggnoiDOnd4AcUZKIkJJqYPQQFpl/8sMMWZd6yXmm3Ooca10fTD1 5ksVqylblbc2zlbrPFbk1P/xn+JaRLdZ6ud6Er5oS7LqBmuxcx5OtXeYe2sei03tsg+DHCax8 azUPORYuYeVdmlSX8nnmbLHle9cf1kqrmRXjxv5t4+L0lXwGB1dMzndSt+pYdfL5vDrn+oP7n q/qiVBiKc5INNRiLipOBADaq8w2wQIAAA== X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-12.tower-21.messagelabs.com!1505402478!82867291!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 16652 invoked from network); 14 Sep 2017 15:21:20 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-12.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 14 Sep 2017 15:21:20 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Thu, 14 Sep 2017 09:21:17 -0600 Message-Id: <59BABA8D020000780017B3FC@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.2 Date: Thu, 14 Sep 2017 09:21:17 -0600 From: "Jan Beulich" To: "xen-devel" References: <59BAB38A020000780017B34E@prv-mh.provo.novell.com> <59BAB38A020000780017B34E@prv-mh.provo.novell.com> In-Reply-To: <59BAB38A020000780017B34E@prv-mh.provo.novell.com> Mime-Version: 1.0 Content-Disposition: inline Cc: George Dunlap , Andrew Cooper Subject: [Xen-devel] [PATCH v2 16/17] x86emul: make all FPU emulation use the stub X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP While this means quite some reduction of (source) code, the main purpose is to no longer have exceptions raised from other than stubs. Signed-off-by: Jan Beulich --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1261,28 +1261,25 @@ static inline bool fpu_check_write(void) return !(fsw & FSW_ES); } -#define emulate_fpu_insn(_op) \ - asm volatile ( \ - "movb $2f-1f,%0 \n" \ - "1: " _op " \n" \ - "2: \n" \ - : "=m" (fic.insn_bytes) : : "memory" ) - -#define emulate_fpu_insn_memdst(_op, _arg) \ - asm volatile ( \ - "movb $2f-1f,%0 \n" \ - "1: " _op " %1 \n" \ - "2: \n" \ - : "=m" (fic.insn_bytes), "=m" (_arg) \ - : : "memory" ) - -#define emulate_fpu_insn_memsrc(_op, _arg) \ - asm volatile ( \ - "movb $2f-1f,%0 \n" \ - "1: " _op " %1 \n" \ - "2: \n" \ - : "=m" (fic.insn_bytes) \ - : "m" (_arg) : "memory" ) +#define emulate_fpu_insn_memdst(opc, ext, arg) \ +do { \ + /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ + fic.insn_bytes = 2; \ + memcpy(get_stub(stub), \ + ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + invoke_stub("", "", "+m" (fic), "+m" (arg) : "a" (&(arg))); \ + put_stub(stub); \ +} while (0) + +#define emulate_fpu_insn_memsrc(opc, ext, arg) \ +do { \ + /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ + fic.insn_bytes = 2; \ + memcpy(get_stub(stub), \ + ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + invoke_stub("", "", "+m" (fic) : "m" (arg), "a" (&(arg))); \ + put_stub(stub); \ +} while (0) #define emulate_fpu_insn_stub(bytes...) \ do { \ @@ -3843,8 +3840,7 @@ x86_emulate( case 0x9b: /* wait/fwait */ host_and_vcpu_must_have(fpu); get_fpu(X86EMUL_FPU_wait, &fic); - fic.insn_bytes = 1; - asm volatile ( "fwait" ::: "memory" ); + emulate_fpu_insn_stub(b); check_fpu_exn(&fic); break; @@ -4263,37 +4259,13 @@ x86_emulate( emulate_fpu_insn_stub(0xd8, modrm); break; default: + fpu_memsrc32: ASSERT(ea.type == OP_MEM); if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, 4, ctxt)) != X86EMUL_OKAY ) goto done; - switch ( modrm_reg & 7 ) - { - case 0: /* fadd */ - emulate_fpu_insn_memsrc("fadds", src.val); - break; - case 1: /* fmul */ - emulate_fpu_insn_memsrc("fmuls", src.val); - break; - case 2: /* fcom */ - emulate_fpu_insn_memsrc("fcoms", src.val); - break; - case 3: /* fcomp */ - emulate_fpu_insn_memsrc("fcomps", src.val); - break; - case 4: /* fsub */ - emulate_fpu_insn_memsrc("fsubs", src.val); - break; - case 5: /* fsubr */ - emulate_fpu_insn_memsrc("fsubrs", src.val); - break; - case 6: /* fdiv */ - emulate_fpu_insn_memsrc("fdivs", src.val); - break; - case 7: /* fdivr */ - emulate_fpu_insn_memsrc("fdivrs", src.val); - break; - } + emulate_fpu_insn_memsrc(b, modrm_reg, src.val); + break; } check_fpu_exn(&fic); break; @@ -4340,52 +4312,46 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - dst = ea; switch ( modrm_reg & 7 ) { case 0: /* fld m32fp */ - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 4, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("flds", src.val); - dst.type = OP_NONE; - break; + goto fpu_memsrc32; case 2: /* fst m32fp */ - emulate_fpu_insn_memdst("fsts", dst.val); - dst.bytes = 4; - break; case 3: /* fstp m32fp */ - emulate_fpu_insn_memdst("fstps", dst.val); + fpu_memdst32: + dst = ea; dst.bytes = 4; + emulate_fpu_insn_memdst(b, modrm_reg, dst.val); break; case 4: /* fldenv - TODO */ state->fpu_ctrl = true; goto cannot_emulate; case 5: /* fldcw m2byte */ state->fpu_ctrl = true; + fpu_memsrc16: if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, 2, ctxt)) != X86EMUL_OKAY ) goto done; - emulate_fpu_insn_memsrc("fldcw", src.val); - dst.type = OP_NONE; + emulate_fpu_insn_memsrc(b, modrm_reg, src.val); break; case 6: /* fnstenv - TODO */ state->fpu_ctrl = true; goto cannot_emulate; case 7: /* fnstcw m2byte */ state->fpu_ctrl = true; - emulate_fpu_insn_memdst("fnstcw", dst.val); + fpu_memdst16: + dst = ea; dst.bytes = 2; + emulate_fpu_insn_memdst(b, modrm_reg, dst.val); break; default: generate_exception(EXC_UD); } /* * Control instructions can't raise FPU exceptions, so we need - * to consider suppressing writes only for non-control ones. All - * of them in this group have data width 4. + * to consider suppressing writes only for non-control ones. */ - if ( dst.type == OP_MEM && dst.bytes == 4 && !fpu_check_write() ) + if ( dst.type == OP_MEM && !state->fpu_ctrl && !fpu_check_write() ) dst.type = OP_NONE; } check_fpu_exn(&fic); @@ -4408,36 +4374,7 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 4, ctxt)) != X86EMUL_OKAY ) - goto done; - switch ( modrm_reg & 7 ) - { - case 0: /* fiadd m32i */ - emulate_fpu_insn_memsrc("fiaddl", src.val); - break; - case 1: /* fimul m32i */ - emulate_fpu_insn_memsrc("fimull", src.val); - break; - case 2: /* ficom m32i */ - emulate_fpu_insn_memsrc("ficoml", src.val); - break; - case 3: /* ficomp m32i */ - emulate_fpu_insn_memsrc("ficompl", src.val); - break; - case 4: /* fisub m32i */ - emulate_fpu_insn_memsrc("fisubl", src.val); - break; - case 5: /* fisubr m32i */ - emulate_fpu_insn_memsrc("fisubrl", src.val); - break; - case 6: /* fidiv m32i */ - emulate_fpu_insn_memsrc("fidivl", src.val); - break; - case 7: /* fidivr m32i */ - emulate_fpu_insn_memsrc("fidivrl", src.val); - break; - } + goto fpu_memsrc32; } check_fpu_exn(&fic); break; @@ -4467,50 +4404,35 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - dst = ea; switch ( modrm_reg & 7 ) { case 0: /* fild m32i */ - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 4, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("fildl", src.val); - dst.type = OP_NONE; - break; + goto fpu_memsrc32; case 1: /* fisttp m32i */ host_and_vcpu_must_have(sse3); - emulate_fpu_insn_memdst("fisttpl", dst.val); - dst.bytes = 4; - break; + /* fall through */ case 2: /* fist m32i */ - emulate_fpu_insn_memdst("fistl", dst.val); - dst.bytes = 4; - break; case 3: /* fistp m32i */ - emulate_fpu_insn_memdst("fistpl", dst.val); - dst.bytes = 4; - break; + goto fpu_memdst32; case 5: /* fld m80fp */ + fpu_memsrc80: if ( (rc = ops->read(ea.mem.seg, ea.mem.off, mmvalp, 10, ctxt)) != X86EMUL_OKAY ) goto done; - emulate_fpu_insn_memsrc("fldt", *mmvalp); - dst.type = OP_NONE; + emulate_fpu_insn_memsrc(b, modrm_reg, *mmvalp); break; case 7: /* fstp m80fp */ + fpu_memdst80: fail_if(!ops->write); - emulate_fpu_insn_memdst("fstpt", *mmvalp); + emulate_fpu_insn_memdst(b, modrm_reg, *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; break; default: generate_exception(EXC_UD); } - if ( dst.type == OP_MEM && !fpu_check_write() ) - dst.type = OP_NONE; } check_fpu_exn(&fic); break; @@ -4531,37 +4453,13 @@ x86_emulate( emulate_fpu_insn_stub(0xdc, modrm); break; default: + fpu_memsrc64: ASSERT(ea.type == OP_MEM); if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, 8, ctxt)) != X86EMUL_OKAY ) goto done; - switch ( modrm_reg & 7 ) - { - case 0: /* fadd m64fp */ - emulate_fpu_insn_memsrc("faddl", src.val); - break; - case 1: /* fmul m64fp */ - emulate_fpu_insn_memsrc("fmull", src.val); - break; - case 2: /* fcom m64fp */ - emulate_fpu_insn_memsrc("fcoml", src.val); - break; - case 3: /* fcomp m64fp */ - emulate_fpu_insn_memsrc("fcompl", src.val); - break; - case 4: /* fsub m64fp */ - emulate_fpu_insn_memsrc("fsubl", src.val); - break; - case 5: /* fsubr m64fp */ - emulate_fpu_insn_memsrc("fsubrl", src.val); - break; - case 6: /* fdiv m64fp */ - emulate_fpu_insn_memsrc("fdivl", src.val); - break; - case 7: /* fdivr m64fp */ - emulate_fpu_insn_memsrc("fdivrl", src.val); - break; - } + emulate_fpu_insn_memsrc(b, modrm_reg, src.val); + break; } check_fpu_exn(&fic); break; @@ -4581,28 +4479,19 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - dst = ea; switch ( modrm_reg & 7 ) { case 0: /* fld m64fp */; - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 8, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("fldl", src.val); - dst.type = OP_NONE; - break; + goto fpu_memsrc64; case 1: /* fisttp m64i */ host_and_vcpu_must_have(sse3); - emulate_fpu_insn_memdst("fisttpll", dst.val); - dst.bytes = 8; - break; + /* fall through */ case 2: /* fst m64fp */ - emulate_fpu_insn_memdst("fstl", dst.val); - dst.bytes = 8; - break; case 3: /* fstp m64fp */ - emulate_fpu_insn_memdst("fstpl", dst.val); + fpu_memdst64: + dst = ea; dst.bytes = 8; + emulate_fpu_insn_memdst(b, modrm_reg, dst.val); break; case 4: /* frstor - TODO */ case 6: /* fnsave - TODO */ @@ -4610,18 +4499,15 @@ x86_emulate( goto cannot_emulate; case 7: /* fnstsw m2byte */ state->fpu_ctrl = true; - emulate_fpu_insn_memdst("fnstsw", dst.val); - dst.bytes = 2; - break; + goto fpu_memdst16; default: generate_exception(EXC_UD); } /* * Control instructions can't raise FPU exceptions, so we need - * to consider suppressing writes only for non-control ones. All - * of them in this group have data width 8. + * to consider suppressing writes only for non-control ones. */ - if ( dst.type == OP_MEM && dst.bytes == 8 && !fpu_check_write() ) + if ( dst.type == OP_MEM && !state->fpu_ctrl && !fpu_check_write() ) dst.type = OP_NONE; } check_fpu_exn(&fic); @@ -4644,33 +4530,8 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - switch ( modrm_reg & 7 ) - { - case 0: /* fiadd m16i */ - emulate_fpu_insn_memsrc("fiadds", src.val); - break; - case 1: /* fimul m16i */ - emulate_fpu_insn_memsrc("fimuls", src.val); - break; - case 2: /* ficom m16i */ - emulate_fpu_insn_memsrc("ficoms", src.val); - break; - case 3: /* ficomp m16i */ - emulate_fpu_insn_memsrc("ficomps", src.val); - break; - case 4: /* fisub m16i */ - emulate_fpu_insn_memsrc("fisubs", src.val); - break; - case 5: /* fisubr m16i */ - emulate_fpu_insn_memsrc("fisubrs", src.val); - break; - case 6: /* fidiv m16i */ - emulate_fpu_insn_memsrc("fidivs", src.val); - break; - case 7: /* fidivr m16i */ - emulate_fpu_insn_memsrc("fidivrs", src.val); - break; - } + emulate_fpu_insn_memsrc(b, modrm_reg, src.val); + break; } check_fpu_exn(&fic); break; @@ -4686,7 +4547,7 @@ x86_emulate( dst.bytes = 2; dst.type = OP_REG; dst.reg = (void *)&_regs.ax; - emulate_fpu_insn_memdst("fnstsw", dst.val); + emulate_fpu_insn_memdst(b, modrm_reg, dst.val); break; case 0xe8 ... 0xef: /* fucomip %stN */ case 0xf0 ... 0xf7: /* fcomip %stN */ @@ -4701,59 +4562,26 @@ x86_emulate( break; default: generate_exception_if(ea.type != OP_MEM, EXC_UD); - dst = ea; switch ( modrm_reg & 7 ) { case 0: /* fild m16i */ - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 2, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("filds", src.val); - dst.type = OP_NONE; - break; + goto fpu_memsrc16; case 1: /* fisttp m16i */ host_and_vcpu_must_have(sse3); - emulate_fpu_insn_memdst("fisttps", dst.val); - dst.bytes = 2; - break; + /* fall through */ case 2: /* fist m16i */ - emulate_fpu_insn_memdst("fists", dst.val); - dst.bytes = 2; - break; case 3: /* fistp m16i */ - emulate_fpu_insn_memdst("fistps", dst.val); - dst.bytes = 2; - break; + goto fpu_memdst16; case 4: /* fbld m80dec */ - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, mmvalp, - 10, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("fbld", *mmvalp); - dst.type = OP_NONE; - break; + goto fpu_memsrc80; case 5: /* fild m64i */ - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, - 8, ctxt)) != X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc("fildll", src.val); dst.type = OP_NONE; - break; + goto fpu_memsrc64; case 6: /* fbstp packed bcd */ - fail_if(!ops->write); - emulate_fpu_insn_memdst("fbstp", *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; - break; + goto fpu_memdst80; case 7: /* fistp m64i */ - emulate_fpu_insn_memdst("fistpll", dst.val); - dst.bytes = 8; - break; + goto fpu_memdst64; } - if ( dst.type == OP_MEM && !fpu_check_write() ) - dst.type = OP_NONE; } check_fpu_exn(&fic); break;