ANDROID: KVM: arm64: Add 'host_mmio_dabt_handler' to kvm_iommu_ops

Add a new kvm_iommu_ops hook which allows the IOMMU driver to handle
data aborts in unmapped device memory regions. If the abort is handled
by the driver, the global abort handler will not attempt to map in the
page.

For example, this enables the IOMMU driver to virtualize access to
the underlying IOMMU hardware, or to allow access to a subset of the
functionality, eg. performance counters.

Test: builds, boots
Bug: 190463801
Signed-off-by: David Brazdil <dbrazdil@google.com>
Change-Id: Ie2e38652f0568c27d30190fcc3879592872863ae
This commit is contained in:
David Brazdil
2021-10-28 14:26:18 +01:00
parent 3cd8b5b00b
commit 25f81ec77b
2 changed files with 39 additions and 2 deletions

View File

@@ -127,6 +127,9 @@ extern u64 kvm_nvhe_sym(id_aa64mmfr2_el1_sys_val);
struct kvm_iommu_ops {
int (*init)(void);
bool (*host_smc_handler)(struct kvm_cpu_context *host_ctxt);
bool (*host_mmio_dabt_handler)(struct kvm_cpu_context *host_ctxt,
phys_addr_t fault_pa, unsigned int len,
bool is_write, int rd);
void (*host_stage2_set_owner)(phys_addr_t addr, size_t size, u8 owner_id);
};

View File

@@ -11,6 +11,7 @@
#include <asm/kvm_pgtable.h>
#include <asm/stage2_pgtable.h>
#include <hyp/adjust_pc.h>
#include <hyp/fault.h>
#include <nvhe/gfp.h>
@@ -445,16 +446,49 @@ unlock:
return ret;
}
static int host_mmio_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr,
phys_addr_t addr)
{
bool wnr = esr & ESR_ELx_WNR;
unsigned int len = BIT((esr & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
int rd = (esr & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
bool handled = false;
if (kvm_iommu_ops.host_mmio_dabt_handler) {
handled = kvm_iommu_ops.host_mmio_dabt_handler(host_ctxt, addr,
len, wnr, rd);
}
if (!handled)
return -EPERM;
kvm_skip_host_instr();
return 0;
}
static bool is_dabt(u64 esr)
{
return ESR_ELx_EC(esr) == ESR_ELx_EC_DABT_LOW;
}
void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt)
{
struct kvm_vcpu_fault_info fault;
u64 esr, addr;
int ret = 0;
int ret = -EPERM;
esr = read_sysreg_el2(SYS_ESR);
BUG_ON(!__get_fault_info(esr, &fault));
addr = (fault.hpfar_el2 & HPFAR_MASK) << 8;
ret = host_stage2_idmap(addr);
/* See if any subsystem can handle this abort. */
if (is_dabt(esr) && !addr_is_memory(addr))
ret = host_mmio_dabt_handler(host_ctxt, esr, addr);
/* If not handled, attempt to map the page. */
if (ret == -EPERM)
ret = host_stage2_idmap(addr);
BUG_ON(ret && ret != -EAGAIN);
}