From patchwork Wed Aug 24 12:29:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 111332 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B7402B6F69 for ; Wed, 24 Aug 2011 22:29:44 +1000 (EST) Received: from localhost ([::1]:55742 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwCaT-0000AB-LN for incoming@patchwork.ozlabs.org; Wed, 24 Aug 2011 08:29:41 -0400 Received: from eggs.gnu.org ([140.186.70.92]:46420) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwCaO-00009x-4O for qemu-devel@nongnu.org; Wed, 24 Aug 2011 08:29:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QwCaM-0008Jq-VM for qemu-devel@nongnu.org; Wed, 24 Aug 2011 08:29:36 -0400 Received: from david.siemens.de ([192.35.17.14]:34848) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwCaM-0008Je-Iz for qemu-devel@nongnu.org; Wed, 24 Aug 2011 08:29:34 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.13.6/8.13.6) with ESMTP id p7OCTVgt008032; Wed, 24 Aug 2011 14:29:31 +0200 Received: from mchn199C.mchp.siemens.de ([139.25.109.49]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p7OCTU6x004298; Wed, 24 Aug 2011 14:29:31 +0200 Message-ID: <4E54EEAA.7020707@siemens.com> Date: Wed, 24 Aug 2011 14:29:30 +0200 From: Jan Kiszka User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 MIME-Version: 1.0 To: "Michael S. Tsirkin" References: <4E53E328.90601@siemens.com> In-Reply-To: <4E53E328.90601@siemens.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 192.35.17.14 Cc: Alex Williamson , "ddutile@redhat.com" , qemu-devel Subject: [Qemu-devel] [PATCH v2] pci: Error on PCI capability collisions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Nothing good can happen when we overlap capabilities. This may happen when plugging in assigned devices or when devices models contain bugs. Detect the overlap and report it. Based on qemu-kvm commit by Alex Williamson. Signed-off-by: Jan Kiszka --- hw/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-) Changes in v2: - properly find the conflicting CAP - adjust error code diff --git a/hw/pci.c b/hw/pci.c index 6124790..634e789 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1811,6 +1811,25 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, return next; } +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) +{ + uint8_t next, prev, found = 0; + + if (!(pdev->used[offset])) { + return 0; + } + + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); + + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]); + prev = next + PCI_CAP_LIST_NEXT) { + if (next <= offset && next > found) { + found = next; + } + } + return found; +} + /* 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) @@ -1952,11 +1971,26 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size) { uint8_t *config; + int i, overlapping_cap; + if (!offset) { offset = pci_find_space(pdev, size); if (!offset) { return -ENOSPC; } + } else { + for (i = offset; i < offset + size; i++) { + overlapping_cap = pci_find_capability_at_offset(pdev, i); + if (overlapping_cap) { + fprintf(stderr, "ERROR: %04x:%02x:%02x.%x " + "Attempt to add PCI capability %x at offset " + "%x overlaps existing capability %x at offset %x\n", + pci_find_domain(pdev->bus), pci_bus_num(pdev->bus), + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + cap_id, offset, overlapping_cap, i); + return -EINVAL; + } + } } config = pdev->config + offset;