From patchwork Fri Jun 30 15:01:14 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: 9819829 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 13D4A602B1 for ; Fri, 30 Jun 2017 15:04:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E76A528338 for ; Fri, 30 Jun 2017 15:03:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DA8952853A; Fri, 30 Jun 2017 15:03:59 +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 982CA28338 for ; Fri, 30 Jun 2017 15:03:58 +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 1dQxQP-00034e-H5; Fri, 30 Jun 2017 15:01:37 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dQxQO-000347-Ga for xen-devel@lists.xenproject.org; Fri, 30 Jun 2017 15:01:36 +0000 Received: from [85.158.143.35] by server-5.bemta-6.messagelabs.com id 49/2D-03368-FC766595; Fri, 30 Jun 2017 15:01:35 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrCIsWRWlGSWpSXmKPExsXitHRDpO759LB Igy9/uCy+b5nM5MDocfjDFZYAxijWzLyk/IoE1ox7M1uYChr6GCsubP7H3sDYltLFyMkhIeAv 8Wr9dRYQm01AR+Li3J1sXYwcHCICKhK39xp0MXJxMAu0M0s0353PClIjLGAncXzDDEYQm0VAV eLvt+lsIDavgKXE2hO3mCBm6km8nfiCEWQOp4CVxIlJMiBhIaCShX8uM0GUC0qcnPkEbC2zgK ZE6/bf7BC2vETz1tnMEPWKEv3zHrBNYOSbhaRlFpKWWUhaFjAyr2JUL04tKkst0jXWSyrKTM8 oyU3MzNE1NDDTy00tLk5MT81JTCrWS87P3cQIDDUGINjB2PHP6RCjJAeTkijvymuhkUJ8Sfkp lRmJxRnxRaU5qcWHGGU4OJQkeF+mhUUKCRalpqdWpGXmAIMeJi3BwaMkwisbBJTmLS5IzC3OT IdInWK05FjQs+ELE8exGT+/MXGsmgkkhVjy8vNSpcR5z4LMEwBpyCjNgxsHi8xLjLJSwryMQA cK8RSkFuVmlqDKv2IU52BUEuadCDKFJzOvBG7rK6CDmIAOEp4RAnJQSSJCSqqBsbYhU3JG0yF GX1P7JSwmgeKp9gK8vrelgvTZOM6eu/XlZLEUq5hITwFT4qaV18VsHpYZnzUPsg/Ll9OcF5Yv bjSdMdGbcwHD/eu31kk1Lky5OpUnuvtV/kqn5eualmYcqS2yKr5XU/jvsKXQBZ0lF/9UiYdcn XRinofwkjvPtucuD7I6HXxdiaU4I9FQi7moOBEAl3R+rMcCAAA= X-Env-Sender: prvs=3475c4a2e=roger.pau@citrix.com X-Msg-Ref: server-15.tower-21.messagelabs.com!1498834885!70989584!4 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.4.25; banners=-,-,- X-VirusChecked: Checked Received: (qmail 9454 invoked from network); 30 Jun 2017 15:01:34 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-15.tower-21.messagelabs.com with RC4-SHA encrypted SMTP; 30 Jun 2017 15:01:34 -0000 X-IronPort-AV: E=Sophos;i="5.40,287,1496102400"; d="scan'208";a="430013012" From: Roger Pau Monne To: Date: Fri, 30 Jun 2017 16:01:14 +0100 Message-ID: <20170630150117.88489-7-roger.pau@citrix.com> X-Mailer: git-send-email 2.11.0 (Apple Git-81) In-Reply-To: <20170630150117.88489-1-roger.pau@citrix.com> References: <20170630150117.88489-1-roger.pau@citrix.com> MIME-Version: 1.0 Cc: Stefano Stabellini , Wei Liu , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , julien.grall@arm.com, Jan Beulich , boris.ostrovsky@oracle.com, Roger Pau Monne Subject: [Xen-devel] [PATCH v4 6/9] xen/vpci: add handlers to map the BARs 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 that trap accesses to the PCI BARs and the command register, in order to emulate BAR sizing and BAR relocation. The command handler is used to detect changes to bit 2 (response to memory space accesses), and maps/unmaps the BARs of the device into the guest p2m. The BAR register handlers are used to detect attempts by the guest to size or relocate the BARs. Signed-off-by: Roger Pau Monné --- Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu --- Changes since v3: - Propagate previous changes: drop xen_ prefix and use u8/u16/u32 instead of the previous half_word/word/double_word. - Constify some of the paramerters. - s/VPCI_BAR_MEM/VPCI_BAR_MEM32/. - Simplify the number of fields stored for each BAR, a single address field is stored and contains the address of the BAR both on Xen and in the guest. - Allow the guest to move the BARs around in the physical memory map. - Add support for expansion ROM BARs. - Do not cache the value of the command register. - Remove a label used in vpci_cmd_write. - Fix the calculation of the sizing mask in vpci_bar_write. - Check the memory decode bit in order to decide if a BAR is positioned or not. - Disable memory decoding before sizing the BARs in Xen. - When mapping/unmapping BARs check if there's overlap between BARs, in order to avoid unmapping memory required by another BAR. - Introduce a macro to check whether a BAR is mappable or not. - Add a comment regarding the lack of support for SR-IOV. - Remove the usage of the GENMASK macro. Changes since v2: - Detect unset BARs and allow the hardware domain to position them. --- xen/drivers/vpci/Makefile | 2 +- xen/drivers/vpci/header.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++ xen/include/xen/vpci.h | 23 +++ 3 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 xen/drivers/vpci/header.c diff --git a/xen/drivers/vpci/Makefile b/xen/drivers/vpci/Makefile index 840a906470..241467212f 100644 --- a/xen/drivers/vpci/Makefile +++ b/xen/drivers/vpci/Makefile @@ -1 +1 @@ -obj-y += vpci.o +obj-y += vpci.o header.o diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c new file mode 100644 index 0000000000..3c800c4cf7 --- /dev/null +++ b/xen/drivers/vpci/header.c @@ -0,0 +1,473 @@ +/* + * Generic functionality for handling accesses to the PCI header from the + * configuration space. + * + * Copyright (C) 2017 Citrix Systems R&D + * + * This program is free software; you can redistribute it and/or + * modify it under the terms and conditions of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; If not, see . + */ + +#include +#include +#include + +#define MAPPABLE_BAR(x) \ + (((x)->type == VPCI_BAR_MEM32 || (x)->type == VPCI_BAR_MEM64_LO || \ + ((x)->type == VPCI_BAR_ROM && (x)->enabled)) && \ + (x)->addr != INVALID_PADDR) + +static struct rangeset *vpci_get_bar_memory(const struct domain *d, + const struct vpci_bar *map) +{ + const struct pci_dev *pdev; + struct rangeset *mem = rangeset_new(NULL, NULL, 0); + int rc; + + if ( !mem ) + return ERR_PTR(-ENOMEM); + + /* + * Create a rangeset that represents the current BAR memory region + * and compare it against all the currently active BAR memory regions. + * If an overlap is found, subtract it from the region to be + * mapped/unmapped. + * + * NB: the rangeset uses frames, and if start and end addresses are + * equal it means only one frame is used, that's why PFN_DOWN is used + * to calculate the end of the rangeset. + */ + rc = rangeset_add_range(mem, PFN_DOWN(map->addr), + PFN_DOWN(map->addr + map->size)); + if ( rc ) + { + rangeset_destroy(mem); + return ERR_PTR(rc); + } + + list_for_each_entry(pdev, &d->arch.pdev_list, domain_list) + { + uint16_t cmd = pci_conf_read16(pdev->seg, pdev->bus, + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), + PCI_COMMAND); + unsigned int i; + + /* Check if memory decoding is enabled. */ + if ( !(cmd & PCI_COMMAND_MEMORY) ) + continue; + + for ( i = 0; i < ARRAY_SIZE(pdev->vpci->header.bars); i++ ) + { + const struct vpci_bar *bar = &pdev->vpci->header.bars[i]; + + if ( bar == map || !MAPPABLE_BAR(bar) || + !rangeset_overlaps_range(mem, PFN_DOWN(bar->addr), + PFN_DOWN(bar->addr + bar->size)) ) + continue; + + rc = rangeset_remove_range(mem, PFN_DOWN(bar->addr), + PFN_DOWN(bar->addr + bar->size)); + if ( rc ) + { + rangeset_destroy(mem); + return ERR_PTR(rc); + } + } + } + + return mem; +} + +struct map_data { + struct domain *d; + bool map; +}; + +static int vpci_map_range(unsigned long s, unsigned long e, void *data) +{ + const struct map_data *map = data; + + return modify_mmio(map->d, _gfn(s), _mfn(s), e - s + 1, map->map); +} + +static int vpci_modify_bar(struct domain *d, const struct vpci_bar *bar, + const bool map) +{ + struct rangeset *mem; + struct map_data data = { .d = d, .map = map }; + int rc; + + ASSERT(MAPPABLE_BAR(bar)); + + mem = vpci_get_bar_memory(d, bar); + if ( IS_ERR(mem) ) + return -PTR_ERR(mem); + + rc = rangeset_report_ranges(mem, 0, ~0ul, vpci_map_range, &data); + rangeset_destroy(mem); + if ( rc ) + return rc; + + return 0; +} + +static int vpci_modify_bars(const struct pci_dev *pdev, const bool map) +{ + const struct vpci_header *header = &pdev->vpci->header; + unsigned int i; + + for ( i = 0; i < ARRAY_SIZE(header->bars); i++ ) + { + const struct vpci_bar *bar = &header->bars[i]; + int rc; + + if ( !MAPPABLE_BAR(bar) ) + continue; + + rc = vpci_modify_bar(pdev->domain, bar, map); + if ( rc ) + return rc; + } + + return 0; +} + +static void vpci_cmd_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + + val->u16 = pci_conf_read16(seg, bus, slot, func, reg); +} + +static void vpci_cmd_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + uint16_t cmd = val.u16, current_cmd; + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + int rc; + + current_cmd = pci_conf_read16(seg, bus, slot, func, reg); + + if ( !((cmd ^ current_cmd) & PCI_COMMAND_MEMORY) ) + { + /* + * Let the guest play with all the bits directly except for the + * memory decoding one. + */ + pci_conf_write16(seg, bus, slot, func, reg, cmd); + return; + } + + /* Memory space access change. */ + rc = vpci_modify_bars(pdev, cmd & PCI_COMMAND_MEMORY); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u:unable to %smap BARs: %d\n", + seg, bus, slot, func, + cmd & PCI_COMMAND_MEMORY ? "" : "un", rc); + return; + } + + pci_conf_write16(seg, bus, slot, func, reg, cmd); +} + +static void vpci_bar_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + const struct vpci_bar *bar = data; + bool hi = false; + + ASSERT(bar->type == VPCI_BAR_MEM32 || bar->type == VPCI_BAR_MEM64_LO || + bar->type == VPCI_BAR_MEM64_HI); + + if ( bar->type == VPCI_BAR_MEM64_HI ) + { + ASSERT(reg > PCI_BASE_ADDRESS_0); + bar--; + hi = true; + } + + if ( bar->sizing ) + val->u32 = ~(bar->size - 1) >> (hi ? 32 : 0); + else + val->u32 = bar->addr >> (hi ? 32 : 0); + + if ( !hi ) + { + val->u32 |= bar->type == VPCI_BAR_MEM32 ? PCI_BASE_ADDRESS_MEM_TYPE_32 + : PCI_BASE_ADDRESS_MEM_TYPE_64; + val->u32 |= bar->prefetchable ? PCI_BASE_ADDRESS_MEM_PREFETCH : 0; + } +} + +static void vpci_bar_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_bar *bar = data; + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + uint32_t wdata = val.u32, size_mask; + bool hi = false; + + switch ( bar->type ) + { + case VPCI_BAR_MEM32: + case VPCI_BAR_MEM64_LO: + size_mask = (uint32_t)PCI_BASE_ADDRESS_MEM_MASK; + break; + case VPCI_BAR_MEM64_HI: + size_mask = ~0u; + break; + default: + ASSERT_UNREACHABLE(); + return; + } + + if ( (wdata & size_mask) == size_mask ) + { + /* Next reads from this register are going to return the BAR size. */ + bar->sizing = true; + return; + } + + /* End previous sizing cycle if any. */ + bar->sizing = false; + + /* + * Ignore attempts to change the position of the BAR if memory decoding is + * active. + */ + if ( pci_conf_read16(seg, bus, slot, func, PCI_COMMAND) & + PCI_COMMAND_MEMORY ) + return; + + if ( bar->type == VPCI_BAR_MEM64_HI ) + { + ASSERT(reg > PCI_BASE_ADDRESS_0); + bar--; + hi = true; + } + + if ( !hi ) + wdata &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Update the relevant part of the BAR address. */ + bar->addr &= ~((uint64_t)0xffffffff << (hi ? 32 : 0)); + bar->addr |= (uint64_t)wdata << (hi ? 32 : 0); + + /* Make sure Xen writes back the same value for the BAR RO bits. */ + if ( !hi ) + wdata |= pci_conf_read32(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), reg) & + ~PCI_BASE_ADDRESS_MEM_MASK; + pci_conf_write32(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), reg, wdata); +} + +static void vpci_rom_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + const struct vpci_bar *rom = data; + + if ( rom->sizing ) + val->u32 = ~(rom->size - 1); + else + val->u32 = rom->addr; + + val->u32 |= rom->enabled ? PCI_ROM_ADDRESS_ENABLE : 0; +} + +static void vpci_rom_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_bar *rom = data; + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + const uint32_t wdata = val.u32; + + if ( (wdata & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK ) + { + /* Next reads from this register are going to return the BAR size. */ + rom->sizing = true; + return; + } + + /* End previous sizing cycle if any. */ + rom->sizing = false; + + rom->addr = wdata & PCI_ROM_ADDRESS_MASK; + + /* Check if memory decoding is enabled. */ + if ( pci_conf_read16(seg, bus, slot, func, PCI_COMMAND) & + PCI_COMMAND_MEMORY && + (rom->enabled ^ (wdata & PCI_ROM_ADDRESS_ENABLE)) ) + { + if ( vpci_modify_bar(pdev->domain, rom, + wdata & PCI_ROM_ADDRESS_ENABLE) ) + return; + + rom->enabled = wdata & PCI_ROM_ADDRESS_ENABLE; + } + + pci_conf_write32(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), reg, wdata); +} + +static int vpci_init_bars(struct pci_dev *pdev) +{ + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + uint8_t header_type; + uint16_t cmd; + uint32_t rom_val; + uint64_t addr, size; + unsigned int i, num_bars, rom_reg; + struct vpci_header *header = &pdev->vpci->header; + struct vpci_bar *bars = header->bars; + int rc; + + header_type = pci_conf_read8(seg, bus, slot, func, PCI_HEADER_TYPE) & 0x7f; + switch ( header_type ) + { + case PCI_HEADER_TYPE_NORMAL: + num_bars = 6; + rom_reg = PCI_ROM_ADDRESS; + break; + case PCI_HEADER_TYPE_BRIDGE: + num_bars = 2; + rom_reg = PCI_ROM_ADDRESS1; + break; + default: + return -EOPNOTSUPP; + } + + /* Setup a handler for the command register. */ + cmd = pci_conf_read16(seg, bus, slot, func, PCI_COMMAND); + rc = vpci_add_register(pdev, vpci_cmd_read, vpci_cmd_write, PCI_COMMAND, + 2, header); + if ( rc ) + return rc; + + /* Disable memory decoding before sizing. */ + if ( cmd & PCI_COMMAND_MEMORY ) + pci_conf_write16(seg, bus, slot, func, PCI_COMMAND, + cmd & ~PCI_COMMAND_MEMORY); + + for ( i = 0; i < num_bars; i++ ) + { + uint8_t reg = PCI_BASE_ADDRESS_0 + i * 4; + uint32_t val = pci_conf_read32(seg, bus, slot, func, reg); + + if ( i && bars[i - 1].type == VPCI_BAR_MEM64_LO ) + { + bars[i].type = VPCI_BAR_MEM64_HI; + rc = vpci_add_register(pdev, vpci_bar_read, vpci_bar_write, reg, 4, + &bars[i]); + if ( rc ) + return rc; + + continue; + } + if ( (val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO ) + { + bars[i].type = VPCI_BAR_IO; + continue; + } + if ( (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64 ) + bars[i].type = VPCI_BAR_MEM64_LO; + else + bars[i].type = VPCI_BAR_MEM32; + + /* Size the BAR and map it. */ + rc = pci_size_mem_bar(seg, bus, slot, func, reg, i == num_bars - 1, + &addr, &size); + if ( rc < 0 ) + return rc; + + if ( size == 0 ) + { + bars[i].type = VPCI_BAR_EMPTY; + continue; + } + + bars[i].addr = (cmd & PCI_COMMAND_MEMORY) ? addr : INVALID_PADDR; + bars[i].size = size; + bars[i].prefetchable = val & PCI_BASE_ADDRESS_MEM_PREFETCH; + + rc = vpci_add_register(pdev, vpci_bar_read, vpci_bar_write, reg, 4, + &bars[i]); + if ( rc ) + return rc; + } + + /* Check expansion ROM. */ + rom_val = pci_conf_read32(seg, bus, slot, func, rom_reg); + if ( rom_val & PCI_ROM_ADDRESS_ENABLE ) + pci_conf_write32(seg, bus, slot, func, rom_reg, + rom_val & ~PCI_ROM_ADDRESS_ENABLE); + + rc = pci_size_mem_bar(seg, bus, slot, func, rom_reg, true, &addr, &size); + if ( rc < 0 ) + return rc; + + if ( size ) + { + struct vpci_bar *rom = &header->bars[num_bars]; + + rom->type = VPCI_BAR_ROM; + rom->size = size; + rom->enabled = rom_val & PCI_ROM_ADDRESS_ENABLE; + if ( rom->enabled ) + rom->addr = addr; + else + rom->addr = INVALID_PADDR; + + rc = vpci_add_register(pdev, vpci_rom_read, vpci_rom_write, rom_reg, 4, + rom); + if ( rc ) + return rc; + + if ( rom->enabled ) + pci_conf_write32(seg, bus, slot, func, rom_reg, rom_val); + } + + if ( cmd & PCI_COMMAND_MEMORY ) + { + rc = vpci_modify_bars(pdev, true); + if ( rc ) + return rc; + + /* Enable memory decoding. */ + pci_conf_write16(seg, bus, slot, func, PCI_COMMAND, cmd); + } + + return 0; +} + +REGISTER_VPCI_INIT(vpci_init_bars); + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index 5e1b0bb3da..452ee482e8 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -63,6 +63,29 @@ void vpci_write(unsigned int seg, unsigned int bus, unsigned int slot, struct vpci { /* Root pointer for the tree of vPCI handlers. */ struct list_head handlers; + +#ifdef __XEN__ + /* Hide the rest of the vpci struct from the user-space test harness. */ + struct vpci_header { + /* Information about the PCI BARs of this device. */ + struct vpci_bar { + enum { + VPCI_BAR_EMPTY, + VPCI_BAR_IO, + VPCI_BAR_MEM32, + VPCI_BAR_MEM64_LO, + VPCI_BAR_MEM64_HI, + VPCI_BAR_ROM, + } type; + paddr_t addr; + uint64_t size; + bool prefetchable; + bool sizing; + bool enabled; + } bars[7]; /* At most 6 BARS + 1 expansion ROM BAR. */ + /* FIXME: currently there's no support for SR-IOV. */ + } header; +#endif }; #endif