mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
ANDROID: KVM: arm64: pkvm: Add MMIO guard infrastructure
Introduce the infrastructure required to identify an IPA region that is expected to be used as an MMIO window. This include mapping, unmapping and checking the regions. Nothing calls into it yet, so no expected functional change. Bug: 209580772 Change-Id: I227eaa28b98e067e3daae4f9e1071eb37a6761cc Signed-off-by: Marc Zyngier <maz@kernel.org> [tabba@: use the new pkvm_hyp_* infrastructure, and remove redundant reassignment in __pkvm_remove_ioguard_page()] Signed-off-by: Fuad Tabba <tabba@google.com>
This commit is contained in:
@@ -74,6 +74,9 @@ int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
|
||||
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
|
||||
int __pkvm_guest_relinquish_to_host(struct pkvm_hyp_vcpu *vcpu,
|
||||
u64 ipa, u64 *ppa);
|
||||
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
|
||||
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
|
||||
bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu);
|
||||
|
||||
bool addr_is_memory(phys_addr_t phys);
|
||||
int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);
|
||||
|
||||
@@ -1823,3 +1823,103 @@ unlock:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Replace this with something more structured once day */
|
||||
#define MMIO_NOTE (('M' << 24 | 'M' << 16 | 'I' << 8 | 'O') << 1)
|
||||
|
||||
static bool __check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
|
||||
{
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
int ret;
|
||||
|
||||
ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
/* Must be a PAGE_SIZE mapping with our annotation */
|
||||
return (BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)) == PAGE_SIZE &&
|
||||
pte == MMIO_NOTE);
|
||||
}
|
||||
|
||||
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
|
||||
{
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
int ret;
|
||||
|
||||
if (!test_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vm->kvm.arch.flags))
|
||||
return -EINVAL;
|
||||
|
||||
if (ipa & ~PAGE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
guest_lock_component(vm);
|
||||
|
||||
ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (pte && BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)) == PAGE_SIZE) {
|
||||
/*
|
||||
* Already flagged as MMIO, let's accept it, and fail
|
||||
* otherwise
|
||||
*/
|
||||
if (pte != MMIO_NOTE)
|
||||
ret = -EBUSY;
|
||||
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = kvm_pgtable_stage2_annotate(&vm->pgt, ipa, PAGE_SIZE,
|
||||
&hyp_vcpu->vcpu.arch.pkvm_memcache,
|
||||
MMIO_NOTE);
|
||||
|
||||
unlock:
|
||||
guest_unlock_component(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
|
||||
{
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
|
||||
if (!test_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vm->kvm.arch.flags))
|
||||
return -EINVAL;
|
||||
|
||||
guest_lock_component(vm);
|
||||
|
||||
if (__check_ioguard_page(hyp_vcpu, ipa))
|
||||
WARN_ON(kvm_pgtable_stage2_unmap(&vm->pgt,
|
||||
ALIGN_DOWN(ipa, PAGE_SIZE), PAGE_SIZE));
|
||||
|
||||
guest_unlock_component(vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
u64 ipa, end;
|
||||
bool ret;
|
||||
|
||||
if (!kvm_vcpu_dabt_isvalid(&hyp_vcpu->vcpu))
|
||||
return false;
|
||||
|
||||
if (!test_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vm->kvm.arch.flags))
|
||||
return true;
|
||||
|
||||
ipa = kvm_vcpu_get_fault_ipa(&hyp_vcpu->vcpu);
|
||||
ipa |= kvm_vcpu_get_hfar(&hyp_vcpu->vcpu) & FAR_MASK;
|
||||
end = ipa + kvm_vcpu_dabt_get_as(&hyp_vcpu->vcpu) - 1;
|
||||
|
||||
guest_lock_component(vm);
|
||||
ret = __check_ioguard_page(hyp_vcpu, ipa);
|
||||
if ((end & PAGE_MASK) != (ipa & PAGE_MASK))
|
||||
ret &= __check_ioguard_page(hyp_vcpu, end);
|
||||
guest_unlock_component(vm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user