From patchwork Tue Sep 27 15:57:21 2016 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: 9352195 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 2473060757 for ; Tue, 27 Sep 2016 16:00:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 152382927A for ; Tue, 27 Sep 2016 16:00:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 097A929290; Tue, 27 Sep 2016 16:00: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 56B662927A for ; Tue, 27 Sep 2016 16:00:52 +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 1boumM-0008Rs-Ej; Tue, 27 Sep 2016 15:58:46 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1boumK-0008NS-Rs for xen-devel@lists.xenproject.org; Tue, 27 Sep 2016 15:58:44 +0000 Received: from [85.158.137.68] by server-7.bemta-3.messagelabs.com id 6E/0E-03271-4379AE75; Tue, 27 Sep 2016 15:58:44 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBIsWRWlGSWpSXmKPExsXitHSDva7x9Ff hBlfnqFt83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBlTpzayFayxr3gy5QpbA2OXXhcjJ4eEgL9E x+47zCA2m4COxMW5O9m6GDk4RARUJG7vNehi5OJgFrjBKPFp7V1GkBphAVOJ//ues4LYLAKqE v1bb4H18gq4Siycep8ZYqauxMNzv8FqOIHivW0LmEBsIQEXibszP7JC1AtKnJz5hAXEZhbQlG jd/psdwpaXaN46mxmiXlGif94DNoiZ3BK3T09lnsDIPwtJ+ywk7bOQtC9gZF7FqF6cWlSWWqR rqJdUlJmeUZKbmJmja2hgrJebWlycmJ6ak5hUrJecn7uJERiCDECwg3H5R6dDjJIcTEqivBrt r8KF+JLyUyozEosz4otKc1KLDzHKcHAoSfB6TAXKCRalpqdWpGXmAKMBJi3BwaMkwsszDSjNW 1yQmFucmQ6ROsWoKCXO2wDSJwCSyCjNg2uDReAlRlkpYV5GoEOEeApSi3IzS1DlXzGKczAqCf MqgIznycwrgZv+CmgxE9DipSdegCwuSURISTUwxs/TPqT3bN5Gxn0Or2R+rHhgs/X7wjZOT8N X8nU/T+zr23387tyJuy+nrb6wiDNdJfz5R/3mnQxxDJFyfbWMblUl79LDSrJzJS5+5Vk6WUa4 c+mKOB9z3ka3yuOJr6Ov10w/dkzw8Ly/EUec7xX1txjO1ihYor/P+PavPX/Sny4Ke2zqKxszQ YmlOCPRUIu5qDgRAAYTute7AgAA X-Env-Sender: prvs=071b8e69e=roger.pau@citrix.com X-Msg-Ref: server-12.tower-31.messagelabs.com!1474991908!46201907!6 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: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 19331 invoked from network); 27 Sep 2016 15:58:43 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-12.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 27 Sep 2016 15:58:43 -0000 X-IronPort-AV: E=Sophos;i="5.30,405,1470700800"; d="scan'208";a="389169861" From: Roger Pau Monne To: Date: Tue, 27 Sep 2016 17:57:21 +0200 Message-ID: <1474991845-27962-27-git-send-email-roger.pau@citrix.com> X-Mailer: git-send-email 2.7.4 (Apple Git-66) In-Reply-To: <1474991845-27962-1-git-send-email-roger.pau@citrix.com> References: <1474991845-27962-1-git-send-email-roger.pau@citrix.com> MIME-Version: 1.0 X-DLP: MIA2 Cc: Andrew Cooper , Paul Durrant , Jan Beulich , boris.ostrovsky@oracle.com, Roger Pau Monne Subject: [Xen-devel] [PATCH v2 26/30] xen/x86: add PCIe emulation 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 Add a new MMIO handler that traps accesses to PCIe regions, as discovered by Xen from the MCFG ACPI table. The handler used is the same as the one used for accesses to the IO PCI configuration space. Signed-off-by: Roger Pau MonnĂ© --- Cc: Paul Durrant Cc: Jan Beulich Cc: Andrew Cooper --- xen/arch/x86/hvm/io.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 779babb..088e3ec 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -46,6 +46,8 @@ #include #include +#include "../x86_64/mmconfig.h" + /* Set permissive mode for HVM Dom0 PCI pass-through by default */ static bool_t opt_dom0permissive = 1; boolean_param("dom0permissive", opt_dom0permissive); @@ -363,7 +365,7 @@ static int hvm_pt_pci_config_access_check(struct hvm_pt_device *d, } static int hvm_pt_pci_read_config(struct hvm_pt_device *d, uint32_t addr, - uint32_t *data, int len) + uint32_t *data, int len, bool pcie) { uint32_t val = 0; struct hvm_pt_reg_group *reg_grp_entry = NULL; @@ -377,7 +379,7 @@ static int hvm_pt_pci_read_config(struct hvm_pt_device *d, uint32_t addr, unsigned int func = PCI_FUNC(d->pdev->devfn); /* Sanity checks. */ - if ( hvm_pt_pci_config_access_check(d, addr, len) ) + if ( !pcie && hvm_pt_pci_config_access_check(d, addr, len) ) return X86EMUL_UNHANDLEABLE; /* Find register group entry. */ @@ -468,7 +470,7 @@ static int hvm_pt_pci_read_config(struct hvm_pt_device *d, uint32_t addr, } static int hvm_pt_pci_write_config(struct hvm_pt_device *d, uint32_t addr, - uint32_t val, int len) + uint32_t val, int len, bool pcie) { int index = 0; struct hvm_pt_reg_group *reg_grp_entry = NULL; @@ -485,7 +487,7 @@ static int hvm_pt_pci_write_config(struct hvm_pt_device *d, uint32_t addr, unsigned int func = PCI_FUNC(d->pdev->devfn); /* Sanity checks. */ - if ( hvm_pt_pci_config_access_check(d, addr, len) ) + if ( !pcie && hvm_pt_pci_config_access_check(d, addr, len) ) return X86EMUL_UNHANDLEABLE; /* Find register group entry. */ @@ -677,7 +679,7 @@ static int hw_dpci_portio_read(const struct hvm_io_handler *handler, if ( dev != NULL ) { reg = (currd->arch.pci_cf8 & 0xfc) | (addr & 0x3); - rc = hvm_pt_pci_read_config(dev, reg, &data32, size); + rc = hvm_pt_pci_read_config(dev, reg, &data32, size, false); if ( rc == X86EMUL_OKAY ) { read_unlock(&currd->arch.hvm_domain.pt_lock); @@ -722,7 +724,7 @@ static int hw_dpci_portio_write(const struct hvm_io_handler *handler, if ( dev != NULL ) { reg = (currd->arch.pci_cf8 & 0xfc) | (addr & 0x3); - rc = hvm_pt_pci_write_config(dev, reg, data32, size); + rc = hvm_pt_pci_write_config(dev, reg, data32, size, false); if ( rc == X86EMUL_OKAY ) { read_unlock(&currd->arch.hvm_domain.pt_lock); @@ -1002,6 +1004,166 @@ static const struct hvm_io_ops hw_dpci_portio_ops = { .write = hw_dpci_portio_write }; +static struct acpi_mcfg_allocation *pcie_find_mmcfg(unsigned long addr) +{ + int i; + + for ( i = 0; i < pci_mmcfg_config_num; i++ ) + { + unsigned long start, end; + + start = pci_mmcfg_config[i].address; + end = pci_mmcfg_config[i].address + + ((pci_mmcfg_config[i].end_bus_number + 1) << 20); + if ( addr >= start && addr < end ) + return &pci_mmcfg_config[i]; + } + + return NULL; +} + +static struct hvm_pt_device *hw_pcie_get_device(unsigned int seg, + unsigned int bus, + unsigned int slot, + unsigned int func) +{ + struct hvm_pt_device *dev; + struct domain *d = current->domain; + + list_for_each_entry( dev, &d->arch.hvm_domain.pt_devices, entries ) + { + if ( dev->pdev->seg != seg || dev->pdev->bus != bus || + dev->pdev->devfn != PCI_DEVFN(slot, func) ) + continue; + + return dev; + } + + return NULL; +} + +static void pcie_decode_addr(unsigned long addr, unsigned int *bus, + unsigned int *slot, unsigned int *func, + unsigned int *reg) +{ + + *bus = (addr >> 20) & 0xff; + *slot = (addr >> 15) & 0x1f; + *func = (addr >> 12) & 0x7; + *reg = addr & 0xfff; +} + +static int pcie_range(struct vcpu *v, unsigned long addr) +{ + + return pcie_find_mmcfg(addr) != NULL ? 1 : 0; +} + +static int pcie_read(struct vcpu *v, unsigned long addr, + unsigned int len, unsigned long *pval) +{ + struct acpi_mcfg_allocation *mmcfg = pcie_find_mmcfg(addr); + struct domain *d = v->domain; + unsigned int seg, bus, slot, func, reg; + struct hvm_pt_device *dev; + uint32_t val; + int rc; + + ASSERT(mmcfg != NULL); + + if ( len > 4 || len == 3 ) + return X86EMUL_UNHANDLEABLE; + + addr -= mmcfg->address; + seg = mmcfg->pci_segment; + pcie_decode_addr(addr, &bus, &slot, &func, ®); + + read_lock(&d->arch.hvm_domain.pt_lock); + dev = hw_pcie_get_device(seg, bus, slot, func); + if ( dev != NULL ) + { + rc = hvm_pt_pci_read_config(dev, reg, &val, len, true); + if ( rc == X86EMUL_OKAY ) + { + read_unlock(&d->arch.hvm_domain.pt_lock); + goto out; + } + } + read_unlock(&d->arch.hvm_domain.pt_lock); + + /* Pass-through */ + switch ( len ) + { + case 1: + val = pci_conf_read8(seg, bus, slot, func, reg); + break; + case 2: + val = pci_conf_read16(seg, bus, slot, func, reg); + break; + case 4: + val = pci_conf_read32(seg, bus, slot, func, reg); + break; + } + + out: + *pval = val; + return X86EMUL_OKAY; +} + +static int pcie_write(struct vcpu *v, unsigned long addr, + unsigned int len, unsigned long val) +{ + struct acpi_mcfg_allocation *mmcfg = pcie_find_mmcfg(addr); + struct domain *d = v->domain; + unsigned int seg, bus, slot, func, reg; + struct hvm_pt_device *dev; + int rc; + + ASSERT(mmcfg != NULL); + + if ( len > 4 || len == 3 ) + return X86EMUL_UNHANDLEABLE; + + addr -= mmcfg->address; + seg = mmcfg->pci_segment; + pcie_decode_addr(addr, &bus, &slot, &func, ®); + + read_lock(&d->arch.hvm_domain.pt_lock); + dev = hw_pcie_get_device(seg, bus, slot, func); + if ( dev != NULL ) + { + rc = hvm_pt_pci_write_config(dev, reg, val, len, true); + if ( rc == X86EMUL_OKAY ) + { + read_unlock(&d->arch.hvm_domain.pt_lock); + return rc; + } + } + read_unlock(&d->arch.hvm_domain.pt_lock); + + /* Pass-through */ + switch ( len ) + { + case 1: + pci_conf_write8(seg, bus, slot, func, reg, val); + break; + case 2: + pci_conf_write16(seg, bus, slot, func, reg, val); + break; + case 4: + pci_conf_write32(seg, bus, slot, func, reg, val); + break; + } + + return X86EMUL_OKAY; +} + +static const struct hvm_mmio_ops pcie_mmio_ops = { + .check = pcie_range, + .read = pcie_read, + .write = pcie_write +}; + void register_dpci_portio_handler(struct domain *d) { struct hvm_io_handler *handler = hvm_next_io_handler(d); @@ -1011,7 +1173,10 @@ void register_dpci_portio_handler(struct domain *d) handler->type = IOREQ_TYPE_PIO; if ( is_hardware_domain(d) ) + { handler->ops = &hw_dpci_portio_ops; + register_mmio_handler(d, &pcie_mmio_ops); + } else handler->ops = &dpci_portio_ops; }