Commit e8e7fcc5 authored by Anup Patel's avatar Anup Patel Committed by Christoffer Dall

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: default avatarAnup Patel <anup.patel@linaro.org>
Signed-off-by: default avatarPranavkumar Sawargaonkar <pranavkumar@linaro.org>
Reviewed-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Acked-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
parent 50bb0c94
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
#define KVM_ARM_PSCI_0_2 2 #define KVM_ARM_PSCI_0_2 2
int kvm_psci_version(struct kvm_vcpu *vcpu); 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__ */ #endif /* __ARM_KVM_PSCI_H__ */
...@@ -38,14 +38,18 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) ...@@ -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) static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
int ret;
trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
kvm_vcpu_hvc_get_imm(vcpu)); kvm_vcpu_hvc_get_imm(vcpu));
if (kvm_psci_call(vcpu)) ret = kvm_psci_call(vcpu);
return 1; if (ret < 0) {
kvm_inject_undefined(vcpu); kvm_inject_undefined(vcpu);
return 1; return 1;
}
return ret;
} }
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
......
...@@ -93,7 +93,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) ...@@ -93,7 +93,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
return KVM_ARM_PSCI_0_1; 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 psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
unsigned long val; unsigned long val;
...@@ -128,14 +128,14 @@ static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu) ...@@ -128,14 +128,14 @@ static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
val = PSCI_RET_NOT_SUPPORTED; val = PSCI_RET_NOT_SUPPORTED;
break; break;
default: default:
return false; return -EINVAL;
} }
*vcpu_reg(vcpu, 0) = val; *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 psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
unsigned long val; unsigned long val;
...@@ -153,11 +153,11 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu) ...@@ -153,11 +153,11 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
val = PSCI_RET_NOT_SUPPORTED; val = PSCI_RET_NOT_SUPPORTED;
break; break;
default: default:
return false; return -EINVAL;
} }
*vcpu_reg(vcpu, 0) = val; *vcpu_reg(vcpu, 0) = val;
return true; return 1;
} }
/** /**
...@@ -165,12 +165,16 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu) ...@@ -165,12 +165,16 @@ static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
* @vcpu: Pointer to the VCPU struct * @vcpu: Pointer to the VCPU struct
* *
* Handle PSCI calls from guests through traps from HVC instructions. * Handle PSCI calls from guests through traps from HVC instructions.
* The calling convention is similar to SMC calls to the secure world where * The calling convention is similar to SMC calls to the secure world
* the function number is placed in r0 and this function returns true if the * where the function number is placed in r0.
* function number specified in r0 is withing the PSCI range, and false *
* otherwise. * 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)) { switch (kvm_psci_version(vcpu)) {
case KVM_ARM_PSCI_0_2: case KVM_ARM_PSCI_0_2:
...@@ -178,6 +182,6 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu) ...@@ -178,6 +182,6 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
case KVM_ARM_PSCI_0_1: case KVM_ARM_PSCI_0_1:
return kvm_psci_0_1_call(vcpu); return kvm_psci_0_1_call(vcpu);
default: default:
return false; return -EINVAL;
}; };
} }
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
#define KVM_ARM_PSCI_0_2 2 #define KVM_ARM_PSCI_0_2 2
int kvm_psci_version(struct kvm_vcpu *vcpu); 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__ */ #endif /* __ARM64_KVM_PSCI_H__ */
...@@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); ...@@ -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) static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
if (kvm_psci_call(vcpu)) int ret;
return 1;
ret = kvm_psci_call(vcpu);
if (ret < 0) {
kvm_inject_undefined(vcpu); kvm_inject_undefined(vcpu);
return 1; return 1;
}
return ret;
} }
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment