From 54f8a207e85be33fb129cc1f79ad58535b7b84ce Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 30 Apr 2018 10:50:50 -0700 Subject: [PATCH] 4.14-stable patches added patches: arm-arm64-kvm-add-psci-version-selection-api.patch --- ...4-kvm-add-psci-version-selection-api.patch | 367 ++++++++++++++++++ queue-4.14/series | 1 + 2 files changed, 368 insertions(+) create mode 100644 queue-4.14/arm-arm64-kvm-add-psci-version-selection-api.patch diff --git a/queue-4.14/arm-arm64-kvm-add-psci-version-selection-api.patch b/queue-4.14/arm-arm64-kvm-add-psci-version-selection-api.patch new file mode 100644 index 00000000000..f37f1108e4a --- /dev/null +++ b/queue-4.14/arm-arm64-kvm-add-psci-version-selection-api.patch @@ -0,0 +1,367 @@ +From 85bd0ba1ff9875798fad94218b627ea9f768f3c3 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sun, 21 Jan 2018 16:42:56 +0000 +Subject: arm/arm64: KVM: Add PSCI version selection API + +From: Marc Zyngier + +commit 85bd0ba1ff9875798fad94218b627ea9f768f3c3 upstream. + +Although we've implemented PSCI 0.1, 0.2 and 1.0, we expose either 0.1 +or 1.0 to a guest, defaulting to the latest version of the PSCI +implementation that is compatible with the requested version. This is +no different from doing a firmware upgrade on KVM. + +But in order to give a chance to hypothetical badly implemented guests +that would have a fit by discovering something other than PSCI 0.2, +let's provide a new API that allows userspace to pick one particular +version of the API. + +This is implemented as a new class of "firmware" registers, where +we expose the PSCI version. This allows the PSCI version to be +save/restored as part of a guest migration, and also set to +any supported version if the guest requires it. + +Cc: stable@vger.kernel.org #4.16 +Reviewed-by: Christoffer Dall +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/virtual/kvm/api.txt | 9 ++++ + Documentation/virtual/kvm/arm/psci.txt | 30 ++++++++++++++++ + arch/arm/include/asm/kvm_host.h | 3 + + arch/arm/include/uapi/asm/kvm.h | 6 +++ + arch/arm/kvm/guest.c | 13 +++++++ + arch/arm64/include/asm/kvm_host.h | 3 + + arch/arm64/include/uapi/asm/kvm.h | 6 +++ + arch/arm64/kvm/guest.c | 14 +++++++ + include/kvm/arm_psci.h | 16 +++++++- + virt/kvm/arm/psci.c | 60 +++++++++++++++++++++++++++++++++ + 10 files changed, 156 insertions(+), 4 deletions(-) + +--- a/Documentation/virtual/kvm/api.txt ++++ b/Documentation/virtual/kvm/api.txt +@@ -1940,6 +1940,9 @@ ARM 32-bit VFP control registers have th + ARM 64-bit FP registers have the following id bit patterns: + 0x4030 0000 0012 0 + ++ARM firmware pseudo-registers have the following bit pattern: ++ 0x4030 0000 0014 ++ + + arm64 registers are mapped using the lower 32 bits. The upper 16 of + that is the register group type, or coprocessor number: +@@ -1956,6 +1959,9 @@ arm64 CCSIDR registers are demultiplexed + arm64 system registers have the following id bit patterns: + 0x6030 0000 0013 + ++arm64 firmware pseudo-registers have the following bit pattern: ++ 0x6030 0000 0014 ++ + + MIPS registers are mapped using the lower 32 bits. The upper 16 of that is + the register group type: +@@ -2490,7 +2496,8 @@ Possible features: + and execute guest code when KVM_RUN is called. + - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. + Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). +- - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. ++ - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision ++ backward compatible with v0.2) for the CPU. + Depends on KVM_CAP_ARM_PSCI_0_2. + - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU. + Depends on KVM_CAP_ARM_PMU_V3. +--- /dev/null ++++ b/Documentation/virtual/kvm/arm/psci.txt +@@ -0,0 +1,30 @@ ++KVM implements the PSCI (Power State Coordination Interface) ++specification in order to provide services such as CPU on/off, reset ++and power-off to the guest. ++ ++The PSCI specification is regularly updated to provide new features, ++and KVM implements these updates if they make sense from a virtualization ++point of view. ++ ++This means that a guest booted on two different versions of KVM can ++observe two different "firmware" revisions. This could cause issues if ++a given guest is tied to a particular PSCI revision (unlikely), or if ++a migration causes a different PSCI version to be exposed out of the ++blue to an unsuspecting guest. ++ ++In order to remedy this situation, KVM exposes a set of "firmware ++pseudo-registers" that can be manipulated using the GET/SET_ONE_REG ++interface. These registers can be saved/restored by userspace, and set ++to a convenient value if required. ++ ++The following register is defined: ++ ++* KVM_REG_ARM_PSCI_VERSION: ++ ++ - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set ++ (and thus has already been initialized) ++ - Returns the current PSCI version on GET_ONE_REG (defaulting to the ++ highest PSCI version implemented by KVM and compatible with v0.2) ++ - Allows any PSCI version implemented by KVM and compatible with ++ v0.2 to be set with SET_ONE_REG ++ - Affects the whole VM (even if the register view is per-vcpu) +--- a/arch/arm/include/asm/kvm_host.h ++++ b/arch/arm/include/asm/kvm_host.h +@@ -75,6 +75,9 @@ struct kvm_arch { + /* Interrupt controller */ + struct vgic_dist vgic; + int max_vcpus; ++ ++ /* Mandated version of PSCI */ ++ u32 psci_version; + }; + + #define KVM_NR_MEM_OBJS 40 +--- a/arch/arm/include/uapi/asm/kvm.h ++++ b/arch/arm/include/uapi/asm/kvm.h +@@ -180,6 +180,12 @@ struct kvm_arch_memory_slot { + #define KVM_REG_ARM_VFP_FPINST 0x1009 + #define KVM_REG_ARM_VFP_FPINST2 0x100A + ++/* KVM-as-firmware specific pseudo-registers */ ++#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) ++#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ ++ KVM_REG_ARM_FW | ((r) & 0xffff)) ++#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) ++ + /* Device Control API: ARM VGIC */ + #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 + #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +--- a/arch/arm/kvm/guest.c ++++ b/arch/arm/kvm/guest.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -176,6 +177,7 @@ static unsigned long num_core_regs(void) + unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) + { + return num_core_regs() + kvm_arm_num_coproc_regs(vcpu) ++ + kvm_arm_get_fw_num_regs(vcpu) + + NUM_TIMER_REGS; + } + +@@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_ + uindices++; + } + ++ ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); ++ if (ret) ++ return ret; ++ uindices += kvm_arm_get_fw_num_regs(vcpu); ++ + ret = copy_timer_indices(vcpu, uindices); + if (ret) + return ret; +@@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcp + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) + return get_core_reg(vcpu, reg); + ++ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) ++ return kvm_arm_get_fw_reg(vcpu, reg); ++ + if (is_timer_reg(reg->id)) + return get_timer_reg(vcpu, reg); + +@@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcp + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) + return set_core_reg(vcpu, reg); + ++ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) ++ return kvm_arm_set_fw_reg(vcpu, reg); ++ + if (is_timer_reg(reg->id)) + return set_timer_reg(vcpu, reg); + +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -71,6 +71,9 @@ struct kvm_arch { + + /* Interrupt controller */ + struct vgic_dist vgic; ++ ++ /* Mandated version of PSCI */ ++ u32 psci_version; + }; + + #define KVM_NR_MEM_OBJS 40 +--- a/arch/arm64/include/uapi/asm/kvm.h ++++ b/arch/arm64/include/uapi/asm/kvm.h +@@ -200,6 +200,12 @@ struct kvm_arch_memory_slot { + #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) + #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) + ++/* KVM-as-firmware specific pseudo-registers */ ++#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) ++#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ ++ KVM_REG_ARM_FW | ((r) & 0xffff)) ++#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) ++ + /* Device Control API: ARM VGIC */ + #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 + #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +--- a/arch/arm64/kvm/guest.c ++++ b/arch/arm64/kvm/guest.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu + unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) + { + return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu) +- + NUM_TIMER_REGS; ++ + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS; + } + + /** +@@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_ + uindices++; + } + ++ ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); ++ if (ret) ++ return ret; ++ uindices += kvm_arm_get_fw_num_regs(vcpu); ++ + ret = copy_timer_indices(vcpu, uindices); + if (ret) + return ret; +@@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcp + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) + return get_core_reg(vcpu, reg); + ++ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) ++ return kvm_arm_get_fw_reg(vcpu, reg); ++ + if (is_timer_reg(reg->id)) + return get_timer_reg(vcpu, reg); + +@@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcp + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) + return set_core_reg(vcpu, reg); + ++ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) ++ return kvm_arm_set_fw_reg(vcpu, reg); ++ + if (is_timer_reg(reg->id)) + return set_timer_reg(vcpu, reg); + +--- a/include/kvm/arm_psci.h ++++ b/include/kvm/arm_psci.h +@@ -37,10 +37,15 @@ static inline int kvm_psci_version(struc + * Our PSCI implementation stays the same across versions from + * v0.2 onward, only adding the few mandatory functions (such + * as FEATURES with 1.0) that are required by newer +- * revisions. It is thus safe to return the latest. ++ * revisions. It is thus safe to return the latest, unless ++ * userspace has instructed us otherwise. + */ +- if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) ++ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) { ++ if (vcpu->kvm->arch.psci_version) ++ return vcpu->kvm->arch.psci_version; ++ + return KVM_ARM_PSCI_LATEST; ++ } + + return KVM_ARM_PSCI_0_1; + } +@@ -48,4 +53,11 @@ static inline int kvm_psci_version(struc + + int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); + ++struct kvm_one_reg; ++ ++int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); ++int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); ++int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); ++int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); ++ + #endif /* __KVM_ARM_PSCI_H__ */ +--- a/virt/kvm/arm/psci.c ++++ b/virt/kvm/arm/psci.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -427,3 +428,62 @@ int kvm_hvc_call_handler(struct kvm_vcpu + smccc_set_retval(vcpu, val, 0, 0, 0); + return 1; + } ++ ++int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) ++{ ++ return 1; /* PSCI version */ ++} ++ ++int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) ++{ ++ if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ++{ ++ if (reg->id == KVM_REG_ARM_PSCI_VERSION) { ++ void __user *uaddr = (void __user *)(long)reg->addr; ++ u64 val; ++ ++ val = kvm_psci_version(vcpu, vcpu->kvm); ++ if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ++{ ++ if (reg->id == KVM_REG_ARM_PSCI_VERSION) { ++ void __user *uaddr = (void __user *)(long)reg->addr; ++ bool wants_02; ++ u64 val; ++ ++ if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) ++ return -EFAULT; ++ ++ wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); ++ ++ switch (val) { ++ case KVM_ARM_PSCI_0_1: ++ if (wants_02) ++ return -EINVAL; ++ vcpu->kvm->arch.psci_version = val; ++ return 0; ++ case KVM_ARM_PSCI_0_2: ++ case KVM_ARM_PSCI_1_0: ++ if (!wants_02) ++ return -EINVAL; ++ vcpu->kvm->arch.psci_version = val; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} diff --git a/queue-4.14/series b/queue-4.14/series index f670c6a0172..239a864cd49 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -86,3 +86,4 @@ x86-smpboot-don-t-use-mwait_play_dead-on-amd-systems.patch x86-microcode-intel-save-microcode-patch-unconditionally.patch x86-microcode-do-not-exit-early-from-__reload_late.patch tick-sched-do-not-mess-with-an-enqueued-hrtimer.patch +arm-arm64-kvm-add-psci-version-selection-api.patch -- 2.47.3