From patchwork Tue Apr 11 10:04:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Roger_Pau_Monn=C3=A9?= X-Patchwork-Id: 9674843 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 CAF8760382 for ; Tue, 11 Apr 2017 10:07:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3BB7284DC for ; Tue, 11 Apr 2017 10:07:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B82AA28500; Tue, 11 Apr 2017 10:07:52 +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 31236284EF for ; Tue, 11 Apr 2017 10:07:51 +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 1cxsg5-0006BX-1C; Tue, 11 Apr 2017 10:05:37 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cxsg4-0006B7-0c for xen-devel@lists.xenproject.org; Tue, 11 Apr 2017 10:05:36 +0000 Received: from [85.158.139.211] by server-2.bemta-5.messagelabs.com id A4/64-01909-E6AACE85; Tue, 11 Apr 2017 10:05:34 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrOIsWRWlGSWpSXmKPExsXitHSDvW7Wqjc RBscOall83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBmzZh9kLZhuWfHri0ED4ymdLkZODgkBf4me vd+ZQGw2AR2Ji3N3snUxcnCICKhI3N5r0MXIxcEs8JFR4t/vo6wgNcICgRJ7Z/WA2SwCqhLbm k+D2bwClhInZm1lhZipJ/F24gtGEJtTwEpi3ql3bCC2EFDNthPbmSDqBSVOznzCAmIzC2hKtG 7/zQ5hy0s0b53NDFGvKNE/7wHbBEa+WUhaZiFpmYWkZQEj8ypG9eLUorLUIl0jvaSizPSMktz EzBxdQwNTvdzU4uLE9NScxKRiveT83E2MwEBjAIIdjN//OB1ilORgUhLlDZj5OkKILyk/pTIj sTgjvqg0J7X4EKMGB4fA5rWrLzBKseTl56UqSfDOWfkmQkiwKDU9tSItMwcYCzClEhw8SiK8P iBp3uKCxNzizHSI1ClGRSlxXiaQhABIIqM0D64NFn+XGGWlhHkZgY4S4ilILcrNLEGVf8Uozs GoJMy7CWQKT2ZeCdz0V0CLmYAWn9n1EmRxSSJCSqqBMeKugPHGt4YyzHMNOVqsA9PcI1q+9dm EFRyreM+0uT3WNeo6f/Gn80rnHL6vt1VQrXcUa7+xb0Kw7b1ry+V6Zjrmis9wDZadFHNFZ0br z2Pxr3Z+aWRwt/k754n9Htf839cF0mfK/PHffM3h2vbVGQ/C9uaY69eXvvKfYik0S8r2346ak HxjJZbijERDLeai4kQAnivQ0roCAAA= X-Env-Sender: prvs=267e7865b=roger.pau@citrix.com X-Msg-Ref: server-15.tower-206.messagelabs.com!1491905127!78911912!1 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.4.12; banners=-,-,- X-VirusChecked: Checked Received: (qmail 33669 invoked from network); 11 Apr 2017 10:05:29 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-15.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 11 Apr 2017 10:05:29 -0000 X-IronPort-AV: E=Sophos;i="5.37,185,1488844800"; d="scan'208";a="427326475" From: Roger Pau Monne To: Date: Tue, 11 Apr 2017 11:04:00 +0100 Message-ID: <20170411100402.56246-5-roger.pau@citrix.com> X-Mailer: git-send-email 2.11.0 (Apple Git-81) In-Reply-To: <20170411100402.56246-1-roger.pau@citrix.com> References: <20170411100402.56246-1-roger.pau@citrix.com> MIME-Version: 1.0 Cc: Andrew Cooper , julien.grall@arm.com, Paul Durrant , Jan Beulich , boris.ostrovsky@oracle.com, Roger Pau Monne Subject: [Xen-devel] [PATCH for-next 4/6] x86/ecam: add handlers for the PVH Dom0 MMCFG areas 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 Introduce a set of handlers for the accesses to the ECAM areas. Those areas are setup based on the contents of the hardware MMCFG tables, and the list of handled ECAM areas is stored inside of the hvm_domain struct. The read/writes are forwarded to the generic vpci handlers once the address is decoded in order to obtain the device and register the guest is trying to access. Signed-off-by: Roger Pau MonnĂ© --- Cc: Jan Beulich Cc: Andrew Cooper Cc: Paul Durrant --- xen/arch/x86/hvm/dom0_build.c | 27 +++++++++++ xen/arch/x86/hvm/hvm.c | 1 + xen/arch/x86/hvm/io.c | 101 +++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/hvm/domain.h | 10 ++++ xen/include/asm-x86/hvm/io.h | 4 ++ 5 files changed, 143 insertions(+) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index 07bfa0be46..47600345ab 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -38,6 +38,8 @@ #include #include +#include "../x86_64/mmconfig.h" + /* * Have the TSS cover the ISA port range, which makes it * - 104 bytes base structure @@ -1022,6 +1024,24 @@ static int __init pvh_setup_acpi(struct domain *d, paddr_t start_info) return 0; } +int __init pvh_setup_ecam(struct domain *d) +{ + unsigned int i; + int rc; + + for ( i = 0; i < pci_mmcfg_config_num; i++ ) + { + size_t size = (pci_mmcfg_config[i].end_bus_number + 1) << 20; + + rc = register_vpci_ecam_handler(d, pci_mmcfg_config[i].address, size, + pci_mmcfg_config[i].pci_segment); + if ( rc ) + return rc; + } + + return 0; +} + int __init dom0_construct_pvh(struct domain *d, const module_t *image, unsigned long image_headroom, module_t *initrd, @@ -1064,6 +1084,13 @@ int __init dom0_construct_pvh(struct domain *d, const module_t *image, return rc; } + rc = pvh_setup_ecam(d); + if ( rc ) + { + printk("Failed to setup Dom0 PCI ECAM areas: %d\n", rc); + return rc; + } + panic("Building a PVHv2 Dom0 is not yet supported."); return 0; } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index c2a9b76a81..d8f3dcdc7c 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -613,6 +613,7 @@ int hvm_domain_initialise(struct domain *d) spin_lock_init(&d->arch.hvm_domain.write_map.lock); INIT_LIST_HEAD(&d->arch.hvm_domain.write_map.list); INIT_LIST_HEAD(&d->arch.hvm_domain.g2m_ioport_list); + INIT_LIST_HEAD(&d->arch.hvm_domain.ecam_regions); hvm_init_cacheattr_region_list(d); diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 11d561e861..b78d668fc1 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -375,6 +375,107 @@ void register_vpci_portio_handler(struct domain *d) handler->ops = &vpci_portio_ops; } +/* Handlers to trap PCI ECAM config accesses. */ +static struct hvm_ecam *vpci_ecam_find(struct domain *d, unsigned long addr) +{ + struct hvm_ecam *ecam = NULL; + + list_for_each_entry ( ecam, &d->arch.hvm_domain.ecam_regions, next ) + if ( addr >= ecam->addr && addr < ecam->addr + ecam->size ) + return ecam; + + return NULL; +} + +static void vpci_ecam_decode_addr(unsigned long addr, unsigned int *bus, + unsigned int *devfn, unsigned int *reg) +{ + *bus = (addr >> 20) & 0xff; + *devfn = (addr >> 12) & 0xff; + *reg = addr & 0xfff; +} + +static int vpci_ecam_accept(struct vcpu *v, unsigned long addr) +{ + + return !!vpci_ecam_find(v->domain, addr); +} + +static int vpci_ecam_read(struct vcpu *v, unsigned long addr, + unsigned int len, unsigned long *data) +{ + struct domain *d = v->domain; + struct hvm_ecam *ecam = vpci_ecam_find(d, addr); + unsigned int bus, devfn, reg; + uint32_t data32; + int rc; + + ASSERT(ecam); + + vpci_ecam_decode_addr(addr - ecam->addr, &bus, &devfn, ®); + + if ( vpci_access_check(reg, len) || reg >= 0xfff ) + return X86EMUL_UNHANDLEABLE; + + rc = xen_vpci_read(ecam->segment, bus, devfn, reg, len, &data32); + if ( !rc ) + *data = data32; + + return rc ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; +} + +static int vpci_ecam_write(struct vcpu *v, unsigned long addr, + unsigned int len, unsigned long data) +{ + struct domain *d = v->domain; + struct hvm_ecam *ecam = vpci_ecam_find(d, addr); + unsigned int bus, devfn, reg; + int rc; + + ASSERT(ecam); + + vpci_ecam_decode_addr(addr - ecam->addr, &bus, &devfn, ®); + + if ( vpci_access_check(reg, len) || reg >= 0xfff ) + return X86EMUL_UNHANDLEABLE; + + rc = xen_vpci_write(ecam->segment, bus, devfn, reg, len, data); + + return rc ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; +} + +static const struct hvm_mmio_ops vpci_ecam_ops = { + .check = vpci_ecam_accept, + .read = vpci_ecam_read, + .write = vpci_ecam_write, +}; + +int register_vpci_ecam_handler(struct domain *d, paddr_t addr, size_t size, + unsigned int seg) +{ + struct hvm_ecam *ecam; + + ASSERT(is_hardware_domain(d)); + ASSERT(atomic_read(&d->pause_count)); + + if ( vpci_ecam_find(d, addr) ) + return -EEXIST; + + ecam = xzalloc(struct hvm_ecam); + if ( !ecam ) + return -ENOMEM; + + if ( list_empty(&d->arch.hvm_domain.ecam_regions) ) + register_mmio_handler(d, &vpci_ecam_ops); + + ecam->addr = addr; + ecam->segment = seg; + ecam->size = size; + list_add(&ecam->next, &d->arch.hvm_domain.ecam_regions); + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index d2899c9bb2..9b5425f0a4 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -100,6 +100,13 @@ struct hvm_pi_ops { void (*do_resume)(struct vcpu *v); }; +struct hvm_ecam { + paddr_t addr; + size_t size; + unsigned int segment; + struct list_head next; +}; + struct hvm_domain { /* Guest page range used for non-default ioreq servers */ struct { @@ -184,6 +191,9 @@ struct hvm_domain { /* List of guest to machine IO ports mapping. */ struct list_head g2m_ioport_list; + /* List of ECAM regions. */ + struct list_head ecam_regions; + /* List of permanently write-mapped pages. */ struct { spinlock_t lock; diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h index 2dbf92f13e..0434aca706 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -158,6 +158,10 @@ void register_g2m_portio_handler(struct domain *d); /* HVM port IO handler for PCI accesses. */ void register_vpci_portio_handler(struct domain *d); +/* HVM MMIO handler for PCI ECAM accesses. */ +int register_vpci_ecam_handler(struct domain *d, paddr_t addr, size_t size, + unsigned int seg); + #endif /* __ASM_X86_HVM_IO_H__ */