From patchwork Mon Oct 18 17:55:11 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Weil X-Patchwork-Id: 68220 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 2BBFCB70E2 for ; Tue, 19 Oct 2010 04:57:55 +1100 (EST) Received: from localhost ([127.0.0.1]:35452 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1P7ty5-0000sg-30 for incoming@patchwork.ozlabs.org; Mon, 18 Oct 2010 13:57:53 -0400 Received: from [140.186.70.92] (port=38919 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1P7tw2-00083b-8n for qemu-devel@nongnu.org; Mon, 18 Oct 2010 13:55:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1P7tw0-0002k2-R8 for qemu-devel@nongnu.org; Mon, 18 Oct 2010 13:55:46 -0400 Received: from moutng.kundenserver.de ([212.227.126.171]:62033) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1P7tw0-0002jO-G2 for qemu-devel@nongnu.org; Mon, 18 Oct 2010 13:55:44 -0400 Received: from flocke.fritz.box (p54ADB483.dip.t-dialin.net [84.173.180.131]) by mrelayeu.kundenserver.de (node=mrbap0) with ESMTP (Nemesis) id 0LjuXJ-1OWdMx0a41-00bi94; Mon, 18 Oct 2010 19:55:14 +0200 Received: from stefan by flocke.fritz.box with local (Exim 4.72) (envelope-from ) id 1P7tvV-0005jh-26; Mon, 18 Oct 2010 19:55:13 +0200 From: Stefan Weil To: QEMU Developers Date: Mon, 18 Oct 2010 19:55:11 +0200 Message-Id: <1287424511-22021-1-git-send-email-weil@mail.berlios.de> X-Mailer: git-send-email 1.7.1 In-Reply-To: <4CBC6CDB.109@redhat.com> References: <4CBC6CDB.109@redhat.com> X-Provags-ID: V02:K0:58q6YrYEuKTM6nmWRZopjhe6/p5EdKp/nB7sBp7sPS8 2jO+yIDK12HJ8dN7yDNrZgXKi+iN9qr0z2idzt8582J47CiFgk B+lvM5geAlalPN+m7hBy4VXEg/2b5uo3iIVU9cSBo65jferfRe i+Xzin4wk+qYPtn035e7M3niY+1LBqDeWu7UhGhSuwItloCQ5+ GpFHs9VwZlr4oOoKykiXHTohTq8a5MtHLoAi4opNgz6u8fQrq0 GVP+J4jYz2/Dy X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: "Michael S. Tsirkin" , Gerd Hoffmann , Markus Armbruster Subject: [Qemu-devel] [PATCH 1/2] pci: Automatically patch PCI vendor id and device id in PCI ROM X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org PCI devices with different vendor or device ids sometimes share the same rom code. Only the ids and the checksum differs in a boot rom for such devices. The i825xx ethernet controller family is a typical example which is implemented in hw/eepro100.c. It uses at least 3 different device ids, so normally 3 boot roms would be needed. By automatically patching vendor id and device id (and the checksum) in qemu, all emulated family members can share the same boot rom. VGA bios roms are another example with different vendor and device ids. v2: * Patch also the vendor id (and remove the sanity check for vendor id). Cc: Gerd Hoffmann Cc: Markus Armbruster Cc: Michael S. Tsirkin Signed-off-by: Stefan Weil --- hw/pci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 58 insertions(+), 0 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 1280d4d..139eb24 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1797,6 +1797,62 @@ static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, p cpu_register_physical_memory(addr, size, pdev->rom_offset); } +/* Patch the PCI vendor and device ids in a PCI rom image if necessary. + This is needed for an option rom which is used for more than one device. */ +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) +{ + uint16_t vendor_id; + uint16_t device_id; + uint16_t rom_vendor_id; + uint16_t rom_device_id; + uint16_t rom_magic; + uint16_t pcir_offset; + uint8_t checksum; + + /* Words in rom data are little endian (like in PCI configuration), + so they can be read / written with pci_get_word / pci_set_word. */ + + /* Only a valid rom will be patched. */ + rom_magic = pci_get_word(ptr); + if (rom_magic != 0xaa55) { + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); + return; + } + pcir_offset = pci_get_word(ptr + 0x18); + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); + return; + } + + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); + rom_device_id = pci_get_word(ptr + pcir_offset + 6); + + PCI_DPRINTF("ROM id %04x%04x / PCI id %04x%04x\n", + vendor_id, device_id, rom_vendor_id, rom_device_id); + + checksum = ptr[6]; + + if (vendor_id != rom_vendor_id) { + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 4, vendor_id); + } + + if (device_id != rom_device_id) { + /* Patch device id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 6, device_id); + } +} + /* Add an option rom for the device */ static int pci_add_option_rom(PCIDevice *pdev) { @@ -1849,6 +1905,8 @@ static int pci_add_option_rom(PCIDevice *pdev) load_image(path, ptr); qemu_free(path); + pci_patch_ids(pdev, ptr, size); + pci_register_bar(pdev, PCI_ROM_SLOT, size, 0, pci_map_option_rom);