From patchwork Mon Jun 15 16:29:17 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 30374 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n5FGTLGJ030158 for ; Mon, 15 Jun 2009 16:29:21 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1763054AbZFOQ2n (ORCPT ); Mon, 15 Jun 2009 12:28:43 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1761023AbZFOQ2n (ORCPT ); Mon, 15 Jun 2009 12:28:43 -0400 Received: from g4t0014.houston.hp.com ([15.201.24.17]:13704 "EHLO g4t0014.houston.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1763251AbZFOQ2l (ORCPT ); Mon, 15 Jun 2009 12:28:41 -0400 Received: from g1t0038.austin.hp.com (g1t0038.austin.hp.com [16.236.32.44]) by g4t0014.houston.hp.com (Postfix) with ESMTP id 1886D24327; Mon, 15 Jun 2009 16:28:44 +0000 (UTC) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by g1t0038.austin.hp.com (Postfix) with ESMTP id B25693010A; Mon, 15 Jun 2009 16:28:43 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id 694B339C00B; Mon, 15 Jun 2009 10:28:43 -0600 (MDT) X-Virus-Scanned: Debian amavisd-new at ldl.fc.hp.com Received: from ldl.fc.hp.com ([127.0.0.1]) by localhost (ldl.fc.hp.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id RafGkGfNPUEj; Mon, 15 Jun 2009 10:28:41 -0600 (MDT) Received: from host.lart (lart.fc.hp.com [15.11.146.31]) by ldl.fc.hp.com (Postfix) with ESMTP id 607CB39C001; Mon, 15 Jun 2009 10:28:41 -0600 (MDT) From: Alex Williamson Subject: [PATCH] kvm: device-assignment: Add PCI option ROM support To: kvm@vger.kernel.org Cc: sheng.yang@intel.com, alex.williamson@hp.com Date: Mon, 15 Jun 2009 10:29:17 -0600 Message-ID: <20090615162815.4830.38216.stgit@host.lart> User-Agent: StGIT/0.14.2 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The PCI code already knows about option ROMs, so we just need to mmap some space for it, load it with a copy of the contents, and complete the plubming to the generic code. With this a Linux guest can get access to the ROM contents via /sys/bus/pci/devices//rom. This might also enable the BIOS to execute ROMs by loading them dynamically from the device rather than hoping they all fit into RAM. Signed-off-by: Alex Williamson --- hw/device-assignment.c | 60 ++++++++++++++++++++++++++++++++++++------------ hw/device-assignment.h | 5 +--- 2 files changed, 46 insertions(+), 19 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 65920d0..dfcd670 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -286,8 +286,8 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address, /* Continue to program the card */ } - if ((address >= 0x10 && address <= 0x24) || address == 0x34 || - address == 0x3c || address == 0x3d || + if ((address >= 0x10 && address <= 0x24) || address == 0x30 || + address == 0x34 || address == 0x3c || address == 0x3d || pci_access_cap_config(d, address, len)) { /* used for update-mappings (BAR emulation) */ pci_default_write_config(d, address, val, len); @@ -322,8 +322,8 @@ static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address, AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev); if (address < 0x4 || (pci_dev->need_emulate_cmd && address == 0x4) || - (address >= 0x10 && address <= 0x24) || address == 0x34 || - address == 0x3c || address == 0x3d || + (address >= 0x10 && address <= 0x24) || address == 0x30 || + address == 0x34 || address == 0x3c || address == 0x3d || pci_access_cap_config(d, address, len)) { val = pci_default_read_config(d, address, len); DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n", @@ -384,11 +384,20 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, /* map physical memory */ pci_dev->v_addrs[i].e_physbase = cur_region->base_addr; - pci_dev->v_addrs[i].u.r_virtbase = - mmap(NULL, - (cur_region->size + 0xFFF) & 0xFFFFF000, - PROT_WRITE | PROT_READ, MAP_SHARED, - cur_region->resource_fd, (off_t) 0); + if (i == PCI_ROM_SLOT) { + pci_dev->v_addrs[i].u.r_virtbase = + mmap(NULL, + (cur_region->size + 0xFFF) & 0xFFFFF000, + PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, + 0, (off_t) 0); + + } else { + pci_dev->v_addrs[i].u.r_virtbase = + mmap(NULL, + (cur_region->size + 0xFFF) & 0xFFFFF000, + PROT_WRITE | PROT_READ, MAP_SHARED, + cur_region->resource_fd, (off_t) 0); + } if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) { pci_dev->v_addrs[i].u.r_virtbase = NULL; @@ -397,6 +406,14 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, (uint32_t) (cur_region->base_addr)); return -1; } + + if (i == PCI_ROM_SLOT) { + memset(pci_dev->v_addrs[i].u.r_virtbase, 0, + (cur_region->size + 0xFFF) & 0xFFFFF000); + mprotect(pci_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase, + (cur_region->size + 0xFFF) & 0xFFFFF000, PROT_READ); + } + pci_dev->v_addrs[i].r_size = cur_region->size; pci_dev->v_addrs[i].e_size = 0; @@ -468,7 +485,7 @@ again: return 1; } - for (r = 0; r < MAX_IO_REGIONS; r++) { + for (r = 0; r < PCI_NUM_REGIONS; r++) { if (fscanf(f, "%lli %lli %lli\n", &start, &end, &flags) != 3) break; @@ -480,11 +497,13 @@ again: continue; if (flags & IORESOURCE_MEM) { flags &= ~IORESOURCE_IO; - snprintf(name, sizeof(name), "%sresource%d", dir, r); - fd = open(name, O_RDWR); - if (fd == -1) - continue; /* probably ROM */ - rp->resource_fd = fd; + if (r != PCI_ROM_SLOT) { + snprintf(name, sizeof(name), "%sresource%d", dir, r); + fd = open(name, O_RDWR); + if (fd == -1) + continue; + rp->resource_fd = fd; + } } else flags &= ~IORESOURCE_PREFETCH; @@ -1390,6 +1409,17 @@ ram_addr_t assigned_dev_load_option_roms(ram_addr_t rom_base_offset) continue; } + /* Copy ROM contents into the space backing the ROM BAR */ + if (adev->assigned_dev->v_addrs[PCI_ROM_SLOT].r_size >= size && + adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase) { + mprotect(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase, + size, PROT_READ | PROT_WRITE); + memcpy(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase, + buf, size); + mprotect(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase, + size, PROT_READ); + } + /* Scan the buffer for suitable ROMs and increase the offset */ offset += scan_option_rom(adev->assigned_dev->dev.devfn, buf, offset); diff --git a/hw/device-assignment.h b/hw/device-assignment.h index c691e11..713f9b7 100644 --- a/hw/device-assignment.h +++ b/hw/device-assignment.h @@ -36,9 +36,6 @@ /* From include/linux/pci.h in the kernel sources */ #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) -/* The number of BARs in the config space header */ -#define MAX_IO_REGIONS (6) - typedef struct { int type; /* Memory or port I/O */ int valid; @@ -53,7 +50,7 @@ typedef struct { uint16_t region_number; /* number of active regions */ /* Port I/O or MMIO Regions */ - PCIRegion regions[MAX_IO_REGIONS]; + PCIRegion regions[PCI_NUM_REGIONS]; int config_fd; } PCIDevRegions;