Skip to contentSkip to conversation

In-kernel PSCI v0.2 emulation for KVM ARM/ARM64

PATCH Superseded Anup Patel 5 participants 25 messages Mar 21, 2014 – Mar 26, 2014

Subsystems (5)
Documentation Arm (32-bit) KVM arm64 +1 more subsystems

v5 of 11 Superseded Latest is v11 →

lore
Share & tools
lore

Anup Patel

author
#0 lore raw

v5 cover In-kernel PSCI v0.2 emulation for KVM ARM/ARM64

Currently, KVM ARM/ARM64 only provides in-kernel emulation of Power State and Coordination Interface (PSCI) v0.1.

This patchset aims at providing newer PSCI v0.2 for KVM ARM/ARM64 VCPUs such that it does not break current KVM ARM/ARM64 ABI.

The user space tools (i.e. QEMU or KVMTOOL) will have to explicitly enable KVM_ARM_VCPU_PSCI_0_2 feature using KVM_ARM_VCPU_INIT ioctl for providing PSCI v0.2 to VCPUs.

Changlog:

V5:
- Have separate last patch to advertise KVM_CAP_ARM_PSCI_0_2
- Use kvm_psci_version() in kvm_psci_vcpu_on()
- Return ALREADY_ON for PSCI v0.2 CPU_ON if VCPU is not paused
- Remove per-VCPU suspend context
- As-per PSCI v0.2 spec, only current CPU can suspend itself

V4:
- Implement all mandatory functions required by PSCI v0.2

V3:
- Make KVM_ARM_VCPU_PSCI_0_2 feature experiementatl for now so that it fails for user space till all mandatory PSCI v0.2 functions are emulated by KVM ARM/ARM64
- Have separate patch for making KVM_ARM_VCPU_PSCI_0_2 feature available to user space. This patch can be defferred for now

V2:
- Don't rename PSCI return values KVM_PSCI_RET_NI and KVM_PSCI_RET_INVAL
- Added kvm_psci_version() to get PSCI version available to VCPU
- Fixed grammer in Documentation/virtual/kvm/api.txt

V1:
- Initial RFC PATCH

Anup Patel (11):
KVM: Add capability to advertise PSCI v0.2 support ARM/ARM64: KVM: Add base for PSCI v0.2 emulation
KVM: Documentation: Add info regarding KVM_ARM_VCPU_PSCI_0_2 feature ARM/ARM64: KVM: Make kvm_psci_call() return convention more flexible
KVM: Add KVM_EXIT_SYSTEM_EVENT to user space API header ARM/ARM64: KVM: Emulate PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET ARM/ARM64: KVM: Emulate PSCI v0.2 AFFINITY_INFO ARM/ARM64: KVM: Emulate PSCI v0.2 MIGRATE_INFO_TYPE and related
functions
ARM/ARM64: KVM: Fix CPU_ON emulation for PSCI v0.2 ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND
ARM/ARM64: KVM: Advertise KVM_CAP_ARM_PSCI_0_2 to user space

 Documentation/virtual/kvm/api.txt |   17 +++
 arch/arm/include/asm/kvm_host.h   |    2 +-
 arch/arm/include/asm/kvm_psci.h   |    6 +-
 arch/arm/include/uapi/asm/kvm.h   |   35 +++++-
 arch/arm/kvm/arm.c                |    1 +
 arch/arm/kvm/handle_exit.c        |   10 +-
 arch/arm/kvm/psci.c               |  220 ++++++++++++++++++++++++++++++++++---
 arch/arm64/include/asm/kvm_host.h |    2 +-
 arch/arm64/include/asm/kvm_psci.h |    6 +-
 arch/arm64/include/uapi/asm/kvm.h |   35 +++++-
 arch/arm64/kvm/handle_exit.c      |   10 +-
 include/uapi/linux/kvm.h          |    9 ++
 12 files changed, 326 insertions(+), 27 deletions(-)
Signature · 1 line
1.7.9.5
author
#1 lore raw

PATCH v5 1/11 KVM: Add capability to advertise PSCI v0.2 support

User space (i.e. QEMU or KVMTOOL) should be able to check whether KVM ARM/ARM64 supports in-kernel PSCI v0.2 emulation. For this purpose, we define KVM_CAP_ARM_PSCI_0_2 in KVM user space interface header.

---
 include/uapi/linux/kvm.h |    1 +
 1 file changed, 1 insertion(+)
include/uapi/linux/kvm.h +1 -0
index a7518be..260d3ae 100644
@@ -741,6 +741,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_EXT_EMUL_CPUID 95
 #define KVM_CAP_HYPERV_TIME 96
 #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
+#define KVM_CAP_ARM_PSCI_0_2 98
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v5 1/11 KVM: Add capability to advertise PSCI v0.2 support

Quoted 6 lines · Anup Patel

User space (i.e. QEMU or KVMTOOL) should be able to check whether KVM ARM/ARM64 supports in-kernel PSCI v0.2 emulation. For this purpose, we define KVM_CAP_ARM_PSCI_0_2 in KVM user space interface header.

Please add the acked-by tags when people give them to you - otherwise it's a bit of a wasted effort and I have to go back and check so I don't review the patches again.

Thanks,
-Christoffer

author
#3 lore raw

PATCH v5 1/11 KVM: Add capability to advertise PSCI v0.2 support

Quoted 11 lines · Christoffer Dall
Quoted 6 lines · Anup Patel

User space (i.e. QEMU or KVMTOOL) should be able to check whether KVM ARM/ARM64 supports in-kernel PSCI v0.2 emulation. For this purpose, we define KVM_CAP_ARM_PSCI_0_2 in KVM user space interface header.

Please add the acked-by tags when people give them to you - otherwise it's a bit of a wasted effort and I have to go back and check so I don't review the patches again.

OK.

Quoted 3 lines

Thanks,
-Christoffer

author
#4 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

In reply to Anup Patel

Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to VCPUs. This patch extends current in-kernel PSCI emulation to provide PSCI v0.2 interface to VCPUs.

By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for keeping the ABI backward-compatible.

To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU init using KVM_ARM_VCPU_INIT ioctl.

---
 arch/arm/include/asm/kvm_host.h   |    2 +-
 arch/arm/include/asm/kvm_psci.h   |    4 ++
 arch/arm/include/uapi/asm/kvm.h   |   35 ++++++++++++++-
 arch/arm/kvm/psci.c               |   85 +++++++++++++++++++++++++++++++------
 arch/arm64/include/asm/kvm_host.h |    2 +-
 arch/arm64/include/asm/kvm_psci.h |    4 ++
 arch/arm64/include/uapi/asm/kvm.h |   35 ++++++++++++++-
 7 files changed, 151 insertions(+), 16 deletions(-)
arch/arm/include/asm/kvm_host.h +1 -1
index 09af149..193ceaf 100644
@@ -36,7 +36,7 @@
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #define KVM_HAVE_ONE_REG
 
-#define KVM_VCPU_MAX_FEATURES 1
+#define KVM_VCPU_MAX_FEATURES 2
 
 #include <kvm/arm_vgic.h>
 
arch/arm/include/asm/kvm_psci.h +4 -0
index 9a83d98..4c0e3e1 100644
@@ -18,6 +18,10 @@
 #ifndef __ARM_KVM_PSCI_H__
 #define __ARM_KVM_PSCI_H__
 
+#define KVM_ARM_PSCI_0_1	1
+#define KVM_ARM_PSCI_0_2	2
+
+int kvm_psci_version(struct kvm_vcpu *vcpu);
 bool kvm_psci_call(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM_KVM_PSCI_H__ */
arch/arm/include/uapi/asm/kvm.h +34 -1
index ef0c878..9c922d9 100644
@@ -83,6 +83,7 @@ struct kvm_regs {
 #define KVM_VGIC_V2_CPU_SIZE		0x2000
 
 #define KVM_ARM_VCPU_POWER_OFF		0 /* CPU is started in OFF state */
+#define KVM_ARM_VCPU_PSCI_0_2		1 /* CPU uses PSCI v0.2 */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -192,7 +193,7 @@ struct kvm_arch_memory_slot {
 /* Highest supported SPI, from VGIC_NR_IRQS */
 #define KVM_ARM_IRQ_GIC_MAX		127
 
-/* PSCI interface */
+/* PSCI v0.1 interface */
 #define KVM_PSCI_FN_BASE		0x95c1ba5e
 #define KVM_PSCI_FN(n)			(KVM_PSCI_FN_BASE + (n))
 
@@ -201,9 +202,41 @@ struct kvm_arch_memory_slot {
 #define KVM_PSCI_FN_CPU_ON		KVM_PSCI_FN(2)
 #define KVM_PSCI_FN_MIGRATE		KVM_PSCI_FN(3)
 
+/* PSCI v0.2 interface */
+#define KVM_PSCI_0_2_FN_BASE		0x84000000
+#define KVM_PSCI_0_2_FN(n)		(KVM_PSCI_0_2_FN_BASE + (n))
+#define KVM_PSCI_0_2_FN64_BASE		0xC4000000
+#define KVM_PSCI_0_2_FN64(n)		(KVM_PSCI_0_2_FN64_BASE + (n))
+
+#define KVM_PSCI_0_2_FN_PSCI_VERSION	KVM_PSCI_0_2_FN(0)
+#define KVM_PSCI_0_2_FN_CPU_SUSPEND	KVM_PSCI_0_2_FN(1)
+#define KVM_PSCI_0_2_FN_CPU_OFF		KVM_PSCI_0_2_FN(2)
+#define KVM_PSCI_0_2_FN_CPU_ON		KVM_PSCI_0_2_FN(3)
+#define KVM_PSCI_0_2_FN_AFFINITY_INFO	KVM_PSCI_0_2_FN(4)
+#define KVM_PSCI_0_2_FN_MIGRATE		KVM_PSCI_0_2_FN(5)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE \
+					KVM_PSCI_0_2_FN(6)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU \
+					KVM_PSCI_0_2_FN(7)
+#define KVM_PSCI_0_2_FN_SYSTEM_OFF	KVM_PSCI_0_2_FN(8)
+#define KVM_PSCI_0_2_FN_SYSTEM_RESET	KVM_PSCI_0_2_FN(9)
+
+#define KVM_PSCI_0_2_FN64_CPU_SUSPEND	KVM_PSCI_0_2_FN64(1)
+#define KVM_PSCI_0_2_FN64_CPU_ON	KVM_PSCI_0_2_FN64(3)
+#define KVM_PSCI_0_2_FN64_AFFINITY_INFO	KVM_PSCI_0_2_FN64(4)
+#define KVM_PSCI_0_2_FN64_MIGRATE	KVM_PSCI_0_2_FN64(5)
+#define KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU \
+					KVM_PSCI_0_2_FN64(7)
+
+/* PSCI return values */
 #define KVM_PSCI_RET_SUCCESS		0
 #define KVM_PSCI_RET_NI			((unsigned long)-1)
 #define KVM_PSCI_RET_INVAL		((unsigned long)-2)
 #define KVM_PSCI_RET_DENIED		((unsigned long)-3)
+#define KVM_PSCI_RET_ALREADY_ON		((unsigned long)-4)
+#define KVM_PSCI_RET_ON_PENDING		((unsigned long)-5)
+#define KVM_PSCI_RET_INTERNAL_FAILURE	((unsigned long)-6)
+#define KVM_PSCI_RET_NOT_PRESENT	((unsigned long)-7)
+#define KVM_PSCI_RET_DISABLED		((unsigned long)-8)
 
 #endif /* __ARM_KVM_H__ */
arch/arm/kvm/psci.c +73 -12

100 lines not on this page · raw message

arch/arm64/include/asm/kvm_host.h +1 -1
index 0a1d697..92242ce 100644
@@ -39,7 +39,7 @@
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
 
-#define KVM_VCPU_MAX_FEATURES 2
+#define KVM_VCPU_MAX_FEATURES 3
 
 struct kvm_vcpu;
 int kvm_target_cpu(void);
arch/arm64/include/asm/kvm_psci.h +4 -0
index e301a48..e25c658 100644
@@ -18,6 +18,10 @@
 #ifndef __ARM64_KVM_PSCI_H__
 #define __ARM64_KVM_PSCI_H__
 
+#define KVM_ARM_PSCI_0_1	1
+#define KVM_ARM_PSCI_0_2	2
+
+int kvm_psci_version(struct kvm_vcpu *vcpu);
 bool kvm_psci_call(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM64_KVM_PSCI_H__ */
arch/arm64/include/uapi/asm/kvm.h +34 -1
index eaf54a3..cadc318 100644
@@ -77,6 +77,7 @@ struct kvm_regs {
 
 #define KVM_ARM_VCPU_POWER_OFF		0 /* CPU is started in OFF state */
 #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
+#define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -177,7 +178,7 @@ struct kvm_arch_memory_slot {
 /* Highest supported SPI, from VGIC_NR_IRQS */
 #define KVM_ARM_IRQ_GIC_MAX		127
 
-/* PSCI interface */
+/* PSCI v0.1 interface */
 #define KVM_PSCI_FN_BASE		0x95c1ba5e
 #define KVM_PSCI_FN(n)			(KVM_PSCI_FN_BASE + (n))
 
@@ -186,10 +187,42 @@ struct kvm_arch_memory_slot {
 #define KVM_PSCI_FN_CPU_ON		KVM_PSCI_FN(2)
 #define KVM_PSCI_FN_MIGRATE		KVM_PSCI_FN(3)
 
+/* PSCI v0.2 interface */
+#define KVM_PSCI_0_2_FN_BASE		0x84000000
+#define KVM_PSCI_0_2_FN(n)		(KVM_PSCI_0_2_FN_BASE + (n))
+#define KVM_PSCI_0_2_FN64_BASE		0xC4000000
+#define KVM_PSCI_0_2_FN64(n)		(KVM_PSCI_0_2_FN64_BASE + (n))
+
+#define KVM_PSCI_0_2_FN_PSCI_VERSION	KVM_PSCI_0_2_FN(0)
+#define KVM_PSCI_0_2_FN_CPU_SUSPEND	KVM_PSCI_0_2_FN(1)
+#define KVM_PSCI_0_2_FN_CPU_OFF		KVM_PSCI_0_2_FN(2)
+#define KVM_PSCI_0_2_FN_CPU_ON		KVM_PSCI_0_2_FN(3)
+#define KVM_PSCI_0_2_FN_AFFINITY_INFO	KVM_PSCI_0_2_FN(4)
+#define KVM_PSCI_0_2_FN_MIGRATE		KVM_PSCI_0_2_FN(5)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE \
+					KVM_PSCI_0_2_FN(6)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU \
+					KVM_PSCI_0_2_FN(7)
+#define KVM_PSCI_0_2_FN_SYSTEM_OFF	KVM_PSCI_0_2_FN(8)
+#define KVM_PSCI_0_2_FN_SYSTEM_RESET	KVM_PSCI_0_2_FN(9)
+
+#define KVM_PSCI_0_2_FN64_CPU_SUSPEND	KVM_PSCI_0_2_FN64(1)
+#define KVM_PSCI_0_2_FN64_CPU_ON	KVM_PSCI_0_2_FN64(3)
+#define KVM_PSCI_0_2_FN64_AFFINITY_INFO	KVM_PSCI_0_2_FN64(4)
+#define KVM_PSCI_0_2_FN64_MIGRATE	KVM_PSCI_0_2_FN64(5)
+#define KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU \
+					KVM_PSCI_0_2_FN64(7)
+
+/* PSCI return values */
 #define KVM_PSCI_RET_SUCCESS		0
 #define KVM_PSCI_RET_NI			((unsigned long)-1)
 #define KVM_PSCI_RET_INVAL		((unsigned long)-2)
 #define KVM_PSCI_RET_DENIED		((unsigned long)-3)
+#define KVM_PSCI_RET_ALREADY_ON		((unsigned long)-4)
+#define KVM_PSCI_RET_ON_PENDING		((unsigned long)-5)
+#define KVM_PSCI_RET_INTERNAL_FAILURE	((unsigned long)-6)
+#define KVM_PSCI_RET_NOT_PRESENT	((unsigned long)-7)
+#define KVM_PSCI_RET_DISABLED		((unsigned long)-8)
 
 #endif
 
Signature · 1 line
1.7.9.5
#5 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Quoted 7 lines · Anup Patel

Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to VCPUs. This patch extends current in-kernel PSCI emulation to provide PSCI v0.2 interface to VCPUs.

By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for keeping the ABI backward-compatible.

Quoted 6 lines

To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU init using KVM_ARM_VCPU_INIT ioctl.

The content here can carry my Reviewed-by tag, but I think Rob's point about sharing this code between KVM arm/arm64 and the PSCI code itself it important, see:

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241792.html

Thanks,
-Christoffer

author
#6 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Quoted 12 lines · Christoffer Dall
Quoted 11 lines · Anup Patel

Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to VCPUs. This patch extends current in-kernel PSCI emulation to provide PSCI v0.2 interface to VCPUs.

By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for keeping the ABI backward-compatible.

To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU init using KVM_ARM_VCPU_INIT ioctl.

Quoted 8 lines
Quoted 2 lines

The content here can carry my Reviewed-by tag, but I think Rob's point about sharing this code between KVM arm/arm64 and the PSCI code itself it important, see:

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241792.html

My apologies, I totally missed Rob's comment.

My suggestion would be to have:
arch/arm/include/uapi/asm/psci.h
arch/arm64/include/uapi/asm/psci.h

These headers can have following defines:

/* PSCI v0.1 interface */
#define PSCI_FN(base, n) (base + (n))

#define PSCI_FN_CPU_SUSPEND(base) PSCI_FN(base, 0)
#define PSCI_FN_CPU_OFF(base) PSCI_FN(base, 1)
#define PSCI_FN_CPU_ON(base) PSCI_FN(base, 2)
#define PSCI_FN_MIGRATE(base) PSCI_FN(base, 3)

/* PSCI v0.2 interface */
#define PSCI_0_2_FN_BASE 0x84000000
#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n))
#define PSCI_0_2_FN64_BASE 0xC4000000
#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n))

#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0)
#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1)
#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2)
#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3)
#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4)
#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5)

#define PSCI_0_2_FN_MIGRATE_INFO_TYPE \
                    PSCI_0_2_FN(6)
#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU \
                    PSCI_0_2_FN(7)

#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8)
#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9)

#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1)
#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3)
#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4)
#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5)

#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU \
                    PSCI_0_2_FN64(7)

/* PSCI return values */
#define PSCI_RET_SUCCESS 0
#define PSCI_RET_NI ((unsigned long)-1)
#define PSCI_RET_INVAL ((unsigned long)-2)
#define PSCI_RET_DENIED ((unsigned long)-3)
#define PSCI_RET_ALREADY_ON ((unsigned long)-4)
#define PSCI_RET_ON_PENDING ((unsigned long)-5)
#define PSCI_RET_INTERNAL_FAILURE ((unsigned long)-6)
#define PSCI_RET_NOT_PRESENT ((unsigned long)-7)
#define PSCI_RET_DISABLED ((unsigned long)-8)

The usual headers arch/arm/include/uapi/asm/kvm.h and arch/arm64/include/uapi/asm/kvm.h will only define KVM_PSCI_FN_BASE for PSCI v0.1

Regards,
Anup

Quoted 4 lines

Thanks,
-Christoffer

#7 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Quoted 16 lines · Anup Patel
Quoted 15 lines · Christoffer Dall
Quoted 13 lines · Anup Patel

Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to VCPUs. This patch extends current in-kernel PSCI emulation to provide PSCI v0.2 interface to VCPUs.

By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for keeping the ABI backward-compatible.

To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU init using KVM_ARM_VCPU_INIT ioctl.

Quoted 7 lines
Quoted 5 lines

The content here can carry my Reviewed-by tag, but I think Rob's point about sharing this code between KVM arm/arm64 and the PSCI code itself it important, see:

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241792.html

My apologies, I totally missed Rob's comment.

No worries at all.

Quoted 4 lines

My suggestion would be to have:
arch/arm/include/uapi/asm/psci.h
arch/arm64/include/uapi/asm/psci.h

I think the suggestion was to move all this to include/uapi/linux/psci.h or something equivalent so also arm and arm64 can share these defines, but maybe I read too much into it.

Rob?

#8 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Quoted 28 lines · Christoffer Dall
Quoted 16 lines · Anup Patel
Quoted 15 lines · Christoffer Dall
Quoted 13 lines · Anup Patel

Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to VCPUs. This patch extends current in-kernel PSCI emulation to provide PSCI v0.2 interface to VCPUs.

By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for keeping the ABI backward-compatible.

To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU init using KVM_ARM_VCPU_INIT ioctl.

Quoted 7 lines
Quoted 5 lines

The content here can carry my Reviewed-by tag, but I think Rob's point about sharing this code between KVM arm/arm64 and the PSCI code itself it important, see:

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241792.html

My apologies, I totally missed Rob's comment.

No worries at all.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

My suggestion would be to have:
arch/arm/include/uapi/asm/psci.h
arch/arm64/include/uapi/asm/psci.h

I think the suggestion was to move all this to include/uapi/linux/psci.h or something equivalent so also arm and arm64 can share these defines, but maybe I read too much into it.

Yes. It is perfectly fine for a somewhat architecture specific header to live in include/linux (or include/uapi/linux).

Rob

#9 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Hello,

Quoted 5 lines · Rob Herring
Quoted 5 lines
Quoted 4 lines

My suggestion would be to have:
arch/arm/include/uapi/asm/psci.h
arch/arm64/include/uapi/asm/psci.h

Quoted 8 lines
Quoted 3 lines

I think the suggestion was to move all this to include/uapi/linux/psci.h or something equivalent so also arm and arm64 can share these defines, but maybe I read too much into it.

Yes. It is perfectly fine for a somewhat architecture specific header to live in include/linux (or include/uapi/linux).

While I'm aware that we wouldn't want to push seemingly irrelevant stuff into this header, I'm thinking of ways to unify the ARM and ARM64 PSCI code. A lot of it is reusable between the two. So, can this header also include all the common PSCI functions between ARM and ARM64? And can KVM possibly use these functions as well?

Alternately, is drivers/psci.c a more suitable place? In this case, at least one function will be guarded by CONFIG_ARM64.

Cheers,
Ashwin

#10 lore raw

PATCH v5 2/11 ARM/ARM64: KVM: Add base for PSCI v0.2 emulation

Quoted 17 lines · Ashwin Chaugule

Hello,

Quoted 5 lines · Rob Herring
Quoted 5 lines
Quoted 4 lines

My suggestion would be to have:
arch/arm/include/uapi/asm/psci.h
arch/arm64/include/uapi/asm/psci.h

Quoted 8 lines
Quoted 3 lines

I think the suggestion was to move all this to include/uapi/linux/psci.h or something equivalent so also arm and arm64 can share these defines, but maybe I read too much into it.

Yes. It is perfectly fine for a somewhat architecture specific header to live in include/linux (or include/uapi/linux).

Quoted 5 lines

While I'm aware that we wouldn't want to push seemingly irrelevant stuff into this header, I'm thinking of ways to unify the ARM and ARM64 PSCI code. A lot of it is reusable between the two. So, can this header also include all the common PSCI functions between ARM and ARM64? And can KVM possibly use these functions as well?

Anything under uapi should be related to the PSCI ABI. If there are headers to be shared that are just kernel implementation specific, then they can go in include/linux/.

Quoted 2 lines

Alternately, is drivers/psci.c a more suitable place? In this case, at least one function will be guarded by CONFIG_ARM64.

No. For .c files, I don't think we have a good solution. Some of the kvm stuff does ../../ type includes back to arch/arm, but that's not a very clean solution.

Rob

author
#11 lore raw

PATCH v5 3/11 KVM: Documentation: Add info regarding KVM_ARM_VCPU_PSCI_0_2 feature

In reply to Anup Patel

We have in-kernel emulation of PSCI v0.2 in KVM ARM/ARM64. To provide PSCI v0.2 interface to VCPUs, we have to enable KVM_ARM_VCPU_PSCI_0_2 feature when doing KVM_ARM_VCPU_INIT ioctl.

The patch updates documentation of KVM_ARM_VCPU_INIT ioctl to provide info regarding KVM_ARM_VCPU_PSCI_0_2 feature.

---
 Documentation/virtual/kvm/api.txt |    2 ++
 1 file changed, 2 insertions(+)
Documentation/virtual/kvm/api.txt +2 -0
index 4714f28..0114d5b 100644
@@ -2361,6 +2361,8 @@ Possible features:
 	  Depends on KVM_CAP_ARM_PSCI.
 	- 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.
+	  Depends on KVM_CAP_ARM_PSCI_0_2.
 
 
 4.83 KVM_ARM_PREFERRED_TARGET
Signature · 1 line
1.7.9.5
author
#12 lore raw

PATCH v5 4/11 ARM/ARM64: KVM: Make kvm_psci_call() return convention more flexible

In reply to Anup Patel

Currently, the kvm_psci_call() returns 'true' or 'false' based on whether the PSCI function call was handled successfully or not. This does not help us emulate system-level PSCI functions where the actual emulation work will be done by user space (QEMU or KVMTOOL). Examples of such system-level PSCI functions are: PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET.

This patch updates kvm_psci_call() to return three types of values:
1) > 0 (success)
2) = 0 (success but exit to user space)
3) < 0 (errors)

---
 arch/arm/include/asm/kvm_psci.h   |    2 +-
 arch/arm/kvm/handle_exit.c        |   10 +++++++---
 arch/arm/kvm/psci.c               |   28 ++++++++++++++++------------
 arch/arm64/include/asm/kvm_psci.h |    2 +-
 arch/arm64/kvm/handle_exit.c      |   10 +++++++---
 5 files changed, 32 insertions(+), 20 deletions(-)
arch/arm/include/asm/kvm_psci.h +1 -1
index 4c0e3e1..6bda945 100644
@@ -22,6 +22,6 @@
 #define KVM_ARM_PSCI_0_2	2
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
-bool kvm_psci_call(struct kvm_vcpu *vcpu);
+int kvm_psci_call(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM_KVM_PSCI_H__ */
arch/arm/kvm/handle_exit.c +7 -3
index 0de91fc..1270095 100644
@@ -38,14 +38,18 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+	int ret;
+
 	trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
 		      kvm_vcpu_hvc_get_imm(vcpu));
 
-	if (kvm_psci_call(vcpu))
+	ret = kvm_psci_call(vcpu);
+	if (ret == -EINVAL) {
+		kvm_inject_undefined(vcpu);
 		return 1;
+	}
 
-	kvm_inject_undefined(vcpu);
-	return 1;
+	return ret;
 }
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
arch/arm/kvm/psci.c +16 -12
index e4ec4af..252acd0 100644
@@ -93,7 +93,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 	return KVM_ARM_PSCI_0_1;
 }
 
-static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
 	unsigned long val;
@@ -128,14 +128,14 @@ static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		val = KVM_PSCI_RET_NI;
 		break;
 	default:
-		return false;
+		return -EINVAL;
 	}
 
 	*vcpu_reg(vcpu, 0) = val;
-	return true;
+	return 1;
 }
 
-static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
 	unsigned long val;
@@ -153,11 +153,11 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 		val = KVM_PSCI_RET_NI;
 		break;
 	default:
-		return false;
+		return -EINVAL;
 	}
 
 	*vcpu_reg(vcpu, 0) = val;
-	return true;
+	return 1;
 }
 
 /**
@@ -165,12 +165,16 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  * @vcpu: Pointer to the VCPU struct
  *
  * Handle PSCI calls from guests through traps from HVC instructions.
- * The calling convention is similar to SMC calls to the secure world where
- * the function number is placed in r0 and this function returns true if the
- * function number specified in r0 is withing the PSCI range, and false
- * otherwise.
+ * The calling convention is similar to SMC calls to the secure world
+ * where the function number is placed in r0.
+ *
+ * This function returns: > 0 (success), 0 (success but exit to user
+ * space), and < 0 (errors)
+ *
+ * Errors:
+ * -EINVAL: Unrecognized PSCI function
  */
-bool kvm_psci_call(struct kvm_vcpu *vcpu)
+int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
 	case KVM_ARM_PSCI_0_2:
@@ -178,6 +182,6 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
 	case KVM_ARM_PSCI_0_1:
 		return kvm_psci_0_1_call(vcpu);
 	default:
-		return false;
+		return -EINVAL;
 	};
 }
arch/arm64/include/asm/kvm_psci.h +1 -1
index e25c658..bc39e55 100644
@@ -22,6 +22,6 @@
 #define KVM_ARM_PSCI_0_2	2
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
-bool kvm_psci_call(struct kvm_vcpu *vcpu);
+int kvm_psci_call(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM64_KVM_PSCI_H__ */
arch/arm64/kvm/handle_exit.c +7 -3
index 7bc41ea..743a74d 100644
@@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
 
 static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	if (kvm_psci_call(vcpu))
+	int ret;
+
+	ret = kvm_psci_call(vcpu);
+	if (ret == -EINVAL) {
+		kvm_inject_undefined(vcpu);
 		return 1;
+	}
 
-	kvm_inject_undefined(vcpu);
-	return 1;
+	return ret;
 }
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
Signature · 1 line
1.7.9.5
author
#13 lore raw

PATCH v5 5/11 KVM: Add KVM_EXIT_SYSTEM_EVENT to user space API header

In reply to Anup Patel

Currently, we don't have an exit reason to notify user space about a system-level event (for e.g. system reset or shutdown) triggered by the VCPU. This patch adds exit reason KVM_EXIT_SYSTEM_EVENT for this purpose. We can also inform user space about the 'type' and architecture specific 'flags' of a system-level event using the kvm_run structure.

This newly added KVM_EXIT_SYSTEM_EVENT will be used by KVM ARM/ARM64 in-kernel PSCI v0.2 support to reset/shutdown VMs.

---
 Documentation/virtual/kvm/api.txt |   15 +++++++++++++++
 include/uapi/linux/kvm.h          |    8 ++++++++
 2 files changed, 23 insertions(+)
Documentation/virtual/kvm/api.txt +15 -0
index 0114d5b..e675ec2 100644
@@ -2721,6 +2721,21 @@ It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
 external interrupt has just been delivered into the guest. User space
 should put the acknowledged interrupt vector into the 'epr' field.
 
+		/* KVM_EXIT_SYSTEM_EVENT */
+		struct {
+#define KVM_SYSTEM_EVENT_SHUTDOWN       1
+#define KVM_SYSTEM_EVENT_RESET          2
+			__u32 type;
+			__u64 flags;
+		} system_event;
+
+If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered
+a system-level event using some architecture specific mechanism (hypercall
+or some special instruction). In case of ARM/ARM64, this is triggered using
+HVC instruction based PSCI call from the vcpu. The 'type' field describes
+the system-level event type. The 'flags' field describes architecture
+specific flags for the system-level event.
+
 		/* Fix the size of the union. */
 		char padding[256];
 	};
include/uapi/linux/kvm.h +8 -0
index 260d3ae..0cf2882 100644
@@ -171,6 +171,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_WATCHDOG         21
 #define KVM_EXIT_S390_TSCH        22
 #define KVM_EXIT_EPR              23
+#define KVM_EXIT_SYSTEM_EVENT     24
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -301,6 +302,13 @@ struct kvm_run {
 		struct {
 			__u32 epr;
 		} epr;
+		/* KVM_EXIT_SYSTEM_EVENT */
+		struct {
+#define KVM_SYSTEM_EVENT_SHUTDOWN       1
+#define KVM_SYSTEM_EVENT_RESET          2
+			__u32 type;
+			__u64 flags;
+		} system_event;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
Signature · 1 line
1.7.9.5
author
#14 lore raw

PATCH v5 6/11 ARM/ARM64: KVM: Emulate PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET

In reply to Anup Patel

The PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET functions are system-level functions hence cannot be fully emulated by in-kernel PSCI emulation code.

To tackle this, we forward PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET function calls from vcpu to user space (i.e. QEMU or KVMTOOL) via kvm_run structure using KVM_EXIT_SYSTEM_EVENT exit reasons.

---
 arch/arm/kvm/psci.c |   32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)
arch/arm/kvm/psci.c +29 -3
index 252acd0..1f1720a 100644
@@ -85,6 +85,23 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	return KVM_PSCI_RET_SUCCESS;
 }
 
+static inline void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type)
+{
+	memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
+	vcpu->run->system_event.type = type;
+	vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
+}
+
+static void kvm_psci_system_off(struct kvm_vcpu *vcpu)
+{
+	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN);
+}
+
+static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
+{
+	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
+}
+
 int kvm_psci_version(struct kvm_vcpu *vcpu)
 {
 	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
@@ -95,6 +112,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
+	int ret = 1;
 	unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
 	unsigned long val;
 
@@ -114,13 +132,21 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	case KVM_PSCI_0_2_FN64_CPU_ON:
 		val = kvm_psci_vcpu_on(vcpu);
 		break;
+	case KVM_PSCI_0_2_FN_SYSTEM_OFF:
+		kvm_psci_system_off(vcpu);
+		val = KVM_PSCI_RET_SUCCESS;
+		ret = 0;
+		break;
+	case KVM_PSCI_0_2_FN_SYSTEM_RESET:
+		kvm_psci_system_reset(vcpu);
+		val = KVM_PSCI_RET_SUCCESS;
+		ret = 0;
+		break;
 	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
 	case KVM_PSCI_0_2_FN_AFFINITY_INFO:
 	case KVM_PSCI_0_2_FN_MIGRATE:
 	case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
 	case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
-	case KVM_PSCI_0_2_FN_SYSTEM_OFF:
-	case KVM_PSCI_0_2_FN_SYSTEM_RESET:
 	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
 	case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
 	case KVM_PSCI_0_2_FN64_MIGRATE:
@@ -132,7 +158,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	}
 
 	*vcpu_reg(vcpu, 0) = val;
-	return 1;
+	return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
Signature · 1 line
1.7.9.5
author
#15 lore raw

PATCH v5 7/11 ARM/ARM64: KVM: Emulate PSCI v0.2 AFFINITY_INFO

In reply to Anup Patel

This patch adds emulation of PSCI v0.2 AFFINITY_INFO function call for KVM ARM/ARM64. This is a VCPU-level function call which will be used to determine current state of given affinity level.

---
 arch/arm/kvm/psci.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 2 deletions(-)
arch/arm/kvm/psci.c +65 -2
index 1f1720a..5bd9ae4 100644
@@ -27,6 +27,31 @@
  * as described in ARM document number ARM DEN 0022A.
  */
 
+static unsigned long psci_affinity_mask(unsigned long affinity_level)
+{
+	unsigned long affinity_mask = MPIDR_HWID_BITMASK;
+
+	switch (affinity_level) {
+	case 0: /* All affinity levels are valid */
+		affinity_mask &= ~0x0UL;
+		break;
+	case 1: /* Aff0 ignored */
+		affinity_mask &= ~0xFFUL;
+		break;
+	case 2: /* Aff0 and Aff1 ignored */
+		affinity_mask &= ~0xFFFFUL;
+		break;
+	case 3: /* Aff0, Aff1, and Aff2 ignored */
+		affinity_mask &= ~0xFFFFFFUL;
+		break;
+	default:
+		affinity_mask = 0;
+		break;
+	};
+
+	return affinity_mask;
+}
+
 static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.pause = true;
@@ -85,6 +110,42 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	return KVM_PSCI_RET_SUCCESS;
 }
 
+static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
+{
+	int i;
+	unsigned long mpidr;
+	unsigned long target_affinity;
+	unsigned long target_affinity_mask;
+	unsigned long lowest_affinity_level;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *tmp;
+
+	target_affinity = *vcpu_reg(vcpu, 1);
+	lowest_affinity_level = *vcpu_reg(vcpu, 2);
+
+	/* Determine target affinity mask */
+	target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
+	if (!target_affinity_mask)
+		return KVM_PSCI_RET_INVAL;
+
+	/* Ignore other bits of target affinity */
+	target_affinity &= target_affinity_mask;
+
+	/*
+	 * If one or more VCPU matching target affinity are running
+	 * then return 0 (ON) else return 1 (OFF)
+	 */
+	kvm_for_each_vcpu(i, tmp, kvm) {
+		mpidr = kvm_vcpu_get_mpidr(tmp);
+		if (((mpidr & target_affinity_mask) == target_affinity) &&
+		    !tmp->arch.pause) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
 static inline void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type)
 {
 	memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
@@ -132,6 +193,10 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	case KVM_PSCI_0_2_FN64_CPU_ON:
 		val = kvm_psci_vcpu_on(vcpu);
 		break;
+	case KVM_PSCI_0_2_FN_AFFINITY_INFO:
+	case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
+		val = kvm_psci_vcpu_affinity_info(vcpu);
+		break;
 	case KVM_PSCI_0_2_FN_SYSTEM_OFF:
 		kvm_psci_system_off(vcpu);
 		val = KVM_PSCI_RET_SUCCESS;
@@ -143,12 +208,10 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		ret = 0;
 		break;
 	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN_AFFINITY_INFO:
 	case KVM_PSCI_0_2_FN_MIGRATE:
 	case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
 	case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
 	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
 	case KVM_PSCI_0_2_FN64_MIGRATE:
 	case KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
 		val = KVM_PSCI_RET_NI;
Signature · 1 line
1.7.9.5
author
#16 lore raw

PATCH v5 8/11 ARM/ARM64: KVM: Emulate PSCI v0.2 MIGRATE_INFO_TYPE and related functions

In reply to Anup Patel

This patch adds emulation of PSCI v0.2 MIGRATE, MIGRATE_INFO_TYPE, and MIGRATE_INFO_UP_CPU function calls for KVM ARM/ARM64.

KVM ARM/ARM64 being a hypervisor (and not a Trusted OS), we cannot provide this functions hence we emulate these functions in following way:
1. MIGRATE - Returns "Not Supported"
2. MIGRATE_INFO_TYPE - Return 2 i.e. Trusted OS is either not present or does not require migration
3. MIGRATE_INFO_UP_CPU - Returns "Not Supported"

---
 arch/arm/kvm/psci.c |   20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
arch/arm/kvm/psci.c +15 -5
index 5bd9ae4..ab1d098 100644
@@ -197,6 +197,21 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
 		val = kvm_psci_vcpu_affinity_info(vcpu);
 		break;
+	case KVM_PSCI_0_2_FN_MIGRATE:
+	case KVM_PSCI_0_2_FN64_MIGRATE:
+		val = KVM_PSCI_RET_NI;
+		break;
+	case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+		/*
+		 * Trusted OS is either not present or
+		 * does not require migration
+		 */
+		val = 2;
+		break;
+	case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
+	case KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
+		val = KVM_PSCI_RET_NI;
+		break;
 	case KVM_PSCI_0_2_FN_SYSTEM_OFF:
 		kvm_psci_system_off(vcpu);
 		val = KVM_PSCI_RET_SUCCESS;
@@ -208,12 +223,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		ret = 0;
 		break;
 	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN_MIGRATE:
-	case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
-	case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
 	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN64_MIGRATE:
-	case KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
 		val = KVM_PSCI_RET_NI;
 		break;
 	default:
Signature · 1 line
1.7.9.5
author
#17 lore raw

PATCH v5 9/11 ARM/ARM64: KVM: Fix CPU_ON emulation for PSCI v0.2

In reply to Anup Patel

As-per PSCI v0.2, the source CPU provides physical address of "entry point" and "context id" for starting a target CPU. Also, if target CPU is already running then we should return ALREADY_ON.

Current emulation of CPU_ON function does not consider physical address of "context id" and returns INVALID_PARAMETERS if target CPU is already running.

This patch updates kvm_psci_vcpu_on() such that it works for both PSCI v0.1 and PSCI v0.2.

---
 arch/arm/kvm/psci.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
arch/arm/kvm/psci.c +11 -1
index ab1d098..1e85452 100644
@@ -63,6 +63,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	struct kvm_vcpu *vcpu = NULL, *tmp;
 	wait_queue_head_t *wq;
 	unsigned long cpu_id;
+	unsigned long context_id;
 	unsigned long mpidr;
 	phys_addr_t target_pc;
 	int i;
@@ -83,10 +84,17 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 * Make sure the caller requested a valid CPU and that the CPU is
 	 * turned off.
 	 */
-	if (!vcpu || !vcpu->arch.pause)
+	if (!vcpu)
 		return KVM_PSCI_RET_INVAL;
+	if (!vcpu->arch.pause) {
+		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+			return KVM_PSCI_RET_ALREADY_ON;
+		else
+			return KVM_PSCI_RET_INVAL;
+	}
 
 	target_pc = *vcpu_reg(source_vcpu, 2);
+	context_id = *vcpu_reg(source_vcpu, 3);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -101,6 +109,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 		kvm_vcpu_set_be(vcpu);
 
 	*vcpu_pc(vcpu) = target_pc;
+	if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+		*vcpu_reg(vcpu, 0) = context_id;
 	vcpu->arch.pause = false;
 	smp_mb();		/* Make sure the above is visible */
 
Signature · 1 line
1.7.9.5
#18 lore raw

PATCH v5 9/11 ARM/ARM64: KVM: Fix CPU_ON emulation for PSCI v0.2

Quoted 60 lines · Anup Patel

As-per PSCI v0.2, the source CPU provides physical address of "entry point" and "context id" for starting a target CPU. Also, if target CPU is already running then we should return ALREADY_ON.

Current emulation of CPU_ON function does not consider physical address of "context id" and returns INVALID_PARAMETERS if target CPU is already running.

This patch updates kvm_psci_vcpu_on() such that it works for both PSCI v0.1 and PSCI v0.2.

---
 arch/arm/kvm/psci.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
arch/arm/kvm/psci.c +11 -1
index ab1d098..1e85452 100644
@@ -63,6 +63,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	struct kvm_vcpu *vcpu = NULL, *tmp;
 	wait_queue_head_t *wq;
 	unsigned long cpu_id;
+	unsigned long context_id;
 	unsigned long mpidr;
 	phys_addr_t target_pc;
 	int i;
@@ -83,10 +84,17 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 * Make sure the caller requested a valid CPU and that the CPU is
 	 * turned off.
 	 */
-	if (!vcpu || !vcpu->arch.pause)
+	if (!vcpu)
 		return KVM_PSCI_RET_INVAL;
+	if (!vcpu->arch.pause) {
+		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+			return KVM_PSCI_RET_ALREADY_ON;
+		else
+			return KVM_PSCI_RET_INVAL;
+	}
 
 	target_pc = *vcpu_reg(source_vcpu, 2);
+	context_id = *vcpu_reg(source_vcpu, 3);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -101,6 +109,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 		kvm_vcpu_set_be(vcpu);
 
 	*vcpu_pc(vcpu) = target_pc;
+	if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+		*vcpu_reg(vcpu, 0) = context_id;
 	vcpu->arch.pause = false;
 	smp_mb();		/* Make sure the above is visible */
 
Signature · 1 line
1.7.9.5
author
#19 lore raw

PATCH v5 10/11 ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND

In reply to Anup Patel

This patch adds emulation of PSCI v0.2 CPU_SUSPEND function call for KVM ARM/ARM64. This is a CPU-level function call which can suspend current CPU or current CPU cluster. We don't have VCPU clusters in KVM so for KVM we simply suspend the current VCPU.

The CPU_SUSPEND emulation is not tested much because currently there is no CPUIDLE driver in Linux kernel that uses PSCI CPU_SUSPEND. The PSCI CPU_SUSPEND implementation in ARM64 kernel was tested using a Simple CPUIDLE driver which is not published due to unstable DT-bindings for PSCI.
(For more info, http://lwn.net/Articles/574950/)

Even if we had stable DT-bindings for PSCI and CPUIDLE driver that uses PSCI CPU_SUSPEND then still we need to define SUSPEND states for KVM ARM/ARM64.

Due to this, the CPU_SUSPEND emulation added by this patch only pause current VCPU and to wakeup a suspended VCPU we need to explicity call PSCI CPU_ON from Guest.

---
 arch/arm/kvm/psci.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
arch/arm/kvm/psci.c +20 -4
index 1e85452..e32ad10 100644
@@ -52,6 +52,22 @@ static unsigned long psci_affinity_mask(unsigned long affinity_level)
 	return affinity_mask;
 }
 
+static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * NOTE: Currently, we don't have any wakeup events for KVM
+	 * hence VCPU suspend turns-out to be same as VCPU off request.
+	 * This means to suspend a VCPU we simply set the pause flag
+	 * and update VCPU registers as-per wakeup parameters provided
+	 * via r2 & r3 (or x2 & x3).
+	 */
+	vcpu->arch.pause = true;
+	*vcpu_pc(vcpu) = *vcpu_reg(vcpu, 2);
+	*vcpu_reg(vcpu, 0) = *vcpu_reg(vcpu, 3);
+
+	return KVM_PSCI_RET_SUCCESS;
+}
+
 static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.pause = true;
@@ -195,6 +211,10 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		 */
 		val = 2;
 		break;
+	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
+	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
+		val = kvm_psci_vcpu_suspend(vcpu);
+		break;
 	case KVM_PSCI_0_2_FN_CPU_OFF:
 		kvm_psci_vcpu_off(vcpu);
 		val = KVM_PSCI_RET_SUCCESS;
@@ -232,10 +252,6 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		val = KVM_PSCI_RET_SUCCESS;
 		ret = 0;
 		break;
-	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
-		val = KVM_PSCI_RET_NI;
-		break;
 	default:
 		return -EINVAL;
 	}
Signature · 1 line
1.7.9.5
#20 lore raw

PATCH v5 10/11 ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND

Quoted 36 lines · Anup Patel

This patch adds emulation of PSCI v0.2 CPU_SUSPEND function call for KVM ARM/ARM64. This is a CPU-level function call which can suspend current CPU or current CPU cluster. We don't have VCPU clusters in KVM so for KVM we simply suspend the current VCPU.

The CPU_SUSPEND emulation is not tested much because currently there is no CPUIDLE driver in Linux kernel that uses PSCI CPU_SUSPEND. The PSCI CPU_SUSPEND implementation in ARM64 kernel was tested using a Simple CPUIDLE driver which is not published due to unstable DT-bindings for PSCI.
(For more info, http://lwn.net/Articles/574950/)

Even if we had stable DT-bindings for PSCI and CPUIDLE driver that uses PSCI CPU_SUSPEND then still we need to define SUSPEND states for KVM ARM/ARM64.

Due to this, the CPU_SUSPEND emulation added by this patch only pause current VCPU and to wakeup a suspended VCPU we need to explicity call PSCI CPU_ON from Guest.

---
 arch/arm/kvm/psci.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
arch/arm/kvm/psci.c +2 -0
index 1e85452..e32ad10 100644
@@ -52,6 +52,22 @@ static unsigned long psci_affinity_mask(unsigned long affinity_level)
 	return affinity_mask;
 }
 
+static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
+{

arch/arm/kvm/psci.c static unsigned long psci_affinity_mask(unsigned long affinity_level) · line 66

Quoted 10 lines
arch/arm/kvm/psci.c +10 -0
+	/*
+	 * NOTE: Currently, we don't have any wakeup events for KVM
+	 * hence VCPU suspend turns-out to be same as VCPU off request.
+	 * This means to suspend a VCPU we simply set the pause flag
+	 * and update VCPU registers as-per wakeup parameters provided
+	 * via r2 & r3 (or x2 & x3).
+	 */
+	vcpu->arch.pause = true;
+	*vcpu_pc(vcpu) = *vcpu_reg(vcpu, 2);
+	*vcpu_reg(vcpu, 0) = *vcpu_reg(vcpu, 3);

But the spec states in Section 5.1.2 that if Bit[16] StateType == 0, then the entry point and context_id parameters are ignored, because all state is retained for a standby state.

I think Mark Rutland commented that KVM should define at last interrupts to the CPU as a wakeup event.

Quoted 32 lines
arch/arm/kvm/psci.c +8 -4
+
+	return KVM_PSCI_RET_SUCCESS;
+}
+
 static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.pause = true;
@@ -195,6 +211,10 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		 */
 		val = 2;
 		break;
+	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
+	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
+		val = kvm_psci_vcpu_suspend(vcpu);
+		break;
 	case KVM_PSCI_0_2_FN_CPU_OFF:
 		kvm_psci_vcpu_off(vcpu);
 		val = KVM_PSCI_RET_SUCCESS;
@@ -232,10 +252,6 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		val = KVM_PSCI_RET_SUCCESS;
 		ret = 0;
 		break;
-	case KVM_PSCI_0_2_FN_CPU_SUSPEND:
-	case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
-		val = KVM_PSCI_RET_NI;
-		break;
 	default:
 		return -EINVAL;
 	}
Signature · 1 line
1.7.9.5

Thanks,
-Christoffer

author
#21 lore raw

PATCH v5 10/11 ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND

Quoted 35 lines · Christoffer Dall
Quoted 34 lines · Anup Patel

This patch adds emulation of PSCI v0.2 CPU_SUSPEND function call for KVM ARM/ARM64. This is a CPU-level function call which can suspend current CPU or current CPU cluster. We don't have VCPU clusters in KVM so for KVM we simply suspend the current VCPU.

The CPU_SUSPEND emulation is not tested much because currently there is no CPUIDLE driver in Linux kernel that uses PSCI CPU_SUSPEND. The PSCI CPU_SUSPEND implementation in ARM64 kernel was tested using a Simple CPUIDLE driver which is not published due to unstable DT-bindings for PSCI.
(For more info, http://lwn.net/Articles/574950/)

Even if we had stable DT-bindings for PSCI and CPUIDLE driver that uses PSCI CPU_SUSPEND then still we need to define SUSPEND states for KVM ARM/ARM64.

Due to this, the CPU_SUSPEND emulation added by this patch only pause current VCPU and to wakeup a suspended VCPU we need to explicity call PSCI CPU_ON from Guest.

---
 arch/arm/kvm/psci.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
arch/arm/kvm/psci.c +0 -0
index 1e85452..e32ad10 100644
@@ -52,6 +52,22 @@ static unsigned long psci_affinity_mask(unsigned long affinity_level)
      return affinity_mask;
 }
 
Quoted 16 lines

arch/arm/kvm/psci.c static unsigned long psci_affinity_mask(unsigned long affinity_level) · line 66

Quoted 12 lines
arch/arm/kvm/psci.c +12 -0
+static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
+{
+     /*
+      * NOTE: Currently, we don't have any wakeup events for KVM
+      * hence VCPU suspend turns-out to be same as VCPU off request.
+      * This means to suspend a VCPU we simply set the pause flag
+      * and update VCPU registers as-per wakeup parameters provided
+      * via r2 & r3 (or x2 & x3).
+      */
+     vcpu->arch.pause = true;
+     *vcpu_pc(vcpu) = *vcpu_reg(vcpu, 2);
+     *vcpu_reg(vcpu, 0) = *vcpu_reg(vcpu, 3);

But the spec states in Section 5.1.2 that if Bit[16] StateType == 0, then the entry point and context_id parameters are ignored, because all state is retained for a standby state.

OK, I will update this accordingly.

Quoted 3 lines

I think Mark Rutland commented that KVM should define at last interrupts to the CPU as a wakeup event.

How about using kvm_vcpu_block(vcpu) instead of "vcpu->arch.pause = true"?

This will make CPU_SUSPEND emulation very similar to WFI emulation.

Regards,
Anup

Quoted 37 lines
Quoted 31 lines
arch/arm/kvm/psci.c +8 -5
+
+     return KVM_PSCI_RET_SUCCESS;
+}
+
 static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
 {
      vcpu->arch.pause = true;
@@ -195,6 +211,10 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
               */
              val = 2;
              break;
+     case KVM_PSCI_0_2_FN_CPU_SUSPEND:
+     case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
+             val = kvm_psci_vcpu_suspend(vcpu);
+             break;
      case KVM_PSCI_0_2_FN_CPU_OFF:
              kvm_psci_vcpu_off(vcpu);
              val = KVM_PSCI_RET_SUCCESS;
@@ -232,10 +252,6 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
              val = KVM_PSCI_RET_SUCCESS;
              ret = 0;
              break;
-     case KVM_PSCI_0_2_FN_CPU_SUSPEND:
-     case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
-             val = KVM_PSCI_RET_NI;
-             break;
      default:
              return -EINVAL;
      }
--
Quoted 2 lines

1.7.9.5

Thanks,
-Christoffer

#22 lore raw

PATCH v5 10/11 ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND

Quoted 53 lines · Anup Patel
Quoted 35 lines · Christoffer Dall
Quoted 34 lines · Anup Patel

This patch adds emulation of PSCI v0.2 CPU_SUSPEND function call for KVM ARM/ARM64. This is a CPU-level function call which can suspend current CPU or current CPU cluster. We don't have VCPU clusters in KVM so for KVM we simply suspend the current VCPU.

The CPU_SUSPEND emulation is not tested much because currently there is no CPUIDLE driver in Linux kernel that uses PSCI CPU_SUSPEND. The PSCI CPU_SUSPEND implementation in ARM64 kernel was tested using a Simple CPUIDLE driver which is not published due to unstable DT-bindings for PSCI.
(For more info, http://lwn.net/Articles/574950/)

Even if we had stable DT-bindings for PSCI and CPUIDLE driver that uses PSCI CPU_SUSPEND then still we need to define SUSPEND states for KVM ARM/ARM64.

Due to this, the CPU_SUSPEND emulation added by this patch only pause current VCPU and to wakeup a suspended VCPU we need to explicity call PSCI CPU_ON from Guest.

---
 arch/arm/kvm/psci.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
arch/arm/kvm/psci.c +0 -0
index 1e85452..e32ad10 100644
@@ -52,6 +52,22 @@ static unsigned long psci_affinity_mask(unsigned long affinity_level)
      return affinity_mask;
 }
 
Quoted 16 lines

arch/arm/kvm/psci.c static unsigned long psci_affinity_mask(unsigned long affinity_level) · line 66

Quoted 12 lines
arch/arm/kvm/psci.c +12 -0
+static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
+{
+     /*
+      * NOTE: Currently, we don't have any wakeup events for KVM
+      * hence VCPU suspend turns-out to be same as VCPU off request.
+      * This means to suspend a VCPU we simply set the pause flag
+      * and update VCPU registers as-per wakeup parameters provided
+      * via r2 & r3 (or x2 & x3).
+      */
+     vcpu->arch.pause = true;
+     *vcpu_pc(vcpu) = *vcpu_reg(vcpu, 2);
+     *vcpu_reg(vcpu, 0) = *vcpu_reg(vcpu, 3);

But the spec states in Section 5.1.2 that if Bit[16] StateType == 0, then the entry point and context_id parameters are ignored, because all state is retained for a standby state.

Quoted 7 lines

OK, I will update this accordingly.

Quoted 3 lines

I think Mark Rutland commented that KVM should define at last interrupts to the CPU as a wakeup event.

How about using kvm_vcpu_block(vcpu) instead of "vcpu->arch.pause = true"?

You mean if StateType==0 only, or will you always force a shutdown event to be handled as a suspend event (I believe the spec allows for you to do so)? If you are going down this path, please document that clearly somewhere.

I definitely want to see us using something like kvm_vcpu_block(vcpu) for suspend requests, but the thing with kvm_vcpu_block() is that a regular signal to the VCPU thread wakes up that VCPU, which I think we agreed was fine for the WFI implementation, as it should handle spurious interrupts as wake up events (which is also how we handle the fact that any VCPUs in WFI will be woken up when migrated).

But for PSCI CPU_SUSPEND, I'm not sure if that's still a valid assumption. Anyone?

Quoted 3 lines

This will make CPU_SUSPEND emulation very similar to WFI emulation.

Yes, I think the PSCI docs suggest this should be the behavior as well.

Thanks,
-Christoffer

author
#23 lore raw

PATCH v5 11/11 ARM/ARM64: KVM: Advertise KVM_CAP_ARM_PSCI_0_2 to user space

In reply to Anup Patel

We have PSCI v0.2 emulation available in KVM ARM/ARM64 hence advertise this to user space (i.e. QEMU or KVMTOOL) via KVM_CHECK_EXTENSION ioctl.

---
 arch/arm/kvm/arm.c |    1 +
 1 file changed, 1 insertion(+)
arch/arm/kvm/arm.c +1 -0
index bd18bb8..2076605 100644
@@ -197,6 +197,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
 	case KVM_CAP_ONE_REG:
 	case KVM_CAP_ARM_PSCI:
+	case KVM_CAP_ARM_PSCI_0_2:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
Signature · 1 line
1.7.9.5
#24 lore raw

PATCH v5 11/11 ARM/ARM64: KVM: Advertise KVM_CAP_ARM_PSCI_0_2 to user space

Quoted 25 lines · Anup Patel

We have PSCI v0.2 emulation available in KVM ARM/ARM64 hence advertise this to user space (i.e. QEMU or KVMTOOL) via KVM_CHECK_EXTENSION ioctl.

---
 arch/arm/kvm/arm.c |    1 +
 1 file changed, 1 insertion(+)
arch/arm/kvm/arm.c +1 -0
index bd18bb8..2076605 100644
@@ -197,6 +197,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
 	case KVM_CAP_ONE_REG:
 	case KVM_CAP_ARM_PSCI:
+	case KVM_CAP_ARM_PSCI_0_2:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
Signature · 1 line
1.7.9.5