aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/virtual/kvm/api.txt9
-rw-r--r--Documentation/virtual/kvm/arm/psci.txt30
-rw-r--r--arch/arm/include/asm/kvm_host.h3
-rw-r--r--arch/arm/include/uapi/asm/kvm.h6
-rw-r--r--arch/arm/kvm/guest.c13
-rw-r--r--arch/arm64/include/asm/kvm_host.h3
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h6
-rw-r--r--arch/arm64/kvm/guest.c14
-rw-r--r--include/kvm/arm_psci.h16
-rw-r--r--virt/kvm/arm/psci.c60
10 files changed, 156 insertions, 4 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 1c7958b57fe9..758bf403a169 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1960,6 +1960,9 @@ ARM 32-bit VFP control registers have the following id bit patterns:
1960ARM 64-bit FP registers have the following id bit patterns: 1960ARM 64-bit FP registers have the following id bit patterns:
1961 0x4030 0000 0012 0 <regno:12> 1961 0x4030 0000 0012 0 <regno:12>
1962 1962
1963ARM firmware pseudo-registers have the following bit pattern:
1964 0x4030 0000 0014 <regno:16>
1965
1963 1966
1964arm64 registers are mapped using the lower 32 bits. The upper 16 of 1967arm64 registers are mapped using the lower 32 bits. The upper 16 of
1965that is the register group type, or coprocessor number: 1968that is the register group type, or coprocessor number:
@@ -1976,6 +1979,9 @@ arm64 CCSIDR registers are demultiplexed by CSSELR value:
1976arm64 system registers have the following id bit patterns: 1979arm64 system registers have the following id bit patterns:
1977 0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3> 1980 0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
1978 1981
1982arm64 firmware pseudo-registers have the following bit pattern:
1983 0x6030 0000 0014 <regno:16>
1984
1979 1985
1980MIPS registers are mapped using the lower 32 bits. The upper 16 of that is 1986MIPS registers are mapped using the lower 32 bits. The upper 16 of that is
1981the register group type: 1987the register group type:
@@ -2510,7 +2516,8 @@ Possible features:
2510 and execute guest code when KVM_RUN is called. 2516 and execute guest code when KVM_RUN is called.
2511 - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. 2517 - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
2512 Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). 2518 Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
2513 - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. 2519 - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
2520 backward compatible with v0.2) for the CPU.
2514 Depends on KVM_CAP_ARM_PSCI_0_2. 2521 Depends on KVM_CAP_ARM_PSCI_0_2.
2515 - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU. 2522 - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
2516 Depends on KVM_CAP_ARM_PMU_V3. 2523 Depends on KVM_CAP_ARM_PMU_V3.
diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
new file mode 100644
index 000000000000..aafdab887b04
--- /dev/null
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -0,0 +1,30 @@
1KVM implements the PSCI (Power State Coordination Interface)
2specification in order to provide services such as CPU on/off, reset
3and power-off to the guest.
4
5The PSCI specification is regularly updated to provide new features,
6and KVM implements these updates if they make sense from a virtualization
7point of view.
8
9This means that a guest booted on two different versions of KVM can
10observe two different "firmware" revisions. This could cause issues if
11a given guest is tied to a particular PSCI revision (unlikely), or if
12a migration causes a different PSCI version to be exposed out of the
13blue to an unsuspecting guest.
14
15In order to remedy this situation, KVM exposes a set of "firmware
16pseudo-registers" that can be manipulated using the GET/SET_ONE_REG
17interface. These registers can be saved/restored by userspace, and set
18to a convenient value if required.
19
20The following register is defined:
21
22* KVM_REG_ARM_PSCI_VERSION:
23
24 - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set
25 (and thus has already been initialized)
26 - Returns the current PSCI version on GET_ONE_REG (defaulting to the
27 highest PSCI version implemented by KVM and compatible with v0.2)
28 - Allows any PSCI version implemented by KVM and compatible with
29 v0.2 to be set with SET_ONE_REG
30 - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index c6a749568dd6..c7c28c885a19 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -77,6 +77,9 @@ struct kvm_arch {
77 /* Interrupt controller */ 77 /* Interrupt controller */
78 struct vgic_dist vgic; 78 struct vgic_dist vgic;
79 int max_vcpus; 79 int max_vcpus;
80
81 /* Mandated version of PSCI */
82 u32 psci_version;
80}; 83};
81 84
82#define KVM_NR_MEM_OBJS 40 85#define KVM_NR_MEM_OBJS 40
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 2ba95d6fe852..caae4843cb70 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -195,6 +195,12 @@ struct kvm_arch_memory_slot {
195#define KVM_REG_ARM_VFP_FPINST 0x1009 195#define KVM_REG_ARM_VFP_FPINST 0x1009
196#define KVM_REG_ARM_VFP_FPINST2 0x100A 196#define KVM_REG_ARM_VFP_FPINST2 0x100A
197 197
198/* KVM-as-firmware specific pseudo-registers */
199#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
200#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
201 KVM_REG_ARM_FW | ((r) & 0xffff))
202#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
203
198/* Device Control API: ARM VGIC */ 204/* Device Control API: ARM VGIC */
199#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 205#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
200#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 206#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784ebbfd6..a18f33edc471 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -22,6 +22,7 @@
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/vmalloc.h> 23#include <linux/vmalloc.h>
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <kvm/arm_psci.h>
25#include <asm/cputype.h> 26#include <asm/cputype.h>
26#include <linux/uaccess.h> 27#include <linux/uaccess.h>
27#include <asm/kvm.h> 28#include <asm/kvm.h>
@@ -176,6 +177,7 @@ static unsigned long num_core_regs(void)
176unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 177unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
177{ 178{
178 return num_core_regs() + kvm_arm_num_coproc_regs(vcpu) 179 return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
180 + kvm_arm_get_fw_num_regs(vcpu)
179 + NUM_TIMER_REGS; 181 + NUM_TIMER_REGS;
180} 182}
181 183
@@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
196 uindices++; 198 uindices++;
197 } 199 }
198 200
201 ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
202 if (ret)
203 return ret;
204 uindices += kvm_arm_get_fw_num_regs(vcpu);
205
199 ret = copy_timer_indices(vcpu, uindices); 206 ret = copy_timer_indices(vcpu, uindices);
200 if (ret) 207 if (ret)
201 return ret; 208 return ret;
@@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
214 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 221 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
215 return get_core_reg(vcpu, reg); 222 return get_core_reg(vcpu, reg);
216 223
224 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
225 return kvm_arm_get_fw_reg(vcpu, reg);
226
217 if (is_timer_reg(reg->id)) 227 if (is_timer_reg(reg->id))
218 return get_timer_reg(vcpu, reg); 228 return get_timer_reg(vcpu, reg);
219 229
@@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
230 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 240 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
231 return set_core_reg(vcpu, reg); 241 return set_core_reg(vcpu, reg);
232 242
243 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
244 return kvm_arm_set_fw_reg(vcpu, reg);
245
233 if (is_timer_reg(reg->id)) 246 if (is_timer_reg(reg->id))
234 return set_timer_reg(vcpu, reg); 247 return set_timer_reg(vcpu, reg);
235 248
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ab46bc70add6..469de8acd06f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -75,6 +75,9 @@ struct kvm_arch {
75 75
76 /* Interrupt controller */ 76 /* Interrupt controller */
77 struct vgic_dist vgic; 77 struct vgic_dist vgic;
78
79 /* Mandated version of PSCI */
80 u32 psci_version;
78}; 81};
79 82
80#define KVM_NR_MEM_OBJS 40 83#define KVM_NR_MEM_OBJS 40
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9abbf3044654..04b3256f8e6d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,6 +206,12 @@ struct kvm_arch_memory_slot {
206#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) 206#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2)
207#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) 207#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2)
208 208
209/* KVM-as-firmware specific pseudo-registers */
210#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
211#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
212 KVM_REG_ARM_FW | ((r) & 0xffff))
213#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
214
209/* Device Control API: ARM VGIC */ 215/* Device Control API: ARM VGIC */
210#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 216#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
211#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 217#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 959e50d2588c..56a0260ceb11 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -25,6 +25,7 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/vmalloc.h> 26#include <linux/vmalloc.h>
27#include <linux/fs.h> 27#include <linux/fs.h>
28#include <kvm/arm_psci.h>
28#include <asm/cputype.h> 29#include <asm/cputype.h>
29#include <linux/uaccess.h> 30#include <linux/uaccess.h>
30#include <asm/kvm.h> 31#include <asm/kvm.h>
@@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
205unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 206unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
206{ 207{
207 return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu) 208 return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
208 + NUM_TIMER_REGS; 209 + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS;
209} 210}
210 211
211/** 212/**
@@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
225 uindices++; 226 uindices++;
226 } 227 }
227 228
229 ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
230 if (ret)
231 return ret;
232 uindices += kvm_arm_get_fw_num_regs(vcpu);
233
228 ret = copy_timer_indices(vcpu, uindices); 234 ret = copy_timer_indices(vcpu, uindices);
229 if (ret) 235 if (ret)
230 return ret; 236 return ret;
@@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
243 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 249 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
244 return get_core_reg(vcpu, reg); 250 return get_core_reg(vcpu, reg);
245 251
252 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
253 return kvm_arm_get_fw_reg(vcpu, reg);
254
246 if (is_timer_reg(reg->id)) 255 if (is_timer_reg(reg->id))
247 return get_timer_reg(vcpu, reg); 256 return get_timer_reg(vcpu, reg);
248 257
@@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
259 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 268 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
260 return set_core_reg(vcpu, reg); 269 return set_core_reg(vcpu, reg);
261 270
271 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
272 return kvm_arm_set_fw_reg(vcpu, reg);
273
262 if (is_timer_reg(reg->id)) 274 if (is_timer_reg(reg->id))
263 return set_timer_reg(vcpu, reg); 275 return set_timer_reg(vcpu, reg);
264 276
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index e518e4e3dfb5..4b1548129fa2 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -37,10 +37,15 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
37 * Our PSCI implementation stays the same across versions from 37 * Our PSCI implementation stays the same across versions from
38 * v0.2 onward, only adding the few mandatory functions (such 38 * v0.2 onward, only adding the few mandatory functions (such
39 * as FEATURES with 1.0) that are required by newer 39 * as FEATURES with 1.0) that are required by newer
40 * revisions. It is thus safe to return the latest. 40 * revisions. It is thus safe to return the latest, unless
41 * userspace has instructed us otherwise.
41 */ 42 */
42 if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) 43 if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
44 if (vcpu->kvm->arch.psci_version)
45 return vcpu->kvm->arch.psci_version;
46
43 return KVM_ARM_PSCI_LATEST; 47 return KVM_ARM_PSCI_LATEST;
48 }
44 49
45 return KVM_ARM_PSCI_0_1; 50 return KVM_ARM_PSCI_0_1;
46} 51}
@@ -48,4 +53,11 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
48 53
49int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); 54int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
50 55
56struct kvm_one_reg;
57
58int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu);
59int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
60int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
61int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
62
51#endif /* __KVM_ARM_PSCI_H__ */ 63#endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 6919352cbf15..c4762bef13c6 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -18,6 +18,7 @@
18#include <linux/arm-smccc.h> 18#include <linux/arm-smccc.h>
19#include <linux/preempt.h> 19#include <linux/preempt.h>
20#include <linux/kvm_host.h> 20#include <linux/kvm_host.h>
21#include <linux/uaccess.h>
21#include <linux/wait.h> 22#include <linux/wait.h>
22 23
23#include <asm/cputype.h> 24#include <asm/cputype.h>
@@ -427,3 +428,62 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
427 smccc_set_retval(vcpu, val, 0, 0, 0); 428 smccc_set_retval(vcpu, val, 0, 0, 0);
428 return 1; 429 return 1;
429} 430}
431
432int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
433{
434 return 1; /* PSCI version */
435}
436
437int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
438{
439 if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices))
440 return -EFAULT;
441
442 return 0;
443}
444
445int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
446{
447 if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
448 void __user *uaddr = (void __user *)(long)reg->addr;
449 u64 val;
450
451 val = kvm_psci_version(vcpu, vcpu->kvm);
452 if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
453 return -EFAULT;
454
455 return 0;
456 }
457
458 return -EINVAL;
459}
460
461int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
462{
463 if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
464 void __user *uaddr = (void __user *)(long)reg->addr;
465 bool wants_02;
466 u64 val;
467
468 if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
469 return -EFAULT;
470
471 wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
472
473 switch (val) {
474 case KVM_ARM_PSCI_0_1:
475 if (wants_02)
476 return -EINVAL;
477 vcpu->kvm->arch.psci_version = val;
478 return 0;
479 case KVM_ARM_PSCI_0_2:
480 case KVM_ARM_PSCI_1_0:
481 if (!wants_02)
482 return -EINVAL;
483 vcpu->kvm->arch.psci_version = val;
484 return 0;
485 }
486 }
487
488 return -EINVAL;
489}