From patchwork Thu Dec 17 20:22:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Ostrovsky X-Patchwork-Id: 7877171 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B2D579F349 for ; Thu, 17 Dec 2015 20:24:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7E96620392 for ; Thu, 17 Dec 2015 20:24:54 +0000 (UTC) Received: from lists.xen.org (lists.xenproject.org [50.57.142.19]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 10D1C20398 for ; Thu, 17 Dec 2015 20:24:53 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1a9f3s-00057W-0N; Thu, 17 Dec 2015 20:22:04 +0000 Received: from mail6.bemta14.messagelabs.com ([193.109.254.103]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1a9f3q-00055N-K7 for xen-devel@lists.xen.org; Thu, 17 Dec 2015 20:22:02 +0000 Received: from [193.109.254.147] by server-14.bemta-14.messagelabs.com id 1E/41-07165-96913765; Thu, 17 Dec 2015 20:22:01 +0000 X-Env-Sender: boris.ostrovsky@oracle.com X-Msg-Ref: server-12.tower-27.messagelabs.com!1450383719!11756281!1 X-Originating-IP: [156.151.31.81] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTU2LjE1MS4zMS44MSA9PiAyODgzMzk=\n X-StarScan-Received: X-StarScan-Version: 7.35.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 52226 invoked from network); 17 Dec 2015 20:22:00 -0000 Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by server-12.tower-27.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 17 Dec 2015 20:22:00 -0000 Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id tBHKLvNZ015261 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 17 Dec 2015 20:21:57 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0021.oracle.com (8.13.8/8.13.8) with ESMTP id tBHKLvXU021473 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Thu, 17 Dec 2015 20:21:57 GMT Received: from abhmp0005.oracle.com (abhmp0005.oracle.com [141.146.116.11]) by userv0121.oracle.com (8.13.8/8.13.8) with ESMTP id tBHKLvGd029767; Thu, 17 Dec 2015 20:21:57 GMT Received: from ovs104.us.oracle.com (/10.149.76.204) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 17 Dec 2015 12:21:56 -0800 From: Boris Ostrovsky To: jbeulich@suse.com, andrew.cooper3@citrix.com, keir@xen.org Date: Thu, 17 Dec 2015 15:22:51 -0500 Message-Id: <1450383771-3636-3-git-send-email-boris.ostrovsky@oracle.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1450383771-3636-1-git-send-email-boris.ostrovsky@oracle.com> References: <1450383771-3636-1-git-send-email-boris.ostrovsky@oracle.com> X-Source-IP: userv0021.oracle.com [156.151.31.71] Cc: Boris Ostrovsky , xen-devel@lists.xen.org Subject: [Xen-devel] [PATCH v2 2/2] x86/PCI: Intercept Dom0 MMCFG from dom0s in HVM containers X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Commit 9256f66c1606 ("x86/PCI: intercept all PV Dom0 MMCFG writes") added intercepts for writes to RO MMCFG space from PV dom0. Similar functionality is needed by dom0s in HVM containers (such as PVH and, in the future, HVMlite). Signed-off-by: Boris Ostrovsky --- xen/arch/x86/hvm/emulate.c | 34 ++++++++++++++++++++ xen/arch/x86/hvm/hvm.c | 15 +++++++++ xen/arch/x86/mm.c | 53 +++++++++++--------------------- xen/arch/x86/x86_emulate/x86_emulate.c | 10 ++++++ xen/arch/x86/x86_emulate/x86_emulate.h | 13 ++++++++ xen/include/asm-x86/hvm/emulate.h | 4 ++ xen/include/asm-x86/mm.h | 17 ++++++++++ 7 files changed, 111 insertions(+), 35 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index e1017b5..6f6ec61 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1778,6 +1778,40 @@ int hvm_emulate_one_no_write( return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops_no_write); } +int hvm_emulate_one_mmcfg(unsigned seg, unsigned bdf, unsigned long gla) +{ + static const struct x86_emulate_ops hvm_emulate_ops_mmcfg = { + .read = unhandleable_rwx, + .insn_fetch = hvmemul_insn_fetch, + .write = mmcfg_intercept_write, + }; + struct mmio_ro_emulate_ctxt mmio_ro_ctxt = { + .cr2 = gla, + .seg = seg, + .bdf = bdf + }; + struct hvm_emulate_ctxt ctxt; + int rc; + + hvm_emulate_prepare(&ctxt, guest_cpu_user_regs()); + ctxt.ctxt.data = &mmio_ro_ctxt; + rc = _hvm_emulate_one(&ctxt, &hvm_emulate_ops_mmcfg); + switch ( rc ) + { + case X86EMUL_UNHANDLEABLE: + hvm_dump_emulation_state(XENLOG_G_WARNING "MMCFG", &ctxt); + break; + case X86EMUL_EXCEPTION: + if ( ctxt.exn_pending ) + hvm_inject_trap(&ctxt.trap); + /* fallthrough */ + default: + hvm_emulate_writeback(&ctxt); + } + + return rc; +} + void hvm_mem_access_emulate_one(enum emul_kind kind, unsigned int trapnr, unsigned int errcode) { diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 08cef1f..7cc057b 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3115,6 +3115,21 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, goto out_put_gfn; } + if ( (p2mt == p2m_mmio_direct) && is_hardware_domain(currd) && + npfec.write_access && npfec.present ) + { + unsigned int seg, bdf; + const unsigned long *ro_map; + + if ( pci_mmcfg_decode(mfn_x(mfn), &seg, &bdf) && + ((ro_map = pci_get_ro_map(seg)) == NULL || !test_bit(bdf, ro_map)) && + (hvm_emulate_one_mmcfg(seg, bdf, gla) == X86EMUL_OKAY) ) + { + rc = 1; + goto out_put_gfn; + } + } + /* If we fell through, the vcpu will retry now that access restrictions have * been removed. It may fault again if the p2m entry type still requires so. * Otherwise, this is an error condition. */ diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 92df36f..a7767f8 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -5243,31 +5243,14 @@ int ptwr_do_page_fault(struct vcpu *v, unsigned long addr, * fault handling for read-only MMIO pages */ -struct mmio_ro_emulate_ctxt { - struct x86_emulate_ctxt ctxt; - unsigned long cr2; - unsigned int seg, bdf; -}; - -static int mmio_ro_emulated_read( - enum x86_segment seg, - unsigned long offset, - void *p_data, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - return X86EMUL_UNHANDLEABLE; -} - -static int mmio_ro_emulated_write( +int mmio_ro_emulated_write( enum x86_segment seg, unsigned long offset, void *p_data, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - struct mmio_ro_emulate_ctxt *mmio_ro_ctxt = - container_of(ctxt, struct mmio_ro_emulate_ctxt, ctxt); + struct mmio_ro_emulate_ctxt *mmio_ro_ctxt = ctxt->data; /* Only allow naturally-aligned stores at the original %cr2 address. */ if ( ((bytes | offset) & (bytes - 1)) || offset != mmio_ro_ctxt->cr2 ) @@ -5281,20 +5264,19 @@ static int mmio_ro_emulated_write( } static const struct x86_emulate_ops mmio_ro_emulate_ops = { - .read = mmio_ro_emulated_read, + .read = unhandleable_rwx, .insn_fetch = ptwr_emulated_read, .write = mmio_ro_emulated_write, }; -static int mmio_intercept_write( +int mmcfg_intercept_write( enum x86_segment seg, unsigned long offset, void *p_data, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - struct mmio_ro_emulate_ctxt *mmio_ctxt = - container_of(ctxt, struct mmio_ro_emulate_ctxt, ctxt); + struct mmio_ro_emulate_ctxt *mmio_ctxt = ctxt->data; /* * Only allow naturally-aligned stores no wider than 4 bytes to the @@ -5303,7 +5285,7 @@ static int mmio_intercept_write( if ( ((bytes | offset) & (bytes - 1)) || bytes > 4 || offset != mmio_ctxt->cr2 ) { - MEM_LOG("mmio_intercept: bad write (cr2=%lx, addr=%lx, bytes=%u)", + MEM_LOG("mmcfg_intercept: bad write (cr2=%lx, addr=%lx, bytes=%u)", mmio_ctxt->cr2, offset, bytes); return X86EMUL_UNHANDLEABLE; } @@ -5318,10 +5300,10 @@ static int mmio_intercept_write( return X86EMUL_OKAY; } -static const struct x86_emulate_ops mmio_intercept_ops = { - .read = mmio_ro_emulated_read, +static const struct x86_emulate_ops mmcfg_intercept_ops = { + .read = unhandleable_rwx, .insn_fetch = ptwr_emulated_read, - .write = mmio_intercept_write, + .write = mmcfg_intercept_write, }; /* Check if guest is trying to modify a r/o MMIO page. */ @@ -5331,12 +5313,13 @@ int mmio_ro_do_page_fault(struct vcpu *v, unsigned long addr, l1_pgentry_t pte; unsigned long mfn; unsigned int addr_size = is_pv_32bit_vcpu(v) ? 32 : BITS_PER_LONG; - struct mmio_ro_emulate_ctxt mmio_ro_ctxt = { - .ctxt.regs = regs, - .ctxt.addr_size = addr_size, - .ctxt.sp_size = addr_size, - .ctxt.swint_emulate = x86_swint_emulate_none, - .cr2 = addr + struct mmio_ro_emulate_ctxt mmio_ro_ctxt = { .cr2 = addr }; + struct x86_emulate_ctxt ctxt = { + .regs = regs, + .addr_size = addr_size, + .sp_size = addr_size, + .swint_emulate = x86_swint_emulate_none, + .data = &mmio_ro_ctxt }; const unsigned long *ro_map; int rc; @@ -5366,9 +5349,9 @@ int mmio_ro_do_page_fault(struct vcpu *v, unsigned long addr, if ( pci_mmcfg_decode(mfn, &mmio_ro_ctxt.seg, &mmio_ro_ctxt.bdf) && ((ro_map = pci_get_ro_map(mmio_ro_ctxt.seg)) == NULL || !test_bit(mmio_ro_ctxt.bdf, ro_map)) ) - rc = x86_emulate(&mmio_ro_ctxt.ctxt, &mmio_intercept_ops); + rc = x86_emulate(&ctxt, &mmcfg_intercept_ops); else - rc = x86_emulate(&mmio_ro_ctxt.ctxt, &mmio_ro_emulate_ops); + rc = x86_emulate(&ctxt, &mmio_ro_emulate_ops); return rc != X86EMUL_UNHANDLEABLE ? EXCRET_fault_fixed : 0; } diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index f1454ce..dde37ba 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1444,6 +1444,16 @@ static int inject_swint(enum x86_swint_type type, return ops->inject_hw_exception(fault_type, error_code, ctxt); } +int unhandleable_rwx( + enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_UNHANDLEABLE; +} + int x86_emulate( struct x86_emulate_ctxt *ctxt, diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h index cfac09b..d1754b9 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -430,6 +430,9 @@ struct x86_emulate_ctxt } flags; uint8_t byte; } retire; + + /* Caller data that can be used by x86_emulate_ops' routines. */ + void *data; }; struct x86_emulate_stub { @@ -463,4 +466,14 @@ void * decode_register( uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs); +/* Unhadleable read, write or instruction fetch */ +int +unhandleable_rwx( + enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt); + + #endif /* __X86_EMULATE_H__ */ diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h index 49134b5..2f39ff8 100644 --- a/xen/include/asm-x86/hvm/emulate.h +++ b/xen/include/asm-x86/hvm/emulate.h @@ -57,6 +57,10 @@ void hvm_emulate_writeback( struct segment_register *hvmemul_get_seg_reg( enum x86_segment seg, struct hvm_emulate_ctxt *hvmemul_ctxt); +int hvm_emulate_one_mmcfg( + unsigned int seg, + unsigned int bdf, + unsigned long gla); int hvmemul_do_pio_buffer(uint16_t port, unsigned int size, diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 67b34c6..773ba5d 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -7,6 +7,7 @@ #include #include #include +#include /* * Per-page-frame information. @@ -488,6 +489,22 @@ void memguard_unguard_range(void *p, unsigned long l); void memguard_guard_stack(void *p); void memguard_unguard_stack(void *p); +struct mmio_ro_emulate_ctxt { + unsigned long cr2; + unsigned int seg, bdf; +}; + +extern int mmio_ro_emulate_write(enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt); +extern int mmcfg_intercept_write(enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt); + int ptwr_do_page_fault(struct vcpu *, unsigned long, struct cpu_user_regs *); int mmio_ro_do_page_fault(struct vcpu *, unsigned long,