From: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
To: kvm@vger.kernel.org
Cc: will.deacon@arm.com, robin.murphy@arm.com,
lorenzo.pieralisi@arm.com, marc.zyngier@arm.com
Subject: [PATCH v2 kvmtool 01/10] pci: add config operations callbacks on the PCI header
Date: Thu, 22 Jun 2017 18:05:27 +0100 [thread overview]
Message-ID: <20170622170536.14319-2-jean-philippe.brucker@arm.com> (raw)
In-Reply-To: <20170622170536.14319-1-jean-philippe.brucker@arm.com>
When implementing PCI device passthrough, we will need to forward config
accesses from a guest to the VFIO driver. Add a private cfg_ops structure
to the PCI header, and use it in the PCI config access functions.
A read from the guest first calls into the device's cfg_ops.read, to let
the backend update the local header before filling the guest register.
Same happens for a write, we let the backend perform the write and replace
the guest-provided register with whatever sticks, before updating the local
header.
Try to untangle the PCI config access logic while we're at it.
Signed-off-by: Will Deacon <will.deacon@arm.com>
[JPB: moved to a separate patch]
Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
include/kvm/pci.h | 72 ++++++++++++++++++++++++++++----------------
pci.c | 89 ++++++++++++++++++++++++++-----------------------------
2 files changed, 89 insertions(+), 72 deletions(-)
diff --git a/include/kvm/pci.h b/include/kvm/pci.h
index b0c28a10..56649d87 100644
--- a/include/kvm/pci.h
+++ b/include/kvm/pci.h
@@ -57,33 +57,55 @@ struct msix_cap {
u32 pba_offset;
};
+#define PCI_BAR_OFFSET(b) (offsetof(struct pci_device_header, bar[b]))
+#define PCI_DEV_CFG_SIZE 256
+#define PCI_DEV_CFG_MASK (PCI_DEV_CFG_SIZE - 1)
+
+struct pci_device_header;
+
+struct pci_config_operations {
+ void (*write)(struct kvm *kvm, struct pci_device_header *pci_hdr,
+ u8 offset, void *data, int sz);
+ void (*read)(struct kvm *kvm, struct pci_device_header *pci_hdr,
+ u8 offset, void *data, int sz);
+};
+
struct pci_device_header {
- u16 vendor_id;
- u16 device_id;
- u16 command;
- u16 status;
- u8 revision_id;
- u8 class[3];
- u8 cacheline_size;
- u8 latency_timer;
- u8 header_type;
- u8 bist;
- u32 bar[6];
- u32 card_bus;
- u16 subsys_vendor_id;
- u16 subsys_id;
- u32 exp_rom_bar;
- u8 capabilities;
- u8 reserved1[3];
- u32 reserved2;
- u8 irq_line;
- u8 irq_pin;
- u8 min_gnt;
- u8 max_lat;
- struct msix_cap msix;
- u8 empty[136]; /* Rest of PCI config space */
+ /* Configuration space, as seen by the guest */
+ union {
+ struct {
+ u16 vendor_id;
+ u16 device_id;
+ u16 command;
+ u16 status;
+ u8 revision_id;
+ u8 class[3];
+ u8 cacheline_size;
+ u8 latency_timer;
+ u8 header_type;
+ u8 bist;
+ u32 bar[6];
+ u32 card_bus;
+ u16 subsys_vendor_id;
+ u16 subsys_id;
+ u32 exp_rom_bar;
+ u8 capabilities;
+ u8 reserved1[3];
+ u32 reserved2;
+ u8 irq_line;
+ u8 irq_pin;
+ u8 min_gnt;
+ u8 max_lat;
+ struct msix_cap msix;
+ } __attribute__((packed));
+ /* Pad to PCI config space size */
+ u8 __pad[PCI_DEV_CFG_SIZE];
+ };
+
+ /* Private to lkvm */
u32 bar_size[6];
-} __attribute__((packed));
+ struct pci_config_operations cfg_ops;
+};
int pci__init(struct kvm *kvm);
int pci__exit(struct kvm *kvm);
diff --git a/pci.c b/pci.c
index 3a6696c5..e48e24b8 100644
--- a/pci.c
+++ b/pci.c
@@ -8,8 +8,6 @@
#include <linux/err.h>
#include <assert.h>
-#define PCI_BAR_OFFSET(b) (offsetof(struct pci_device_header, bar[b]))
-
static u32 pci_config_address_bits;
/* This is within our PCI gap - in an unused area.
@@ -131,59 +129,56 @@ static struct ioport_operations pci_config_data_ops = {
void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size)
{
- u8 dev_num;
-
- dev_num = addr.device_number;
-
- if (pci_device_exists(0, dev_num, 0)) {
- unsigned long offset;
-
- offset = addr.w & 0xff;
- if (offset < sizeof(struct pci_device_header)) {
- void *p = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
- struct pci_device_header *hdr = p;
- u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
- u32 sz = cpu_to_le32(PCI_IO_SIZE);
-
- if (bar < 6 && hdr->bar_size[bar])
- sz = hdr->bar_size[bar];
-
- /*
- * If the kernel masks the BAR it would expect to find the
- * size of the BAR there next time it reads from it.
- * When the kernel got the size it would write the address
- * back.
- */
- if (*(u32 *)(p + offset)) {
- /* See if kernel tries to mask one of the BARs */
- if ((offset >= PCI_BAR_OFFSET(0)) &&
- (offset <= PCI_BAR_OFFSET(6)) &&
- (ioport__read32(data) == 0xFFFFFFFF))
- memcpy(p + offset, &sz, sizeof(sz));
- else
- memcpy(p + offset, data, size);
- }
- }
+ void *base;
+ u8 bar, offset;
+ struct pci_device_header *pci_hdr;
+ u8 dev_num = addr.device_number;
+
+ if (!pci_device_exists(addr.bus_number, dev_num, 0))
+ return;
+
+ offset = addr.w & PCI_DEV_CFG_MASK;
+ base = pci_hdr = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
+
+ if (pci_hdr->cfg_ops.write)
+ pci_hdr->cfg_ops.write(kvm, pci_hdr, offset, data, size);
+
+ /*
+ * legacy hack: ignore writes to uninitialized regions (e.g. ROM BAR).
+ * Not very nice but has been working so far.
+ */
+ if (*(u32 *)(base + offset) == 0)
+ return;
+
+ bar = (offset - PCI_BAR_OFFSET(0)) / sizeof(u32);
+
+ /*
+ * If the kernel masks the BAR it would expect to find the size of the
+ * BAR there next time it reads from it. When the kernel got the size it
+ * would write the address back.
+ */
+ if (bar < 6 && ioport__read32(data) == 0xFFFFFFFF) {
+ u32 sz = pci_hdr->bar_size[bar];
+ memcpy(base + offset, &sz, sizeof(sz));
+ } else {
+ memcpy(base + offset, data, size);
}
}
void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size)
{
- u8 dev_num;
-
- dev_num = addr.device_number;
+ u8 offset;
+ struct pci_device_header *pci_hdr;
+ u8 dev_num = addr.device_number;
- if (pci_device_exists(0, dev_num, 0)) {
- unsigned long offset;
+ if (pci_device_exists(addr.bus_number, dev_num, 0)) {
+ pci_hdr = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
+ offset = addr.w & PCI_DEV_CFG_MASK;
- offset = addr.w & 0xff;
- if (offset < sizeof(struct pci_device_header)) {
- void *p = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
+ if (pci_hdr->cfg_ops.read)
+ pci_hdr->cfg_ops.read(kvm, pci_hdr, offset, data, size);
- memcpy(data, p + offset, size);
- } else {
- memset(data, 0x00, size);
- }
+ memcpy(data, (void *)pci_hdr + offset, size);
} else {
memset(data, 0xff, size);
}
--
2.13.1
next prev parent reply other threads:[~2017-06-22 17:03 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-22 17:05 [PATCH v2 kvmtool 00/10] Add PCI passthrough support with VFIO Jean-Philippe Brucker
2017-06-22 17:05 ` Jean-Philippe Brucker [this message]
2017-06-22 17:05 ` [PATCH v2 kvmtool 02/10] pci: allow to specify IRQ type for PCI devices Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 03/10] irq: add irqfd helpers Jean-Philippe Brucker
2017-07-31 17:55 ` Punit Agrawal
2017-08-02 15:17 ` Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 04/10] Extend memory bank API with memory types Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 05/10] pci: add capability helpers Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 06/10] Add PCI device passthrough using VFIO Jean-Philippe Brucker
2017-07-31 17:52 ` Punit Agrawal
2017-08-02 15:17 ` Jean-Philippe Brucker
2017-08-03 9:36 ` Punit Agrawal
2017-08-03 11:24 ` Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 07/10] vfio-pci: add MSI-X support Jean-Philippe Brucker
2017-07-31 17:49 ` Punit Agrawal
2017-08-01 16:04 ` Punit Agrawal
2017-08-02 15:18 ` Jean-Philippe Brucker
2017-08-03 10:25 ` Punit Agrawal
2017-08-03 10:53 ` Jean-Philippe Brucker
2017-08-18 17:42 ` Jean-Philippe Brucker
2017-08-22 11:25 ` Punit Agrawal
2017-06-22 17:05 ` [PATCH v2 kvmtool 08/10] vfio-pci: add MSI support Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 09/10] Introduce reserved memory regions Jean-Philippe Brucker
2017-06-22 17:05 ` [PATCH v2 kvmtool 10/10] vfio: check reserved regions before mapping DMA Jean-Philippe Brucker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170622170536.14319-2-jean-philippe.brucker@arm.com \
--to=jean-philippe.brucker@arm.com \
--cc=kvm@vger.kernel.org \
--cc=lorenzo.pieralisi@arm.com \
--cc=marc.zyngier@arm.com \
--cc=robin.murphy@arm.com \
--cc=will.deacon@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).