History

KVM: ARM: Power State Coordination Interface implementation

Implement the PSCI specification (ARM DEN 0022A) to control virtual CPUs being "powered" on or off. PSCI/KVM is detected using the KVM_CAP_ARM_PSCI capability. A virtual CPU can now be initialized in a "powered off" state, using the KVM_ARM_VCPU_POWER_OFF feature flag. The guest can use either SMC or HVC to execute a PSCI function.

Marc Zyngier committed 13 years ago

Commit aa024c21 parent 45e96ea9 files · +195 −4Browse files

Unified · Split

9 files
  1. Documentation/virtual/kvm/api.txt +4 −0
  2. arch/arm/include/asm/kvm_emulate.h +10 −0
  3. arch/arm/include/asm/kvm_host.h +4 −1
  4. arch/arm/include/asm/kvm_psci.h +23 −0
  5. arch/arm/include/uapi/asm/kvm.h +16 −0
  6. arch/arm/kvm/Makefile +1 −1
  7. arch/arm/kvm/arm.c +28 −2
  8. arch/arm/kvm/psci.c +108 −0
  9. include/uapi/linux/kvm.h +1 −0
Documentation/virtual/kvm/api.txt+4−0
@@ -2185,6 +2185,10 @@ return ENOEXEC for that vcpu. · 2184 unmodified lines
21852185 Note that because some registers reflect machine topology, all vcpus
21862186 should be created before this ioctl is invoked.
21872187
2188+Possible features:
2189+ - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
2190+ Depends on KVM_CAP_ARM_PSCI.
2191+
21882192
21892193 4.78 KVM_GET_REG_LIST
21902194
arch/arm/include/asm/kvm_emulate.h+10−0
@@ -32,6 +32,11 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu); · 31 unmodified lines
3232 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
3333 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
3434
35+static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu)
36+{
37+ return 1;
38+}
39+
3540 static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu)
3641 {
3742 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc;
@@ -42,6 +47,11 @@ static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu) · 4 unmodified lines
4247 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr;
4348 }
4449
50+static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
51+{
52+ *vcpu_cpsr(vcpu) |= PSR_T_BIT;
53+}
54+
4555 static inline bool mode_has_spsr(struct kvm_vcpu *vcpu)
4656 {
4757 unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK;
arch/arm/include/asm/kvm_host.h+4−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
3131 #define KVM_HAVE_ONE_REG
3232
33−#define KVM_VCPU_MAX_FEATURES 0
33+#define KVM_VCPU_MAX_FEATURES 1
3434
3535 /* We don't currently support large pages. */
3636 #define KVM_HPAGE_GFN_SHIFT(x) 0
@@ -100,6 +100,9 @@ struct kvm_vcpu_arch { · 63 unmodified lines
100100 int last_pcpu;
101101 cpumask_t require_dcache_flush;
102102
103+ /* Don't run the guest on this vcpu */
104+ bool pause;
105+
103106 /* IO related fields */
104107 struct kvm_decode mmio_decode;
105108
arch/arm/include/asm/kvm_psci.h+23−0
@@ -0,0 +1,23 @@
1+/*
2+ * Copyright (C) 2012 - ARM Ltd
3+ * Author: Marc Zyngier <marc.zyngier@arm.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License version 2 as
7+ * published by the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#ifndef __ARM_KVM_PSCI_H__
19+#define __ARM_KVM_PSCI_H__
20+
21+bool kvm_psci_call(struct kvm_vcpu *vcpu);
22+
23+#endif /* __ARM_KVM_PSCI_H__ */
arch/arm/include/uapi/asm/kvm.h+16−0
@@ -65,6 +65,8 @@ struct kvm_regs { · 64 unmodified lines
6565 #define KVM_ARM_TARGET_CORTEX_A15 0
6666 #define KVM_ARM_NUM_TARGETS 1
6767
68+#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
69+
6870 struct kvm_vcpu_init {
6971 __u32 target;
7072 __u32 features[7];
@@ -145,4 +147,18 @@ struct kvm_arch_memory_slot { · 74 unmodified lines
145147 /* Highest supported SPI, from VGIC_NR_IRQS */
146148 #define KVM_ARM_IRQ_GIC_MAX 127
147149
150+/* PSCI interface */
151+#define KVM_PSCI_FN_BASE 0x95c1ba5e
152+#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
153+
154+#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0)
155+#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1)
156+#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
157+#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
158+
159+#define KVM_PSCI_RET_SUCCESS 0
160+#define KVM_PSCI_RET_NI ((unsigned long)-1)
161+#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
162+#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
163+
148164 #endif /* __ARM_KVM_H__ */
arch/arm/kvm/Makefile+1−1
@@ -18,4 +18,4 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) · 17 unmodified lines
1818
1919 obj-y += kvm-arm.o init.o interrupts.o
2020 obj-y += arm.o guest.o mmu.o emulate.o reset.o
21−obj-y += coproc.o coproc_a15.o mmio.o
21+obj-y += coproc.o coproc_a15.o mmio.o psci.o
arch/arm/kvm/arm.c+28−2
@@ -43,6 +43,7 @@ · 42 unmodified lines
4343 #include <asm/kvm_mmu.h>
4444 #include <asm/kvm_emulate.h>
4545 #include <asm/kvm_coproc.h>
46+#include <asm/kvm_psci.h>
4647 #include <asm/opcodes.h>
4748
4849 #ifdef REQUIRES_VIRT
@@ -160,6 +161,7 @@ int kvm_dev_ioctl_check_extension(long ext) · 111 unmodified lines
160161 case KVM_CAP_SYNC_MMU:
161162 case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
162163 case KVM_CAP_ONE_REG:
164+ case KVM_CAP_ARM_PSCI:
163165 r = 1;
164166 break;
165167 case KVM_CAP_COALESCED_MMIO:
@@ -443,14 +445,18 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) · 277 unmodified lines
443445 trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
444446 vcpu->arch.hsr & HSR_HVC_IMM_MASK);
445447
448+ if (kvm_psci_call(vcpu))
449+ return 1;
450+
446451 kvm_inject_undefined(vcpu);
447452 return 1;
448453 }
449454
450455 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
451456 {
452− /* We don't support SMC; don't do that. */
453− kvm_debug("smc: at %08x", *vcpu_pc(vcpu));
457+ if (kvm_psci_call(vcpu))
458+ return 1;
459+
454460 kvm_inject_undefined(vcpu);
455461 return 1;
456462 }
@@ -589,9 +595,26 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) · 132 unmodified lines
589595 return 0;
590596
591597 vcpu->arch.has_run_once = true;
598+
599+ /*
600+ * Handle the "start in power-off" case by calling into the
601+ * PSCI code.
602+ */
603+ if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) {
604+ *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
605+ kvm_psci_call(vcpu);
606+ }
607+
592608 return 0;
593609 }
594610
611+static void vcpu_pause(struct kvm_vcpu *vcpu)
612+{
613+ wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
614+
615+ wait_event_interruptible(*wq, !vcpu->arch.pause);
616+}
617+
595618 /**
596619 * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
597620 * @vcpu: The VCPU pointer
@@ -635,6 +658,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · 37 unmodified lines
635658
636659 update_vttbr(vcpu->kvm);
637660
661+ if (vcpu->arch.pause)
662+ vcpu_pause(vcpu);
663+
638664 local_irq_disable();
639665
640666 /*
arch/arm/kvm/psci.c+108−0
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2012 - ARM Ltd
3+ * Author: Marc Zyngier <marc.zyngier@arm.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License version 2 as
7+ * published by the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#include <linux/kvm_host.h>
19+#include <linux/wait.h>
20+
21+#include <asm/kvm_emulate.h>
22+#include <asm/kvm_psci.h>
23+
24+/*
25+ * This is an implementation of the Power State Coordination Interface
26+ * as described in ARM document number ARM DEN 0022A.
27+ */
28+
29+static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
30+{
31+ vcpu->arch.pause = true;
32+}
33+
34+static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
35+{
36+ struct kvm *kvm = source_vcpu->kvm;
37+ struct kvm_vcpu *vcpu;
38+ wait_queue_head_t *wq;
39+ unsigned long cpu_id;
40+ phys_addr_t target_pc;
41+
42+ cpu_id = *vcpu_reg(source_vcpu, 1);
43+ if (vcpu_mode_is_32bit(source_vcpu))
44+ cpu_id &= ~((u32) 0);
45+
46+ if (cpu_id >= atomic_read(&kvm->online_vcpus))
47+ return KVM_PSCI_RET_INVAL;
48+
49+ target_pc = *vcpu_reg(source_vcpu, 2);
50+
51+ vcpu = kvm_get_vcpu(kvm, cpu_id);
52+
53+ wq = kvm_arch_vcpu_wq(vcpu);
54+ if (!waitqueue_active(wq))
55+ return KVM_PSCI_RET_INVAL;
56+
57+ kvm_reset_vcpu(vcpu);
58+
59+ /* Gracefully handle Thumb2 entry point */
60+ if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) {
61+ target_pc &= ~((phys_addr_t) 1);
62+ vcpu_set_thumb(vcpu);
63+ }
64+
65+ *vcpu_pc(vcpu) = target_pc;
66+ vcpu->arch.pause = false;
67+ smp_mb(); /* Make sure the above is visible */
68+
69+ wake_up_interruptible(wq);
70+
71+ return KVM_PSCI_RET_SUCCESS;
72+}
73+
74+/**
75+ * kvm_psci_call - handle PSCI call if r0 value is in range
76+ * @vcpu: Pointer to the VCPU struct
77+ *
78+ * Handle PSCI calls from guests through traps from HVC or SMC instructions.
79+ * The calling convention is similar to SMC calls to the secure world where
80+ * the function number is placed in r0 and this function returns true if the
81+ * function number specified in r0 is withing the PSCI range, and false
82+ * otherwise.
83+ */
84+bool kvm_psci_call(struct kvm_vcpu *vcpu)
85+{
86+ unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
87+ unsigned long val;
88+
89+ switch (psci_fn) {
90+ case KVM_PSCI_FN_CPU_OFF:
91+ kvm_psci_vcpu_off(vcpu);
92+ val = KVM_PSCI_RET_SUCCESS;
93+ break;
94+ case KVM_PSCI_FN_CPU_ON:
95+ val = kvm_psci_vcpu_on(vcpu);
96+ break;
97+ case KVM_PSCI_FN_CPU_SUSPEND:
98+ case KVM_PSCI_FN_MIGRATE:
99+ val = KVM_PSCI_RET_NI;
100+ break;
101+
102+ default:
103+ return false;
104+ }
105+
106+ *vcpu_reg(vcpu, 0) = val;
107+ return true;
108+}
include/uapi/linux/kvm.h+1−0
@@ -636,6 +636,7 @@ struct kvm_ppc_smmu_info { · 635 unmodified lines
636636 #define KVM_CAP_IRQFD_RESAMPLE 82
637637 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
638638 #define KVM_CAP_PPC_HTAB_FD 84
639+#define KVM_CAP_ARM_PSCI 87
639640
640641 #ifdef KVM_CAP_IRQ_ROUTING
641642

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t