From patchwork Thu Sep 8 13:17:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9321379 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 7B993607D3 for ; Thu, 8 Sep 2016 13:19:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6B9E82987B for ; Thu, 8 Sep 2016 13:19:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5FE2829880; Thu, 8 Sep 2016 13:19:24 +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 82EBB2987B for ; Thu, 8 Sep 2016 13:19:23 +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 1bhzCZ-0001Sr-JY; Thu, 08 Sep 2016 13:17:11 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bhzCY-0001Sg-CW for xen-devel@lists.xenproject.org; Thu, 08 Sep 2016 13:17:10 +0000 Received: from [85.158.143.35] by server-1.bemta-6.messagelabs.com id B0/54-21406-5D461D75; Thu, 08 Sep 2016 13:17:09 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrBIsWRWlGSWpSXmKPExsXS6fjDS/dKysV wg08nRS2+b5nM5MDocfjDFZYAxijWzLyk/IoE1oyXZxYzFnwrrTjUdY29gXGRfxcjJ4eQQJ7E +TWdbF2MHBy8AnYSx+engYQlBAwlnr6/DhZmEVCV2LM/ACTMJqAu0fZsOytIWETAQOLc0SQQk 1lAX2LbOhaQCmGBeIlrl08xQ8y2k3h26iBYnFPAXuJL6xxGiD2CEn93CEN02kkc+qw5gZFnFk JiFkJiFlArs4CWxMNft1ggbG2JZQtfM0OUSEss/8cBEbaTeLrxGxuqEhDbU+LSyyfsCxg5VjF qFKcWlaUW6RoZ6iUVZaZnlOQmZuboGhqY6eWmFhcnpqfmJCYV6yXn525iBIYoAxDsYPyzLOAQ oyQHk5Ior0/xhXAhvqT8lMqMxOKM+KLSnNTiQ4wyHBxKErw2yRfDhQSLUtNTK9Iyc4DRApOW4 OBREuHNBUnzFhck5hZnpkOkTjEqSonzVoMkBEASGaV5cG2wCL3EKCslzMsIdIgQT0FqUW5mCa r8K0ZxDkYlYd54kCk8mXklcNNfAS1mAlosdOo8yOKSRISUVAPjUZUm8YntyavTkiSL5rJvy/r aderrtxCH5wFbco4kH+7tWNSr+WZT4vwf8tnebFIyzCbBrKIy873+fDj3bW3esn177+c8uvnJ 33j5jlv7tG179davTXle3x1umHuR7ensPXZG75Q6yh9bfhHINWL5ZGo2NVZb1iX1q4NS6/pft YwyWl8f72FSYinOSDTUYi4qTgQAA/o16MsCAAA= X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-16.tower-21.messagelabs.com!1473340626!27810464!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 64483 invoked from network); 8 Sep 2016 13:17:07 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-16.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 8 Sep 2016 13:17:07 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Thu, 08 Sep 2016 07:17:02 -0600 Message-Id: <57D180EE020000780010D197@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.1 Date: Thu, 08 Sep 2016 07:17:02 -0600 From: "Jan Beulich" To: "xen-devel" References: <57D17C78020000780010D127@prv-mh.provo.novell.com> In-Reply-To: <57D17C78020000780010D127@prv-mh.provo.novell.com> Mime-Version: 1.0 Cc: Andrew Cooper Subject: [Xen-devel] [PATCH 11/17] 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 @@ -2242,6 +2242,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 | @@ -2654,48 +2755,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?, */ { @@ -2719,56 +2781,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; } --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2242,6 +2242,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 | @@ -2654,48 +2755,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?, */ { @@ -2719,56 +2781,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; }