diff mbox series

[v1,4/5] arm/kvm: add skeleton implementation for userspace SMCCC call handling

Message ID 20230626064910.1787255-5-shahuang@redhat.com
State New
Headers show
Series target/arm: Handle psci calls in userspace | expand

Commit Message

Shaoqin Huang June 26, 2023, 6:49 a.m. UTC
The SMCCC call filtering provide the ability to forward the SMCCC call
to userspace, so we provide a new option `user-smccc` to enable handling
SMCCC call in userspace, the default value is off.

And add the skeleton implementation for userspace SMCCC call
initialization and handling.

Signed-off-by: Shaoqin Huang <shahuang@redhat.com>
---
 docs/system/arm/virt.rst |  4 +++
 hw/arm/virt.c            | 21 ++++++++++++++++
 include/hw/arm/virt.h    |  1 +
 target/arm/kvm.c         | 54 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+)

Comments

Cornelia Huck July 4, 2023, 9:17 a.m. UTC | #1
On Mon, Jun 26 2023, Shaoqin Huang <shahuang@redhat.com> wrote:

> The SMCCC call filtering provide the ability to forward the SMCCC call
> to userspace, so we provide a new option `user-smccc` to enable handling
> SMCCC call in userspace, the default value is off.
>
> And add the skeleton implementation for userspace SMCCC call
> initialization and handling.
>
> Signed-off-by: Shaoqin Huang <shahuang@redhat.com>
> ---
>  docs/system/arm/virt.rst |  4 +++
>  hw/arm/virt.c            | 21 ++++++++++++++++
>  include/hw/arm/virt.h    |  1 +
>  target/arm/kvm.c         | 54 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 80 insertions(+)
>
> diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
> index 1cab33f02e..ff43d52f04 100644
> --- a/docs/system/arm/virt.rst
> +++ b/docs/system/arm/virt.rst
> @@ -155,6 +155,10 @@ dtb-randomness
>    DTB to be non-deterministic. It would be the responsibility of
>    the firmware to come up with a seed and pass it on if it wants to.
>  
> +user-smccc
> +  Set ``on``/``off`` to enable/disable handling smccc call in userspace
> +  instead of kernel.
> +
>  dtb-kaslr-seed
>    A deprecated synonym for dtb-randomness.
>  
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 9b9f7d9c68..767720321c 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -42,6 +42,7 @@
>  #include "hw/vfio/vfio-amd-xgbe.h"
>  #include "hw/display/ramfb.h"
>  #include "net/net.h"
> +#include "qom/object.h"
>  #include "sysemu/device_tree.h"
>  #include "sysemu/numa.h"
>  #include "sysemu/runstate.h"
> @@ -2511,6 +2512,19 @@ static void virt_set_oem_table_id(Object *obj, const char *value,
>      strncpy(vms->oem_table_id, value, 8);
>  }
>  
> +static bool virt_get_user_smccc(Object *obj, Error **errp)
> +{
> +    VirtMachineState *vms = VIRT_MACHINE(obj);
> +
> +    return vms->user_smccc;
> +}
> +
> +static void virt_set_user_smccc(Object *obj, bool value, Error **errp)
> +{
> +    VirtMachineState *vms = VIRT_MACHINE(obj);
> +
> +    vms->user_smccc = value;
> +}
>  
>  bool virt_is_acpi_enabled(VirtMachineState *vms)
>  {
> @@ -3155,6 +3169,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
>                                            "in ACPI table header."
>                                            "The string may be up to 8 bytes in size");
>  
> +    object_class_property_add_bool(oc, "user-smccc",
> +                                   virt_get_user_smccc,
> +                                   virt_set_user_smccc);
> +    object_class_property_set_description(oc, "user-smccc",
> +                                          "Set on/off to enable/disable "
> +                                          "handling smccc call in userspace");
> +
>  }
>  
>  static void virt_instance_init(Object *obj)

This knob pretty much only makes sense for KVM guests, and we'll ignore
it with tcg -- would it make sense to check that we are actually using
KVM before we proceed (like we do for the tcg-only props?)
diff mbox series

Patch

diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index 1cab33f02e..ff43d52f04 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -155,6 +155,10 @@  dtb-randomness
   DTB to be non-deterministic. It would be the responsibility of
   the firmware to come up with a seed and pass it on if it wants to.
 
+user-smccc
+  Set ``on``/``off`` to enable/disable handling smccc call in userspace
+  instead of kernel.
+
 dtb-kaslr-seed
   A deprecated synonym for dtb-randomness.
 
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9b9f7d9c68..767720321c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -42,6 +42,7 @@ 
 #include "hw/vfio/vfio-amd-xgbe.h"
 #include "hw/display/ramfb.h"
 #include "net/net.h"
+#include "qom/object.h"
 #include "sysemu/device_tree.h"
 #include "sysemu/numa.h"
 #include "sysemu/runstate.h"
@@ -2511,6 +2512,19 @@  static void virt_set_oem_table_id(Object *obj, const char *value,
     strncpy(vms->oem_table_id, value, 8);
 }
 
+static bool virt_get_user_smccc(Object *obj, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    return vms->user_smccc;
+}
+
+static void virt_set_user_smccc(Object *obj, bool value, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    vms->user_smccc = value;
+}
 
 bool virt_is_acpi_enabled(VirtMachineState *vms)
 {
@@ -3155,6 +3169,13 @@  static void virt_machine_class_init(ObjectClass *oc, void *data)
                                           "in ACPI table header."
                                           "The string may be up to 8 bytes in size");
 
+    object_class_property_add_bool(oc, "user-smccc",
+                                   virt_get_user_smccc,
+                                   virt_set_user_smccc);
+    object_class_property_set_description(oc, "user-smccc",
+                                          "Set on/off to enable/disable "
+                                          "handling smccc call in userspace");
+
 }
 
 static void virt_instance_init(Object *obj)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index e1ddbea96b..4f1bc12680 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -160,6 +160,7 @@  struct VirtMachineState {
     bool ras;
     bool mte;
     bool dtb_randomness;
+    bool user_smccc;
     OnOffAuto acpi;
     VirtGICType gic_version;
     VirtIOMMUType iommu;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 84da49332c..579c6edd49 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -9,6 +9,8 @@ 
  */
 
 #include "qemu/osdep.h"
+#include <asm-arm64/kvm.h>
+#include <linux/arm-smccc.h>
 #include <sys/ioctl.h>
 
 #include <linux/kvm.h>
@@ -247,6 +249,20 @@  int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
     return ret > 0 ? ret : 40;
 }
 
+static int kvm_arm_init_smccc_filter(KVMState *s)
+{
+    int ret = 0;
+
+    if (kvm_vm_check_attr(s, KVM_ARM_VM_SMCCC_CTRL, KVM_ARM_VM_SMCCC_FILTER)) {
+        error_report("ARM SMCCC filter not supported");
+        ret = -EINVAL;
+        goto out;
+    }
+
+out:
+    return ret;
+}
+
 int kvm_arch_init(MachineState *ms, KVMState *s)
 {
     int ret = 0;
@@ -282,6 +298,10 @@  int kvm_arch_init(MachineState *ms, KVMState *s)
 
     kvm_arm_init_debug(s);
 
+    if (ret == 0 && object_property_get_bool(OBJECT(ms), "user-smccc", NULL)) {
+        ret = kvm_arm_init_smccc_filter(s);
+    }
+
     return ret;
 }
 
@@ -912,6 +932,37 @@  static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss,
     return -1;
 }
 
+static void kvm_arm_smccc_return_result(CPUState *cs, struct arm_smccc_res *res)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    env->xregs[0] = res->a0;
+    env->xregs[1] = res->a1;
+    env->xregs[2] = res->a2;
+    env->xregs[3] = res->a3;
+}
+
+static int kvm_arm_handle_hypercall(CPUState *cs, struct kvm_run *run)
+{
+    uint32_t fn = run->hypercall.nr;
+    struct arm_smccc_res res = {
+        .a0     = SMCCC_RET_NOT_SUPPORTED,
+    };
+    int ret = 0;
+
+    kvm_cpu_synchronize_state(cs);
+
+    switch (ARM_SMCCC_OWNER_NUM(fn)) {
+    default:
+        break;
+    }
+
+    kvm_arm_smccc_return_result(cs, &res);
+
+    return ret;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret = 0;
@@ -927,6 +978,9 @@  int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
         ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
                                        run->arm_nisv.fault_ipa);
         break;
+    case KVM_EXIT_HYPERCALL:
+        ret = kvm_arm_handle_hypercall(cs, run);
+        break;
     default:
         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
                       __func__, run->exit_reason);