@@ -374,6 +374,7 @@ static void xen_enable_tpm(void)
static void xen_arm_init(MachineState *machine)
{
XenArmState *xam = XEN_ARM(machine);
+ DeviceState *dev;
int rc;
if (!xen_enabled()) {
@@ -405,6 +406,11 @@ static void xen_arm_init(MachineState *machine)
xen_enable_tpm();
+ dev = qdev_new("arm-its-xen");
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GUEST_GICV3_ITS_BASE);
+ msi_nonbroken = true;
return;
}
@@ -35,6 +35,11 @@ config ARM_GIC_KVM
default y
depends on ARM_GIC && KVM
+config ARM_GIC_XEN
+ bool
+ default y
+ depends on ARM_GIC && XEN
+
config XICS
bool
new file mode 100644
@@ -0,0 +1,115 @@
+/*
+ * Xen-based ITS implementation for a GICv3-based system
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Written by Pavel Fedin <p.fedin@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "hw/xen/xen-hvm-common.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/runstate.h"
+#include "migration/blocker.h"
+#include "qom/object.h"
+#include "hw/pci/msi.h"
+#include "qemu/log.h"
+
+#define TYPE_XEN_ARM_ITS "arm-its-xen"
+
+static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ printf("ITS read at offset 0x%"PRIx64"\n", offset);
+ *data = 0;
+ return MEMTX_OK;
+}
+
+static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ if (offset == 0x0040 && ((size == 2) || (size == 4))) {
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(opaque);
+ GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
+ int ret = c->send_msi(s, le64_to_cpu(value), attrs.requester_id);
+
+ if (ret < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ITS: Error sending MSI: %s\n", strerror(-ret));
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ITS: Error sending MSI: %s\n", strerror(EINVAL));
+ }
+ return MEMTX_OK;
+}
+static const MemoryRegionOps gicv3_its_trans_ops = {
+ .read_with_attrs = gicv3_its_trans_read,
+ .write_with_attrs = gicv3_its_trans_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int xen_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
+{
+ xendevicemodel_arm_inject_msi(xen_dmod, xen_domid, s->gits_translater_gpa, value, devid);
+ return 0;
+}
+
+static void xen_arm_its_realize(DeviceState *dev, Error **errp)
+{
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(s);
+
+ memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
+ &gicv3_its_trans_ops, s,
+ "translation", ITS_TRANS_SIZE);
+
+ memory_region_init(&s->iomem_main, OBJECT(s), "gicv3_its", ITS_SIZE);
+ memory_region_add_subregion(&s->iomem_main, ITS_CONTROL_SIZE,
+ &s->iomem_its_translation);
+ sysbus_init_mmio(sbd, &s->iomem_main);
+
+ printf("init mmio done\n");
+ msi_nonbroken = true;
+ return;
+}
+
+static void xen_arm_its_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
+
+ dc->realize = xen_arm_its_realize;
+ icc->send_msi = xen_its_send_msi;
+}
+
+static const TypeInfo xen_arm_its_info = {
+ .name = TYPE_XEN_ARM_ITS,
+ .parent = TYPE_ARM_GICV3_ITS_COMMON,
+ .instance_size = sizeof(GICv3ITSState),
+ .class_init = xen_arm_its_class_init,
+};
+
+static void xen_arm_its_register_types(void)
+{
+ type_register_static(&xen_arm_its_info);
+}
+
+type_init(xen_arm_its_register_types)
@@ -31,6 +31,7 @@ specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c
specific_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files('arm_gicv3_cpuif.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
+specific_ss.add(when: 'CONFIG_ARM_GIC_XEN', if_true: files('arm_gicv3_its_xen.c'))
specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
specific_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
specific_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
Introduce the Xen variant of Arm ITS. It is hooked into the mmio subsystem and recieves MSI messages. Upon receiving the MSI messages it gets transfered to the Xen hypervisor with the new device model call for further processing. This change will allow for virtio-pci backends to send MSI interrupts to the Xen guests. Change marked as RFC to get some feedback on the approach while the relevant Xen changes are being reviewed. Link to relevant Xen changes: https://patchwork.kernel.org/project/xen-devel/patch/6a631756a126e73390f95b9e86c69e3286c92f59.1702991909.git.mykyta_poturai@epam.com Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com> --- hw/arm/xen_arm.c | 6 ++ hw/intc/Kconfig | 5 ++ hw/intc/arm_gicv3_its_xen.c | 115 ++++++++++++++++++++++++++++++++++++ hw/intc/meson.build | 1 + 4 files changed, 127 insertions(+) create mode 100644 hw/intc/arm_gicv3_its_xen.c