ANDROID: KVM: arm64: Add HVC handling for protected guests at EL2

Rather than forwarding guest hypercalls back to the host for handling,
implement some basic handling at EL2 which will later be extending to
provide additional functionality such as PSCI.

Signed-off-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Will Deacon <willdeacon@google.com>
Bug: 233587962
Change-Id: I14613c416078818b25bb29ed8899d7b71f8c40cc
This commit is contained in:
Fuad Tabba
2022-04-26 12:36:39 +00:00
committed by Will Deacon
parent c63694a9a0
commit e781b3cf0f
4 changed files with 51 additions and 0 deletions

View File

@@ -94,4 +94,6 @@ bool kvm_handle_pvm_restricted(struct kvm_vcpu *vcpu, u64 *exit_code);
void kvm_reset_pvm_sys_regs(struct kvm_vcpu *vcpu);
int kvm_check_pvm_sysreg_table(void);
bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code);
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */

View File

@@ -4,6 +4,8 @@
* Author: Andrew Scull <ascull@google.com>
*/
#include <kvm/arm_hypercalls.h>
#include <hyp/adjust_pc.h>
#include <asm/pgtable-types.h>
@@ -44,6 +46,13 @@ static void handle_pvm_entry_wfx(struct pkvm_hyp_vcpu *hyp_vcpu)
}
}
static void handle_pvm_entry_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
{
u64 ret = READ_ONCE(hyp_vcpu->host_vcpu->arch.ctxt.regs.regs[0]);
vcpu_set_reg(&hyp_vcpu->vcpu, 0, ret);
}
static void handle_pvm_entry_sys64(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
@@ -177,6 +186,21 @@ static void handle_pvm_exit_sys64(struct pkvm_hyp_vcpu *hyp_vcpu)
}
}
static void handle_pvm_exit_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
int i;
WRITE_ONCE(host_vcpu->arch.fault.esr_el2,
hyp_vcpu->vcpu.arch.fault.esr_el2);
/* Pass the hvc function id (r0) as well as any potential arguments. */
for (i = 0; i < 8; i++) {
WRITE_ONCE(host_vcpu->arch.ctxt.regs.regs[i],
vcpu_get_reg(&hyp_vcpu->vcpu, i));
}
}
static void handle_pvm_exit_iabt(struct pkvm_hyp_vcpu *hyp_vcpu)
{
WRITE_ONCE(hyp_vcpu->host_vcpu->arch.fault.esr_el2,
@@ -250,6 +274,7 @@ static void handle_vm_exit_abt(struct pkvm_hyp_vcpu *hyp_vcpu)
static const hyp_entry_exit_handler_fn entry_hyp_pvm_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = NULL,
[ESR_ELx_EC_WFx] = handle_pvm_entry_wfx,
[ESR_ELx_EC_HVC64] = handle_pvm_entry_hvc64,
[ESR_ELx_EC_SYS64] = handle_pvm_entry_sys64,
[ESR_ELx_EC_IABT_LOW] = handle_pvm_entry_iabt,
[ESR_ELx_EC_DABT_LOW] = handle_pvm_entry_dabt,
@@ -258,6 +283,7 @@ static const hyp_entry_exit_handler_fn entry_hyp_pvm_handlers[] = {
static const hyp_entry_exit_handler_fn exit_hyp_pvm_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = NULL,
[ESR_ELx_EC_WFx] = handle_pvm_exit_wfx,
[ESR_ELx_EC_HVC64] = handle_pvm_exit_hvc64,
[ESR_ELx_EC_SYS64] = handle_pvm_exit_sys64,
[ESR_ELx_EC_IABT_LOW] = handle_pvm_exit_iabt,
[ESR_ELx_EC_DABT_LOW] = handle_pvm_exit_dabt,

View File

@@ -7,6 +7,8 @@
#include <linux/kvm_host.h>
#include <linux/mm.h>
#include <kvm/arm_hypercalls.h>
#include <asm/kvm_emulate.h>
#include <nvhe/mem_protect.h>
@@ -803,3 +805,23 @@ err_unlock:
hyp_spin_unlock(&vm_table_lock);
return err;
}
/*
* Handler for protected VM HVC calls.
*
* Returns true if the hypervisor has handled the exit, and control should go
* back to the guest, or false if it hasn't.
*/
bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
{
u32 fn = smccc_get_function(vcpu);
switch (fn) {
case ARM_SMCCC_VERSION_FUNC_ID:
/* Nothing to be handled by the host. Go back to the guest. */
smccc_set_retval(vcpu, ARM_SMCCC_VERSION_1_1, 0, 0, 0);
return true;
default:
return false;
}
}

View File

@@ -217,6 +217,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
static const exit_handler_fn pvm_exit_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = NULL,
[ESR_ELx_EC_HVC64] = kvm_handle_pvm_hvc64,
[ESR_ELx_EC_SYS64] = kvm_handle_pvm_sys64,
[ESR_ELx_EC_SVE] = kvm_handle_pvm_restricted,
[ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd,