From patchwork Thu Apr 27 14:35:39 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: 9702967 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 84A77601D3 for ; Thu, 27 Apr 2017 14:40:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A7F928636 for ; Thu, 27 Apr 2017 14:40:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5C27328652; Thu, 27 Apr 2017 14:40:56 +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 949AA28636 for ; Thu, 27 Apr 2017 14:40:55 +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 1d3kYn-0001nx-3i; Thu, 27 Apr 2017 14:38:21 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1d3kYm-0001nr-6t for xen-devel@lists.xenproject.org; Thu, 27 Apr 2017 14:38:20 +0000 Received: from [85.158.137.68] by server-12.bemta-3.messagelabs.com id 0E/1B-27980-B5202095; Thu, 27 Apr 2017 14:38:19 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrKIsWRWlGSWpSXmKPExsXitHSDvW4UE1O kwdLrGhbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8a5H/PYCprcKr7MyWtgfGrSxcjBISHgL3H4 TVEXIycHm4COxMW5O9lAwiICKhK39xqAhJkFPjJKTHqRB2ILC3hLLFh+kQnEZhFQlZh/YCeYz StgKbHpwkt2EFtCQE/i7cQXjCA2p4CVxLvXl8FsIaCayXMfQtULSpyc+YQFYr6mROv23+wQtr xE89bZzBD1ihL98x6wTWDkm4WkZRaSlllIWhYwMq9iVC9OLSpLLdI11ksqykzPKMlNzMzRNTQ w1stNLS5OTE/NSUwq1kvOz93ECAwyBiDYwdj8xekQoyQHk5Ior+xBxkghvqT8lMqMxOKM+KLS nNTiQ4waHBwCm9euvsAoxZKXn5eqJMFbxMgUKSRYlJqeWpGWmQOMA5hSCQ4eJRFeaZA0b3FBY m5xZjpE6hSjopQ4rx1IQgAkkVGaB9cGi71LjLJSwryMQEcJ8RSkFuVmlqDKv2IU52BUEubdyA A0hSczrwRu+iugxUxAi1lcGEAWlyQipKQaGLs8lav7mhRvb/eZuoJlaiaTwvWlhidunmc6/yz dcL11Keu+jT0PI1MC0sWU3s+ZoFeRsjK57/Qvg+R/LCcWdZm8/b7DzvT6+uBn5cFXXi67Gr6F 1er8M+vErWa1QhU79qyZpW7lvWyJLfsUHX5d5qVp2Z+KuXUvmEpdu/Q+JKlX2Nfe8/IeeSWW4 oxEQy3mouJEAA9iQTW4AgAA X-Env-Sender: prvs=283fe5697=roger.pau@citrix.com X-Msg-Ref: server-7.tower-31.messagelabs.com!1493303896!90164940!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 22631 invoked from network); 27 Apr 2017 14:38:18 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-7.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 27 Apr 2017 14:38:18 -0000 X-IronPort-AV: E=Sophos;i="5.37,384,1488844800"; d="scan'208";a="430027795" From: Roger Pau Monne To: Date: Thu, 27 Apr 2017 15:35:39 +0100 Message-ID: <20170427143546.14662-3-roger.pau@citrix.com> X-Mailer: git-send-email 2.11.0 (Apple Git-81) In-Reply-To: <20170427143546.14662-1-roger.pau@citrix.com> References: <20170427143546.14662-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 v3 2/9] 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 --- Changes since v1: - Added locking. --- xen/arch/x86/hvm/dom0_build.c | 27 ++++++++ xen/arch/x86/hvm/hvm.c | 10 +++ xen/arch/x86/hvm/io.c | 139 +++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/hvm/domain.h | 11 ++++ xen/include/asm-x86/hvm/io.h | 5 ++ 5 files changed, 192 insertions(+) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index 020c355faf..b8999a053a 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 @@ -1048,6 +1050,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++ ) + { + rc = register_vpci_ecam_handler(d, pci_mmcfg_config[i].address, + pci_mmcfg_config[i].start_bus_number, + pci_mmcfg_config[i].end_bus_number, + 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, @@ -1090,6 +1110,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 7f3322ede6..ef3ad2a615 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); @@ -725,6 +726,7 @@ void hvm_domain_destroy(struct domain *d) { struct list_head *ioport_list, *tmp; struct g2m_ioport *ioport; + struct hvm_ecam *ecam, *etmp; xfree(d->arch.hvm_domain.io_handler); d->arch.hvm_domain.io_handler = NULL; @@ -752,6 +754,14 @@ void hvm_domain_destroy(struct domain *d) list_del(&ioport->list); xfree(ioport); } + + list_for_each_entry_safe ( ecam, etmp, &d->arch.hvm_domain.ecam_regions, + next ) + { + list_del(&ecam->next); + xfree(ecam); + } + } static int hvm_save_tsc_adjust(struct domain *d, hvm_domain_context_t *h) diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 80f842b092..1f138989ff 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -403,6 +403,145 @@ 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; + + ASSERT(vpci_locked(d)); + 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(struct hvm_ecam *ecam, unsigned long addr, + unsigned int *bus, unsigned int *devfn, + unsigned int *reg) +{ + addr -= ecam->addr; + *bus = ((addr >> 20) & 0xff) + ecam->bus; + *devfn = (addr >> 12) & 0xff; + *reg = addr & 0xfff; +} + +static int vpci_ecam_accept(struct vcpu *v, unsigned long addr) +{ + struct domain *d = v->domain; + int found; + + vpci_lock(d); + found = !!vpci_ecam_find(v->domain, addr); + vpci_unlock(d); + + return found; +} + +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; + unsigned int bus, devfn, reg; + uint32_t data32; + int rc; + + vpci_lock(d); + ecam = vpci_ecam_find(d, addr); + if ( !ecam ) + { + vpci_unlock(d); + return X86EMUL_UNHANDLEABLE; + } + + vpci_ecam_decode_addr(ecam, addr, &bus, &devfn, ®); + + if ( vpci_access_check(reg, len) || reg >= 0xfff ) + { + vpci_unlock(d); + return X86EMUL_UNHANDLEABLE; + } + + rc = xen_vpci_read(ecam->segment, bus, devfn, reg, len, &data32); + if ( !rc ) + *data = data32; + vpci_unlock(d); + + 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; + unsigned int bus, devfn, reg; + int rc; + + vpci_lock(d); + ecam = vpci_ecam_find(d, addr); + if ( !ecam ) + { + vpci_unlock(d); + return X86EMUL_UNHANDLEABLE; + } + + vpci_ecam_decode_addr(ecam, addr, &bus, &devfn, ®); + + if ( vpci_access_check(reg, len) || reg >= 0xfff ) + { + vpci_unlock(d); + return X86EMUL_UNHANDLEABLE; + } + + rc = xen_vpci_write(ecam->segment, bus, devfn, reg, len, data); + vpci_unlock(d); + + 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, + unsigned int start_bus, unsigned int end_bus, + unsigned int seg) +{ + struct hvm_ecam *ecam; + + ASSERT(is_hardware_domain(d)); + + vpci_lock(d); + if ( vpci_ecam_find(d, addr) ) + { + vpci_unlock(d); + return -EEXIST; + } + + ecam = xzalloc(struct hvm_ecam); + if ( !ecam ) + { + vpci_unlock(d); + return -ENOMEM; + } + + if ( list_empty(&d->arch.hvm_domain.ecam_regions) ) + register_mmio_handler(d, &vpci_ecam_ops); + + ecam->addr = addr + (start_bus << 20); + ecam->bus = start_bus; + ecam->segment = seg; + ecam->size = (end_bus - start_bus + 1) << 20; + list_add(&ecam->next, &d->arch.hvm_domain.ecam_regions); + vpci_unlock(d); + + 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 cbf4170789..b69c33df3c 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -100,6 +100,14 @@ struct hvm_pi_ops { void (*do_resume)(struct vcpu *v); }; +struct hvm_ecam { + paddr_t addr; + size_t size; + unsigned int bus; + unsigned int segment; + struct list_head next; +}; + struct hvm_domain { /* Guest page range used for non-default ioreq servers */ struct { @@ -187,6 +195,9 @@ struct hvm_domain { /* Lock for the PCI emulation layer (vPCI). */ spinlock_t vpci_lock; + /* List of ECAM (MMCFG) regions trapped by Xen. */ + 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 9ed1bf2e06..f9b9829eaf 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -163,6 +163,11 @@ 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, + unsigned int start_bus, unsigned int end_bus, + unsigned int seg); + #endif /* __ASM_X86_HVM_IO_H__ */