On 27/11/23 06:20, Gustavo Romero wrote:
Add a new device, ivshmem-flat, which is similar to the ivshmem PCI but
does not require a PCI bus. It's meant to be used on machines like those
with Cortex-M MCUs, which usually lack a PCI/PCIe bus, e.g. lm3s6965evb
and mps2-an385.
The device currently only supports the sysbus bus.
The following is an example on how to create the ivshmem-flat device on
a Stellaris machine:
$ qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic
-net none -chardev stdio,id=con,mux=on
-serial chardev:con -mon chardev=con,mode=readline
-chardev socket,path=/tmp/ivshmem_socket,id=ivf
-device
ivshmem-flat,x-irq-qompath=/machine/unattached/device[1]/nvic/unnamed-gpio-in[0],x-bus-qompath="/sysbus",chardev=ivf
-kernel zephyr_qemu.elf
The new device, just like the ivshmem PCI device, supports both peer
notification via hardware interrupts and shared memory.
The IRQ QOM path for the target machine can be determined by creating
the VM without the ivshmem-flat device, going to the QEMU console and
listing the QOM nodes with 'info qom-tree'. In the Stellaris example
above the input IRQ is in the NVIC IC.
The MMRs for status and control (notification) are mapped to the MMIO
region at 0x400FF000 (default), whilst the shared memory region start
is mapped at addr. 0x40100000 (default), but both addresses can be set
when creating the device by using 'x-bus-address-{mmr,shmem}' options,
respectively.
The device shared memory size can be set using the 'shmem-size' option
and it defaults to 4 MiB, which is the default size of shmem allocated
by the ivshmem server.
Signed-off-by: Gustavo Romero <gustavo.rom...@linaro.org>
---
docs/system/devices/ivshmem-flat.rst | 89 +++++
hw/arm/mps2.c | 2 +
hw/arm/stellaris.c | 5 +-
hw/arm/virt.c | 2 +
hw/core/sysbus-fdt.c | 1 +
hw/misc/Kconfig | 5 +
hw/misc/ivshmem-flat.c | 477 +++++++++++++++++++++++++++
hw/misc/meson.build | 2 +
hw/misc/trace-events | 18 +
include/hw/misc/ivshmem-flat.h | 72 ++++
10 files changed, 672 insertions(+), 1 deletion(-)
create mode 100644 docs/system/devices/ivshmem-flat.rst
create mode 100644 hw/misc/ivshmem-flat.c
create mode 100644 include/hw/misc/ivshmem-flat.h
diff --git a/include/hw/misc/ivshmem-flat.h b/include/hw/misc/ivshmem-flat.h
new file mode 100644
index 0000000000..2f6f7462f6
--- /dev/null
+++ b/include/hw/misc/ivshmem-flat.h
@@ -0,0 +1,72 @@
+/*
+ * Inter-VM Shared Memory Flat Device
+ *
+ * SPDX-FileCopyrightText: 2023 Linaro Ltd.
+ * SPDX-FileContributor: Gustavo Romero <gustavo.rom...@linaro.org>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#ifndef IVSHMEM_FLAT_H
+#define IVSHMEM_FLAT_H
+
I had to include the following headers:
#include "qemu/queue.h"
#include "qemu/event_notifier.h"
#include "chardev/char-fe.h"
#include "exec/memory.h"
#include "qom/object.h"
#include "hw/sysbus.h"
in order to fix:
include/hw/misc/ivshmem-flat.h:50:19: error: field has incomplete type
'EventNotifier' (aka 'struct EventNotifier')
EventNotifier event_notifier;
^
include/hw/misc/ivshmem-flat.h:55:5: error: type name requires a
specifier or qualifier
QTAILQ_ENTRY(IvshmemPeer) next;
^
include/hw/misc/ivshmem-flat.h:62:5: error: unknown type name 'SysBusDevice'
SysBusDevice parent_obj;
^
include/hw/misc/ivshmem-flat.h:70:5: error: unknown type name 'CharBackend'
CharBackend server_chr;
^
include/hw/misc/ivshmem-flat.h:76:18: error: field has incomplete type
'MemoryRegion' (aka 'struct MemoryRegion')
MemoryRegion iomem;
^
+#define IVSHMEM_MAX_VECTOR_NUM 64
+
+#define TYPE_IVSHMEM_FLAT "ivshmem-flat"
+typedef struct IvshmemFTState IvshmemFTState;
+
+DECLARE_INSTANCE_CHECKER(IvshmemFTState, IVSHMEM_FLAT, TYPE_IVSHMEM_FLAT)
+
+/* Ivshmem registers. See ./docs/specs/ivshmem-spec.txt for details. */
+enum ivshmem_registers {
+ INTMASK = 0,
+ INTSTATUS = 4,
+ IVPOSITION = 8,
+ DOORBELL = 12,
+};
+
+typedef struct VectorInfo {
+ EventNotifier event_notifier;
+ uint16_t id;
+} VectorInfo;
+
+typedef struct IvshmemPeer {
+ QTAILQ_ENTRY(IvshmemPeer) next;
+ VectorInfo vector[IVSHMEM_MAX_VECTOR_NUM];
+ int vector_counter;
+ uint16_t id;
+} IvshmemPeer;
+
+struct IvshmemFTState {
+ SysBusDevice parent_obj;
+
+ uint64_t msg_buf;
+ int msg_buffered_bytes;
+
+ QTAILQ_HEAD(, IvshmemPeer) peer;
+ IvshmemPeer own;
+
+ CharBackend server_chr;
+
+ char *bus_qompath;
+
+ /* IRQ */
+ qemu_irq irq;
+ char *irq_qompath;
+
+ /* MMRs */
+ MemoryRegion iomem;
+ uint64_t bus_address_mmr;
+ uint32_t intmask;
+ uint32_t intstatus;
+ uint32_t ivposition;
+ uint32_t doorbell;
+
+ /* Shared memory */
+ MemoryRegion shmem;
+ int shmem_fd;
+ uint32_t shmem_size;
+ uint64_t bus_address_shmem;
+};
+
+#endif /* IVSHMEM_FLAT_H */