* [Qemu-devel] [RFC 0/2] Implement versatile PCI IMAP registers
@ 2013-08-22 18:28 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 ` [Qemu-devel] [RFC 2/2] hw/pci-host/versatile: Implement IMAP registers Peter Maydell
0 siblings, 2 replies; 3+ messages in thread
From: Peter Maydell @ 2013-08-22 18:28 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael S. Tsirkin, patches
This RFC patchset implements the versatile PCI controller's
IMAP registers correctly. These registers deal with the mapping
of the system address space into PCI space, ie they control
what bits of RAM are written to by bus-mastering PCI devices.
(At the moment we just use the system memory space as the
PCI DMA address space, which means that there is always a
flat 1:1 mapping, which is what Linux happens to expect.)
This is an RFC for two reasons:
(1) I needed to add support to the PCI core code for
"allow this device to respond if its MMIO BARs are
programmed for address zero", and I'm not sure I did
this the right way.
(2) since the core code doesn't forbid a PCI device from
doing a bus-master access back into its own MMIO bars,
it's possible for a 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().
Suggestions for how to avoid this welcome...
thanks
-- PMM
Peter Maydell (2):
hw/pci: Add PCI capability to allow BARs at 0
hw/pci-host/versatile: Implement IMAP registers
hw/pci-host/versatile.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
hw/pci/pci.c | 3 +-
include/hw/pci/pci.h | 3 ++
3 files changed, 77 insertions(+), 1 deletion(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Qemu-devel] [RFC 1/2] hw/pci: Add PCI capability to allow BARs at 0
2013-08-22 18:28 [Qemu-devel] [RFC 0/2] Implement versatile PCI IMAP registers Peter Maydell
@ 2013-08-22 18:28 ` Peter Maydell
2013-08-22 18:28 ` [Qemu-devel] [RFC 2/2] hw/pci-host/versatile: Implement IMAP registers Peter Maydell
1 sibling, 0 replies; 3+ messages in thread
From: Peter Maydell @ 2013-08-22 18:28 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael S. Tsirkin, patches
The PCI specification says that 0 isn't a valid address
for an MMIO bar. However some devices won't object if you
program a BAR at address 0 and will then respond to bus
accesses at that address. (In particular the host
PCI controller for the Versatile/Realview boards behaves
like this, and Linux relies on it for setting up a 1:1
mapping between PCI address space and system address
space for bus-mastering DMA.)
To allow us to model devices with this out-of-spec
quirk, add a new QEMU_PCI_ADDR0_ALLOWED flag to
cap_present which bypasses the "address 0 is not valid"
test in pci_bar_address().
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/pci/pci.c | 3 ++-
include/hw/pci/pci.h | 3 +++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4c004f5..f09d799 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1058,7 +1058,8 @@ static pcibus_t pci_bar_address(PCIDevice *d,
/* XXX: as we cannot support really dynamic
mappings, we handle specific values as invalid
mappings. */
- if (last_addr <= new_addr || new_addr == 0 ||
+ if (last_addr <= new_addr ||
+ (new_addr == 0 && !(d->cap_present & QEMU_PCI_ADDR0_ALLOWED)) ||
last_addr == PCI_BAR_UNMAPPED) {
return PCI_BAR_UNMAPPED;
}
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index ccec2ba..3d6a940 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -157,6 +157,9 @@ enum {
QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
#define QEMU_PCI_SLOTID_BITNR 6
QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR),
+ /* PCI device (in breach of the spec) allows MMIO BAR at address 0 */
+#define QEMU_PCI_ADDR0_ALLOWED_BITNR 7
+ QEMU_PCI_ADDR0_ALLOWED = (1 << QEMU_PCI_ADDR0_ALLOWED_BITNR)
};
#define TYPE_PCI_DEVICE "pci-device"
--
1.7.9.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [Qemu-devel] [RFC 2/2] hw/pci-host/versatile: Implement IMAP registers
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
1 sibling, 0 replies; 3+ messages in thread
From: Peter Maydell @ 2013-08-22 18:28 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael S. Tsirkin, patches
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
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-08-22 18:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [Qemu-devel] [RFC 2/2] hw/pci-host/versatile: Implement IMAP registers Peter Maydell
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).