mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
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
Change-Id: I84adbc992e577ac6ceb09f4856e1c648df580f76
Signed-off-by: David Brazdil <dbrazdil@google.com>
(cherry picked from commit 25f81ec77b)
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
committed by
Quentin Perret
parent
6cf8566b50
commit
59d406c88d
@@ -134,7 +134,10 @@ extern bool kvm_nvhe_sym(smccc_trng_available);
|
||||
struct kvm_iommu_ops {
|
||||
int (*init)(void);
|
||||
bool (*host_smc_handler)(struct kvm_cpu_context *host_ctxt);
|
||||
void (*host_stage2_set_owner)(phys_addr_t addr, size_t size, u8 owner_id);
|
||||
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, u32 owner_id);
|
||||
};
|
||||
|
||||
extern struct kvm_iommu_ops kvm_iommu_ops;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <asm/kvm_pkvm.h>
|
||||
#include <asm/stage2_pgtable.h>
|
||||
|
||||
#include <hyp/adjust_pc.h>
|
||||
#include <hyp/fault.h>
|
||||
|
||||
#include <nvhe/gfp.h>
|
||||
@@ -679,17 +680,49 @@ static void host_inject_abort(struct kvm_cpu_context *host_ctxt)
|
||||
write_sysreg_el2(spsr, SYS_SPSR);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (ret == -EPERM)
|
||||
host_inject_abort(host_ctxt);
|
||||
|
||||
Reference in New Issue
Block a user