ANDROID: KVM: arm64: Handle hyp s1 allocation failures gracefully

Now that we have removed several indirection layers in the mem_protect
machinery, it becomes a little simpler to handle allocation failures
gracefully. Use this opportunity to handle hyp stage-1 mapping failures
without BUG-ing, hence paving the way for reducing its associated
carveout.

Bug: 357781595
Suggested-by: Vincent Donnefort <vdonnefort@google.com>
Change-Id: Ib8b27e59903f3223eaf82a915fe45ba4bcf976ba
Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
Quentin Perret
2025-01-31 15:01:39 +00:00
parent ab910ce16b
commit f3e6f2c64d
4 changed files with 34 additions and 5 deletions
+1
View File
@@ -33,6 +33,7 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr);
int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr);
void pkvm_remove_mappings(void *from, void *to);
unsigned long pkvm_remove_mappings_locked(void *from, void *to);
phys_addr_t __pkvm_private_range_pa(void *va);
int __hyp_allocator_map(unsigned long start, phys_addr_t phys);
+15 -2
View File
@@ -1285,7 +1285,14 @@ int __pkvm_host_share_hyp(u64 pfn)
}
prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_SHARED_BORROWED);
WARN_ON(pkvm_create_mappings_locked(virt, virt + size, prot));
ret = pkvm_create_mappings_locked(virt, virt + size, prot);
if (ret) {
WARN_ON(ret != -ENOMEM);
/* We might have failed halfway through, so remove anything we've installed */
pkvm_remove_mappings_locked(virt, virt + size);
goto unlock;
}
WARN_ON(__host_set_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED));
unlock:
@@ -1477,7 +1484,13 @@ int __pkvm_host_donate_hyp_locked(u64 pfn, u64 nr_pages, enum kvm_pgtable_prot p
}
prot = pkvm_mkstate(prot, PKVM_PAGE_OWNED);
WARN_ON(pkvm_create_mappings_locked(virt, virt + size, prot));
ret = pkvm_create_mappings_locked(virt, virt + size, prot);
if (ret) {
WARN_ON(ret != -ENOMEM);
/* We might have failed halfway through, so remove anything we've installed */
pkvm_remove_mappings_locked(virt, virt + size);
goto unlock;
}
WARN_ON(host_stage2_set_owner_locked(phys, size, PKVM_ID_HYP));
unlock:
+15 -2
View File
@@ -178,7 +178,13 @@ void __pkvm_unmap_module_page(u64 pfn, void *va)
int __hyp_allocator_map(unsigned long va, phys_addr_t phys)
{
return __pkvm_create_mappings(va, PAGE_SIZE, phys, PAGE_HYP);
int ret = __pkvm_create_mappings(va, PAGE_SIZE, phys, PAGE_HYP);
/* Let's not confuse the hyp_alloc callers who will try to top-up pointlessly on -ENOMEM */
if (ret == -ENOMEM)
ret = -EBUSY;
return ret;
}
int pkvm_create_mappings_locked(void *from, void *to, enum kvm_pgtable_prot prot)
@@ -217,12 +223,19 @@ int pkvm_create_mappings(void *from, void *to, enum kvm_pgtable_prot prot)
return ret;
}
unsigned long pkvm_remove_mappings_locked(void *from, void *to)
{
unsigned long size = (unsigned long)to - (unsigned long)from;
return kvm_pgtable_hyp_unmap(&pkvm_pgtable, (u64)from, size);
}
void pkvm_remove_mappings(void *from, void *to)
{
unsigned long size = (unsigned long)to - (unsigned long)from;
hyp_spin_lock(&pkvm_pgd_lock);
WARN_ON(kvm_pgtable_hyp_unmap(&pkvm_pgtable, (u64)from, size) != size);
WARN_ON(pkvm_remove_mappings_locked(from, to) != size);
hyp_spin_unlock(&pkvm_pgd_lock);
}
+3 -1
View File
@@ -1639,8 +1639,10 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,
}
ret = kvm_call_hyp_nvhe(__pkvm_host_share_guest, pfn, gfn, prot, size / PAGE_SIZE);
if (WARN_ON(ret))
if (ret) {
WARN_ON(ret != -ENOMEM);
return ret;
}
swap(mapping, cache->mapping);
mapping->gfn = gfn;