@@ -31,3 +31,60 @@ the IRQ mechanism is disabled). The shared memory region is always present.
The MMRs (INTRMASK, INTRSTATUS, IVPOSITION, and DOORBELL registers) offsets at
the MMR region, and their functions, follow the ivshmem spec, so they work
exactly as in the ivshmem PCI device (see ./specs/ivshmem-spec.txt).
+
+
+Device Options
+--------------
+
+The required options to create an ivshmem-flat device are: (a) the UNIX
+socket where the ivshmem server is listening, usually ``/tmp/ivshmem_socket``;
+(b) the address where to map the MMRs (``x-bus-address-iomem=``) in the VM
+memory layout; and (c) the address where to map the shared memory in the VM
+memory layout (``x-bus-address-shmem=``). Both (a) and (b) depend on the VM
+being used, as the MMRs and shmem must be mapped to a region not previously
+occupied in the VM.
+
+Example:
+
+.. parsed-literal::
+
+ |qemu-system-arm| -chardev socket,path=/tmp/ivshmem_socket,id=ivshmem_flat -device ivshmem-flat,chardev=ivshmem_flat,x-irq-qompath='/machine/soc/v7m/nvic/unnamed-gpio-in[0]',x-bus-address-iomem=0x400FF000,x-bus-address-shmem=0x40100000
+
+The other option, ``x-irq-qompath=``, is not required if the user doesn't want
+the device supporting notifications.
+
+``x-irq-qompath``. Used to inform the device what IRQ input line it can attach
+to to enable the notification mechanism (IRQ). The ivshmem-flat device currently
+only supports notification via vector 0. Notification via other vectors are
+ignored. (optional)
+
+Two examples for different machines follow.
+
+Stellaris machine (``-machine lm3s6965evb``):
+
+::
+
+ x-irq-qompath=/machine/soc/v7m/nvic/unnamed-gpio-in[0]
+
+Arm mps2-an385 machine (``-machine mps2-an385``):
+
+::
+
+ x-irq-qompath=/machine/armv7m/nvic/unnamed-gpio-in[0]
+
+The available IRQ input lines on a given VM that the ivshmem-flat device can be
+attached should be found using the QEMU monitor (Ctrl-a + c) with:
+
+(qemu) info qom-tree
+
+``x-bus-address-iomem``. Allows changing the address where the MMRs are mapped
+into the VM memory layout. (required)
+
+ ``x-bus-address-shmem``. Allows changing the address where the shared memory
+region is mapped into the VM memory layout. (required)
+
+``shmem-size``. Allows changing the size (in bytes) of shared memory region.
+Default is 4 MiB, which is the same default used by the ivshmem server, so
+usually it's not necessary to change it. The size must match the size of the
+shared memory reserved and informed by the ivshmem server, otherwise the device
+creation fails. (optional)
@@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
#include "sysemu/tpm.h"
+#include "hw/misc/ivshmem-flat.h"
#include "hw/platform-bus.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
@@ -495,6 +496,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
#endif
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
+ TYPE_BINDING(TYPE_IVSHMEM_FLAT, no_fdt_node),
TYPE_BINDING("", NULL), /* last element */
};
@@ -420,16 +420,86 @@ static bool ivshmem_flat_connect_server(DeviceState *dev, Error **errp)
return true;
}
+static bool ivshmem_flat_sysbus_wire(DeviceState *dev, Error **errp)
+{
+ IvshmemFTState *s = IVSHMEM_FLAT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ if (s->x_sysbus_mmio_addr != UINT64_MAX) {
+ trace_ivshmem_flat_mmio_map(s->x_sysbus_mmio_addr);
+ sysbus_mmio_map(sbd, 0, s->x_sysbus_mmio_addr);
+ } else {
+ error_setg(errp, "No address for iomem (MMRs) specified. Can't create"
+ " ivshmem-flat device. Use 'x-bus-address-iomem'"
+ " option.");
+ return false;
+ }
+
+ if (s->x_sysbus_shmem_addr != UINT64_MAX) {
+ trace_ivshmem_flat_shmem_map(s->x_sysbus_shmem_addr);
+ sysbus_mmio_map(sbd, 1, s->x_sysbus_shmem_addr);
+ } else {
+ error_setg(errp, "No address for shmem specified. Can't create"
+ " ivshmem-flat device. Use 'x-bus-address-shmem'"
+ " option.");
+ return false;
+ }
+
+ /* Check for input IRQ line, if it's provided, connect it. */
+ if (s->x_sysbus_irq_qompath) {
+ Object *oirq;
+ bool ambiguous = false;
+ qemu_irq irq;
+
+ oirq = object_resolve_path_type(s->x_sysbus_irq_qompath, TYPE_IRQ,
+ &ambiguous);
+ if (ambiguous) {
+ error_setg(errp, "Specified IRQ is ambiguous. Can't create"
+ " ivshmem-flat device.");
+ return false;
+ }
+
+ if (!oirq) {
+ error_setg(errp, "Can't resolve IRQ QOM path.");
+ return false;
+ }
+ irq = (qemu_irq)oirq;
+ trace_ivshmem_flat_irq_resolved(s->x_sysbus_irq_qompath);
+
+ /*
+ * Connect device out irq line to interrupt controller input irq line.
+ */
+ sysbus_connect_irq(sbd, 0, irq);
+ } else {
+ /*
+ * If input IRQ is not provided, warn user the device won't be able
+ * to trigger any interrupts.
+ */
+ warn_report("Input IRQ not specified, device won't be able"
+ " to handle IRQs!");
+ }
+
+ return true;
+}
+
static void ivshmem_flat_realize(DeviceState *dev, Error **errp)
{
if (!ivshmem_flat_connect_server(dev, errp)) {
return;
}
+ if (!ivshmem_flat_sysbus_wire(dev, errp)) {
+ return;
+ }
}
static Property ivshmem_flat_props[] = {
DEFINE_PROP_CHR("chardev", IvshmemFTState, server_chr),
DEFINE_PROP_UINT32("shmem-size", IvshmemFTState, shmem_size, 4 * MiB),
+ DEFINE_PROP_STRING("x-irq-qompath", IvshmemFTState, x_sysbus_irq_qompath),
+ DEFINE_PROP_UINT64("x-bus-address-iomem", IvshmemFTState,
+ x_sysbus_mmio_addr, UINT64_MAX),
+ DEFINE_PROP_UINT64("x-bus-address-shmem", IvshmemFTState,
+ x_sysbus_shmem_addr, UINT64_MAX),
DEFINE_PROP_END_OF_LIST(),
};
@@ -438,13 +508,11 @@ static void ivshmem_flat_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->hotpluggable = true;
+ dc->user_creatable = true;
dc->realize = ivshmem_flat_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
device_class_set_props(dc, ivshmem_flat_props);
-
- /* Reason: Must be wired up in code (sysbus MRs and IRQ) */
- dc->user_creatable = false;
}
static const TypeInfo ivshmem_flat_info = {
@@ -25,6 +25,12 @@
* socket
* + QOM property "shmem-size" sets the size of the RAM region shared between
* the device and the ivshmem server
+ * + QOM property "x-bus-address-iomem" is the base address of the I/O region
+ * on the main system bus
+ * + QOM property "x-bus-address-shmem" is the base address of the shared RAM
+ * region on the main system bus
+ * + QOM property "x-irq-qompath" is the QOM path of the interrupt being
+ * notified
* + sysbus MMIO region 0: device I/O mapped registers
* + sysbus MMIO region 1: shared memory with ivshmem server
* + sysbus IRQ 0: single output interrupt
@@ -68,9 +74,11 @@ struct IvshmemFTState {
/* IRQ */
qemu_irq irq;
+ char *x_sysbus_irq_qompath;
/* I/O registers */
MemoryRegion iomem;
+ uint64_t x_sysbus_mmio_addr;
uint32_t intmask;
uint32_t intstatus;
uint32_t ivposition;
@@ -80,6 +88,7 @@ struct IvshmemFTState {
MemoryRegion shmem;
int shmem_fd;
uint32_t shmem_size;
+ uint64_t x_sysbus_shmem_addr;
};
#endif /* IVSHMEM_FLAT_H */