qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/12] Add SDEI support for arm64
@ 2019-09-24 15:21 Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 01/12] linux-headers: import arm_sdei.h Heyi Guo
                   ` (14 more replies)
  0 siblings, 15 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

As promised, this is the first RFC patch set for arm64 SDEI support.
Key points:
- We propose to only support kvm enabled arm64 virtual machines, for
  non-kvm VMs can emulate EL3 and have Trusted Firmware run on it,
  which has a builtin SDEI dispatcher.
- New kvm capability KVM_CAP_FORWARD_HYPERCALL is added to probe if
  kvm supports forwarding hypercalls, and the capability should be
  enabled explicitly. PSCI can be set as exception for backward
  compatibility.
- We make the dispatcher as a logical device, to save the states
  during migration or save/restore operation; only one instance is
  allowed in one VM.
- We use qemu_irq as the bridge for other qemu modules to switch from
  irq injection to SDEI event trigger after VM binds the interrupt to
  SDEI event. We use qemu_irq_intercept_in() to override qemu_irq
  handler with SDEI event trigger, and a new interface
  qemu_irq_remove_intercept() is added to restore the handler to
  default one (i.e. ARM GIC).

More details are in the commit message of each patch.

Basic tests are done by emulating a watchdog timer and triggering SDEI
event in every 10s.

As this is the first rough RFC, please focus on the interfaces and
framework first. We can refine the code for several rounds after the
big things have been determined.

Please give your comments and suggestions.

Thanks,
HG

Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>

Heyi Guo (12):
  linux-headers: import arm_sdei.h
  arm/sdei: add virtual device framework
  arm/sdei: add support to handle SDEI requests from guest
  arm/sdei: add system reset callback
  arm/sdei: add support to trigger event by GIC interrupt ID
  core/irq: add qemu_irq_remove_intercept interface
  arm/sdei: override qemu_irq handler when binding interrupt
  arm/sdei: add support to register interrupt bind notifier
  linux-headers/kvm.h: add capability to forward hypercall
  arm/sdei: check KVM cap and enable SDEI
  arm/kvm: handle guest exit of hypercall
  virt/acpi: add SDEI table if SDEI is enabled

 hw/arm/virt-acpi-build.c       |   16 +
 hw/core/irq.c                  |   11 +
 include/hw/acpi/acpi-defs.h    |    5 +
 include/hw/irq.h               |    8 +-
 linux-headers/linux/arm_sdei.h |   73 ++
 linux-headers/linux/kvm.h      |    3 +
 target/arm/Makefile.objs       |    1 +
 target/arm/kvm.c               |   17 +
 target/arm/sdei.c              | 1518 ++++++++++++++++++++++++++++++++++++++++
 target/arm/sdei.h              |   60 ++
 target/arm/sdei_int.h          |  109 +++
 11 files changed, 1819 insertions(+), 2 deletions(-)
 create mode 100644 linux-headers/linux/arm_sdei.h
 create mode 100644 target/arm/sdei.c
 create mode 100644 target/arm/sdei.h
 create mode 100644 target/arm/sdei_int.h

-- 
1.8.3.1



^ permalink raw reply	[flat|nested] 25+ messages in thread

* [RFC PATCH 01/12] linux-headers: import arm_sdei.h
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:39   ` Michael S. Tsirkin
  2019-09-24 15:21 ` [RFC PATCH 02/12] arm/sdei: add virtual device framework Heyi Guo
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	Cornelia Huck, James Morse, Paolo Bonzini, Heyi Guo,
	wanghaibin.wang, Dave Martin

Import Linux header file include/uapi/linux/arm_sdei.h from kernel
v5.3 release.

This is to prepare for qemu SDEI emulation.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
---
 linux-headers/linux/arm_sdei.h | 73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 linux-headers/linux/arm_sdei.h

diff --git a/linux-headers/linux/arm_sdei.h b/linux-headers/linux/arm_sdei.h
new file mode 100644
index 0000000..af0630b
--- /dev/null
+++ b/linux-headers/linux/arm_sdei.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (C) 2017 Arm Ltd. */
+#ifndef _UAPI_LINUX_ARM_SDEI_H
+#define _UAPI_LINUX_ARM_SDEI_H
+
+#define SDEI_1_0_FN_BASE			0xC4000020
+#define SDEI_1_0_MASK				0xFFFFFFE0
+#define SDEI_1_0_FN(n)				(SDEI_1_0_FN_BASE + (n))
+
+#define SDEI_1_0_FN_SDEI_VERSION			SDEI_1_0_FN(0x00)
+#define SDEI_1_0_FN_SDEI_EVENT_REGISTER			SDEI_1_0_FN(0x01)
+#define SDEI_1_0_FN_SDEI_EVENT_ENABLE			SDEI_1_0_FN(0x02)
+#define SDEI_1_0_FN_SDEI_EVENT_DISABLE			SDEI_1_0_FN(0x03)
+#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT			SDEI_1_0_FN(0x04)
+#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE			SDEI_1_0_FN(0x05)
+#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME	SDEI_1_0_FN(0x06)
+#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER		SDEI_1_0_FN(0x07)
+#define SDEI_1_0_FN_SDEI_EVENT_STATUS			SDEI_1_0_FN(0x08)
+#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO			SDEI_1_0_FN(0x09)
+#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET		SDEI_1_0_FN(0x0A)
+#define SDEI_1_0_FN_SDEI_PE_MASK			SDEI_1_0_FN(0x0B)
+#define SDEI_1_0_FN_SDEI_PE_UNMASK			SDEI_1_0_FN(0x0C)
+#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND			SDEI_1_0_FN(0x0D)
+#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE		SDEI_1_0_FN(0x0E)
+#define SDEI_1_0_FN_SDEI_PRIVATE_RESET			SDEI_1_0_FN(0x11)
+#define SDEI_1_0_FN_SDEI_SHARED_RESET			SDEI_1_0_FN(0x12)
+
+#define SDEI_VERSION_MAJOR_SHIFT			48
+#define SDEI_VERSION_MAJOR_MASK				0x7fff
+#define SDEI_VERSION_MINOR_SHIFT			32
+#define SDEI_VERSION_MINOR_MASK				0xffff
+#define SDEI_VERSION_VENDOR_SHIFT			0
+#define SDEI_VERSION_VENDOR_MASK			0xffffffff
+
+#define SDEI_VERSION_MAJOR(x)	(x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK)
+#define SDEI_VERSION_MINOR(x)	(x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK)
+#define SDEI_VERSION_VENDOR(x)	(x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK)
+
+/* SDEI return values */
+#define SDEI_SUCCESS		0
+#define SDEI_NOT_SUPPORTED	-1
+#define SDEI_INVALID_PARAMETERS	-2
+#define SDEI_DENIED		-3
+#define SDEI_PENDING		-5
+#define SDEI_OUT_OF_RESOURCE	-10
+
+/* EVENT_REGISTER flags */
+#define SDEI_EVENT_REGISTER_RM_ANY	0
+#define SDEI_EVENT_REGISTER_RM_PE	1
+
+/* EVENT_STATUS return value bits */
+#define SDEI_EVENT_STATUS_RUNNING	2
+#define SDEI_EVENT_STATUS_ENABLED	1
+#define SDEI_EVENT_STATUS_REGISTERED	0
+
+/* EVENT_COMPLETE status values */
+#define SDEI_EV_HANDLED	0
+#define SDEI_EV_FAILED	1
+
+/* GET_INFO values */
+#define SDEI_EVENT_INFO_EV_TYPE			0
+#define SDEI_EVENT_INFO_EV_SIGNALED		1
+#define SDEI_EVENT_INFO_EV_PRIORITY		2
+#define SDEI_EVENT_INFO_EV_ROUTING_MODE		3
+#define SDEI_EVENT_INFO_EV_ROUTING_AFF		4
+
+/* and their results */
+#define SDEI_EVENT_TYPE_PRIVATE			0
+#define SDEI_EVENT_TYPE_SHARED			1
+#define SDEI_EVENT_PRIORITY_NORMAL		0
+#define SDEI_EVENT_PRIORITY_CRITICAL		1
+
+#endif /* _UAPI_LINUX_ARM_SDEI_H */
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 02/12] arm/sdei: add virtual device framework
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 01/12] linux-headers: import arm_sdei.h Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 03/12] arm/sdei: add support to handle SDEI requests from guest Heyi Guo
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, James Morse, Marc Zyngier,
	Jingyi Wang, Heyi Guo, wanghaibin.wang, Dave Martin

SDEI is useful to emulate NMI on arm64 platforms. To support SDEI in
virtual machine with KVM enabled, we choose to implement SDEI
interfaces in qemu. It is targeted for KVM mode only, for the full
user space emulation can also emulate secure world and have ARM
Trusted Firmware to run on emulated EL3.

- We create a logical SDEI device to hold the states of SDEI services,
  to support VM migration.
- Only one SDEI virtual device is allowed in the whole VM to provide
  SDEI services.
- We create struct QemuSDE to hold states of each SDEI event, and
  private events with the same ID on different CPUs have their own
  QemuSDE instance.
- We create struct QemuSDEProp to hold properties of each SDEI event,
  so all private instances with the same ID will pointed to the same
  QemuSDEProp.
- We create struct QemuSDECpu to hold CPU/PE states, including the
  interrupted CPU context.
- Slot numbers for private and shared event are fixed, for guests
  cannot request more interrupt binds than BIND_SLOTS in SDEI_FEATURES
  call.
- The first PRIVATE_SLOT_COUNT slots in property array are for private
  events, and the next SHARED_SLOT_COUNT slots are for shared events.
- We use property slot index as lower bit for each allocated event
  number, so that we can get property easily from valid input event
  number, as well as the QemuSDE instance.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/Makefile.objs |   1 +
 target/arm/sdei.c        | 351 +++++++++++++++++++++++++++++++++++++++++++++++
 target/arm/sdei_int.h    | 106 ++++++++++++++
 3 files changed, 458 insertions(+)
 create mode 100644 target/arm/sdei.c
 create mode 100644 target/arm/sdei_int.h

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index cf26c16..674109d 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -7,6 +7,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o
 obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
 
 obj-$(CONFIG_KVM) += kvm.o
+obj-$(CONFIG_KVM) += sdei.o
 obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
 obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
new file mode 100644
index 0000000..7f12d69
--- /dev/null
+++ b/target/arm/sdei.c
@@ -0,0 +1,351 @@
+/*
+ * ARM SDEI emulation for ARM64 virtual machine with KVM
+ *
+ * Copyright (c) 2019 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Heyi Guo <guoheyi@huawei.com>
+ *    Jingyi Wang <wangjingyi11@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "arm-powerctl.h"
+#include "qemu/timer.h"
+#include "sysemu/kvm.h"
+#include "sysemu/kvm_int.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/reset.h"
+#include "qemu/error-report.h"
+#include "sdei_int.h"
+#include "internals.h"
+#include "hw/boards.h"
+#include "hw/intc/arm_gicv3.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qom/object.h"
+
+#define TYPE_QEMU_SDEI "qemu_sdei"
+#define QEMU_SDEI(obj) OBJECT_CHECK(QemuSDEState, (obj), TYPE_QEMU_SDEI)
+
+static QemuSDEState *sde_state;
+
+static void qemu_sde_prop_init(QemuSDEState *s)
+{
+    QemuSDEProp *sde_props = s->sde_props_state;
+    int i;
+    for (i = 0; i < ARRAY_SIZE(s->sde_props_state); i++) {
+        sde_props[i].event_id = SDEI_INVALID_EVENT_ID;
+        sde_props[i].interrupt = SDEI_INVALID_INTERRUPT;
+        sde_props[i].sde_index = i >= PRIVATE_SLOT_COUNT ?
+                                 i - PRIVATE_SLOT_COUNT : i;
+
+        qemu_mutex_init(&(sde_props[i].lock));
+        sde_props[i].refcount = 0;
+    }
+    sde_props[0].event_id = SDEI_STD_EVT_SOFTWARE_SIGNAL;
+    sde_props[0].interrupt = SDEI_INVALID_INTERRUPT;
+    sde_props[0].is_shared = false;
+    sde_props[0].is_critical = false;
+
+    for (i = 0; i < ARRAY_SIZE(s->irq_map); i++) {
+        s->irq_map[i] = SDEI_INVALID_EVENT_ID;
+    }
+
+    qemu_mutex_init(&s->sdei_interrupt_bind_lock);
+}
+
+static void qemu_sde_cpu_init(QemuSDEState *s)
+{
+    int i;
+    QemuSDECpu *sde_cpus;
+
+    s->sdei_max_cpus = current_machine->smp.max_cpus;
+    s->sde_cpus = g_new0(QemuSDECpu, s->sdei_max_cpus);
+    sde_cpus = s->sde_cpus;
+    for (i = 0; i < s->sdei_max_cpus; i++) {
+        sde_cpus[i].masked = true;
+        sde_cpus[i].critical_running_event = SDEI_INVALID_EVENT_ID;
+        sde_cpus[i].normal_running_event = SDEI_INVALID_EVENT_ID;
+    }
+}
+
+static bool is_valid_event_number(int32_t event)
+{
+    int32_t slot_id;
+
+    if (event < 0 || (event & 0x3F000000)) {
+        return false;
+    }
+
+    slot_id = SDEI_EVENT_TO_SLOT(event);
+    if (slot_id >= PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool is_valid_event(QemuSDEState *s, int32_t event)
+{
+    if (!is_valid_event_number(event)) {
+        return false;
+    }
+
+    if (s->sde_props_state[SDEI_EVENT_TO_SLOT(event)].event_id != event) {
+        return false;
+    }
+
+    return true;
+}
+
+static QemuSDEProp *get_sde_prop_no_lock(QemuSDEState *s, int32_t event)
+{
+    if (!is_valid_event(s, event)) {
+        return NULL;
+    }
+
+    return &s->sde_props_state[SDEI_EVENT_TO_SLOT(event)];
+}
+
+static void qemu_shared_sde_init(QemuSDEState *s)
+{
+    int i;
+    for (i = 0; i < SHARED_SLOT_COUNT; i++) {
+        QemuSDE *sde;
+        sde = s->shared_sde_array[i];
+        if (!sde) {
+            sde = g_new0(QemuSDE, 1);
+        }
+        sde->event_id = SDEI_INVALID_EVENT_ID;
+        sde->enabled = false;
+        sde->running = false;
+        sde->pending = false;
+        sde->unregister_pending = false;
+        qemu_mutex_init(&sde->lock);
+        s->shared_sde_array[i] = sde;
+    }
+}
+
+static void qemu_private_sde_init(QemuSDEState *s)
+{
+    int i, j;
+    for (i = 0; i < s->sdei_max_cpus; i++) {
+        QemuSDE **array = s->sde_cpus[i].private_sde_array;
+        for (j = 0; j < PRIVATE_SLOT_COUNT; j++) {
+            QemuSDE *sde;
+            sde = array[j];
+            if (!sde) {
+                sde = g_new0(QemuSDE, 1);
+            }
+            sde->event_id = SDEI_INVALID_EVENT_ID;
+            sde->enabled = false;
+            sde->running = false;
+            sde->pending = false;
+            sde->unregister_pending = false;
+            qemu_mutex_init(&sde->lock);
+            array[j] = sde;
+        }
+    }
+}
+
+static void qemu_sde_init(QemuSDEState *s)
+{
+    qemu_sde_prop_init(s);
+    qemu_sde_cpu_init(s);
+
+    qemu_shared_sde_init(s);
+    qemu_private_sde_init(s);
+}
+
+static int qemu_sdei_pre_save(void *opaque)
+{
+    QemuSDEState *s = opaque;
+    QemuSDE **array;
+    int i, j;
+
+    for (i = 0; i < s->sdei_max_cpus; i++) {
+        array = s->sde_cpus[i].private_sde_array;
+        for (j = 0; j < PRIVATE_SLOT_COUNT; j++) {
+            QemuSDE *sde = array[j];
+            if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+                sde->event_id = sde->prop->event_id;
+                sde->cpu_affinity = ARM_CPU(sde->target_cpu)->mp_affinity;
+            }
+        }
+    }
+
+    array = s->shared_sde_array;
+    for (j = 0; j < SHARED_SLOT_COUNT; j++) {
+        QemuSDE *sde = array[j];
+        if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+            sde->event_id = sde->prop->event_id;
+            sde->cpu_affinity = ARM_CPU(sde->target_cpu)->mp_affinity;
+        }
+    }
+
+    return 0;
+}
+
+
+static int qemu_sdei_post_load(void *opaque, int version_id)
+{
+    QemuSDEState *s = opaque;
+    QemuSDEProp *sde_props = s->sde_props_state;
+    QemuSDE **array;
+    int i, j;
+
+    for (i = 0; i < s->sdei_max_cpus; i++) {
+        array = s->sde_cpus[i].private_sde_array;
+        for (j = 0; j < PRIVATE_SLOT_COUNT; j++) {
+            QemuSDE *sde = array[j];
+            if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+                sde->prop = get_sde_prop_no_lock(s, sde->event_id);
+                sde->target_cpu = arm_get_cpu_by_id(sde->cpu_affinity);
+            }
+        }
+    }
+
+    array = s->shared_sde_array;
+    for (j = 0; j < SHARED_SLOT_COUNT; j++) {
+        QemuSDE *sde = array[j];
+        if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+            sde->prop = get_sde_prop_no_lock(s, sde->event_id);
+            sde->target_cpu = arm_get_cpu_by_id(sde->cpu_affinity);
+        }
+    }
+
+    for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+        if (sde_props[i].interrupt != SDEI_INVALID_INTERRUPT) {
+            s->irq_map[sde_props[i].interrupt] = sde_props[i].event_id;
+        }
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_sdes = {
+    .name = "qemu_sdei/sdes",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(enabled, QemuSDE),
+        VMSTATE_BOOL(running, QemuSDE),
+        VMSTATE_BOOL(pending, QemuSDE),
+        VMSTATE_BOOL(unregister_pending, QemuSDE),
+        VMSTATE_UINT64(ep_address, QemuSDE),
+        VMSTATE_UINT64(ep_argument, QemuSDE),
+        VMSTATE_UINT64(routing_mode, QemuSDE),
+        VMSTATE_INT32(event_id, QemuSDE),
+        VMSTATE_UINT64(cpu_affinity, QemuSDE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_sde_props = {
+    .name = "qemu_sdei/sde_props",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(event_id, QemuSDEProp),
+        VMSTATE_INT32(interrupt, QemuSDEProp),
+        VMSTATE_BOOL(is_shared, QemuSDEProp),
+        VMSTATE_BOOL(is_critical, QemuSDEProp),
+        VMSTATE_INT32(sde_index, QemuSDEProp),
+        VMSTATE_INT32(refcount, QemuSDEProp),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_sde_cpu = {
+    .name = "qemu_sdei/sde_cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(private_sde_array, QemuSDECpu,
+                                           PRIVATE_SLOT_COUNT, 1,
+                                           vmstate_sdes, QemuSDE),
+        VMSTATE_UINT64_ARRAY(ctx[0].xregs, QemuSDECpu, 18),
+        VMSTATE_UINT64_ARRAY(ctx[1].xregs, QemuSDECpu, 18),
+        VMSTATE_UINT64(ctx[0].pc, QemuSDECpu),
+        VMSTATE_UINT64(ctx[1].pc, QemuSDECpu),
+        VMSTATE_UINT32(ctx[0].pstate, QemuSDECpu),
+        VMSTATE_UINT32(ctx[1].pstate, QemuSDECpu),
+        VMSTATE_INT32(critical_running_event, QemuSDECpu),
+        VMSTATE_INT32(normal_running_event, QemuSDECpu),
+        VMSTATE_BOOL(masked, QemuSDECpu),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_sde_state = {
+    .name = "qemu_sdei",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = qemu_sdei_pre_save,
+    .post_load = qemu_sdei_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(sde_props_state, QemuSDEState,
+                             PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT, 1,
+                             vmstate_sde_props, QemuSDEProp),
+        VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(shared_sde_array, QemuSDEState,
+                                           SHARED_SLOT_COUNT, 1,
+                                           vmstate_sdes, QemuSDE),
+        VMSTATE_STRUCT_VARRAY_POINTER_INT32(sde_cpus, QemuSDEState,
+                                            sdei_max_cpus,
+                                            vmstate_sde_cpu, QemuSDECpu),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static void sdei_initfn(Object *obj)
+{
+    QemuSDEState *s = QEMU_SDEI(obj);
+
+    if (sde_state) {
+        error_report("Only one SDEI dispatcher is allowed!");
+        abort();
+    }
+    sde_state = s;
+
+    qemu_sde_init(s);
+}
+
+static void qemu_sde_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "SDEI_QEMU";
+    dc->vmsd = &vmstate_sde_state;
+    dc->user_creatable = true;
+}
+
+static const TypeInfo sde_qemu_info = {
+    .name          = TYPE_QEMU_SDEI,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(QemuSDEState),
+    .instance_init = sdei_initfn,
+    .class_init    = qemu_sde_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&sde_qemu_info);
+}
+
+type_init(register_types);
diff --git a/target/arm/sdei_int.h b/target/arm/sdei_int.h
new file mode 100644
index 0000000..7f69507
--- /dev/null
+++ b/target/arm/sdei_int.h
@@ -0,0 +1,106 @@
+/*
+ * ARM SDEI emulation internal interfaces
+ *
+ * Copyright (c) 2019 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Heyi Guo <guoheyi@huawei.com>
+ *    Jingyi Wang <wangjingyi11@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SDEI_INT_H
+#define QEMU_SDEI_INT_H
+
+#include <linux/kvm.h>
+#include <linux/arm_sdei.h>
+#include <asm-arm64/kvm.h>
+#include "hw/intc/arm_gic_common.h"
+#include "qemu/thread.h"
+
+#define SDEI_STD_EVT_SOFTWARE_SIGNAL        0
+#define SDEI_FEATURE_BIND_SLOTS             0
+#define SDEI_PARAM_MAX                      18
+
+#define PRIVATE_SLOT_COUNT                  16
+#define PLAT_PRIVATE_SLOT_COUNT             8
+#define SHARED_SLOT_COUNT                   32
+#define PLAT_SHARED_SLOT_COUNT              16
+#define SDEI_INVALID_INTERRUPT              -1
+#define SDEI_INVALID_EVENT_ID               -1
+
+#define SDEI_EVENT_TO_SLOT(event)           ((event) & 0xFFFFFF)
+#define SDEI_IS_SHARED_EVENT(event)         \
+    (SDEI_EVENT_TO_SLOT(event) >= PRIVATE_SLOT_COUNT)
+
+typedef enum {
+    SDEI_PRIO_NORMAL        = 0,
+    SDEI_PRIO_CRITICAL      = 1,
+} QemuSDEIPriority;
+
+typedef struct QemuSDEProp {
+    QemuMutex       lock;
+    int32_t         event_id;
+    int             interrupt;
+    bool            is_shared;
+    bool            is_critical;
+    /* This is the internal index for private or shared SDE */
+    int             sde_index;
+    int             refcount;
+} QemuSDEProp;
+
+typedef struct QemuSDE {
+    QemuSDEProp     *prop;
+    CPUState        *target_cpu;
+    QemuMutex       lock;
+    bool            enabled;
+    bool            running;
+    bool            pending;
+    bool            unregister_pending;
+    uint64_t        ep_address;
+    uint64_t        ep_argument;
+    uint64_t        routing_mode;
+    int32_t         event_id;
+    /*
+     * For it is not easy to save the pointer target_cpu during migration, we
+     * add below field to save the corresponding numerical values.
+     */
+    uint64_t        cpu_affinity;
+} QemuSDE;
+
+typedef struct QemuSDECpuCtx {
+    uint64_t        xregs[18];
+    uint64_t        pc;
+    uint32_t        pstate;
+} QemuSDECpuCtx;
+
+typedef struct QemuSDECpu {
+    QemuSDE         *private_sde_array[PRIVATE_SLOT_COUNT];
+    QemuSDECpuCtx   ctx[2];
+    bool            masked;
+    int32_t         critical_running_event;
+    int32_t         normal_running_event;
+} QemuSDECpu;
+
+typedef struct QemuSDEState {
+    DeviceState     parent_obj;
+    QemuSDEProp     sde_props_state[PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT];
+    QemuSDECpu      *sde_cpus;
+    int             sdei_max_cpus;
+    QemuSDE         *shared_sde_array[SHARED_SLOT_COUNT];
+    int32_t         irq_map[GIC_MAXIRQ];
+    QemuMutex       sdei_interrupt_bind_lock;
+} QemuSDEState;
+
+#endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 03/12] arm/sdei: add support to handle SDEI requests from guest
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 01/12] linux-headers: import arm_sdei.h Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 02/12] arm/sdei: add virtual device framework Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 04/12] arm/sdei: add system reset callback Heyi Guo
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, James Morse, Marc Zyngier,
	Jingyi Wang, Heyi Guo, wanghaibin.wang, Dave Martin

Add support for all interfaces defined in ARM SDEI 1.0 spec.

http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf

The exit reason KVM_EXIT_HYPERCALL is used to indicate it is an
HVC/SMC forward, and the structure kvm_run->hypercall is used to pass
arguments and return values between KVM and qemu:
Input:
  nr: the immediate value of SMC/HVC calls; not really used today.
  args[6]: x0..x5 (This is not fully conform with SMCCC which requires
           x6 as argument as well, but we can use GET_ONE_REG ioctl
           for such rare case).
Return:
  args[0..3]: x0..x3 as defined in SMCCC. We rely on KVM to extract
              args[0..3] and write them to x0..x3 when hypercall exit
              returns.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c | 911 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 target/arm/sdei.h |  34 ++
 2 files changed, 945 insertions(+)
 create mode 100644 target/arm/sdei.h

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 7f12d69..b40fa36 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -29,6 +29,7 @@
 #include "sysemu/sysemu.h"
 #include "sysemu/reset.h"
 #include "qemu/error-report.h"
+#include "sdei.h"
 #include "sdei_int.h"
 #include "internals.h"
 #include "hw/boards.h"
@@ -84,6 +85,12 @@ static void qemu_sde_cpu_init(QemuSDEState *s)
     }
 }
 
+static inline QemuSDECpu *get_sde_cpu(QemuSDEState *s, CPUState *cs)
+{
+    assert(cs->cpu_index < s->sdei_max_cpus);
+    return &s->sde_cpus[cs->cpu_index];
+}
+
 static bool is_valid_event_number(int32_t event)
 {
     int32_t slot_id;
@@ -122,6 +129,910 @@ static QemuSDEProp *get_sde_prop_no_lock(QemuSDEState *s, int32_t event)
     return &s->sde_props_state[SDEI_EVENT_TO_SLOT(event)];
 }
 
+static QemuSDEProp *get_sde_prop(QemuSDEState *s, int32_t event)
+{
+    QemuSDEProp *sde_props = s->sde_props_state;
+
+    if (!is_valid_event_number(event)) {
+        return NULL;
+    }
+
+    event = SDEI_EVENT_TO_SLOT(event);
+
+    qemu_mutex_lock(&sde_props[event].lock);
+    if (sde_props[event].event_id < 0) {
+        qemu_mutex_unlock(&sde_props[event].lock);
+        return NULL;
+    }
+    return &sde_props[event];
+}
+
+static void put_sde_prop(QemuSDEProp *prop)
+{
+    qemu_mutex_unlock(&prop->lock);
+}
+
+static void sde_slot_lock(QemuSDE *sde, CPUState *cs)
+{
+    qemu_mutex_lock(&sde->lock);
+}
+
+static void sde_slot_unlock(QemuSDE *sde, CPUState *cs)
+{
+    qemu_mutex_unlock(&sde->lock);
+}
+
+/*
+ * It will always return a pointer to a preallocated sde; event number must be
+ * validated before calling this function.
+ */
+static QemuSDE *get_sde_no_check(QemuSDEState *s, int32_t event, CPUState *cs)
+{
+    QemuSDE **array = s->sde_cpus[cs->cpu_index].private_sde_array;
+    int32_t sde_index = SDEI_EVENT_TO_SLOT(event);
+    QemuSDE *sde;
+
+    if (SDEI_IS_SHARED_EVENT(event)) {
+        array = s->shared_sde_array;
+        sde_index -= PRIVATE_SLOT_COUNT;
+    }
+
+    sde = array[sde_index];
+    sde_slot_lock(sde, cs);
+    return sde;
+}
+
+static void put_sde(QemuSDE *sde, CPUState *cs)
+{
+    sde_slot_unlock(sde, cs);
+}
+
+static inline bool is_sde_nested(QemuSDECpu *sde_cpu)
+{
+    return sde_cpu->critical_running_event >= 0 &&
+           sde_cpu->normal_running_event >= 0;
+}
+
+static int32_t get_running_sde(QemuSDEState *s, CPUState *cs)
+{
+    QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+
+    if (sde_cpu->critical_running_event >= 0) {
+        return sde_cpu->critical_running_event;
+    }
+    return sde_cpu->normal_running_event;
+}
+
+static void override_return_value(CPUState *cs, uint64_t *args)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        args[i] = env->xregs[i];
+    }
+}
+
+static void sde_save_cpu_ctx(CPUState *cs, QemuSDECpu *sde_cpu, bool critical)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+    memcpy(ctx->xregs, env->xregs, sizeof(ctx->xregs));
+    ctx->pc = env->pc;
+    ctx->pstate = pstate_read(env);
+}
+
+static void sde_restore_cpu_ctx(QemuSDEState *s, CPUState *cs, bool critical)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+    QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+    /*
+     * TODO: we need to optimize to only restore affected registers by calling
+     * ioctl individialy
+     */
+    kvm_arch_get_registers(cs);
+
+    env->aarch64 = ((ctx->pstate & PSTATE_nRW) == 0);
+    memcpy(env->xregs, ctx->xregs, sizeof(ctx->xregs));
+    env->pc = ctx->pc;
+    pstate_write(env, ctx->pstate);
+    aarch64_restore_sp(env, (env->pstate >> 2) & 3);
+}
+
+static void sde_restore_cpu_ctx_for_resume(QemuSDEState *s,
+                                           CPUState *cs,
+                                           bool critical,
+                                           uint64_t resume_addr)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+    QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+    /*
+     * TODO: we need to optimize to only restore affected registers by calling
+     * ioctl individialy
+     */
+    kvm_arch_get_registers(cs);
+
+    memcpy(env->xregs, ctx->xregs, sizeof(ctx->xregs));
+    env->pc = resume_addr;
+    env->aarch64 = 1;
+    /* Constructe pstate in pstate_read() */
+    env->daif = 0xF << 6;
+    /* Clear nRW/M[4] and M[3:0] */
+    env->pstate &= ~0x1F;
+    /* Set exception mode to EL1h */
+    env->pstate |= PSTATE_MODE_EL1h;
+    env->elr_el[1] = ctx->pc;
+    env->banked_spsr[KVM_SPSR_EL1 + 1] = ctx->pstate;
+    aarch64_restore_sp(env, 1);
+}
+
+static void sde_build_cpu_ctx(CPUState *cs, QemuSDECpu *sde_cpu, QemuSDE *sde)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+
+    env->xregs[0] = sde->prop->event_id;
+    env->xregs[1] = sde->ep_argument;
+    env->xregs[2] = env->pc;
+    env->xregs[3] = pstate_read(env);
+    env->pc = sde->ep_address;
+    env->aarch64 = 1;
+    /* Constructe pstate in pstate_read() */
+    env->daif = 0xF << 6;
+    /* Clear nRW/M[4] and M[3:0] */
+    env->pstate &= ~0x1F;
+    /* Set exception mode to EL1h */
+    env->pstate |= PSTATE_MODE_EL1h;
+    aarch64_restore_sp(env, 1);
+}
+
+static void trigger_sde(CPUState *cs, run_on_cpu_data data)
+{
+    QemuSDEState *s = sde_state;
+    QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+    int32_t event = data.host_int;
+    QemuSDE *sde;
+
+    assert(cs == current_cpu);
+
+    if (sde_cpu->masked || sde_cpu->critical_running_event >= 0) {
+        return;
+    }
+
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        /* Some race condition happens! */
+        put_sde(sde, cs);
+        return;
+    }
+
+    if (sde_cpu->normal_running_event >= 0 && !sde->prop->is_critical) {
+        put_sde(sde, cs);
+        return;
+    }
+
+    if (!sde->enabled || !sde->pending || sde->running) {
+        /* Some race condition happens! */
+        put_sde(sde, cs);
+        return;
+    }
+
+    sde->pending = false;
+    sde->running = true;
+
+    if (sde->prop->is_critical) {
+        sde_cpu->critical_running_event = sde->prop->event_id;
+    } else {
+        sde_cpu->normal_running_event = sde->prop->event_id;
+    }
+
+    kvm_arch_get_registers(cs);
+    sde_save_cpu_ctx(cs, sde_cpu, sde->prop->is_critical);
+    sde_build_cpu_ctx(cs, sde_cpu, sde);
+    kvm_arch_put_registers(cs, 1);
+    put_sde(sde, cs);
+}
+
+static int64_t dispatch_single(QemuSDEState *s, QemuSDE *sde, CPUState *cs)
+{
+    int32_t event = sde->prop->event_id;
+    bool pending = sde->pending;
+    bool enabled = sde->enabled;
+    CPUState *target = sde->target_cpu;
+    put_sde(sde, cs);
+
+    if (pending && enabled) {
+        /*
+         * TODO: we need to find a free-unmasked PE to trigger for shared
+         * unpinned event
+         */
+        async_run_on_cpu(target, trigger_sde,
+                         RUN_ON_CPU_HOST_INT(event));
+    }
+    return SDEI_SUCCESS;
+}
+
+static void dispatch_cpu(QemuSDEState *s, CPUState *cs, bool is_critical)
+{
+    QemuSDE *sde;
+    int i;
+
+    for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+        sde = get_sde_no_check(s, i, cs);
+        if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+            put_sde(sde, cs);
+            continue;
+        }
+        if (sde->prop->is_critical != is_critical) {
+            put_sde(sde, cs);
+            continue;
+        }
+        if (!sde->enabled || !sde->pending || sde->running ||
+            sde->target_cpu != cs) {
+            put_sde(sde, cs);
+            continue;
+        }
+
+        dispatch_single(s, sde, cs);
+    }
+}
+
+static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
+                                    bool is_shared, int intid)
+{
+    int index;
+    int start = 0;
+    int count = PRIVATE_SLOT_COUNT;
+    int32_t event;
+    QemuSDEProp *sde_props = s->sde_props_state;
+
+    if (is_shared) {
+        start = PRIVATE_SLOT_COUNT;
+        count = PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT;
+    }
+
+    qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+    for (index = start; index < count; index++) {
+        qemu_mutex_lock(&sde_props[index].lock);
+        if (sde_props[index].interrupt == intid) {
+            event = sde_props[index].event_id;
+            qemu_mutex_unlock(&sde_props[index].lock);
+            qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+            return event;
+        }
+        qemu_mutex_unlock(&sde_props[index].lock);
+    }
+
+    for (index = start; index < count; index++) {
+        qemu_mutex_lock(&sde_props[index].lock);
+        if (sde_props[index].event_id < 0) {
+            event = sde_props[index].event_id = 0x40000000 | index;
+            sde_props[index].interrupt = intid;
+            sde_props[index].is_shared = is_shared;
+            sde_props[index].is_critical = is_critical;
+            s->irq_map[intid] = event;
+            qemu_mutex_unlock(&sde_props[index].lock);
+            qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+            return event;
+        }
+        qemu_mutex_unlock(&sde_props[index].lock);
+    }
+    qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+    return SDEI_OUT_OF_RESOURCE;
+}
+
+static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
+{
+    int32_t ret = SDEI_SUCCESS;
+    if (atomic_read(&prop->refcount) > 0) {
+        ret = SDEI_DENIED;
+        goto unlock_return;
+    }
+
+    s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
+    prop->event_id = SDEI_INVALID_EVENT_ID;
+    prop->interrupt = SDEI_INVALID_INTERRUPT;
+
+unlock_return:
+    qemu_mutex_unlock(&prop->lock);
+    qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+    return ret;
+}
+
+typedef int64_t (*sdei_single_function)(QemuSDEState *s,
+                                        CPUState *cs,
+                                        struct kvm_run *run);
+
+static int64_t sdei_version(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
+{
+    return (1ULL << SDEI_VERSION_MAJOR_SHIFT) |
+           (0ULL << SDEI_VERSION_MINOR_SHIFT);
+}
+
+static int64_t unregister_single_sde(QemuSDEState *s, int32_t event,
+                                     CPUState *cs, bool force)
+{
+    QemuSDE     *sde;
+    QemuSDEProp *prop;
+    int         ret = 0;
+
+    prop = get_sde_prop(s, event);
+    if (!prop) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        put_sde_prop(prop);
+        return SDEI_DENIED;
+    }
+
+    if (sde->running && !force) {
+        sde->unregister_pending = true;
+        ret = SDEI_PENDING;
+    } else {
+        atomic_dec(&prop->refcount);
+        sde->event_id = SDEI_INVALID_EVENT_ID;
+        sde->enabled = false;
+        sde->running = false;
+        sde->pending = false;
+        sde->unregister_pending = false;
+    }
+    put_sde(sde, cs);
+    put_sde_prop(prop);
+    return ret;
+}
+
+static int64_t sdei_private_reset_common(QemuSDEState *s, CPUState *cs,
+                                         bool force)
+{
+    int64_t ret = SDEI_SUCCESS;
+    int i;
+
+    for (i = 0; i < PRIVATE_SLOT_COUNT; i++) {
+        int64_t ret1;
+        ret1 = unregister_single_sde(s, i, cs, force);
+        /* Ignore other return values in reset interface */
+        if (ret1 == SDEI_PENDING) {
+            ret = SDEI_DENIED;
+        }
+    }
+
+    return ret;
+}
+
+static int64_t sdei_shared_reset_common(QemuSDEState *s, CPUState *cs,
+                                        bool force)
+{
+    int             i;
+    QemuSDEProp     *prop;
+    int32_t         start_event = PRIVATE_SLOT_COUNT;
+    int64_t         ret = SDEI_SUCCESS;
+
+    for (i = start_event; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+        int64_t ret1 = unregister_single_sde(s, i, cs, force);
+        /* Ignore other return values in reset interface */
+        if (ret1 == SDEI_PENDING) {
+            ret = SDEI_DENIED;
+        }
+    }
+    if (ret) {
+        return ret;
+    }
+
+    for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+        qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+        prop = get_sde_prop(s, i);
+        if (!prop || prop->interrupt == SDEI_INVALID_INTERRUPT) {
+            if (prop) {
+                put_sde_prop(prop);
+            }
+            qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+            continue;
+        }
+        ret |= sdei_free_event_num_locked(s, prop);
+    }
+
+    return ret ? SDEI_DENIED : SDEI_SUCCESS;
+}
+
+
+static int64_t sdei_event_register(QemuSDEState *s, CPUState *cs,
+                                   struct kvm_run *run)
+{
+    QemuSDE *sde;
+    QemuSDEProp *prop;
+    CPUState *target = cs;
+    uint64_t *args = (uint64_t *)run->hypercall.args;
+    int32_t event = args[1];
+    uint64_t rm_mode = SDEI_EVENT_REGISTER_RM_PE;
+
+    prop = get_sde_prop(s, event);
+    if (!prop) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        put_sde_prop(prop);
+        return SDEI_DENIED;
+    }
+
+    if (prop->is_shared) {
+        rm_mode = args[4] & 1ULL;
+        if (rm_mode == SDEI_EVENT_REGISTER_RM_PE) {
+            target = arm_get_cpu_by_id(args[5]);
+            if (!target) {
+                put_sde_prop(prop);
+                return SDEI_INVALID_PARAMETERS;
+            }
+        }
+    }
+
+    sde->target_cpu = target;
+    sde->ep_address = args[2];
+    sde->ep_argument = args[3];
+    sde->prop = prop;
+    sde->routing_mode = rm_mode;
+    sde->event_id = prop->event_id;
+
+    put_sde(sde, cs);
+    atomic_inc(&prop->refcount);
+    put_sde_prop(prop);
+
+    return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_enable(QemuSDEState *s, CPUState *cs,
+                                 struct kvm_run *run)
+{
+    QemuSDE *sde;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    int32_t event = args[1];
+
+    if (!is_valid_event_number(event)) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde->enabled = true;
+    return dispatch_single(s, sde, cs);
+}
+
+static int64_t sdei_event_disable(QemuSDEState *s, CPUState *cs,
+                                  struct kvm_run *run)
+{
+    QemuSDE *sde;
+    uint64_t *args = (uint64_t *)run->hypercall.args;
+    int32_t event = args[1];
+
+    if (!is_valid_event_number(event)) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde->enabled = false;
+    put_sde(sde, cs);
+    return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_context(QemuSDEState *s, CPUState *cs,
+                                  struct kvm_run *run)
+{
+    QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    uint32_t param_id = args[1];
+    int critical;
+    QemuSDECpuCtx *ctx;
+
+    if (param_id >= SDEI_PARAM_MAX) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    if (sde_cpu->critical_running_event >= 0) {
+        critical = 1;
+    } else if (sde_cpu->normal_running_event >= 0) {
+        critical = 0;
+    } else {
+        return SDEI_DENIED;
+    }
+
+    ctx = &sde_cpu->ctx[critical];
+    return ctx->xregs[param_id];
+}
+
+static int64_t sdei_event_complete(QemuSDEState *s, CPUState *cs,
+                                   struct kvm_run *run)
+{
+    QemuSDE *sde;
+    QemuSDECpu *cpu = get_sde_cpu(s, cs);
+    int32_t event;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    bool is_critical;
+
+    event = get_running_sde(s, cs);
+    if (event < 0) {
+        return SDEI_DENIED;
+    }
+
+    assert(is_valid_event_number(event));
+    sde = get_sde_no_check(s, event, cs);
+    assert(sde->event_id != SDEI_INVALID_EVENT_ID);
+
+    sde->running = false;
+    is_critical = sde->prop->is_critical;
+    if (sde->unregister_pending) {
+        atomic_dec(&sde->prop->refcount);
+        sde->event_id = SDEI_INVALID_EVENT_ID;
+        sde->unregister_pending = false;
+    }
+    put_sde(sde, cs);
+
+    sde_restore_cpu_ctx(s, cs, is_critical);
+
+    kvm_arch_put_registers(cs, 1);
+    override_return_value(cs, args);
+    if (cpu->critical_running_event >= 0) {
+        cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+    } else {
+        cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+    }
+
+    /* TODO: we should not queue more than one sde in work queue */
+    dispatch_cpu(s, cs, true);
+    if (cpu->critical_running_event < 0 && cpu->normal_running_event < 0) {
+        dispatch_cpu(s, cs, false);
+    }
+    return args[0];
+}
+
+static int64_t sdei_event_complete_and_resume(QemuSDEState *s, CPUState *cs,
+                                              struct kvm_run *run)
+{
+    QemuSDE *sde;
+    QemuSDECpu *cpu = get_sde_cpu(s, cs);
+    int32_t event;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    bool is_critical;
+    uint64_t resume_addr = args[1];
+
+    event = get_running_sde(s, cs);
+    if (event < 0) {
+        return SDEI_DENIED;
+    }
+
+    assert(is_valid_event_number(event));
+    sde = get_sde_no_check(s, event, cs);
+    assert(sde->event_id != SDEI_INVALID_EVENT_ID);
+
+    sde->running = false;
+    is_critical = sde->prop->is_critical;
+
+    if (sde->unregister_pending) {
+        atomic_dec(&sde->prop->refcount);
+        sde->event_id = SDEI_INVALID_EVENT_ID;
+        sde->unregister_pending = false;
+    }
+    put_sde(sde, cs);
+
+    sde_restore_cpu_ctx_for_resume(s, cs, is_critical, resume_addr);
+    kvm_arch_put_registers(cs, 1);
+
+    override_return_value(cs, args);
+    if (cpu->critical_running_event >= 0) {
+        cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+    } else {
+        cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+    }
+
+    dispatch_cpu(s, cs, true);
+    if (cpu->critical_running_event < 0 && cpu->normal_running_event < 0) {
+        dispatch_cpu(s, cs, false);
+    }
+    return args[0];
+}
+
+static int64_t sdei_event_unregister(QemuSDEState *s, CPUState *cs,
+                                     struct kvm_run *run)
+{
+    uint64_t        *args = (uint64_t *)(run->hypercall.args);
+    int32_t         event = args[1];
+
+    return unregister_single_sde(s, event, cs, false);
+}
+
+static int64_t sdei_event_status(QemuSDEState *s, CPUState *cs,
+                                 struct kvm_run *run)
+{
+    QemuSDE *sde;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    int32_t event = args[1];
+    int64_t status = 0;
+
+    if (!is_valid_event(s, event)) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return status;
+    }
+
+    status |= SDEI_EVENT_STATUS_REGISTERED;
+    if (sde->enabled) {
+        status |= SDEI_EVENT_STATUS_ENABLED;
+    }
+    if (sde->running) {
+        status |= SDEI_EVENT_STATUS_RUNNING;
+    }
+    put_sde(sde, cs);
+    return status;
+}
+
+static int64_t sdei_event_get_info(QemuSDEState *s, CPUState *cs,
+                                   struct kvm_run *run)
+{
+    QemuSDEProp *prop;
+    QemuSDE *sde;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    int32_t event = args[1];
+    uint32_t info = args[2];
+    int64_t ret;
+
+    if (info > SDEI_EVENT_INFO_EV_ROUTING_AFF) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    prop = get_sde_prop(s, event);
+    if (!prop) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    switch (info) {
+    case SDEI_EVENT_INFO_EV_TYPE:
+        ret = prop->is_shared;
+        break;
+    case SDEI_EVENT_INFO_EV_SIGNALED:
+        ret = (event == SDEI_STD_EVT_SOFTWARE_SIGNAL) ? 1 : 0;
+        break;
+    case SDEI_EVENT_INFO_EV_PRIORITY:
+        ret = prop->is_critical;
+        break;
+    case SDEI_EVENT_INFO_EV_ROUTING_MODE:
+    case SDEI_EVENT_INFO_EV_ROUTING_AFF:
+        ret = SDEI_INVALID_PARAMETERS;
+        if (!prop->is_shared) {
+            break;
+        }
+        sde = get_sde_no_check(s, event, cs);
+        if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+            put_sde(sde, cs);
+            ret = SDEI_DENIED;
+            break;
+        }
+        if (info == SDEI_EVENT_INFO_EV_ROUTING_MODE) {
+            ret = sde->routing_mode;
+        } else if (sde->routing_mode == SDEI_EVENT_REGISTER_RM_PE) {
+            ret = ARM_CPU(sde->target_cpu)->mp_affinity;
+        }
+        put_sde(sde, cs);
+        break;
+    default:
+        ret = SDEI_NOT_SUPPORTED;
+    }
+    put_sde_prop(prop);
+    return ret;
+}
+
+static int64_t sdei_event_routing_set(QemuSDEState *s, CPUState *cs,
+                                      struct kvm_run *run)
+{
+    QemuSDE *sde;
+    CPUState *target = cs;
+    uint64_t *args = (uint64_t *)run->hypercall.args;
+    int32_t event = args[1];
+    uint64_t mode = args[2];
+    uint64_t affinity = args[3];
+
+    if (mode & ~1ULL) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+    if (mode == SDEI_EVENT_REGISTER_RM_PE) {
+        target = arm_get_cpu_by_id(affinity);
+        if (!target) {
+            return SDEI_INVALID_PARAMETERS;
+        }
+    }
+
+    if (!is_valid_event(s, event) || !SDEI_IS_SHARED_EVENT(event)) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return SDEI_DENIED;
+    }
+    if (sde->enabled || sde->running ||
+        sde->pending || sde->unregister_pending) {
+        put_sde(sde, cs);
+        return SDEI_DENIED;
+    }
+
+    sde->target_cpu = target;
+    sde->routing_mode = mode;
+    put_sde(sde, cs);
+
+    return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_pe_mask(QemuSDEState *s, CPUState *cs,
+                                  struct kvm_run *run)
+{
+    QemuSDECpu *sde_cpu;
+
+    sde_cpu = get_sde_cpu(s, cs);
+    if (sde_cpu->masked) {
+        return 0;
+    }
+    sde_cpu->masked = true;
+    return 1;
+}
+
+static int64_t sdei_event_pe_unmask(QemuSDEState *s, CPUState *cs,
+                                    struct kvm_run *run)
+{
+    QemuSDECpu *sde_cpu;
+
+    sde_cpu = get_sde_cpu(s, cs);
+    sde_cpu->masked = false;
+    dispatch_cpu(s, cs, true);
+    dispatch_cpu(s, cs, false);
+    return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_interrupt_bind(QemuSDEState *s, CPUState *cs,
+                                         struct kvm_run *run)
+{
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    uint32_t intid = args[1];
+
+    if (intid < GIC_NR_SGIS || intid >= GIC_MAXIRQ) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+    return sdei_alloc_event_num(s, false, intid >= 32, intid);
+}
+
+static int64_t sdei_event_interrupt_release(QemuSDEState *s, CPUState *cs,
+                                            struct kvm_run *run)
+{
+    QemuSDEProp *prop;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    int32_t event = args[1];
+
+    qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+    prop = get_sde_prop(s, event);
+    if (!prop) {
+        qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    return sdei_free_event_num_locked(s, prop);
+}
+
+static int64_t sdei_event_signal(QemuSDEState *s, CPUState *cs,
+                                 struct kvm_run *run)
+{
+    QemuSDE *sde;
+    CPUState *target_cpu;
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    int32_t event = args[1];
+
+    if (event != SDEI_STD_EVT_SOFTWARE_SIGNAL) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    target_cpu = arm_get_cpu_by_id(args[2]);
+    if (!target_cpu) {
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde = get_sde_no_check(s, event, target_cpu);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return SDEI_INVALID_PARAMETERS;
+    }
+
+    sde->pending = true;
+    return dispatch_single(s, sde, target_cpu);
+}
+
+static int64_t sdei_features(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
+{
+    uint64_t *args = (uint64_t *)(run->hypercall.args);
+    uint32_t feature = args[1];
+
+    switch (feature) {
+    case SDEI_FEATURE_BIND_SLOTS:
+        return ((SHARED_SLOT_COUNT - PLAT_SHARED_SLOT_COUNT) << 16) |
+               (PRIVATE_SLOT_COUNT - PLAT_PRIVATE_SLOT_COUNT);
+    default:
+        return SDEI_INVALID_PARAMETERS;
+    }
+}
+
+static int64_t sdei_private_reset(QemuSDEState *s, CPUState *cs,
+                                  struct kvm_run *run)
+{
+    return sdei_private_reset_common(s, cs, false);
+}
+
+static int64_t sdei_shared_reset(QemuSDEState *s, CPUState *cs,
+                                 struct kvm_run *run)
+{
+    return sdei_shared_reset_common(s, cs, false);
+}
+
+static sdei_single_function sdei_functions[] = {
+    sdei_version,
+    sdei_event_register,
+    sdei_event_enable,
+    sdei_event_disable,
+    sdei_event_context,
+    sdei_event_complete,
+    sdei_event_complete_and_resume,
+    sdei_event_unregister,
+    sdei_event_status,
+    sdei_event_get_info,
+    sdei_event_routing_set,
+    sdei_event_pe_mask,
+    sdei_event_pe_unmask,
+    sdei_event_interrupt_bind,
+    sdei_event_interrupt_release,
+    sdei_event_signal,
+    sdei_features,
+    sdei_private_reset,
+    sdei_shared_reset,
+};
+
+void sdei_handle_request(CPUState *cs, struct kvm_run *run)
+{
+    uint32_t func_id = run->hypercall.args[0];
+
+    if (!sde_state) {
+        run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+        return;
+    }
+
+    if (func_id < SDEI_1_0_FN_BASE || func_id > SDEI_MAX_REQ) {
+        error_report("Invalid SDEI function ID: 0x%x", func_id);
+        run->hypercall.args[0] = SDEI_INVALID_PARAMETERS;
+        return;
+    }
+
+    func_id -= SDEI_1_0_FN_BASE;
+    if (func_id < ARRAY_SIZE(sdei_functions) && sdei_functions[func_id]) {
+        run->hypercall.args[0] = sdei_functions[func_id](sde_state, cs, run);
+    } else {
+        run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+    }
+}
+
 static void qemu_shared_sde_init(QemuSDEState *s)
 {
     int i;
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
new file mode 100644
index 0000000..a69a0e4
--- /dev/null
+++ b/target/arm/sdei.h
@@ -0,0 +1,34 @@
+/*
+ * ARM SDEI emulation external interfaces
+ *
+ * Copyright (c) 2019 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Heyi Guo <guoheyi@huawei.com>
+ *    Jingyi Wang <wangjingyi11@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SDEI_H
+#define QEMU_SDEI_H
+
+#include <linux/kvm.h>
+#include <linux/arm_sdei.h>
+#include "hw/core/cpu.h"
+
+#define SDEI_MAX_REQ        SDEI_1_0_FN(0x12)
+
+void sdei_handle_request(CPUState *cs, struct kvm_run *run);
+
+#endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 04/12] arm/sdei: add system reset callback
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (2 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 03/12] arm/sdei: add support to handle SDEI requests from guest Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 05/12] arm/sdei: add support to trigger event by GIC interrupt ID Heyi Guo
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, James Morse, Marc Zyngier,
	Jingyi Wang, Heyi Guo, wanghaibin.wang, Dave Martin

For this is a logical device which is not attached to system bus, we
cannot use DeviceClass->reset interface directly. Instead we register
our own reset callback to reset SDEI services when system resets.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index b40fa36..f9a1208 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -1083,6 +1083,26 @@ static void qemu_sde_init(QemuSDEState *s)
     qemu_private_sde_init(s);
 }
 
+static void qemu_sde_reset(void *opaque)
+{
+    int64_t         ret;
+    CPUState        *cs;
+    QemuSDEState    *s = opaque;
+
+    CPU_FOREACH(cs) {
+        QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+        sdei_private_reset_common(s, cs, true);
+        sde_cpu->masked = true;
+        sde_cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+        sde_cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+    }
+
+    ret = sdei_shared_reset_common(s, first_cpu, true);
+    if (ret) {
+        error_report("SDEI system reset failed: 0x%lx", ret);
+    }
+}
+
 static int qemu_sdei_pre_save(void *opaque)
 {
     QemuSDEState *s = opaque;
@@ -1235,6 +1255,7 @@ static void sdei_initfn(Object *obj)
     sde_state = s;
 
     qemu_sde_init(s);
+    qemu_register_reset(qemu_sde_reset, s);
 }
 
 static void qemu_sde_class_init(ObjectClass *klass, void *data)
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 05/12] arm/sdei: add support to trigger event by GIC interrupt ID
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (3 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 04/12] arm/sdei: add system reset callback Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 06/12] core/irq: add qemu_irq_remove_intercept interface Heyi Guo
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

Add an external interface to trigger an SDEI event bound to an
interrupt by providing GIC interrupt ID.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c | 38 ++++++++++++++++++++++++++++++++++++++
 target/arm/sdei.h |  7 +++++++
 2 files changed, 45 insertions(+)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index f9a1208..088ed76 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -453,6 +453,29 @@ static int64_t sdei_version(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
            (0ULL << SDEI_VERSION_MINOR_SHIFT);
 }
 
+static bool inject_event(QemuSDEState *s, CPUState *cs,
+                             int32_t event, int irq)
+{
+    QemuSDE *sde;
+
+    if (event < 0) {
+        return false;
+    }
+    sde = get_sde_no_check(s, event, cs);
+    if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+        put_sde(sde, cs);
+        return false;
+    }
+    if (irq > 0 && sde->prop->interrupt != irq) {
+        /* Someone unbinds the interrupt! */
+        put_sde(sde, cs);
+        return false;
+    }
+    sde->pending = true;
+    dispatch_single(s, sde, cs);
+    return true;
+}
+
 static int64_t unregister_single_sde(QemuSDEState *s, int32_t event,
                                      CPUState *cs, bool force)
 {
@@ -1033,6 +1056,21 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
     }
 }
 
+bool trigger_sdei_by_irq(int cpu, int irq)
+{
+    QemuSDEState *s = sde_state;
+
+    if (!s || irq >= ARRAY_SIZE(s->irq_map)) {
+        return false;
+    }
+
+    if (s->irq_map[irq] == SDEI_INVALID_EVENT_ID) {
+        return false;
+    }
+
+    return inject_event(s, arm_get_cpu_by_id(cpu), s->irq_map[irq], irq);
+}
+
 static void qemu_shared_sde_init(QemuSDEState *s)
 {
     int i;
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index a69a0e4..a61e788 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -31,4 +31,11 @@
 
 void sdei_handle_request(CPUState *cs, struct kvm_run *run);
 
+/*
+ * Trigger an SDEI event bound to an interrupt.
+ * Return true if event has been triggered successfully.
+ * Return false if event has not been triggered for some reason.
+ */
+bool trigger_sdei_by_irq(int cpu, int irq);
+
 #endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 06/12] core/irq: add qemu_irq_remove_intercept interface
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (4 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 05/12] arm/sdei: add support to trigger event by GIC interrupt ID Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt Heyi Guo
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

We use qemu_irq as the bridge for other qemu modules to switch from
irq injection to SDEI event trigger after VM binds the interrupt to
SDEI event. We use qemu_irq_intercept_in() to override qemu_irq
handler with SDEI event trigger, so we also need a corresponding
interface to restore the handler to default one (i.e. ARM GIC).

qemu_irq_remove_intercept() is the new interface to do the above
job.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 hw/core/irq.c    | 11 +++++++++++
 include/hw/irq.h |  8 ++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/hw/core/irq.c b/hw/core/irq.c
index 7cc0295..114bce6 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -145,6 +145,17 @@ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
     }
 }
 
+void qemu_irq_remove_intercept(qemu_irq *gpio_in, int n)
+{
+    int i;
+    qemu_irq *old_irqs = gpio_in[0]->opaque;
+    for (i = 0; i < n; i++) {
+        gpio_in[i]->handler = old_irqs[i]->handler;
+        gpio_in[i]->opaque = old_irqs[i]->opaque;
+    }
+    qemu_free_irqs(old_irqs, n);
+}
+
 static const TypeInfo irq_type_info = {
    .name = TYPE_IRQ,
    .parent = TYPE_OBJECT,
diff --git a/include/hw/irq.h b/include/hw/irq.h
index fe527f6..1af1db9 100644
--- a/include/hw/irq.h
+++ b/include/hw/irq.h
@@ -56,8 +56,12 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
  */
 qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
 
-/* For internal use in qtest.  Similar to qemu_irq_split, but operating
-   on an existing vector of qemu_irq.  */
+/*
+ * Similar to qemu_irq_split, but operating on an existing vector of qemu_irq.
+ */
 void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
 
+/* Restore the irq handler intercepted by qemu_irq_intercept_in() */
+void qemu_irq_remove_intercept(qemu_irq *gpio_in, int n);
+
 #endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (5 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 06/12] core/irq: add qemu_irq_remove_intercept interface Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-30 13:19   ` Peter Maydell
  2019-09-24 15:21 ` [RFC PATCH 08/12] arm/sdei: add support to register interrupt bind notifier Heyi Guo
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

Override qemu_irq handler to support trigger SDEI event transparently
after guest binds interrupt to SDEI event. We don't have good way to
get GIC device and to guarantee SDEI device is initialized after GIC,
so we search GIC in system bus when the first SDEI request happens or
in VMSTATE post_load().

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c     | 137 ++++++++++++++++++++++++++++++++++++++++++++++++--
 target/arm/sdei_int.h |   3 ++
 2 files changed, 137 insertions(+), 3 deletions(-)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 088ed76..9ceb131 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -85,6 +85,24 @@ static void qemu_sde_cpu_init(QemuSDEState *s)
     }
 }
 
+static int gic_int_to_irq(int num_irq, int intid, int cpu)
+{
+    if (intid >= GIC_INTERNAL) {
+        return intid - GIC_INTERNAL;
+    }
+    return num_irq - GIC_INTERNAL + cpu * GIC_INTERNAL + intid;
+}
+
+static int irq_to_gic_int(int num_irq, int irq, int *cpu)
+{
+    if (irq < num_irq - GIC_INTERNAL) {
+        return irq + GIC_INTERNAL;
+    }
+    irq -= num_irq - GIC_INTERNAL;
+    *cpu = irq / GIC_INTERNAL;
+    return irq % GIC_INTERNAL;
+}
+
 static inline QemuSDECpu *get_sde_cpu(QemuSDEState *s, CPUState *cs)
 {
     assert(cs->cpu_index < s->sdei_max_cpus);
@@ -381,6 +399,76 @@ static void dispatch_cpu(QemuSDEState *s, CPUState *cs, bool is_critical)
     }
 }
 
+static void qemu_sdei_irq_handler(void *opaque, int irq, int level)
+{
+    int cpu = 0;
+    irq = irq_to_gic_int(sde_state->num_irq, irq, &cpu);
+    trigger_sdei_by_irq(cpu, irq);
+}
+
+static void override_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+    qemu_irq irq;
+    QemuSDE *sde;
+    CPUState *cs;
+    int cpu;
+
+    /* SPI */
+    if (intid >= GIC_INTERNAL) {
+        cs = arm_get_cpu_by_id(0);
+        irq = qdev_get_gpio_in(s->gic_dev,
+                               gic_int_to_irq(s->num_irq, intid, 0));
+        if (irq) {
+            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+        }
+        sde = get_sde_no_check(s, event, cs);
+        sde->irq = irq;
+        put_sde(sde, cs);
+        return;
+    }
+    /* PPI */
+    for (cpu = 0; cpu < s->sdei_max_cpus; cpu++) {
+        cs = arm_get_cpu_by_id(cpu);
+        irq = qdev_get_gpio_in(s->gic_dev,
+                               gic_int_to_irq(s->num_irq, intid, cpu));
+        if (irq) {
+            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+        }
+        sde = get_sde_no_check(s, event, cs);
+        sde->irq = irq;
+        put_sde(sde, cs);
+    }
+}
+
+static void restore_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+    QemuSDE *sde;
+    CPUState *cs;
+    int cpu;
+
+    /* SPI */
+    if (intid >= GIC_INTERNAL) {
+        cs = arm_get_cpu_by_id(0);
+        sde = get_sde_no_check(s, event, cs);
+        if (sde->irq) {
+            qemu_irq_remove_intercept(&sde->irq, 1);
+            sde->irq = NULL;
+        }
+        put_sde(sde, cs);
+        return;
+    }
+    /* PPI */
+    for (cpu = 0; cpu < s->sdei_max_cpus; cpu++) {
+        cs = arm_get_cpu_by_id(cpu);
+        sde = get_sde_no_check(s, event, cs);
+        if (sde->irq) {
+            qemu_irq_remove_intercept(&sde->irq, 1);
+            sde->irq = NULL;
+        }
+        put_sde(sde, cs);
+    }
+}
+
 static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
                                     bool is_shared, int intid)
 {
@@ -414,6 +502,7 @@ static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
             sde_props[index].interrupt = intid;
             sde_props[index].is_shared = is_shared;
             sde_props[index].is_critical = is_critical;
+            override_qemu_irq(s, event, intid);
             s->irq_map[intid] = event;
             qemu_mutex_unlock(&sde_props[index].lock);
             qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
@@ -433,6 +522,7 @@ static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
         goto unlock_return;
     }
 
+    restore_qemu_irq(s, prop->event_id, prop->interrupt);
     s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
     prop->event_id = SDEI_INVALID_EVENT_ID;
     prop->interrupt = SDEI_INVALID_INTERRUPT;
@@ -929,13 +1019,33 @@ static int64_t sdei_event_pe_unmask(QemuSDEState *s, CPUState *cs,
     return SDEI_SUCCESS;
 }
 
+static int dev_walkerfn(DeviceState *dev, void *opaque)
+{
+    QemuSDEState *s = opaque;
+
+    if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GICV3_COMMON)) {
+        GICv3State *gic = ARM_GICV3_COMMON(dev);
+        s->num_irq = gic->num_irq;
+        s->gic_dev = dev;
+        return -1;
+    }
+
+    if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GIC_COMMON)) {
+        GICState *gic = ARM_GIC_COMMON(dev);
+        s->num_irq = gic->num_irq;
+        s->gic_dev = dev;
+        return -1;
+    }
+    return 0;
+}
+
 static int64_t sdei_event_interrupt_bind(QemuSDEState *s, CPUState *cs,
                                          struct kvm_run *run)
 {
     uint64_t *args = (uint64_t *)(run->hypercall.args);
     uint32_t intid = args[1];
 
-    if (intid < GIC_NR_SGIS || intid >= GIC_MAXIRQ) {
+    if (intid < GIC_NR_SGIS || intid >= s->num_irq) {
         return SDEI_INVALID_PARAMETERS;
     }
     return sdei_alloc_event_num(s, false, intid >= 32, intid);
@@ -1042,6 +1152,17 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
         return;
     }
 
+    if (!sde_state->gic_dev) {
+        /* Search for ARM GIC device */
+        qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+                           NULL, NULL, NULL, sde_state);
+        if (!sde_state->gic_dev) {
+            error_report("Cannot find ARM GIC device!");
+            run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+            return;
+        }
+    }
+
     if (func_id < SDEI_1_0_FN_BASE || func_id > SDEI_MAX_REQ) {
         error_report("Invalid SDEI function ID: 0x%x", func_id);
         run->hypercall.args[0] = SDEI_INVALID_PARAMETERS;
@@ -1198,9 +1319,19 @@ static int qemu_sdei_post_load(void *opaque, int version_id)
         }
     }
 
+    /* Search for ARM GIC device */
+    qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+                       NULL, NULL, NULL, s);
+    if (!s->gic_dev) {
+        error_report("Cannot find ARM GIC device!");
+        return 0;
+    }
+
     for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
-        if (sde_props[i].interrupt != SDEI_INVALID_INTERRUPT) {
-            s->irq_map[sde_props[i].interrupt] = sde_props[i].event_id;
+        int intid = sde_props[i].interrupt;
+        if (intid != SDEI_INVALID_INTERRUPT) {
+            s->irq_map[intid] = sde_props[i].event_id;
+            override_qemu_irq(s, sde_props[i].event_id, intid);
         }
     }
 
diff --git a/target/arm/sdei_int.h b/target/arm/sdei_int.h
index 7f69507..3930591 100644
--- a/target/arm/sdei_int.h
+++ b/target/arm/sdei_int.h
@@ -63,6 +63,7 @@ typedef struct QemuSDEProp {
 typedef struct QemuSDE {
     QemuSDEProp     *prop;
     CPUState        *target_cpu;
+    qemu_irq        irq;
     QemuMutex       lock;
     bool            enabled;
     bool            running;
@@ -95,9 +96,11 @@ typedef struct QemuSDECpu {
 
 typedef struct QemuSDEState {
     DeviceState     parent_obj;
+    DeviceState     *gic_dev;
     QemuSDEProp     sde_props_state[PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT];
     QemuSDECpu      *sde_cpus;
     int             sdei_max_cpus;
+    int             num_irq;
     QemuSDE         *shared_sde_array[SHARED_SLOT_COUNT];
     int32_t         irq_map[GIC_MAXIRQ];
     QemuMutex       sdei_interrupt_bind_lock;
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 08/12] arm/sdei: add support to register interrupt bind notifier
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (6 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 09/12] linux-headers/kvm.h: add capability to forward hypercall Heyi Guo
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

Other qemu modules related with the interrupt bind operation may want
to be notified when guest requests to bind interrupt to sdei event, so
we add register and unregister interfaces.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 target/arm/sdei.h | 17 +++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 9ceb131..efdb681 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -45,6 +45,52 @@
 
 static QemuSDEState *sde_state;
 
+typedef struct QemuSDEIBindNotifyEntry {
+    QTAILQ_ENTRY(QemuSDEIBindNotifyEntry) entry;
+    QemuSDEIBindNotify *func;
+    void *opaque;
+    int irq;
+} QemuSDEIBindNotifyEntry;
+
+static QTAILQ_HEAD(, QemuSDEIBindNotifyEntry) bind_notifiers =
+    QTAILQ_HEAD_INITIALIZER(bind_notifiers);
+
+void qemu_register_sdei_bind_notifier(QemuSDEIBindNotify *func,
+                                      void *opaque, int irq)
+{
+    QemuSDEIBindNotifyEntry *be = g_new0(QemuSDEIBindNotifyEntry, 1);
+
+    be->func = func;
+    be->opaque = opaque;
+    be->irq = irq;
+    QTAILQ_INSERT_TAIL(&bind_notifiers, be, entry);
+}
+
+void qemu_unregister_sdei_bind_notifier(QemuSDEIBindNotify *func,
+                                        void *opaque, int irq)
+{
+    QemuSDEIBindNotifyEntry *be;
+
+    QTAILQ_FOREACH(be, &bind_notifiers, entry) {
+        if (be->func == func && be->opaque == opaque && be->irq == irq) {
+            QTAILQ_REMOVE(&bind_notifiers, be, entry);
+            g_free(be);
+            return;
+        }
+    }
+}
+
+static void sdei_notify_bind(int irq, int32_t event, bool bind)
+{
+    QemuSDEIBindNotifyEntry *be, *nbe;
+
+    QTAILQ_FOREACH_SAFE(be, &bind_notifiers, entry, nbe) {
+        if (be->irq == irq) {
+            be->func(be->opaque, irq, event, bind);
+        }
+    }
+}
+
 static void qemu_sde_prop_init(QemuSDEState *s)
 {
     QemuSDEProp *sde_props = s->sde_props_state;
@@ -502,6 +548,7 @@ static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
             sde_props[index].interrupt = intid;
             sde_props[index].is_shared = is_shared;
             sde_props[index].is_critical = is_critical;
+            sdei_notify_bind(intid, event, true);
             override_qemu_irq(s, event, intid);
             s->irq_map[intid] = event;
             qemu_mutex_unlock(&sde_props[index].lock);
@@ -522,6 +569,7 @@ static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
         goto unlock_return;
     }
 
+    sdei_notify_bind(prop->interrupt, prop->event_id, false);
     restore_qemu_irq(s, prop->event_id, prop->interrupt);
     s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
     prop->event_id = SDEI_INVALID_EVENT_ID;
@@ -1331,6 +1379,7 @@ static int qemu_sdei_post_load(void *opaque, int version_id)
         int intid = sde_props[i].interrupt;
         if (intid != SDEI_INVALID_INTERRUPT) {
             s->irq_map[intid] = sde_props[i].event_id;
+            sdei_notify_bind(intid, sde_props[i].event_id, true);
             override_qemu_irq(s, sde_props[i].event_id, intid);
         }
     }
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index a61e788..feaaf1a 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -38,4 +38,21 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run);
  */
 bool trigger_sdei_by_irq(int cpu, int irq);
 
+/*
+ * Notify callback prototype; the argument "bind" tells whether it is a bind
+ * operation or unbind one.
+ */
+typedef void QemuSDEIBindNotify(void *opaque, int irq,
+                                int32_t event, bool bind);
+/*
+ * Register a notify callback for a specific interrupt bind operation; the
+ * client be both notified by bind and unbind operation.
+ */
+void qemu_register_sdei_bind_notifier(QemuSDEIBindNotify *func,
+                                      void *opaque, int irq);
+/*
+ * Unregister a notify callback for a specific interrupt bind operation.
+ */
+void qemu_unregister_sdei_bind_notifier(QemuSDEIBindNotify *func,
+                                        void *opaque, int irq);
 #endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 09/12] linux-headers/kvm.h: add capability to forward hypercall
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (7 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 08/12] arm/sdei: add support to register interrupt bind notifier Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 10/12] arm/sdei: check KVM cap and enable SDEI Heyi Guo
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	Cornelia Huck, James Morse, Paolo Bonzini, Heyi Guo,
	wanghaibin.wang, Dave Martin

To keep backward compatibility, we add new KVM capability
"KVM_CAP_FORWARD_HYPERCALL" to probe whether KVM supports forwarding
hypercall to userspace.

The capability should be enabled explicitly, for we don't want user
space application to deal with unexpected hypercall exits. We also use
an additional argument to pass exception bit mask, to request KVM to
forward all hypercalls except the classes specified in the bit mask.

Currently only PSCI can be set as exception, so that we can still keep
consistent with the original PSCI processing flow.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
---
 linux-headers/linux/kvm.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 18892d6..20e8a68 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -711,6 +711,8 @@ struct kvm_enable_cap {
 	__u8  pad[64];
 };
 
+#define KVM_CAP_FORWARD_HYPERCALL_EXCL_PSCI (1 << 0)
+
 /* for KVM_PPC_GET_PVINFO */
 
 #define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
@@ -995,6 +997,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_SVE 170
 #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
 #define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_FORWARD_HYPERCALL 174
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 10/12] arm/sdei: check KVM cap and enable SDEI
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (8 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 09/12] linux-headers/kvm.h: add capability to forward hypercall Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 11/12] arm/kvm: handle guest exit of hypercall Heyi Guo
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

Check KVM hypercall forward capability and enable it, and set global
flag "sdei_enabled" to true if everything works well.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c | 17 +++++++++++++++++
 target/arm/sdei.h |  2 ++
 2 files changed, 19 insertions(+)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index efdb681..000545e 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -43,6 +43,7 @@
 #define TYPE_QEMU_SDEI "qemu_sdei"
 #define QEMU_SDEI(obj) OBJECT_CHECK(QemuSDEState, (obj), TYPE_QEMU_SDEI)
 
+bool sdei_enabled;
 static QemuSDEState *sde_state;
 
 typedef struct QemuSDEIBindNotifyEntry {
@@ -1465,6 +1466,7 @@ static const VMStateDescription vmstate_sde_state = {
 static void sdei_initfn(Object *obj)
 {
     QemuSDEState *s = QEMU_SDEI(obj);
+    KVMState *kvm = KVM_STATE(current_machine->accelerator);
 
     if (sde_state) {
         error_report("Only one SDEI dispatcher is allowed!");
@@ -1474,6 +1476,21 @@ static void sdei_initfn(Object *obj)
 
     qemu_sde_init(s);
     qemu_register_reset(qemu_sde_reset, s);
+
+    if (kvm_check_extension(kvm, KVM_CAP_FORWARD_HYPERCALL)) {
+        int ret;
+        ret = kvm_vm_enable_cap(kvm, KVM_CAP_FORWARD_HYPERCALL, 0,
+                                KVM_CAP_FORWARD_HYPERCALL_EXCL_PSCI);
+        if (ret < 0) {
+            error_report("Enable hypercall forwarding failed: %s",
+                         strerror(-ret));
+            abort();
+        }
+        sdei_enabled = true;
+        info_report("qemu sdei enabled");
+    } else {
+        info_report("KVM does not support forwarding hypercall.");
+    }
 }
 
 static void qemu_sde_class_init(ObjectClass *klass, void *data)
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index feaaf1a..95e7d8d 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -29,6 +29,8 @@
 
 #define SDEI_MAX_REQ        SDEI_1_0_FN(0x12)
 
+extern bool sdei_enabled;
+
 void sdei_handle_request(CPUState *cs, struct kvm_run *run);
 
 /*
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 11/12] arm/kvm: handle guest exit of hypercall
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (9 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 10/12] arm/sdei: check KVM cap and enable SDEI Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-09-24 15:21 ` [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
	wanghaibin.wang, Dave Martin

Add support to handle guest exit of hypercall, and forward to SDEI
dispatcher if SDEI is enabled and it is an SDEI request.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/kvm.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b2eaa50..97a67b1 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -30,6 +30,7 @@
 #include "hw/boards.h"
 #include "hw/irq.h"
 #include "qemu/log.h"
+#include "sdei.h"
 
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
@@ -668,6 +669,19 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 }
 
 
+static void kvm_arm_handle_hypercall(CPUState *cs, struct kvm_run *run)
+{
+    uint32_t func_id = run->hypercall.args[0];
+
+    if (sdei_enabled &&
+        func_id >= SDEI_1_0_FN_BASE && func_id <= SDEI_MAX_REQ) {
+        sdei_handle_request(cs, run);
+    } else {
+        run->hypercall.args[0] = -1;
+    }
+}
+
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret = 0;
@@ -678,6 +692,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
             ret = EXCP_DEBUG;
         } /* otherwise return to guest */
         break;
+    case KVM_EXIT_HYPERCALL:
+        kvm_arm_handle_hypercall(cs, run);
+        break;
     default:
         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
                       __func__, run->exit_reason);
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (10 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 11/12] arm/kvm: handle guest exit of hypercall Heyi Guo
@ 2019-09-24 15:21 ` Heyi Guo
  2019-10-10  9:15   ` Igor Mammedov
  2019-10-10 14:01   ` Michael S. Tsirkin
  2019-09-25  6:54 ` [RFC PATCH 00/12] Add SDEI support for arm64 no-reply
                   ` (2 subsequent siblings)
  14 siblings, 2 replies; 25+ messages in thread
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
  To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	Shannon Zhao, James Morse, Igor Mammedov, Heyi Guo,
	wanghaibin.wang, Dave Martin

Add SDEI table if SDEI is enabled, so that guest OS can get aware and
utilize the interfaces.

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
---
 hw/arm/virt-acpi-build.c    | 16 ++++++++++++++++
 include/hw/acpi/acpi-defs.h |  5 +++++
 2 files changed, 21 insertions(+)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 6cdf156..1088214 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -32,6 +32,7 @@
 #include "trace.h"
 #include "hw/core/cpu.h"
 #include "target/arm/cpu.h"
+#include "target/arm/sdei.h"
 #include "hw/acpi/acpi-defs.h"
 #include "hw/acpi/acpi.h"
 #include "hw/nvram/fw_cfg.h"
@@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 }
 
 static void
+build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
+{
+    int sdei_start = table_data->len;
+
+    (void)acpi_data_push(table_data, sizeof(AcpiSdei));
+    build_header(linker, table_data, (void *)(table_data->data + sdei_start),
+                 "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
+}
+
+static void
 build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
     AcpiSerialPortConsoleRedirection *spcr;
@@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
     acpi_add_table(table_offsets, tables_blob);
     build_spcr(tables_blob, tables->linker, vms);
 
+    if (sdei_enabled) {
+        acpi_add_table(table_offsets, tables_blob);
+        build_sdei(tables_blob, tables->linker, vms);
+    }
+
     if (ms->numa_state->num_nodes > 0) {
         acpi_add_table(table_offsets, tables_blob);
         build_srat(tables_blob, tables->linker, vms);
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 57a3f58..0a2265d 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -634,4 +634,9 @@ struct AcpiIortRC {
 } QEMU_PACKED;
 typedef struct AcpiIortRC AcpiIortRC;
 
+struct AcpiSdei {
+    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
+} QEMU_PACKED;
+typedef struct AcpiSdei AcpiSdei;
+
 #endif
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 01/12] linux-headers: import arm_sdei.h
  2019-09-24 15:21 ` [RFC PATCH 01/12] linux-headers: import arm_sdei.h Heyi Guo
@ 2019-09-24 15:39   ` Michael S. Tsirkin
  2019-09-25  8:12     ` Guoheyi
  0 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2019-09-24 15:39 UTC (permalink / raw)
  To: Heyi Guo
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, Cornelia Huck,
	qemu-devel, Dave Martin, qemu-arm, James Morse, Paolo Bonzini,
	wanghaibin.wang, kvmarm, linux-arm-kernel

On Tue, Sep 24, 2019 at 11:21:40PM +0800, Heyi Guo wrote:
> Import Linux header file include/uapi/linux/arm_sdei.h from kernel
> v5.3 release.
> 
> This is to prepare for qemu SDEI emulation.
> 
> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Cornelia Huck <cohuck@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>

Some issues with this.  First linux-headers is for linux as a host.
This is for linux as a guest, so belongs in include/standard-headers.

Second, please add to scripts/update-linux-headers.sh in a 1st patch,
then add the file in the second patch.



> ---
>  linux-headers/linux/arm_sdei.h | 73 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 73 insertions(+)
>  create mode 100644 linux-headers/linux/arm_sdei.h
> 
> diff --git a/linux-headers/linux/arm_sdei.h b/linux-headers/linux/arm_sdei.h
> new file mode 100644
> index 0000000..af0630b
> --- /dev/null
> +++ b/linux-headers/linux/arm_sdei.h
> @@ -0,0 +1,73 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/* Copyright (C) 2017 Arm Ltd. */
> +#ifndef _UAPI_LINUX_ARM_SDEI_H
> +#define _UAPI_LINUX_ARM_SDEI_H
> +
> +#define SDEI_1_0_FN_BASE			0xC4000020
> +#define SDEI_1_0_MASK				0xFFFFFFE0
> +#define SDEI_1_0_FN(n)				(SDEI_1_0_FN_BASE + (n))
> +
> +#define SDEI_1_0_FN_SDEI_VERSION			SDEI_1_0_FN(0x00)
> +#define SDEI_1_0_FN_SDEI_EVENT_REGISTER			SDEI_1_0_FN(0x01)
> +#define SDEI_1_0_FN_SDEI_EVENT_ENABLE			SDEI_1_0_FN(0x02)
> +#define SDEI_1_0_FN_SDEI_EVENT_DISABLE			SDEI_1_0_FN(0x03)
> +#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT			SDEI_1_0_FN(0x04)
> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE			SDEI_1_0_FN(0x05)
> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME	SDEI_1_0_FN(0x06)
> +#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER		SDEI_1_0_FN(0x07)
> +#define SDEI_1_0_FN_SDEI_EVENT_STATUS			SDEI_1_0_FN(0x08)
> +#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO			SDEI_1_0_FN(0x09)
> +#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET		SDEI_1_0_FN(0x0A)
> +#define SDEI_1_0_FN_SDEI_PE_MASK			SDEI_1_0_FN(0x0B)
> +#define SDEI_1_0_FN_SDEI_PE_UNMASK			SDEI_1_0_FN(0x0C)
> +#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND			SDEI_1_0_FN(0x0D)
> +#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE		SDEI_1_0_FN(0x0E)
> +#define SDEI_1_0_FN_SDEI_PRIVATE_RESET			SDEI_1_0_FN(0x11)
> +#define SDEI_1_0_FN_SDEI_SHARED_RESET			SDEI_1_0_FN(0x12)
> +
> +#define SDEI_VERSION_MAJOR_SHIFT			48
> +#define SDEI_VERSION_MAJOR_MASK				0x7fff
> +#define SDEI_VERSION_MINOR_SHIFT			32
> +#define SDEI_VERSION_MINOR_MASK				0xffff
> +#define SDEI_VERSION_VENDOR_SHIFT			0
> +#define SDEI_VERSION_VENDOR_MASK			0xffffffff
> +
> +#define SDEI_VERSION_MAJOR(x)	(x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK)
> +#define SDEI_VERSION_MINOR(x)	(x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK)
> +#define SDEI_VERSION_VENDOR(x)	(x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK)
> +
> +/* SDEI return values */
> +#define SDEI_SUCCESS		0
> +#define SDEI_NOT_SUPPORTED	-1
> +#define SDEI_INVALID_PARAMETERS	-2
> +#define SDEI_DENIED		-3
> +#define SDEI_PENDING		-5
> +#define SDEI_OUT_OF_RESOURCE	-10
> +
> +/* EVENT_REGISTER flags */
> +#define SDEI_EVENT_REGISTER_RM_ANY	0
> +#define SDEI_EVENT_REGISTER_RM_PE	1
> +
> +/* EVENT_STATUS return value bits */
> +#define SDEI_EVENT_STATUS_RUNNING	2
> +#define SDEI_EVENT_STATUS_ENABLED	1
> +#define SDEI_EVENT_STATUS_REGISTERED	0
> +
> +/* EVENT_COMPLETE status values */
> +#define SDEI_EV_HANDLED	0
> +#define SDEI_EV_FAILED	1
> +
> +/* GET_INFO values */
> +#define SDEI_EVENT_INFO_EV_TYPE			0
> +#define SDEI_EVENT_INFO_EV_SIGNALED		1
> +#define SDEI_EVENT_INFO_EV_PRIORITY		2
> +#define SDEI_EVENT_INFO_EV_ROUTING_MODE		3
> +#define SDEI_EVENT_INFO_EV_ROUTING_AFF		4
> +
> +/* and their results */
> +#define SDEI_EVENT_TYPE_PRIVATE			0
> +#define SDEI_EVENT_TYPE_SHARED			1
> +#define SDEI_EVENT_PRIORITY_NORMAL		0
> +#define SDEI_EVENT_PRIORITY_CRITICAL		1
> +
> +#endif /* _UAPI_LINUX_ARM_SDEI_H */
> -- 
> 1.8.3.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/12] Add SDEI support for arm64
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (11 preceding siblings ...)
  2019-09-24 15:21 ` [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
@ 2019-09-25  6:54 ` no-reply
  2019-09-25  6:58 ` no-reply
  2019-09-30 13:15 ` Peter Maydell
  14 siblings, 0 replies; 25+ messages in thread
From: no-reply @ 2019-09-25  6:54 UTC (permalink / raw)
  To: guoheyi
  Cc: mark.rutland, peter.maydell, marc.zyngier, qemu-devel,
	Dave.Martin, qemu-arm, james.morse, guoheyi, wanghaibin.wang,
	kvmarm, linux-arm-kernel

Patchew URL: https://patchew.org/QEMU/1569338511-3572-1-git-send-email-guoheyi@huawei.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===

libudev           no
default devices   yes

warning: Python 2 support is deprecated
warning: Python 3 will be required for building future versions of QEMU
cross containers  no

NOTE: guest cross-compilers enabled: cc
---
  LINK    aarch64-softmmu/qemu-system-aarch64
hw/arm/virt-acpi-build.o: In function `virt_acpi_build':
/tmp/qemu-test/src/hw/arm/virt-acpi-build.c:810: undefined reference to `sdei_enabled'
collect2: error: ld returned 1 exit status
make[1]: *** [qemu-system-aarch64] Error 1
make: *** [aarch64-softmmu/all] Error 2
Traceback (most recent call last):


The full log is available at
http://patchew.org/logs/1569338511-3572-1-git-send-email-guoheyi@huawei.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/12] Add SDEI support for arm64
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (12 preceding siblings ...)
  2019-09-25  6:54 ` [RFC PATCH 00/12] Add SDEI support for arm64 no-reply
@ 2019-09-25  6:58 ` no-reply
  2019-09-30 13:15 ` Peter Maydell
  14 siblings, 0 replies; 25+ messages in thread
From: no-reply @ 2019-09-25  6:58 UTC (permalink / raw)
  To: guoheyi
  Cc: mark.rutland, peter.maydell, marc.zyngier, qemu-devel,
	Dave.Martin, qemu-arm, james.morse, guoheyi, wanghaibin.wang,
	kvmarm, linux-arm-kernel

Patchew URL: https://patchew.org/QEMU/1569338511-3572-1-git-send-email-guoheyi@huawei.com/



Hi,

This series failed the docker-mingw@fedora build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#! /bin/bash
export ARCH=x86_64
make docker-image-fedora V=1 NETWORK=1
time make docker-test-mingw@fedora J=14 NETWORK=1
=== TEST SCRIPT END ===

  CC      aarch64-softmmu/hw/arm/tosa.o
  CC      aarch64-softmmu/hw/arm/z2.o
In file included from /tmp/qemu-test/src/hw/arm/virt-acpi-build.c:35:
/tmp/qemu-test/src/target/arm/sdei.h:26:10: fatal error: linux/kvm.h: No such file or directory
 #include <linux/kvm.h>
          ^~~~~~~~~~~~~
compilation terminated.


The full log is available at
http://patchew.org/logs/1569338511-3572-1-git-send-email-guoheyi@huawei.com/testing.docker-mingw@fedora/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 01/12] linux-headers: import arm_sdei.h
  2019-09-24 15:39   ` Michael S. Tsirkin
@ 2019-09-25  8:12     ` Guoheyi
  0 siblings, 0 replies; 25+ messages in thread
From: Guoheyi @ 2019-09-25  8:12 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, Cornelia Huck,
	qemu-devel, Dave Martin, qemu-arm, James Morse, Paolo Bonzini,
	wanghaibin.wang, kvmarm, linux-arm-kernel



On 2019/9/24 23:39, Michael S. Tsirkin wrote:
> On Tue, Sep 24, 2019 at 11:21:40PM +0800, Heyi Guo wrote:
>> Import Linux header file include/uapi/linux/arm_sdei.h from kernel
>> v5.3 release.
>>
>> This is to prepare for qemu SDEI emulation.
>>
>> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
>> Cc: Peter Maydell <peter.maydell@linaro.org>
>> Cc: Dave Martin <Dave.Martin@arm.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: James Morse <james.morse@arm.com>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Cornelia Huck <cohuck@redhat.com>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Some issues with this.  First linux-headers is for linux as a host.
> This is for linux as a guest, so belongs in include/standard-headers.
>
> Second, please add to scripts/update-linux-headers.sh in a 1st patch,
> then add the file in the second patch.

Thanks; now I understand the differences. I'll do that in next version.

HG

>
>
>
>> ---
>>   linux-headers/linux/arm_sdei.h | 73 ++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 73 insertions(+)
>>   create mode 100644 linux-headers/linux/arm_sdei.h
>>
>> diff --git a/linux-headers/linux/arm_sdei.h b/linux-headers/linux/arm_sdei.h
>> new file mode 100644
>> index 0000000..af0630b
>> --- /dev/null
>> +++ b/linux-headers/linux/arm_sdei.h
>> @@ -0,0 +1,73 @@
>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> +/* Copyright (C) 2017 Arm Ltd. */
>> +#ifndef _UAPI_LINUX_ARM_SDEI_H
>> +#define _UAPI_LINUX_ARM_SDEI_H
>> +
>> +#define SDEI_1_0_FN_BASE			0xC4000020
>> +#define SDEI_1_0_MASK				0xFFFFFFE0
>> +#define SDEI_1_0_FN(n)				(SDEI_1_0_FN_BASE + (n))
>> +
>> +#define SDEI_1_0_FN_SDEI_VERSION			SDEI_1_0_FN(0x00)
>> +#define SDEI_1_0_FN_SDEI_EVENT_REGISTER			SDEI_1_0_FN(0x01)
>> +#define SDEI_1_0_FN_SDEI_EVENT_ENABLE			SDEI_1_0_FN(0x02)
>> +#define SDEI_1_0_FN_SDEI_EVENT_DISABLE			SDEI_1_0_FN(0x03)
>> +#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT			SDEI_1_0_FN(0x04)
>> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE			SDEI_1_0_FN(0x05)
>> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME	SDEI_1_0_FN(0x06)
>> +#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER		SDEI_1_0_FN(0x07)
>> +#define SDEI_1_0_FN_SDEI_EVENT_STATUS			SDEI_1_0_FN(0x08)
>> +#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO			SDEI_1_0_FN(0x09)
>> +#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET		SDEI_1_0_FN(0x0A)
>> +#define SDEI_1_0_FN_SDEI_PE_MASK			SDEI_1_0_FN(0x0B)
>> +#define SDEI_1_0_FN_SDEI_PE_UNMASK			SDEI_1_0_FN(0x0C)
>> +#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND			SDEI_1_0_FN(0x0D)
>> +#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE		SDEI_1_0_FN(0x0E)
>> +#define SDEI_1_0_FN_SDEI_PRIVATE_RESET			SDEI_1_0_FN(0x11)
>> +#define SDEI_1_0_FN_SDEI_SHARED_RESET			SDEI_1_0_FN(0x12)
>> +
>> +#define SDEI_VERSION_MAJOR_SHIFT			48
>> +#define SDEI_VERSION_MAJOR_MASK				0x7fff
>> +#define SDEI_VERSION_MINOR_SHIFT			32
>> +#define SDEI_VERSION_MINOR_MASK				0xffff
>> +#define SDEI_VERSION_VENDOR_SHIFT			0
>> +#define SDEI_VERSION_VENDOR_MASK			0xffffffff
>> +
>> +#define SDEI_VERSION_MAJOR(x)	(x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK)
>> +#define SDEI_VERSION_MINOR(x)	(x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK)
>> +#define SDEI_VERSION_VENDOR(x)	(x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK)
>> +
>> +/* SDEI return values */
>> +#define SDEI_SUCCESS		0
>> +#define SDEI_NOT_SUPPORTED	-1
>> +#define SDEI_INVALID_PARAMETERS	-2
>> +#define SDEI_DENIED		-3
>> +#define SDEI_PENDING		-5
>> +#define SDEI_OUT_OF_RESOURCE	-10
>> +
>> +/* EVENT_REGISTER flags */
>> +#define SDEI_EVENT_REGISTER_RM_ANY	0
>> +#define SDEI_EVENT_REGISTER_RM_PE	1
>> +
>> +/* EVENT_STATUS return value bits */
>> +#define SDEI_EVENT_STATUS_RUNNING	2
>> +#define SDEI_EVENT_STATUS_ENABLED	1
>> +#define SDEI_EVENT_STATUS_REGISTERED	0
>> +
>> +/* EVENT_COMPLETE status values */
>> +#define SDEI_EV_HANDLED	0
>> +#define SDEI_EV_FAILED	1
>> +
>> +/* GET_INFO values */
>> +#define SDEI_EVENT_INFO_EV_TYPE			0
>> +#define SDEI_EVENT_INFO_EV_SIGNALED		1
>> +#define SDEI_EVENT_INFO_EV_PRIORITY		2
>> +#define SDEI_EVENT_INFO_EV_ROUTING_MODE		3
>> +#define SDEI_EVENT_INFO_EV_ROUTING_AFF		4
>> +
>> +/* and their results */
>> +#define SDEI_EVENT_TYPE_PRIVATE			0
>> +#define SDEI_EVENT_TYPE_SHARED			1
>> +#define SDEI_EVENT_PRIORITY_NORMAL		0
>> +#define SDEI_EVENT_PRIORITY_CRITICAL		1
>> +
>> +#endif /* _UAPI_LINUX_ARM_SDEI_H */
>> -- 
>> 1.8.3.1
> .
>




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/12] Add SDEI support for arm64
  2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
                   ` (13 preceding siblings ...)
  2019-09-25  6:58 ` no-reply
@ 2019-09-30 13:15 ` Peter Maydell
  2019-10-09 13:42   ` Guoheyi
  14 siblings, 1 reply; 25+ messages in thread
From: Peter Maydell @ 2019-09-30 13:15 UTC (permalink / raw)
  To: Heyi Guo
  Cc: Mark Rutland, Marc Zyngier, QEMU Developers, Dave Martin,
	qemu-arm, James Morse, wanghaibin.wang, kvmarm, arm-mail-list

On Tue, 24 Sep 2019 at 16:23, Heyi Guo <guoheyi@huawei.com> wrote:
>
> As promised, this is the first RFC patch set for arm64 SDEI support.

Hi; for the benefit of possible reviewers who aren't familiar
with every corner of the arm ecosystem, could you provide a
summary of:
 * what is SDEI ?
 * what do KVM and QEMU want/need to do with it ?
 * what is this patchset trying to solve ?

That would provide some useful context for trying to
review the patchset.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt
  2019-09-24 15:21 ` [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt Heyi Guo
@ 2019-09-30 13:19   ` Peter Maydell
  2019-10-09 13:06     ` Guoheyi
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Maydell @ 2019-09-30 13:19 UTC (permalink / raw)
  To: Heyi Guo
  Cc: Mark Rutland, Marc Zyngier, QEMU Developers, kvmarm, qemu-arm,
	James Morse, wanghaibin.wang, Dave Martin, arm-mail-list

On Tue, 24 Sep 2019 at 16:23, Heyi Guo <guoheyi@huawei.com> wrote:
>
> Override qemu_irq handler to support trigger SDEI event transparently
> after guest binds interrupt to SDEI event. We don't have good way to
> get GIC device and to guarantee SDEI device is initialized after GIC,
> so we search GIC in system bus when the first SDEI request happens or
> in VMSTATE post_load().
>
> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: James Morse <james.morse@arm.com>


> +static void override_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
> +{
> +    qemu_irq irq;
> +    QemuSDE *sde;
> +    CPUState *cs;
> +    int cpu;
> +
> +    /* SPI */
> +    if (intid >= GIC_INTERNAL) {
> +        cs = arm_get_cpu_by_id(0);
> +        irq = qdev_get_gpio_in(s->gic_dev,
> +                               gic_int_to_irq(s->num_irq, intid, 0));
> +        if (irq) {
> +            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
> +        }

I'm not sure what this code is trying to do, but
qemu_irq_intercept_in() is a function for internal use
by the qtest testing infrastructure, so it shouldn't be
used in 'real' QEMU code.

> +        sde = get_sde_no_check(s, event, cs);
> +        sde->irq = irq;
> +        put_sde(sde, cs);
> +        return;
> +    }

> @@ -1042,6 +1152,17 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
>          return;
>      }
>
> +    if (!sde_state->gic_dev) {
> +        /* Search for ARM GIC device */
> +        qbus_walk_children(sysbus_get_default(), dev_walkerfn,
> +                           NULL, NULL, NULL, sde_state);
> +        if (!sde_state->gic_dev) {
> +            error_report("Cannot find ARM GIC device!");
> +            run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
> +            return;
> +        }
> +    }

Walking through the qbus tree looking for particular devices
isn't really something I'd recommend either.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt
  2019-09-30 13:19   ` Peter Maydell
@ 2019-10-09 13:06     ` Guoheyi
  0 siblings, 0 replies; 25+ messages in thread
From: Guoheyi @ 2019-10-09 13:06 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Mark Rutland, Marc Zyngier, QEMU Developers, Dave Martin,
	qemu-arm, James Morse, wanghaibin.wang, kvmarm, arm-mail-list

Hi Peter,

Thanks for your comments. I will explain SDEI in another mail and please 
provide your suggestions for such situation.

Heyi


On 2019/9/30 21:19, Peter Maydell wrote:
> On Tue, 24 Sep 2019 at 16:23, Heyi Guo <guoheyi@huawei.com> wrote:
>> Override qemu_irq handler to support trigger SDEI event transparently
>> after guest binds interrupt to SDEI event. We don't have good way to
>> get GIC device and to guarantee SDEI device is initialized after GIC,
>> so we search GIC in system bus when the first SDEI request happens or
>> in VMSTATE post_load().
>>
>> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
>> Cc: Peter Maydell <peter.maydell@linaro.org>
>> Cc: Dave Martin <Dave.Martin@arm.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: James Morse <james.morse@arm.com>
>
>> +static void override_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
>> +{
>> +    qemu_irq irq;
>> +    QemuSDE *sde;
>> +    CPUState *cs;
>> +    int cpu;
>> +
>> +    /* SPI */
>> +    if (intid >= GIC_INTERNAL) {
>> +        cs = arm_get_cpu_by_id(0);
>> +        irq = qdev_get_gpio_in(s->gic_dev,
>> +                               gic_int_to_irq(s->num_irq, intid, 0));
>> +        if (irq) {
>> +            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
>> +        }
> I'm not sure what this code is trying to do, but
> qemu_irq_intercept_in() is a function for internal use
> by the qtest testing infrastructure, so it shouldn't be
> used in 'real' QEMU code.
>
>> +        sde = get_sde_no_check(s, event, cs);
>> +        sde->irq = irq;
>> +        put_sde(sde, cs);
>> +        return;
>> +    }
>> @@ -1042,6 +1152,17 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
>>           return;
>>       }
>>
>> +    if (!sde_state->gic_dev) {
>> +        /* Search for ARM GIC device */
>> +        qbus_walk_children(sysbus_get_default(), dev_walkerfn,
>> +                           NULL, NULL, NULL, sde_state);
>> +        if (!sde_state->gic_dev) {
>> +            error_report("Cannot find ARM GIC device!");
>> +            run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
>> +            return;
>> +        }
>> +    }
> Walking through the qbus tree looking for particular devices
> isn't really something I'd recommend either.
>
> thanks
> -- PMM
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/12] Add SDEI support for arm64
  2019-09-30 13:15 ` Peter Maydell
@ 2019-10-09 13:42   ` Guoheyi
  0 siblings, 0 replies; 25+ messages in thread
From: Guoheyi @ 2019-10-09 13:42 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Mark Rutland, Marc Zyngier, QEMU Developers, Dave Martin,
	qemu-arm, James Morse, wanghaibin.wang, kvmarm, arm-mail-list



On 2019/9/30 21:15, Peter Maydell wrote:
> On Tue, 24 Sep 2019 at 16:23, Heyi Guo <guoheyi@huawei.com> wrote:
>> As promised, this is the first RFC patch set for arm64 SDEI support.
> Hi; for the benefit of possible reviewers who aren't familiar
> with every corner of the arm ecosystem, could you provide a
> summary of:
>   * what is SDEI ?
SDEI is for ARM "Software Delegated Exception Interface". AS ARM64 
doesn't have native non-maskable interrupt (NMI), we can rely on higher 
privileged software to change the pc of lower privileged software on 
certain events occur, to emulate NMI mechanism, and SDEI is the standard 
interfaces between the two levels of privileged software. It is based on 
SMC/HVC calls.

In virtualization situation, guest OS is the lower privileged software 
and hypervisor is the higher one. Major interfaces provided by SDEI include:
1. interrupt bind: guest OS can request to bind an interrupt to an SDEI 
event.
2. register: guest OS can request to register a handler to an SDEI 
event, so hypervisor will change pc of guest to this handler when 
certain event occurs.
3. complete: guest OS notifies hypervisor that it has completed the 
event handling, so hypervisor will restore the context of guest when it 
is interrupted.
>   * what do KVM and QEMU want/need to do with it ?
KVM is supposed to pass SMC/HVC calls to qemu, and qemu will serve the 
SDEI requests after parsing SMC/HVC calls. qemu also takes the 
responsibility to trigger the events. If an interrupt is requested to be 
bound to an event, qemu should not inject the interrupt to guest any 
more; instead, it should save the context of VCPU and change the PC to 
event handler which is registered by guest, and then return to guest.

To make the conversion of interrupt to SDEI event transparent to other 
modules in qemu, we used qemu_irq and qemu_irq_intercept_in() to 
override the default irq handler with SDEI event trigger. I saw 
qemu_irq_intercept_in() should be only used in qemu MST, but it seemed 
fit to override interrupt injection with event trigger after guest 
requests to bind interrupt to SDEI event.
>   * what is this patchset trying to solve ?
This patchset is trying to implement the whole SDEI framework in qemu 
with KVM enabled, including all SDEI v1.0 interfaces, as well as event 
trigger conduit from other qemu devices after interrupt binding.

I will also provide the above context in the cover letter of v2 RFC.

Thanks,

Heyi

>
> That would provide some useful context for trying to
> review the patchset.
>
> thanks
> -- PMM
>
> .
>




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
  2019-09-24 15:21 ` [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
@ 2019-10-10  9:15   ` Igor Mammedov
  2019-10-10 13:08     ` Guoheyi
  2019-10-10 14:01   ` Michael S. Tsirkin
  1 sibling, 1 reply; 25+ messages in thread
From: Igor Mammedov @ 2019-10-10  9:15 UTC (permalink / raw)
  To: Heyi Guo
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	qemu-devel, Dave Martin, Shannon Zhao, qemu-arm, James Morse,
	wanghaibin.wang, kvmarm, linux-arm-kernel

On Tue, 24 Sep 2019 23:21:51 +0800
Heyi Guo <guoheyi@huawei.com> wrote:

> Add SDEI table if SDEI is enabled, so that guest OS can get aware and
> utilize the interfaces.
> 
> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> ---
>  hw/arm/virt-acpi-build.c    | 16 ++++++++++++++++
>  include/hw/acpi/acpi-defs.h |  5 +++++
>  2 files changed, 21 insertions(+)
> 
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 6cdf156..1088214 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -32,6 +32,7 @@
>  #include "trace.h"
>  #include "hw/core/cpu.h"
>  #include "target/arm/cpu.h"
> +#include "target/arm/sdei.h"
>  #include "hw/acpi/acpi-defs.h"
>  #include "hw/acpi/acpi.h"
>  #include "hw/nvram/fw_cfg.h"
> @@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>  }
>  

here should be a comment describing purpose with a reference to spec

>  static void
> +build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> +{
> +    int sdei_start = table_data->len;
> +
> +    (void)acpi_data_push(table_data, sizeof(AcpiSdei));
> +    build_header(linker, table_data, (void *)(table_data->data + sdei_start),
> +                 "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
> +}
that's dummy table and doesn't match what spec describes,
It doesn't look correct SDEI table.

> +
> +static void
>  build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>  {
>      AcpiSerialPortConsoleRedirection *spcr;
> @@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
>      acpi_add_table(table_offsets, tables_blob);
>      build_spcr(tables_blob, tables->linker, vms);
>  
> +    if (sdei_enabled) {
> +        acpi_add_table(table_offsets, tables_blob);
> +        build_sdei(tables_blob, tables->linker, vms);
> +    }
> +
>      if (ms->numa_state->num_nodes > 0) {
>          acpi_add_table(table_offsets, tables_blob);
>          build_srat(tables_blob, tables->linker, vms);
> diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
> index 57a3f58..0a2265d 100644
> --- a/include/hw/acpi/acpi-defs.h
> +++ b/include/hw/acpi/acpi-defs.h
> @@ -634,4 +634,9 @@ struct AcpiIortRC {
>  } QEMU_PACKED;
>  typedef struct AcpiIortRC AcpiIortRC;
>  
> +struct AcpiSdei {
> +    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
> +} QEMU_PACKED;
> +typedef struct AcpiSdei AcpiSdei;

we don't use packed structures for ACPI anymore, see build_rsdp() for
example of how tables are composed and comment style required for each field.

>  #endif



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
  2019-10-10  9:15   ` Igor Mammedov
@ 2019-10-10 13:08     ` Guoheyi
  2019-10-10 13:57       ` Igor Mammedov
  0 siblings, 1 reply; 25+ messages in thread
From: Guoheyi @ 2019-10-10 13:08 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	qemu-devel, Dave Martin, Shannon Zhao, qemu-arm, James Morse,
	wanghaibin.wang, kvmarm, linux-arm-kernel

Thanks for your comments.

On 2019/10/10 17:15, Igor Mammedov wrote:
> On Tue, 24 Sep 2019 23:21:51 +0800
> Heyi Guo <guoheyi@huawei.com> wrote:
>
>> Add SDEI table if SDEI is enabled, so that guest OS can get aware and
>> utilize the interfaces.
>>
>> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
>> Cc: Peter Maydell <peter.maydell@linaro.org>
>> Cc: Dave Martin <Dave.Martin@arm.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: James Morse <james.morse@arm.com>
>> Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> ---
>>   hw/arm/virt-acpi-build.c    | 16 ++++++++++++++++
>>   include/hw/acpi/acpi-defs.h |  5 +++++
>>   2 files changed, 21 insertions(+)
>>
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index 6cdf156..1088214 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -32,6 +32,7 @@
>>   #include "trace.h"
>>   #include "hw/core/cpu.h"
>>   #include "target/arm/cpu.h"
>> +#include "target/arm/sdei.h"
>>   #include "hw/acpi/acpi-defs.h"
>>   #include "hw/acpi/acpi.h"
>>   #include "hw/nvram/fw_cfg.h"
>> @@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>>   }
>>   
> here should be a comment describing purpose with a reference to spec
OK.

>
>>   static void
>> +build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> +{
>> +    int sdei_start = table_data->len;
>> +
>> +    (void)acpi_data_push(table_data, sizeof(AcpiSdei));
>> +    build_header(linker, table_data, (void *)(table_data->data + sdei_start),
>> +                 "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
>> +}
> that's dummy table and doesn't match what spec describes,
> It doesn't look correct SDEI table.

Refer to below document, Appendix C, I see the definition of SDEI is 
really a dummy table, also it is said in the document: The table 
consists only of a basic header with revision 1.

http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf

Do I miss anything?

>
>> +
>> +static void
>>   build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>>   {
>>       AcpiSerialPortConsoleRedirection *spcr;
>> @@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
>>       acpi_add_table(table_offsets, tables_blob);
>>       build_spcr(tables_blob, tables->linker, vms);
>>   
>> +    if (sdei_enabled) {
>> +        acpi_add_table(table_offsets, tables_blob);
>> +        build_sdei(tables_blob, tables->linker, vms);
>> +    }
>> +
>>       if (ms->numa_state->num_nodes > 0) {
>>           acpi_add_table(table_offsets, tables_blob);
>>           build_srat(tables_blob, tables->linker, vms);
>> diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
>> index 57a3f58..0a2265d 100644
>> --- a/include/hw/acpi/acpi-defs.h
>> +++ b/include/hw/acpi/acpi-defs.h
>> @@ -634,4 +634,9 @@ struct AcpiIortRC {
>>   } QEMU_PACKED;
>>   typedef struct AcpiIortRC AcpiIortRC;
>>   
>> +struct AcpiSdei {
>> +    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
>> +} QEMU_PACKED;
>> +typedef struct AcpiSdei AcpiSdei;
> we don't use packed structures for ACPI anymore, see build_rsdp() for
> example of how tables are composed and comment style required for each field.
Sure; will fix it in v2.

Thanks,

Heyi

>
>>   #endif
>
> .
>




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
  2019-10-10 13:08     ` Guoheyi
@ 2019-10-10 13:57       ` Igor Mammedov
  0 siblings, 0 replies; 25+ messages in thread
From: Igor Mammedov @ 2019-10-10 13:57 UTC (permalink / raw)
  To: Guoheyi
  Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
	qemu-devel, Dave Martin, Shannon Zhao, qemu-arm, James Morse,
	wanghaibin.wang, kvmarm, linux-arm-kernel

On Thu, 10 Oct 2019 21:08:10 +0800
Guoheyi <guoheyi@huawei.com> wrote:

> Thanks for your comments.
> 
> On 2019/10/10 17:15, Igor Mammedov wrote:
> > On Tue, 24 Sep 2019 23:21:51 +0800
> > Heyi Guo <guoheyi@huawei.com> wrote:
> >  
> >> Add SDEI table if SDEI is enabled, so that guest OS can get aware and
> >> utilize the interfaces.
> >>
> >> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> >> Cc: Peter Maydell <peter.maydell@linaro.org>
> >> Cc: Dave Martin <Dave.Martin@arm.com>
> >> Cc: Marc Zyngier <marc.zyngier@arm.com>
> >> Cc: Mark Rutland <mark.rutland@arm.com>
> >> Cc: James Morse <james.morse@arm.com>
> >> Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> ---
> >>   hw/arm/virt-acpi-build.c    | 16 ++++++++++++++++
> >>   include/hw/acpi/acpi-defs.h |  5 +++++
> >>   2 files changed, 21 insertions(+)
> >>
> >> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> >> index 6cdf156..1088214 100644
> >> --- a/hw/arm/virt-acpi-build.c
> >> +++ b/hw/arm/virt-acpi-build.c
> >> @@ -32,6 +32,7 @@
> >>   #include "trace.h"
> >>   #include "hw/core/cpu.h"
> >>   #include "target/arm/cpu.h"
> >> +#include "target/arm/sdei.h"
> >>   #include "hw/acpi/acpi-defs.h"
> >>   #include "hw/acpi/acpi.h"
> >>   #include "hw/nvram/fw_cfg.h"
> >> @@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> >>   }
> >>     
> > here should be a comment describing purpose with a reference to spec  
> OK.
> 
> >  
> >>   static void
> >> +build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> >> +{
> >> +    int sdei_start = table_data->len;
> >> +
> >> +    (void)acpi_data_push(table_data, sizeof(AcpiSdei));
> >> +    build_header(linker, table_data, (void *)(table_data->data + sdei_start),
> >> +                 "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
> >> +}  
> > that's dummy table and doesn't match what spec describes,
> > It doesn't look correct SDEI table.  
> 
> Refer to below document, Appendix C, I see the definition of SDEI is 
> really a dummy table, also it is said in the document: The table 
> consists only of a basic header with revision 1.
> 
> http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
> 
> Do I miss anything?
No you are right and I was mistaken.
It's pretty waste-full way to communicate to OS a Boolean flag
that a new GHEST event is supported. But since they managed to make
it a spec, it should be coded as such.


> 
> >  
> >> +
> >> +static void
> >>   build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> >>   {
> >>       AcpiSerialPortConsoleRedirection *spcr;
> >> @@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
> >>       acpi_add_table(table_offsets, tables_blob);
> >>       build_spcr(tables_blob, tables->linker, vms);
> >>   
> >> +    if (sdei_enabled) {
> >> +        acpi_add_table(table_offsets, tables_blob);
> >> +        build_sdei(tables_blob, tables->linker, vms);
> >> +    }
> >> +
> >>       if (ms->numa_state->num_nodes > 0) {
> >>           acpi_add_table(table_offsets, tables_blob);
> >>           build_srat(tables_blob, tables->linker, vms);
> >> diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
> >> index 57a3f58..0a2265d 100644
> >> --- a/include/hw/acpi/acpi-defs.h
> >> +++ b/include/hw/acpi/acpi-defs.h
> >> @@ -634,4 +634,9 @@ struct AcpiIortRC {
> >>   } QEMU_PACKED;
> >>   typedef struct AcpiIortRC AcpiIortRC;
> >>   
> >> +struct AcpiSdei {
> >> +    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
> >> +} QEMU_PACKED;
> >> +typedef struct AcpiSdei AcpiSdei;  
> > we don't use packed structures for ACPI anymore, see build_rsdp() for
> > example of how tables are composed and comment style required for each field.  
> Sure; will fix it in v2.
> 
> Thanks,
> 
> Heyi
> 
> >  
> >>   #endif  
> >
> > .
> >  
> 
> 



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
  2019-09-24 15:21 ` [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
  2019-10-10  9:15   ` Igor Mammedov
@ 2019-10-10 14:01   ` Michael S. Tsirkin
  1 sibling, 0 replies; 25+ messages in thread
From: Michael S. Tsirkin @ 2019-10-10 14:01 UTC (permalink / raw)
  To: Heyi Guo
  Cc: Mark Rutland, Peter Maydell, Marc Zyngier, qemu-devel,
	Dave Martin, Shannon Zhao, qemu-arm, James Morse, Igor Mammedov,
	wanghaibin.wang, kvmarm, linux-arm-kernel

On Tue, Sep 24, 2019 at 11:21:51PM +0800, Heyi Guo wrote:
> Add SDEI table if SDEI is enabled, so that guest OS can get aware and
> utilize the interfaces.
> 
> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> ---
>  hw/arm/virt-acpi-build.c    | 16 ++++++++++++++++
>  include/hw/acpi/acpi-defs.h |  5 +++++
>  2 files changed, 21 insertions(+)
> 
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 6cdf156..1088214 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -32,6 +32,7 @@
>  #include "trace.h"
>  #include "hw/core/cpu.h"
>  #include "target/arm/cpu.h"
> +#include "target/arm/sdei.h"
>  #include "hw/acpi/acpi-defs.h"
>  #include "hw/acpi/acpi.h"
>  #include "hw/nvram/fw_cfg.h"
> @@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>  }
>  
>  static void
> +build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> +{
> +    int sdei_start = table_data->len;
> +
> +    (void)acpi_data_push(table_data, sizeof(AcpiSdei));
> +    build_header(linker, table_data, (void *)(table_data->data + sdei_start),
> +                 "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
> +}
> +

Please quote the relevant spec, earliest version that includes
this table, and chapter in that spec.

> +static void
>  build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>  {
>      AcpiSerialPortConsoleRedirection *spcr;
> @@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
>      acpi_add_table(table_offsets, tables_blob);
>      build_spcr(tables_blob, tables->linker, vms);
>  
> +    if (sdei_enabled) {
> +        acpi_add_table(table_offsets, tables_blob);
> +        build_sdei(tables_blob, tables->linker, vms);
> +    }
> +
>      if (ms->numa_state->num_nodes > 0) {
>          acpi_add_table(table_offsets, tables_blob);
>          build_srat(tables_blob, tables->linker, vms);
> diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
> index 57a3f58..0a2265d 100644
> --- a/include/hw/acpi/acpi-defs.h
> +++ b/include/hw/acpi/acpi-defs.h
> @@ -634,4 +634,9 @@ struct AcpiIortRC {
>  } QEMU_PACKED;
>  typedef struct AcpiIortRC AcpiIortRC;
>  
> +struct AcpiSdei {
> +    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
> +} QEMU_PACKED;
> +typedef struct AcpiSdei AcpiSdei;
> +
>  #endif
> -- 
> 1.8.3.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2019-10-10 14:03 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-24 15:21 [RFC PATCH 00/12] Add SDEI support for arm64 Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 01/12] linux-headers: import arm_sdei.h Heyi Guo
2019-09-24 15:39   ` Michael S. Tsirkin
2019-09-25  8:12     ` Guoheyi
2019-09-24 15:21 ` [RFC PATCH 02/12] arm/sdei: add virtual device framework Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 03/12] arm/sdei: add support to handle SDEI requests from guest Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 04/12] arm/sdei: add system reset callback Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 05/12] arm/sdei: add support to trigger event by GIC interrupt ID Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 06/12] core/irq: add qemu_irq_remove_intercept interface Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt Heyi Guo
2019-09-30 13:19   ` Peter Maydell
2019-10-09 13:06     ` Guoheyi
2019-09-24 15:21 ` [RFC PATCH 08/12] arm/sdei: add support to register interrupt bind notifier Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 09/12] linux-headers/kvm.h: add capability to forward hypercall Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 10/12] arm/sdei: check KVM cap and enable SDEI Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 11/12] arm/kvm: handle guest exit of hypercall Heyi Guo
2019-09-24 15:21 ` [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
2019-10-10  9:15   ` Igor Mammedov
2019-10-10 13:08     ` Guoheyi
2019-10-10 13:57       ` Igor Mammedov
2019-10-10 14:01   ` Michael S. Tsirkin
2019-09-25  6:54 ` [RFC PATCH 00/12] Add SDEI support for arm64 no-reply
2019-09-25  6:58 ` no-reply
2019-09-30 13:15 ` Peter Maydell
2019-10-09 13:42   ` Guoheyi

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).