From patchwork Wed Sep 28 08:14:26 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9353225 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 510636077A for ; Wed, 28 Sep 2016 08:20:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3D81729086 for ; Wed, 28 Sep 2016 08:20:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2D9C1292D6; Wed, 28 Sep 2016 08:20:44 +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 33CE829086 for ; Wed, 28 Sep 2016 08:20:42 +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 1bpA3c-0001Mo-Uq; Wed, 28 Sep 2016 08:17:36 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bpA3b-0001MI-6K for xen-devel@lists.xenproject.org; Wed, 28 Sep 2016 08:17:35 +0000 Received: from [85.158.139.211] by server-15.bemta-5.messagelabs.com id 97/B4-01343-E9C7BE75; Wed, 28 Sep 2016 08:17:34 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrKIsWRWlGSWpSXmKPExsXS6fjDS3dWzet wg81zpSy+b5nM5MDocfjDFZYAxijWzLyk/IoE1oxFba4F30or/qywaGBc5N/FyMkhJJAn8XTF JTYQm1fATmLhlY1MILaEgKHE0/fXgeIcHCwCqhKX1teAhNkE1CXanm1nBQmLCBhInDuaBGIyC +hLbFvHAlIhLJAksWX3Y0aI4XYSj1+/AYtzCthLfL32BayTV0BQ4u8OYZAwM1DJ8+7VLBMYeW YhZGYhyUDYWhIPf92CsrUlli18zTwLbK+0xPJ/HDDlTzd+Y0NVAmJ7Slx6+YR9ASPHKkaN4tS istQiXUMjvaSizPSMktzEzBxdQwNTvdzU4uLE9NScxKRiveT83E2MwCBlAIIdjH2znA8xSnIw KYnybg5/HS7El5SfUpmRWJwRX1Sak1p8iFGDg0Ng267VFxilWPLy81KVJHjnVQPVCRalpqdWp GXmAOMIplSCg0dJhDcKJM1bXJCYW5yZDpE6xagoJc4bDpIQAElklObBtcFi9xKjrJQwLyPQUU I8BalFuZklqPKvGMU5GJWEeXVBpvBk5pXATX8FtJgJaPHSEy9AFpckIqSkGhgNpRwMFM7/DrU /dMijwuDrgaXMz1Zv/M1iNSEo9N6l2btWalh9Lly060am7u7JwqkMTMsfzNm4psgwXUer/snG ktwtaTaaPKeU7jQ+YWlwtHrzsD+PO+q+xsn774UsLTqvsa85Hlsx2TVqj7TgvDyZw6Y3XlZf0 Ek4Yj7lYzp39R8XIYtp2wyUWIozEg21mIuKEwGLz1ds2AIAAA== X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-8.tower-206.messagelabs.com!1475050648!61713780!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 53558 invoked from network); 28 Sep 2016 08:17:29 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-8.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 28 Sep 2016 08:17:29 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Wed, 28 Sep 2016 02:14:27 -0600 Message-Id: <57EB980202000078001131D3@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.1 Date: Wed, 28 Sep 2016 02:14:26 -0600 From: "Jan Beulich" To: "xen-devel" References: <57EB94940200007800113179@prv-mh.provo.novell.com> In-Reply-To: <57EB94940200007800113179@prv-mh.provo.novell.com> Mime-Version: 1.0 Cc: Andrew Cooper Subject: [Xen-devel] [PATCH v2 10/16] x86/PV: split out dealing with CRn from privileged instruction handling 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 This is in preparation for using the generic emulator here. Signed-off-by: Jan Beulich x86/PV: split out dealing with CRn from privileged instruction handling This is in preparation for using the generic emulator here. Signed-off-by: Jan Beulich --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2255,6 +2255,107 @@ unsigned long guest_to_host_gpr_switch(u void (*pv_post_outb_hook)(unsigned int port, u8 value); +static int priv_op_read_cr(unsigned int reg, unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + const struct vcpu *curr = current; + + switch ( reg ) + { + case 0: /* Read CR0 */ + *val = (read_cr0() & ~X86_CR0_TS) | curr->arch.pv_vcpu.ctrlreg[0]; + return X86EMUL_OKAY; + + case 2: /* Read CR2 */ + case 4: /* Read CR4 */ + *val = curr->arch.pv_vcpu.ctrlreg[reg]; + return X86EMUL_OKAY; + + case 3: /* Read CR3 */ + { + const struct domain *currd = curr->domain; + unsigned long mfn; + + if ( !is_pv_32bit_domain(currd) ) + { + mfn = pagetable_get_pfn(curr->arch.guest_table); + *val = xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + else + { + l4_pgentry_t *pl4e = + map_domain_page(_mfn(pagetable_get_pfn(curr->arch.guest_table))); + + mfn = l4e_get_pfn(*pl4e); + unmap_domain_page(pl4e); + *val = compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + /* PTs should not be shared */ + BUG_ON(page_get_owner(mfn_to_page(mfn)) == dom_cow); + return X86EMUL_OKAY; + } + } + + return X86EMUL_UNHANDLEABLE; +} + +static int priv_op_write_cr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr = current; + + switch ( reg ) + { + case 0: /* Write CR0 */ + if ( (val ^ read_cr0()) & ~X86_CR0_TS ) + { + gdprintk(XENLOG_WARNING, + "Attempt to change unmodifiable CR0 flags\n"); + break; + } + do_fpu_taskswitch(!!(val & X86_CR0_TS)); + return X86EMUL_OKAY; + + case 2: /* Write CR2 */ + curr->arch.pv_vcpu.ctrlreg[2] = val; + arch_set_cr2(curr, val); + return X86EMUL_OKAY; + + case 3: /* Write CR3 */ + { + struct domain *currd = curr->domain; + unsigned long gfn; + struct page_info *page; + int rc; + + gfn = !is_pv_32bit_domain(currd) + ? xen_cr3_to_pfn(val) : compat_cr3_to_pfn(val); + page = get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); + if ( !page ) + break; + rc = new_guest_cr3(page_to_mfn(page)); + put_page(page); + + switch ( rc ) + { + case 0: + return X86EMUL_OKAY; + case -ERESTART: /* retry after preemption */ + return X86EMUL_RETRY; + } + break; + } + + case 4: /* Write CR4 */ + curr->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(curr, val); + write_cr4(pv_guest_cr4_to_real_cr4(curr)); + ctxt_switch_levelling(curr); + return X86EMUL_OKAY; + } + + return X86EMUL_UNHANDLEABLE; +} + static inline uint64_t guest_misc_enable(uint64_t val) { val &= ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL | @@ -2667,48 +2768,9 @@ static int emulate_privileged_op(struct goto fail; modrm_reg += ((opcode >> 3) & 7) + (lock << 3); modrm_rm |= (opcode >> 0) & 7; - reg = decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) - { - case 0: /* Read CR0 */ - *reg = (read_cr0() & ~X86_CR0_TS) | - v->arch.pv_vcpu.ctrlreg[0]; - break; - - case 2: /* Read CR2 */ - *reg = v->arch.pv_vcpu.ctrlreg[2]; - break; - - case 3: /* Read CR3 */ - { - unsigned long mfn; - - if ( !is_pv_32bit_domain(currd) ) - { - mfn = pagetable_get_pfn(v->arch.guest_table); - *reg = xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - else - { - l4_pgentry_t *pl4e = - map_domain_page(_mfn(pagetable_get_pfn(v->arch.guest_table))); - - mfn = l4e_get_pfn(*pl4e); - unmap_domain_page(pl4e); - *reg = compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - /* PTs should not be shared */ - BUG_ON(page_get_owner(mfn_to_page(mfn)) == dom_cow); - } - break; - - case 4: /* Read CR4 */ - *reg = v->arch.pv_vcpu.ctrlreg[4]; - break; - - default: + if ( priv_op_read_cr(modrm_reg, decode_register(modrm_rm, regs, 0), + NULL) != X86EMUL_OKAY ) goto fail; - } break; case 0x21: /* MOV DR?, */ { @@ -2732,56 +2794,12 @@ static int emulate_privileged_op(struct modrm_reg += ((opcode >> 3) & 7) + (lock << 3); modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) + switch ( priv_op_write_cr(modrm_reg, *reg, NULL) ) { - case 0: /* Write CR0 */ - if ( (*reg ^ read_cr0()) & ~X86_CR0_TS ) - { - gdprintk(XENLOG_WARNING, - "Attempt to change unmodifiable CR0 flags.\n"); - goto fail; - } - (void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS)); - break; - - case 2: /* Write CR2 */ - v->arch.pv_vcpu.ctrlreg[2] = *reg; - arch_set_cr2(v, *reg); - break; - - case 3: {/* Write CR3 */ - unsigned long gfn; - struct page_info *page; - - gfn = !is_pv_32bit_domain(currd) - ? xen_cr3_to_pfn(*reg) : compat_cr3_to_pfn(*reg); - page = get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); - if ( page ) - { - rc = new_guest_cr3(page_to_mfn(page)); - put_page(page); - } - else - rc = -EINVAL; - - switch ( rc ) - { - case 0: - break; - case -ERESTART: /* retry after preemption */ - goto skip; - default: /* not okay */ - goto fail; - } + case X86EMUL_OKAY: break; - } - - case 4: /* Write CR4 */ - v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg); - write_cr4(pv_guest_cr4_to_real_cr4(v)); - ctxt_switch_levelling(v); - break; - + case X86EMUL_RETRY: /* retry after preemption */ + goto skip; default: goto fail; } Reviewed-by: Andrew Cooper --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2255,6 +2255,107 @@ unsigned long guest_to_host_gpr_switch(u void (*pv_post_outb_hook)(unsigned int port, u8 value); +static int priv_op_read_cr(unsigned int reg, unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + const struct vcpu *curr = current; + + switch ( reg ) + { + case 0: /* Read CR0 */ + *val = (read_cr0() & ~X86_CR0_TS) | curr->arch.pv_vcpu.ctrlreg[0]; + return X86EMUL_OKAY; + + case 2: /* Read CR2 */ + case 4: /* Read CR4 */ + *val = curr->arch.pv_vcpu.ctrlreg[reg]; + return X86EMUL_OKAY; + + case 3: /* Read CR3 */ + { + const struct domain *currd = curr->domain; + unsigned long mfn; + + if ( !is_pv_32bit_domain(currd) ) + { + mfn = pagetable_get_pfn(curr->arch.guest_table); + *val = xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + else + { + l4_pgentry_t *pl4e = + map_domain_page(_mfn(pagetable_get_pfn(curr->arch.guest_table))); + + mfn = l4e_get_pfn(*pl4e); + unmap_domain_page(pl4e); + *val = compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + /* PTs should not be shared */ + BUG_ON(page_get_owner(mfn_to_page(mfn)) == dom_cow); + return X86EMUL_OKAY; + } + } + + return X86EMUL_UNHANDLEABLE; +} + +static int priv_op_write_cr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr = current; + + switch ( reg ) + { + case 0: /* Write CR0 */ + if ( (val ^ read_cr0()) & ~X86_CR0_TS ) + { + gdprintk(XENLOG_WARNING, + "Attempt to change unmodifiable CR0 flags\n"); + break; + } + do_fpu_taskswitch(!!(val & X86_CR0_TS)); + return X86EMUL_OKAY; + + case 2: /* Write CR2 */ + curr->arch.pv_vcpu.ctrlreg[2] = val; + arch_set_cr2(curr, val); + return X86EMUL_OKAY; + + case 3: /* Write CR3 */ + { + struct domain *currd = curr->domain; + unsigned long gfn; + struct page_info *page; + int rc; + + gfn = !is_pv_32bit_domain(currd) + ? xen_cr3_to_pfn(val) : compat_cr3_to_pfn(val); + page = get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); + if ( !page ) + break; + rc = new_guest_cr3(page_to_mfn(page)); + put_page(page); + + switch ( rc ) + { + case 0: + return X86EMUL_OKAY; + case -ERESTART: /* retry after preemption */ + return X86EMUL_RETRY; + } + break; + } + + case 4: /* Write CR4 */ + curr->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(curr, val); + write_cr4(pv_guest_cr4_to_real_cr4(curr)); + ctxt_switch_levelling(curr); + return X86EMUL_OKAY; + } + + return X86EMUL_UNHANDLEABLE; +} + static inline uint64_t guest_misc_enable(uint64_t val) { val &= ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL | @@ -2667,48 +2768,9 @@ static int emulate_privileged_op(struct goto fail; modrm_reg += ((opcode >> 3) & 7) + (lock << 3); modrm_rm |= (opcode >> 0) & 7; - reg = decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) - { - case 0: /* Read CR0 */ - *reg = (read_cr0() & ~X86_CR0_TS) | - v->arch.pv_vcpu.ctrlreg[0]; - break; - - case 2: /* Read CR2 */ - *reg = v->arch.pv_vcpu.ctrlreg[2]; - break; - - case 3: /* Read CR3 */ - { - unsigned long mfn; - - if ( !is_pv_32bit_domain(currd) ) - { - mfn = pagetable_get_pfn(v->arch.guest_table); - *reg = xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - else - { - l4_pgentry_t *pl4e = - map_domain_page(_mfn(pagetable_get_pfn(v->arch.guest_table))); - - mfn = l4e_get_pfn(*pl4e); - unmap_domain_page(pl4e); - *reg = compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - /* PTs should not be shared */ - BUG_ON(page_get_owner(mfn_to_page(mfn)) == dom_cow); - } - break; - - case 4: /* Read CR4 */ - *reg = v->arch.pv_vcpu.ctrlreg[4]; - break; - - default: + if ( priv_op_read_cr(modrm_reg, decode_register(modrm_rm, regs, 0), + NULL) != X86EMUL_OKAY ) goto fail; - } break; case 0x21: /* MOV DR?, */ { @@ -2732,56 +2794,12 @@ static int emulate_privileged_op(struct modrm_reg += ((opcode >> 3) & 7) + (lock << 3); modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) + switch ( priv_op_write_cr(modrm_reg, *reg, NULL) ) { - case 0: /* Write CR0 */ - if ( (*reg ^ read_cr0()) & ~X86_CR0_TS ) - { - gdprintk(XENLOG_WARNING, - "Attempt to change unmodifiable CR0 flags.\n"); - goto fail; - } - (void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS)); - break; - - case 2: /* Write CR2 */ - v->arch.pv_vcpu.ctrlreg[2] = *reg; - arch_set_cr2(v, *reg); - break; - - case 3: {/* Write CR3 */ - unsigned long gfn; - struct page_info *page; - - gfn = !is_pv_32bit_domain(currd) - ? xen_cr3_to_pfn(*reg) : compat_cr3_to_pfn(*reg); - page = get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); - if ( page ) - { - rc = new_guest_cr3(page_to_mfn(page)); - put_page(page); - } - else - rc = -EINVAL; - - switch ( rc ) - { - case 0: - break; - case -ERESTART: /* retry after preemption */ - goto skip; - default: /* not okay */ - goto fail; - } + case X86EMUL_OKAY: break; - } - - case 4: /* Write CR4 */ - v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg); - write_cr4(pv_guest_cr4_to_real_cr4(v)); - ctxt_switch_levelling(v); - break; - + case X86EMUL_RETRY: /* retry after preemption */ + goto skip; default: goto fail; }