KVM: arm64: Expose PSCI SYSTEM_RESET2 call to the guest
authorWill Deacon <will@kernel.org>
Mon, 21 Feb 2022 15:35:23 +0000 (15:35 +0000)
committerMarc Zyngier <maz@kernel.org>
Mon, 21 Feb 2022 16:02:55 +0000 (16:02 +0000)
PSCI v1.1 introduces the optional SYSTEM_RESET2 call, which allows the
caller to provide a vendor-specific "reset type" and "cookie" to request
a particular form of reset or shutdown.

Expose this call to the guest and handle it in the same way as PSCI
SYSTEM_RESET, along with some basic range checking on the type argument.

Cc: Marc Zyngier <maz@kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220221153524.15397-3-will@kernel.org
arch/arm64/kvm/psci.c
include/uapi/linux/psci.h

index 70d0747..30fcc5a 100644 (file)
@@ -308,7 +308,7 @@ out:
 static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)
 {
        u32 psci_fn = smccc_get_function(vcpu);
-       u32 feature;
+       u32 arg;
        unsigned long val;
        int ret = 1;
 
@@ -320,12 +320,12 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)
                val = minor == 0 ? KVM_ARM_PSCI_1_0 : KVM_ARM_PSCI_1_1;
                break;
        case PSCI_1_0_FN_PSCI_FEATURES:
-               feature = smccc_get_arg1(vcpu);
-               val = kvm_psci_check_allowed_function(vcpu, feature);
+               arg = smccc_get_arg1(vcpu);
+               val = kvm_psci_check_allowed_function(vcpu, arg);
                if (val)
                        break;
 
-               switch(feature) {
+               switch(arg) {
                case PSCI_0_2_FN_PSCI_VERSION:
                case PSCI_0_2_FN_CPU_SUSPEND:
                case PSCI_0_2_FN64_CPU_SUSPEND:
@@ -341,11 +341,36 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)
                case ARM_SMCCC_VERSION_FUNC_ID:
                        val = 0;
                        break;
+               case PSCI_1_1_FN_SYSTEM_RESET2:
+               case PSCI_1_1_FN64_SYSTEM_RESET2:
+                       if (minor >= 1) {
+                               val = 0;
+                               break;
+                       }
+                       fallthrough;
                default:
                        val = PSCI_RET_NOT_SUPPORTED;
                        break;
                }
                break;
+       case PSCI_1_1_FN_SYSTEM_RESET2:
+               kvm_psci_narrow_to_32bit(vcpu);
+               fallthrough;
+       case PSCI_1_1_FN64_SYSTEM_RESET2:
+               if (minor >= 1) {
+                       arg = smccc_get_arg1(vcpu);
+
+                       if (arg > PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET &&
+                           arg < PSCI_1_1_RESET_TYPE_VENDOR_START) {
+                               val = PSCI_RET_INVALID_PARAMS;
+                       } else {
+                               kvm_psci_system_reset(vcpu);
+                               val = PSCI_RET_INTERNAL_FAILURE;
+                               ret = 0;
+                       }
+                       break;
+               };
+               fallthrough;
        default:
                return kvm_psci_0_2_call(vcpu);
        }
index 2fcad1d..2bf93c0 100644 (file)
 #define PSCI_0_2_TOS_UP_NO_MIGRATE             1
 #define PSCI_0_2_TOS_MP                                2
 
+/* PSCI v1.1 reset type encoding for SYSTEM_RESET2 */
+#define PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET  0
+#define PSCI_1_1_RESET_TYPE_VENDOR_START       0x80000000U
+
 /* PSCI version decoding (independent of PSCI version) */
 #define PSCI_VERSION_MAJOR_SHIFT               16
 #define PSCI_VERSION_MINOR_MASK                        \