From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Michael S. Tsirkin" <mst@redhat.com>, patches@linaro.org
Subject: [Qemu-devel] [RFC 2/2] hw/pci-host/versatile: Implement IMAP registers
Date: Thu, 22 Aug 2013 19:28:12 +0100 [thread overview]
Message-ID: <1377196092-7482-3-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1377196092-7482-1-git-send-email-peter.maydell@linaro.org>
Rather than assuming that PCI bus master devices can DMA directly into
system memory, correctly model the way the hardware does it:
* the host controller has three BARs (one I/O and two memory) which
can be mapped into PCI memory space in the usual way
* each of these BARs is an alias of an area of system memory whose
base address is defined by the host controller's SMAP registers
* PCI bus master devices see the PCI memory space, in the same
way as everybody else
Linux programs the BARs and SMAP registers in such a way that
(for system RAM) you get the identity mapping.
Note that since the QEMU PCI core doesn't forbid PCI devices
from attempting to do bus master accesses to their own MMIO
BARs it is possible for a malicious guest to configure the
controller into a hall-of-mirrors mapping of the PCI and
system memory spaces into each other such that an access would
loop infinitely. This will probably result in infinite
recursion in QEMU in render_memory_region()...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/pci-host/versatile.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
index 9238d39..37c7425 100644
--- a/hw/pci-host/versatile.c
+++ b/hw/pci-host/versatile.c
@@ -75,11 +75,19 @@ typedef struct {
/* Containers representing the PCI address spaces */
MemoryRegion pci_io_space;
MemoryRegion pci_mem_space;
+ /* AddressSpace corresponding to pci_mem_space */
+ AddressSpace pci_mem_as;
/* Alias regions into PCI address spaces which we expose as sysbus regions.
* The offsets into pci_mem_space are controlled by the imap registers.
*/
MemoryRegion pci_io_window;
MemoryRegion pci_mem_window[3];
+ /* Alias regions into system address space which we map into PCI
+ * memory space under the control of the SMAP registers.
+ * Note that which one of the BARs is the I/O bar differs for
+ * realview and versatile.
+ */
+ MemoryRegion pci_bar[3];
PCIBus pci_bus;
PCIDevice pci_dev;
@@ -127,10 +135,38 @@ static void pci_vpb_update_all_windows(PCIVPBState *s)
}
}
+static void pci_vpb_update_smap(PCIVPBState *s, int i)
+{
+ /* After a change to the SMAP registers, we need to update
+ * what part of the system address space we're aliasing
+ * into the PCI memory or IO space. (This is the inverse of
+ * the windows controlled by the IMAP registers, which
+ * map parts of PCI space into system space.)
+ */
+ hwaddr offset;
+
+ if (s->realview) {
+ offset = s->smap[i] & 0xf0000000;
+ } else {
+ offset = s->smap[i] << 28;
+ }
+ memory_region_set_alias_offset(&s->pci_bar[i], offset);
+}
+
+static void pci_vpb_update_all_smaps(PCIVPBState *s)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ pci_vpb_update_smap(s, i);
+ }
+}
+
static int pci_vpb_post_load(void *opaque, int version_id)
{
PCIVPBState *s = opaque;
pci_vpb_update_all_windows(s);
+ pci_vpb_update_all_smaps(s);
return 0;
}
@@ -195,6 +231,7 @@ static void pci_vpb_reg_write(void *opaque, hwaddr addr,
{
int win = (addr - PCI_SMAP0) >> 2;
s->smap[win] = val;
+ pci_vpb_update_smap(s, win);
break;
}
default:
@@ -376,6 +413,13 @@ static void pci_vpb_reset(DeviceState *d)
pci_vpb_update_all_windows(s);
}
+static AddressSpace *pci_vpb_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+ PCIVPBState *s = opaque;
+
+ return &s->pci_mem_as;
+}
+
static void pci_vpb_init(Object *obj)
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
@@ -383,12 +427,15 @@ static void pci_vpb_init(Object *obj)
memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32);
memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32);
+ address_space_init(&s->pci_mem_as, &s->pci_mem_space, "pci_mem");
pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), "pci",
&s->pci_mem_space, &s->pci_io_space,
PCI_DEVFN(11, 0), TYPE_PCI_BUS);
h->bus = &s->pci_bus;
+ pci_setup_iommu(&s->pci_bus, pci_vpb_dma_iommu, s);
+
object_initialize(&s->pci_dev, TYPE_VERSATILE_PCI_HOST);
qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
@@ -458,9 +505,34 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp)
static int versatile_pci_host_init(PCIDevice *d)
{
+ int i;
+ PCIVPBState *s = container_of(d->bus, PCIVPBState, pci_bus);
+ int iobar = s->realview ? 2 : 0;
+
pci_set_word(d->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
+
+ /* The host allows its MMIO BARs to be mapped at PCI address zero
+ * (even though the PCI spec says 0 isn't a valid address), and
+ * Linux relies on this for PCI bus-mastering DMA to work. So we
+ * have to emulate this out-of-spec behaviour.
+ */
+ d->cap_present |= QEMU_PCI_ADDR0_ALLOWED;
+
+ /* Create alias regions corresponding to our own BARs */
+ for (i = 0; i < 3; i++) {
+ uint8_t bar_type = PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+ memory_region_init_alias(&s->pci_bar[i], OBJECT(s),
+ "pci-vpb-bar0", get_system_memory(), 0,
+ 0x10000000);
+ if (i == iobar) {
+ bar_type = PCI_BASE_ADDRESS_SPACE_IO;
+ }
+ pci_register_bar(&s->pci_dev, i, bar_type, &s->pci_bar[i]);
+ }
+
return 0;
}
--
1.7.9.5
prev parent reply other threads:[~2013-08-22 18:28 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-22 18:28 [Qemu-devel] [RFC 0/2] Implement versatile PCI IMAP registers Peter Maydell
2013-08-22 18:28 ` [Qemu-devel] [RFC 1/2] hw/pci: Add PCI capability to allow BARs at 0 Peter Maydell
2013-08-22 18:28 ` Peter Maydell [this message]
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=1377196092-7482-3-git-send-email-peter.maydell@linaro.org \
--to=peter.maydell@linaro.org \
--cc=mst@redhat.com \
--cc=patches@linaro.org \
--cc=qemu-devel@nongnu.org \
/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).