From patchwork Mon Nov 28 11:13:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Cooper X-Patchwork-Id: 9449353 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 C981B60235 for ; Mon, 28 Nov 2016 11:16:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B89C120410 for ; Mon, 28 Nov 2016 11:16:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AD44A2675C; Mon, 28 Nov 2016 11:16: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 9EC6420410 for ; Mon, 28 Nov 2016 11:16:26 +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 1cBJsd-0005Pt-ER; Mon, 28 Nov 2016 11:13:51 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cBJsc-0005Or-B7 for xen-devel@lists.xen.org; Mon, 28 Nov 2016 11:13:50 +0000 Received: from [85.158.137.68] by server-13.bemta-3.messagelabs.com id 83/C9-23854-D611C385; Mon, 28 Nov 2016 11:13:49 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpmkeJIrShJLcpLzFFi42JxWrrBXjdX0Cb CoLOH2WLJx8UsDoweR3f/ZgpgjGLNzEvKr0hgzZi7upe14Fx1xY5Fh5kaGB+EdzFyckgI+EvM eX2XDcRmE9CX2P3iExOILSKgLnG64yIriM0skClx5PZmMFtYIFzix6FZYDUsAqoSP/+cZQaxe QU8JHbv3cEIMVNO4vzxn2BxTgFPiSOT3gPVc3AIAdV0/vMCCQsJqElc67/EDtEqKHFy5hMWiF USEgdfvGCewMg7C0lqFpLUAkamVYzqxalFZalFuuZ6SUWZ6RkluYmZObqGBsZ6uanFxYnpqTm JScV6yfm5mxiBgcMABDsYG787HWKU5GBSEuW9/dg6QogvKT+lMiOxOCO+qDQntfgQowwHh5IE b4CATYSQYFFqempFWmYOMIRh0hIcPEoivDNA0rzFBYm5xZnpEKlTjIpS4ry+IAkBkERGaR5cG yxuLjHKSgnzMgIdIsRTkFqUm1mCKv+KUZyDUUmYdyfIFJ7MvBK46a+AFjMBLX772hpkcUkiQk qqgZHvfE7Tyr2XN4h3fUkpDLLnOHG1r0c775jgct2q/l4VruTPe090ta5u3LBd+HmKoNVN1dk pRw9r/rj/uCVsxfy8nQ8jSw9MUN5eq+wQXOvO9mhh0E1JvsY3F9Tbd7EqP9PW/nzt31JJX64J 2UfmB2Ytt98ecNdKMJVTcovrez6BT5Jb3v7jSFJiKc5INNRiLipOBABngK40lgIAAA== X-Env-Sender: prvs=1334ebad9=Andrew.Cooper3@citrix.com X-Msg-Ref: server-9.tower-31.messagelabs.com!1480331618!17781967!4 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.0.16; banners=-,-,- X-VirusChecked: Checked Received: (qmail 56753 invoked from network); 28 Nov 2016 11:13:48 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-9.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 28 Nov 2016 11:13:48 -0000 X-IronPort-AV: E=Sophos;i="5.31,563,1473120000"; d="scan'208";a="400418849" From: Andrew Cooper To: Xen-devel Date: Mon, 28 Nov 2016 11:13:23 +0000 Message-ID: <1480331616-6165-7-git-send-email-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1480331616-6165-1-git-send-email-andrew.cooper3@citrix.com> References: <1480331616-6165-1-git-send-email-andrew.cooper3@citrix.com> MIME-Version: 1.0 Cc: Andrew Cooper , Tim Deegan , Jan Beulich Subject: [Xen-devel] [PATCH v2 06/19] x86/pv: Implement pv_inject_{event, page_fault, hw_exception}() 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 To help with event injection improvements for the PV uses of x86_emulate(), implement a event injection API which matches its hvm counterpart. This is started with taking do_guest_trap() and modifying its calling API to pv_inject_event(), subsequentally implementing the former in terms of the latter. The existing propagate_page_fault() is fairly similar to pv_inject_page_fault(), although it has a return value. Only a single caller makes use of the return value, and non-NULL is only returned if the passed cr2 is non-canonical. Opencode this single case in handle_gdt_ldt_mapping_fault(), allowing propagate_page_fault() to become void. The #PF specific bits are moved into pv_inject_event(), and pv_inject_page_fault() is implemented as a static inline wrapper. reserved_bit_page_fault() is pure code motion. No functional change. Signed-off-by: Andrew Cooper Acked-by: Tim Deegan --- CC: Jan Beulich CC: Tim Deegan v2: * New --- xen/arch/x86/mm.c | 5 +- xen/arch/x86/mm/shadow/common.c | 4 +- xen/arch/x86/traps.c | 172 ++++++++++++++++++++-------------------- xen/include/asm-x86/domain.h | 26 ++++++ xen/include/asm-x86/mm.h | 1 - 5 files changed, 118 insertions(+), 90 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index d365f59..b7c7122 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -5136,7 +5136,7 @@ static int ptwr_emulated_read( if ( !__addr_ok(addr) || (rc = __copy_from_user(p_data, (void *)addr, bytes)) ) { - propagate_page_fault(addr + bytes - rc, 0); /* read fault */ + pv_inject_page_fault(0, addr + bytes - rc); /* Read fault. */ return X86EMUL_EXCEPTION; } @@ -5177,7 +5177,8 @@ static int ptwr_emulated_update( addr &= ~(sizeof(paddr_t)-1); if ( (rc = copy_from_user(&full, (void *)addr, sizeof(paddr_t))) != 0 ) { - propagate_page_fault(addr+sizeof(paddr_t)-rc, 0); /* read fault */ + pv_inject_page_fault(0, /* Read fault. */ + addr + sizeof(paddr_t) - rc); return X86EMUL_EXCEPTION; } /* Mask out bits provided by caller. */ diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index a4a3c4b..f07803b 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -323,7 +323,7 @@ pv_emulate_read(enum x86_segment seg, if ( (rc = copy_from_user(p_data, (void *)offset, bytes)) != 0 ) { - propagate_page_fault(offset + bytes - rc, 0); /* read fault */ + pv_inject_page_fault(0, offset + bytes - rc); /* Read fault. */ return X86EMUL_EXCEPTION; } @@ -1723,7 +1723,7 @@ static mfn_t emulate_gva_to_mfn(struct vcpu *v, unsigned long vaddr, if ( is_hvm_vcpu(v) ) hvm_inject_page_fault(pfec, vaddr); else - propagate_page_fault(vaddr, pfec); + pv_inject_page_fault(pfec, vaddr); return _mfn(BAD_GVA_TO_GFN); } diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index b464211..7301298 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -625,37 +625,90 @@ void fatal_trap(const struct cpu_user_regs *regs, bool_t show_remote) (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT"); } -static void do_guest_trap(unsigned int trapnr, - const struct cpu_user_regs *regs) +static void reserved_bit_page_fault( + unsigned long addr, struct cpu_user_regs *regs) +{ + printk("%pv: reserved bit in page table (ec=%04X)\n", + current, regs->error_code); + show_page_walk(addr); + show_execution_state(regs); +} + +void pv_inject_event(const struct x86_event *event) { struct vcpu *v = current; + struct cpu_user_regs *regs = guest_cpu_user_regs(); struct trap_bounce *tb; const struct trap_info *ti; + const uint8_t vector = event->vector; const bool use_error_code = - ((trapnr < 32) && (TRAP_HAVE_EC & (1u << trapnr))); + ((vector < 32) && (TRAP_HAVE_EC & (1u << vector))); + unsigned int error_code = event->error_code; - trace_pv_trap(trapnr, regs->eip, use_error_code, regs->error_code); + ASSERT(vector == event->vector); /* Check for no truncation. */ + if ( use_error_code ) + ASSERT(error_code != X86_EVENT_NO_EC); + else + ASSERT(error_code == X86_EVENT_NO_EC); tb = &v->arch.pv_vcpu.trap_bounce; - ti = &v->arch.pv_vcpu.trap_ctxt[trapnr]; + ti = &v->arch.pv_vcpu.trap_ctxt[vector]; tb->flags = TBF_EXCEPTION; tb->cs = ti->cs; tb->eip = ti->address; + if ( vector == TRAP_page_fault ) + { + v->arch.pv_vcpu.ctrlreg[2] = event->cr2; + arch_set_cr2(v, event->cr2); + + /* Re-set error_code.user flag appropriately for the guest. */ + error_code &= ~PFEC_user_mode; + if ( !guest_kernel_mode(v, regs) ) + error_code |= PFEC_user_mode; + + trace_pv_page_fault(event->cr2, error_code); + } + else + trace_pv_trap(vector, regs->eip, use_error_code, error_code); + if ( use_error_code ) { tb->flags |= TBF_EXCEPTION_ERRCODE; - tb->error_code = regs->error_code; + tb->error_code = error_code; } if ( TI_GET_IF(ti) ) tb->flags |= TBF_INTERRUPT; if ( unlikely(null_trap_bounce(v, tb)) ) - gprintk(XENLOG_WARNING, - "Unhandled %s fault/trap [#%d, ec=%04x]\n", - trapstr(trapnr), trapnr, regs->error_code); + { + if ( vector == TRAP_page_fault ) + { + printk("%pv: unhandled page fault (ec=%04X)\n", v, error_code); + show_page_walk(event->cr2); + + if ( unlikely(error_code & PFEC_reserved_bit) ) + reserved_bit_page_fault(event->cr2, regs); + } + else + gprintk(XENLOG_WARNING, + "Unhandled %s fault/trap [#%d, ec=%04x]\n", + trapstr(vector), vector, error_code); + } +} + +static inline void do_guest_trap(unsigned int trapnr, + const struct cpu_user_regs *regs) +{ + const struct x86_event event = { + .vector = trapnr, + .error_code = (((trapnr < 32) && (TRAP_HAVE_EC & (1u << trapnr))) + ? regs->error_code : X86_EVENT_NO_EC), + }; + + pv_inject_event(&event); } static void instruction_done( @@ -1289,7 +1342,7 @@ static int emulate_invalid_rdtscp(struct cpu_user_regs *regs) eip = regs->eip; if ( (rc = copy_from_user(opcode, (char *)eip, sizeof(opcode))) != 0 ) { - propagate_page_fault(eip + sizeof(opcode) - rc, 0); + pv_inject_page_fault(0, eip + sizeof(opcode) - rc); return EXCRET_fault_fixed; } if ( memcmp(opcode, "\xf\x1\xf9", sizeof(opcode)) ) @@ -1310,7 +1363,7 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) /* Check for forced emulation signature: ud2 ; .ascii "xen". */ if ( (rc = copy_from_user(sig, (char *)eip, sizeof(sig))) != 0 ) { - propagate_page_fault(eip + sizeof(sig) - rc, 0); + pv_inject_page_fault(0, eip + sizeof(sig) - rc); return EXCRET_fault_fixed; } if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) ) @@ -1320,7 +1373,7 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) /* We only emulate CPUID. */ if ( ( rc = copy_from_user(instr, (char *)eip, sizeof(instr))) != 0 ) { - propagate_page_fault(eip + sizeof(instr) - rc, 0); + pv_inject_page_fault(0, eip + sizeof(instr) - rc); return EXCRET_fault_fixed; } if ( memcmp(instr, "\xf\xa2", sizeof(instr)) ) @@ -1478,62 +1531,6 @@ void do_int3(struct cpu_user_regs *regs) do_guest_trap(TRAP_int3, regs); } -static void reserved_bit_page_fault( - unsigned long addr, struct cpu_user_regs *regs) -{ - printk("%pv: reserved bit in page table (ec=%04X)\n", - current, regs->error_code); - show_page_walk(addr); - show_execution_state(regs); -} - -struct trap_bounce *propagate_page_fault(unsigned long addr, u16 error_code) -{ - struct trap_info *ti; - struct vcpu *v = current; - struct trap_bounce *tb = &v->arch.pv_vcpu.trap_bounce; - - if ( unlikely(!is_canonical_address(addr)) ) - { - ti = &v->arch.pv_vcpu.trap_ctxt[TRAP_gp_fault]; - tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE; - tb->error_code = 0; - tb->cs = ti->cs; - tb->eip = ti->address; - if ( TI_GET_IF(ti) ) - tb->flags |= TBF_INTERRUPT; - return tb; - } - - v->arch.pv_vcpu.ctrlreg[2] = addr; - arch_set_cr2(v, addr); - - /* Re-set error_code.user flag appropriately for the guest. */ - error_code &= ~PFEC_user_mode; - if ( !guest_kernel_mode(v, guest_cpu_user_regs()) ) - error_code |= PFEC_user_mode; - - trace_pv_page_fault(addr, error_code); - - ti = &v->arch.pv_vcpu.trap_ctxt[TRAP_page_fault]; - tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE; - tb->error_code = error_code; - tb->cs = ti->cs; - tb->eip = ti->address; - if ( TI_GET_IF(ti) ) - tb->flags |= TBF_INTERRUPT; - if ( unlikely(null_trap_bounce(v, tb)) ) - { - printk("%pv: unhandled page fault (ec=%04X)\n", v, error_code); - show_page_walk(addr); - } - - if ( unlikely(error_code & PFEC_reserved_bit) ) - reserved_bit_page_fault(addr, guest_cpu_user_regs()); - - return NULL; -} - static int handle_gdt_ldt_mapping_fault( unsigned long offset, struct cpu_user_regs *regs) { @@ -1565,17 +1562,22 @@ static int handle_gdt_ldt_mapping_fault( } else { - struct trap_bounce *tb; - /* In hypervisor mode? Leave it to the #PF handler to fix up. */ if ( !guest_mode(regs) ) return 0; - /* In guest mode? Propagate fault to guest, with adjusted %cr2. */ - tb = propagate_page_fault(curr->arch.pv_vcpu.ldt_base + offset, - regs->error_code); - if ( tb ) - tb->error_code = (offset & ~(X86_XEC_EXT | X86_XEC_IDT)) | - X86_XEC_TI; + + /* Access would have become non-canonical? Pass #GP[sel] back. */ + if ( unlikely(!is_canonical_address( + curr->arch.pv_vcpu.ldt_base + offset)) ) + { + uint16_t ec = (offset & ~(X86_XEC_EXT | X86_XEC_IDT)) | X86_XEC_TI; + + pv_inject_hw_exception(TRAP_gp_fault, ec); + } + else + /* else pass the #PF back, with adjusted %cr2. */ + pv_inject_page_fault(regs->error_code, + curr->arch.pv_vcpu.ldt_base + offset); } } else @@ -1858,7 +1860,7 @@ void do_page_fault(struct cpu_user_regs *regs) return; } - propagate_page_fault(addr, regs->error_code); + pv_inject_page_fault(regs->error_code, addr); } /* @@ -2788,7 +2790,7 @@ int pv_emul_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, goto fail; \ if ( (_rc = copy_from_user(&_x, (type *)_ptr, sizeof(_x))) != 0 ) \ { \ - propagate_page_fault(_ptr + sizeof(_x) - _rc, 0); \ + pv_inject_page_fault(0, _ptr + sizeof(_x) - _rc); \ goto skip; \ } \ (eip) += sizeof(_x); _x; }) @@ -2953,8 +2955,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) if ( (rc = copy_to_user((void *)data_base + rd_ad(edi), &data, op_bytes)) != 0 ) { - propagate_page_fault(data_base + rd_ad(edi) + op_bytes - rc, - PFEC_write_access); + pv_inject_page_fault(PFEC_write_access, + data_base + rd_ad(edi) + op_bytes - rc); return EXCRET_fault_fixed; } wr_ad(edi, regs->edi + (int)((regs->eflags & X86_EFLAGS_DF) @@ -2971,8 +2973,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) if ( (rc = copy_from_user(&data, (void *)data_base + rd_ad(esi), op_bytes)) != 0 ) { - propagate_page_fault(data_base + rd_ad(esi) - + op_bytes - rc, 0); + pv_inject_page_fault(0, data_base + rd_ad(esi) + + op_bytes - rc); return EXCRET_fault_fixed; } guest_io_write(port, op_bytes, data, currd); @@ -3529,8 +3531,8 @@ static void emulate_gate_op(struct cpu_user_regs *regs) rc = __put_user(item, stkp); \ if ( rc ) \ { \ - propagate_page_fault((unsigned long)(stkp + 1) - rc, \ - PFEC_write_access); \ + pv_inject_page_fault(PFEC_write_access, \ + (unsigned long)(stkp + 1) - rc); \ return; \ } \ } while ( 0 ) @@ -3597,7 +3599,7 @@ static void emulate_gate_op(struct cpu_user_regs *regs) rc = __get_user(parm, ustkp); if ( rc ) { - propagate_page_fault((unsigned long)(ustkp + 1) - rc, 0); + pv_inject_page_fault(0, (unsigned long)(ustkp + 1) - rc); return; } push(parm); diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index f6a40eb..39cc658 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -632,6 +633,31 @@ static inline void free_vcpu_guest_context(struct vcpu_guest_context *vgc) struct vcpu_hvm_context; int arch_set_info_hvm_guest(struct vcpu *v, const struct vcpu_hvm_context *ctx); +void pv_inject_event(const struct x86_event *event); + +static inline void pv_inject_hw_exception(unsigned int vector, int errcode) +{ + const struct x86_event event = { + .vector = vector, + .type = X86_EVENTTYPE_HW_EXCEPTION, + .error_code = errcode, + }; + + pv_inject_event(&event); +} + +static inline void pv_inject_page_fault(int errcode, unsigned long cr2) +{ + const struct x86_event event = { + .vector = TRAP_page_fault, + .type = X86_EVENTTYPE_HW_EXCEPTION, + .error_code = errcode, + .cr2 = cr2, + }; + + pv_inject_event(&event); +} + #endif /* __ASM_DOMAIN_H__ */ /* diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 1b4d1c3..a15029c 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -539,7 +539,6 @@ int new_guest_cr3(unsigned long pfn); void make_cr3(struct vcpu *v, unsigned long mfn); void update_cr3(struct vcpu *v); int vcpu_destroy_pagetables(struct vcpu *); -struct trap_bounce *propagate_page_fault(unsigned long addr, u16 error_code); void *do_page_walk(struct vcpu *v, unsigned long addr); int __sync_local_execstate(void);