diff options
author | Anup Patel <anup.patel@linaro.org> | 2014-04-29 01:54:20 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-04-30 07:18:58 -0400 |
commit | 4b1238269ed340d59ef829fd9c30a39cfb2923a8 (patch) | |
tree | 8e2fcecc8c6e7678a6c70337f892284e487ce8f0 /arch/arm/kvm | |
parent | 8ad6b634928a25971dc42dce101808b1491f87ec (diff) |
ARM/ARM64: KVM: Emulate PSCI v0.2 SYSTEM_OFF and SYSTEM_RESET
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.
Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch/arm/kvm')
-rw-r--r-- | arch/arm/kvm/psci.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 14e6fa6c8e35..59362131b79f 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c | |||
@@ -85,6 +85,23 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) | |||
85 | return PSCI_RET_SUCCESS; | 85 | return PSCI_RET_SUCCESS; |
86 | } | 86 | } |
87 | 87 | ||
88 | static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type) | ||
89 | { | ||
90 | memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); | ||
91 | vcpu->run->system_event.type = type; | ||
92 | vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; | ||
93 | } | ||
94 | |||
95 | static void kvm_psci_system_off(struct kvm_vcpu *vcpu) | ||
96 | { | ||
97 | kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN); | ||
98 | } | ||
99 | |||
100 | static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) | ||
101 | { | ||
102 | kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET); | ||
103 | } | ||
104 | |||
88 | int kvm_psci_version(struct kvm_vcpu *vcpu) | 105 | int kvm_psci_version(struct kvm_vcpu *vcpu) |
89 | { | 106 | { |
90 | if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) | 107 | if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) |
@@ -95,6 +112,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) | |||
95 | 112 | ||
96 | static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | 113 | static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) |
97 | { | 114 | { |
115 | int ret = 1; | ||
98 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | 116 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); |
99 | unsigned long val; | 117 | unsigned long val; |
100 | 118 | ||
@@ -114,13 +132,35 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | |||
114 | case PSCI_0_2_FN64_CPU_ON: | 132 | case PSCI_0_2_FN64_CPU_ON: |
115 | val = kvm_psci_vcpu_on(vcpu); | 133 | val = kvm_psci_vcpu_on(vcpu); |
116 | break; | 134 | break; |
135 | case PSCI_0_2_FN_SYSTEM_OFF: | ||
136 | kvm_psci_system_off(vcpu); | ||
137 | /* | ||
138 | * We should'nt be going back to guest VCPU after | ||
139 | * receiving SYSTEM_OFF request. | ||
140 | * | ||
141 | * If user space accidently/deliberately resumes | ||
142 | * guest VCPU after SYSTEM_OFF request then guest | ||
143 | * VCPU should see internal failure from PSCI return | ||
144 | * value. To achieve this, we preload r0 (or x0) with | ||
145 | * PSCI return value INTERNAL_FAILURE. | ||
146 | */ | ||
147 | val = PSCI_RET_INTERNAL_FAILURE; | ||
148 | ret = 0; | ||
149 | break; | ||
150 | case PSCI_0_2_FN_SYSTEM_RESET: | ||
151 | kvm_psci_system_reset(vcpu); | ||
152 | /* | ||
153 | * Same reason as SYSTEM_OFF for preloading r0 (or x0) | ||
154 | * with PSCI return value INTERNAL_FAILURE. | ||
155 | */ | ||
156 | val = PSCI_RET_INTERNAL_FAILURE; | ||
157 | ret = 0; | ||
158 | break; | ||
117 | case PSCI_0_2_FN_CPU_SUSPEND: | 159 | case PSCI_0_2_FN_CPU_SUSPEND: |
118 | case PSCI_0_2_FN_AFFINITY_INFO: | 160 | case PSCI_0_2_FN_AFFINITY_INFO: |
119 | case PSCI_0_2_FN_MIGRATE: | 161 | case PSCI_0_2_FN_MIGRATE: |
120 | case PSCI_0_2_FN_MIGRATE_INFO_TYPE: | 162 | case PSCI_0_2_FN_MIGRATE_INFO_TYPE: |
121 | case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU: | 163 | case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU: |
122 | case PSCI_0_2_FN_SYSTEM_OFF: | ||
123 | case PSCI_0_2_FN_SYSTEM_RESET: | ||
124 | case PSCI_0_2_FN64_CPU_SUSPEND: | 164 | case PSCI_0_2_FN64_CPU_SUSPEND: |
125 | case PSCI_0_2_FN64_AFFINITY_INFO: | 165 | case PSCI_0_2_FN64_AFFINITY_INFO: |
126 | case PSCI_0_2_FN64_MIGRATE: | 166 | case PSCI_0_2_FN64_MIGRATE: |
@@ -132,7 +172,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | |||
132 | } | 172 | } |
133 | 173 | ||
134 | *vcpu_reg(vcpu, 0) = val; | 174 | *vcpu_reg(vcpu, 0) = val; |
135 | return 1; | 175 | return ret; |
136 | } | 176 | } |
137 | 177 | ||
138 | static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | 178 | static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) |