diff options
author | Anup Patel <anup.patel@linaro.org> | 2014-04-29 01:54:18 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-04-30 07:18:57 -0400 |
commit | e8e7fcc5e2710b31ef842ee799db99c07986c364 (patch) | |
tree | 2f9005ad128030c359da457486de308260ebba89 /arch | |
parent | 50bb0c94759bff8c62f1c7c8f774255e44ec1a41 (diff) |
ARM/ARM64: KVM: Make kvm_psci_call() return convention more flexible
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)
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')
-rw-r--r-- | arch/arm/include/asm/kvm_psci.h | 2 | ||||
-rw-r--r-- | arch/arm/kvm/handle_exit.c | 10 | ||||
-rw-r--r-- | arch/arm/kvm/psci.c | 28 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_psci.h | 2 | ||||
-rw-r--r-- | arch/arm64/kvm/handle_exit.c | 10 |
5 files changed, 32 insertions, 20 deletions
diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h index 4c0e3e1d1597..6bda945d31fa 100644 --- a/arch/arm/include/asm/kvm_psci.h +++ b/arch/arm/include/asm/kvm_psci.h | |||
@@ -22,6 +22,6 @@ | |||
22 | #define KVM_ARM_PSCI_0_2 2 | 22 | #define KVM_ARM_PSCI_0_2 2 |
23 | 23 | ||
24 | int kvm_psci_version(struct kvm_vcpu *vcpu); | 24 | int kvm_psci_version(struct kvm_vcpu *vcpu); |
25 | bool kvm_psci_call(struct kvm_vcpu *vcpu); | 25 | int kvm_psci_call(struct kvm_vcpu *vcpu); |
26 | 26 | ||
27 | #endif /* __ARM_KVM_PSCI_H__ */ | 27 | #endif /* __ARM_KVM_PSCI_H__ */ |
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index 0de91fc6de0f..4c979d466cc1 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c | |||
@@ -38,14 +38,18 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
38 | 38 | ||
39 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 39 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
40 | { | 40 | { |
41 | int ret; | ||
42 | |||
41 | trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), | 43 | trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), |
42 | kvm_vcpu_hvc_get_imm(vcpu)); | 44 | kvm_vcpu_hvc_get_imm(vcpu)); |
43 | 45 | ||
44 | if (kvm_psci_call(vcpu)) | 46 | ret = kvm_psci_call(vcpu); |
47 | if (ret < 0) { | ||
48 | kvm_inject_undefined(vcpu); | ||
45 | return 1; | 49 | return 1; |
50 | } | ||
46 | 51 | ||
47 | kvm_inject_undefined(vcpu); | 52 | return ret; |
48 | return 1; | ||
49 | } | 53 | } |
50 | 54 | ||
51 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 55 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 8c42596cdbdf..14e6fa6c8e35 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c | |||
@@ -93,7 +93,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) | |||
93 | return KVM_ARM_PSCI_0_1; | 93 | return KVM_ARM_PSCI_0_1; |
94 | } | 94 | } |
95 | 95 | ||
96 | static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | 96 | static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) |
97 | { | 97 | { |
98 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | 98 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); |
99 | unsigned long val; | 99 | unsigned long val; |
@@ -128,14 +128,14 @@ static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | |||
128 | val = PSCI_RET_NOT_SUPPORTED; | 128 | val = PSCI_RET_NOT_SUPPORTED; |
129 | break; | 129 | break; |
130 | default: | 130 | default: |
131 | return false; | 131 | return -EINVAL; |
132 | } | 132 | } |
133 | 133 | ||
134 | *vcpu_reg(vcpu, 0) = val; | 134 | *vcpu_reg(vcpu, 0) = val; |
135 | return true; | 135 | return 1; |
136 | } | 136 | } |
137 | 137 | ||
138 | static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | 138 | static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) |
139 | { | 139 | { |
140 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | 140 | unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); |
141 | unsigned long val; | 141 | unsigned long val; |
@@ -153,11 +153,11 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | |||
153 | val = PSCI_RET_NOT_SUPPORTED; | 153 | val = PSCI_RET_NOT_SUPPORTED; |
154 | break; | 154 | break; |
155 | default: | 155 | default: |
156 | return false; | 156 | return -EINVAL; |
157 | } | 157 | } |
158 | 158 | ||
159 | *vcpu_reg(vcpu, 0) = val; | 159 | *vcpu_reg(vcpu, 0) = val; |
160 | return true; | 160 | return 1; |
161 | } | 161 | } |
162 | 162 | ||
163 | /** | 163 | /** |
@@ -165,12 +165,16 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | |||
165 | * @vcpu: Pointer to the VCPU struct | 165 | * @vcpu: Pointer to the VCPU struct |
166 | * | 166 | * |
167 | * Handle PSCI calls from guests through traps from HVC instructions. | 167 | * Handle PSCI calls from guests through traps from HVC instructions. |
168 | * The calling convention is similar to SMC calls to the secure world where | 168 | * The calling convention is similar to SMC calls to the secure world |
169 | * the function number is placed in r0 and this function returns true if the | 169 | * where the function number is placed in r0. |
170 | * function number specified in r0 is withing the PSCI range, and false | 170 | * |
171 | * otherwise. | 171 | * This function returns: > 0 (success), 0 (success but exit to user |
172 | * space), and < 0 (errors) | ||
173 | * | ||
174 | * Errors: | ||
175 | * -EINVAL: Unrecognized PSCI function | ||
172 | */ | 176 | */ |
173 | bool kvm_psci_call(struct kvm_vcpu *vcpu) | 177 | int kvm_psci_call(struct kvm_vcpu *vcpu) |
174 | { | 178 | { |
175 | switch (kvm_psci_version(vcpu)) { | 179 | switch (kvm_psci_version(vcpu)) { |
176 | case KVM_ARM_PSCI_0_2: | 180 | case KVM_ARM_PSCI_0_2: |
@@ -178,6 +182,6 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu) | |||
178 | case KVM_ARM_PSCI_0_1: | 182 | case KVM_ARM_PSCI_0_1: |
179 | return kvm_psci_0_1_call(vcpu); | 183 | return kvm_psci_0_1_call(vcpu); |
180 | default: | 184 | default: |
181 | return false; | 185 | return -EINVAL; |
182 | }; | 186 | }; |
183 | } | 187 | } |
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h index e25c658a757b..bc39e557c56c 100644 --- a/arch/arm64/include/asm/kvm_psci.h +++ b/arch/arm64/include/asm/kvm_psci.h | |||
@@ -22,6 +22,6 @@ | |||
22 | #define KVM_ARM_PSCI_0_2 2 | 22 | #define KVM_ARM_PSCI_0_2 2 |
23 | 23 | ||
24 | int kvm_psci_version(struct kvm_vcpu *vcpu); | 24 | int kvm_psci_version(struct kvm_vcpu *vcpu); |
25 | bool kvm_psci_call(struct kvm_vcpu *vcpu); | 25 | int kvm_psci_call(struct kvm_vcpu *vcpu); |
26 | 26 | ||
27 | #endif /* __ARM64_KVM_PSCI_H__ */ | 27 | #endif /* __ARM64_KVM_PSCI_H__ */ |
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7bc41eab4c64..182415e1a952 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c | |||
@@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); | |||
30 | 30 | ||
31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
32 | { | 32 | { |
33 | if (kvm_psci_call(vcpu)) | 33 | int ret; |
34 | |||
35 | ret = kvm_psci_call(vcpu); | ||
36 | if (ret < 0) { | ||
37 | kvm_inject_undefined(vcpu); | ||
34 | return 1; | 38 | return 1; |
39 | } | ||
35 | 40 | ||
36 | kvm_inject_undefined(vcpu); | 41 | return ret; |
37 | return 1; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 44 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) |