ANDROID: KVM: arm64: Generalize guest PA query
Soon, pvIOMMU would want to map pages from IOVA -> PA, using IPA, so the hypervisor would need to query the PA for this pages and possibly request to map them, this is very similar to the logic used in device token requests. So, reuse the code in a more generic way that is range friendly. Bug: 357781595 Bug: 348382247 Bug: 236685427 Change-Id: Ic0235d97a9722b75c8583dc8550025fa796eda43 Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
ea0829d44f
commit
bd55bd8408
@@ -80,7 +80,9 @@ u64 __pkvm_ptdump_walk_range(pkvm_handle_t handle, struct pkvm_ptdump_log_hdr *l
|
||||
int hyp_check_range_owned(u64 addr, u64 size);
|
||||
int __pkvm_install_guest_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 pfn, u64 gfn);
|
||||
|
||||
int __pkvm_guest_get_valid_phys_page(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa);
|
||||
int pkvm_get_guest_pa_request(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
|
||||
size_t ipa_size_request, u64 *out_pa, s8 *out_level,
|
||||
u64 *exit_code);
|
||||
|
||||
bool addr_is_memory(phys_addr_t phys);
|
||||
int host_stage2_idmap_locked(phys_addr_t addr, u64 size,
|
||||
|
||||
@@ -267,29 +267,6 @@ out_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pkvm_get_device_pa(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa, u64 *pa, u64 *exit_code)
|
||||
{
|
||||
struct kvm_hyp_req *req;
|
||||
int ret;
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
|
||||
ret = __pkvm_guest_get_valid_phys_page(vm, pa, ipa);
|
||||
if (ret == -ENOENT) {
|
||||
/* Page not mapped, create a request*/
|
||||
req = pkvm_hyp_req_reserve(hyp_vcpu, KVM_HYP_REQ_TYPE_MAP);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->map.guest_ipa = ipa;
|
||||
req->map.size = PAGE_SIZE;
|
||||
*exit_code = ARM_EXCEPTION_HYP_REQ;
|
||||
/* Repeat next time. */
|
||||
write_sysreg_el2(read_sysreg_el2(SYS_ELR) - 4, SYS_ELR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pkvm_device_request_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
|
||||
{
|
||||
int i, j, ret;
|
||||
@@ -297,17 +274,22 @@ bool pkvm_device_request_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
u64 ipa = smccc_get_arg1(vcpu);
|
||||
u64 token;
|
||||
s8 level;
|
||||
|
||||
/* arg2 and arg3 reserved for future use. */
|
||||
if (smccc_get_arg2(vcpu) || smccc_get_arg3(vcpu) || !PAGE_ALIGNED(ipa))
|
||||
goto out_inval;
|
||||
|
||||
ret = pkvm_get_device_pa(hyp_vcpu, ipa, &token, exit_code);
|
||||
ret = pkvm_get_guest_pa_request(hyp_vcpu, ipa, PAGE_SIZE,
|
||||
&token, &level, exit_code);
|
||||
if (ret == -ENOENT)
|
||||
return false;
|
||||
else if (ret)
|
||||
goto out_inval;
|
||||
|
||||
/* It's expected the address is mapped as page for MMIO */
|
||||
WARN_ON(level != KVM_PGTABLE_LAST_LEVEL);
|
||||
|
||||
hyp_spin_lock(&device_spinlock);
|
||||
for (i = 0 ; i < registered_devices_nr ; ++i) {
|
||||
struct pkvm_device *dev = ®istered_devices[i];
|
||||
|
||||
@@ -2105,18 +2105,6 @@ static int guest_get_valid_pte(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa, u8 or
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pkvm_guest_get_valid_phys_page(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa)
|
||||
{
|
||||
kvm_pte_t pte;
|
||||
int ret;
|
||||
|
||||
guest_lock_component(vm);
|
||||
ret = guest_get_valid_pte(vm, phys, ipa, 0, &pte);
|
||||
guest_unlock_component(vm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __pkvm_host_relax_perms_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu, enum kvm_pgtable_prot prot)
|
||||
{
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
|
||||
@@ -2743,6 +2731,42 @@ teardown:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return PA for an owned guest IPA or request it, and repeat the guest HVC */
|
||||
int pkvm_get_guest_pa_request(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
|
||||
size_t ipa_size_request, u64 *out_pa, s8 *out_level,
|
||||
u64 *exit_code)
|
||||
{
|
||||
struct kvm_hyp_req *req;
|
||||
kvm_pte_t pte;
|
||||
enum pkvm_page_state state;
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
|
||||
guest_lock_component(vm);
|
||||
WARN_ON(kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, out_level));
|
||||
guest_unlock_component(vm);
|
||||
if (!kvm_pte_valid(pte)) {
|
||||
/* Page not mapped, create a request*/
|
||||
req = pkvm_hyp_req_reserve(hyp_vcpu, KVM_HYP_REQ_TYPE_MAP);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->map.guest_ipa = ipa;
|
||||
req->map.size = ipa_size_request;
|
||||
*exit_code = ARM_EXCEPTION_HYP_REQ;
|
||||
/* Repeat next time. */
|
||||
write_sysreg_el2(read_sysreg_el2(SYS_ELR) - 4, SYS_ELR);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
state = pkvm_getstate(kvm_pgtable_stage2_pte_prot(pte));
|
||||
if (state != PKVM_PAGE_OWNED)
|
||||
return -EPERM;
|
||||
|
||||
*out_pa = kvm_pte_to_phys(pte);
|
||||
*out_pa |= (ipa & kvm_granule_size(*out_level) - 1) & PAGE_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PKVM_SELFTESTS
|
||||
struct pkvm_expected_state {
|
||||
enum pkvm_page_state host;
|
||||
|
||||
Reference in New Issue
Block a user