aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/virtual/kvm/api.txt4
-rw-r--r--arch/arm/include/asm/kvm_emulate.h10
-rw-r--r--arch/arm/include/asm/kvm_host.h5
-rw-r--r--arch/arm/include/asm/kvm_psci.h23
-rw-r--r--arch/arm/include/uapi/asm/kvm.h16
-rw-r--r--arch/arm/kvm/Makefile2
-rw-r--r--arch/arm/kvm/arm.c30
-rw-r--r--arch/arm/kvm/psci.c108
-rw-r--r--include/uapi/linux/kvm.h1
9 files changed, 195 insertions, 4 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 38066a7a74e1..c25439a58274 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2185,6 +2185,10 @@ return ENOEXEC for that vcpu.
2185Note that because some registers reflect machine topology, all vcpus 2185Note that because some registers reflect machine topology, all vcpus
2186should be created before this ioctl is invoked. 2186should be created before this ioctl is invoked.
2187 2187
2188Possible features:
2189 - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
2190 Depends on KVM_CAP_ARM_PSCI.
2191
2188 2192
21894.78 KVM_GET_REG_LIST 21934.78 KVM_GET_REG_LIST
2190 2194
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 4c1a073280be..fd611996bfb5 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -32,6 +32,11 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu);
32void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); 32void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
33void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); 33void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
34 34
35static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu)
36{
37 return 1;
38}
39
35static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu) 40static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu)
36{ 41{
37 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc; 42 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc;
@@ -42,6 +47,11 @@ static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu)
42 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr; 47 return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr;
43} 48}
44 49
50static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
51{
52 *vcpu_cpsr(vcpu) |= PSR_T_BIT;
53}
54
45static inline bool mode_has_spsr(struct kvm_vcpu *vcpu) 55static inline bool mode_has_spsr(struct kvm_vcpu *vcpu)
46{ 56{
47 unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK; 57 unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK;
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index e65fc967a71d..98b4d1a72923 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -30,7 +30,7 @@
30#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 30#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
31#define KVM_HAVE_ONE_REG 31#define KVM_HAVE_ONE_REG
32 32
33#define KVM_VCPU_MAX_FEATURES 0 33#define KVM_VCPU_MAX_FEATURES 1
34 34
35/* We don't currently support large pages. */ 35/* We don't currently support large pages. */
36#define KVM_HPAGE_GFN_SHIFT(x) 0 36#define KVM_HPAGE_GFN_SHIFT(x) 0
@@ -100,6 +100,9 @@ struct kvm_vcpu_arch {
100 int last_pcpu; 100 int last_pcpu;
101 cpumask_t require_dcache_flush; 101 cpumask_t require_dcache_flush;
102 102
103 /* Don't run the guest on this vcpu */
104 bool pause;
105
103 /* IO related fields */ 106 /* IO related fields */
104 struct kvm_decode mmio_decode; 107 struct kvm_decode mmio_decode;
105 108
diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h
new file mode 100644
index 000000000000..9a83d98bf170
--- /dev/null
+++ b/arch/arm/include/asm/kvm_psci.h
@@ -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
21bool kvm_psci_call(struct kvm_vcpu *vcpu);
22
23#endif /* __ARM_KVM_PSCI_H__ */
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index bbb6b2328004..3303ff5adbf3 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -65,6 +65,8 @@ struct kvm_regs {
65#define KVM_ARM_TARGET_CORTEX_A15 0 65#define KVM_ARM_TARGET_CORTEX_A15 0
66#define KVM_ARM_NUM_TARGETS 1 66#define KVM_ARM_NUM_TARGETS 1
67 67
68#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
69
68struct kvm_vcpu_init { 70struct kvm_vcpu_init {
69 __u32 target; 71 __u32 target;
70 __u32 features[7]; 72 __u32 features[7];
@@ -145,4 +147,18 @@ struct kvm_arch_memory_slot {
145/* Highest supported SPI, from VGIC_NR_IRQS */ 147/* Highest supported SPI, from VGIC_NR_IRQS */
146#define KVM_ARM_IRQ_GIC_MAX 127 148#define KVM_ARM_IRQ_GIC_MAX 127
147 149
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
148#endif /* __ARM_KVM_H__ */ 164#endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index 1e45cd97a7fc..ea27987bd07f 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -18,4 +18,4 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
18 18
19obj-y += kvm-arm.o init.o interrupts.o 19obj-y += kvm-arm.o init.o interrupts.o
20obj-y += arm.o guest.o mmu.o emulate.o reset.o 20obj-y += arm.o guest.o mmu.o emulate.o reset.o
21obj-y += coproc.o coproc_a15.o mmio.o 21obj-y += coproc.o coproc_a15.o mmio.o psci.o
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 8680b9ffd2ae..2d30e3afdaf9 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -43,6 +43,7 @@
43#include <asm/kvm_mmu.h> 43#include <asm/kvm_mmu.h>
44#include <asm/kvm_emulate.h> 44#include <asm/kvm_emulate.h>
45#include <asm/kvm_coproc.h> 45#include <asm/kvm_coproc.h>
46#include <asm/kvm_psci.h>
46#include <asm/opcodes.h> 47#include <asm/opcodes.h>
47 48
48#ifdef REQUIRES_VIRT 49#ifdef REQUIRES_VIRT
@@ -160,6 +161,7 @@ int kvm_dev_ioctl_check_extension(long ext)
160 case KVM_CAP_SYNC_MMU: 161 case KVM_CAP_SYNC_MMU:
161 case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: 162 case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
162 case KVM_CAP_ONE_REG: 163 case KVM_CAP_ONE_REG:
164 case KVM_CAP_ARM_PSCI:
163 r = 1; 165 r = 1;
164 break; 166 break;
165 case KVM_CAP_COALESCED_MMIO: 167 case KVM_CAP_COALESCED_MMIO:
@@ -443,14 +445,18 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
443 trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), 445 trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
444 vcpu->arch.hsr & HSR_HVC_IMM_MASK); 446 vcpu->arch.hsr & HSR_HVC_IMM_MASK);
445 447
448 if (kvm_psci_call(vcpu))
449 return 1;
450
446 kvm_inject_undefined(vcpu); 451 kvm_inject_undefined(vcpu);
447 return 1; 452 return 1;
448} 453}
449 454
450static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) 455static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
451{ 456{
452 /* We don't support SMC; don't do that. */ 457 if (kvm_psci_call(vcpu))
453 kvm_debug("smc: at %08x", *vcpu_pc(vcpu)); 458 return 1;
459
454 kvm_inject_undefined(vcpu); 460 kvm_inject_undefined(vcpu);
455 return 1; 461 return 1;
456} 462}
@@ -589,9 +595,26 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
589 return 0; 595 return 0;
590 596
591 vcpu->arch.has_run_once = true; 597 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
592 return 0; 608 return 0;
593} 609}
594 610
611static 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
595/** 618/**
596 * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code 619 * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
597 * @vcpu: The VCPU pointer 620 * @vcpu: The VCPU pointer
@@ -635,6 +658,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
635 658
636 update_vttbr(vcpu->kvm); 659 update_vttbr(vcpu->kvm);
637 660
661 if (vcpu->arch.pause)
662 vcpu_pause(vcpu);
663
638 local_irq_disable(); 664 local_irq_disable();
639 665
640 /* 666 /*
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
new file mode 100644
index 000000000000..7ee5bb7a3667
--- /dev/null
+++ b/arch/arm/kvm/psci.c
@@ -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
29static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
30{
31 vcpu->arch.pause = true;
32}
33
34static 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 */
84bool 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}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dc63665e73ad..7f2360a46fc2 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -636,6 +636,7 @@ struct kvm_ppc_smmu_info {
636#define KVM_CAP_IRQFD_RESAMPLE 82 636#define KVM_CAP_IRQFD_RESAMPLE 82
637#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 637#define KVM_CAP_PPC_BOOKE_WATCHDOG 83
638#define KVM_CAP_PPC_HTAB_FD 84 638#define KVM_CAP_PPC_HTAB_FD 84
639#define KVM_CAP_ARM_PSCI 87
639 640
640#ifdef KVM_CAP_IRQ_ROUTING 641#ifdef KVM_CAP_IRQ_ROUTING
641 642