mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
ANDROID: KVM: arm64: Turn llist of pinned pages into an rb-tree
Indexed by IPA, so we can efficiently lookup. Bug: 240239989 Change-Id: I10ad6ad5a7a6aa34a0814ed334b20f4ae42ca830 Signed-off-by: Quentin Perret <qperret@google.com> Signed-off-by: Keir Fraser <keirf@google.com>
This commit is contained in:
committed by
Keir Fraser
parent
1789c47646
commit
581ea11154
@@ -173,8 +173,9 @@ struct kvm_smccc_features {
|
||||
};
|
||||
|
||||
struct kvm_pinned_page {
|
||||
struct list_head link;
|
||||
struct rb_node node;
|
||||
struct page *page;
|
||||
u64 ipa;
|
||||
};
|
||||
|
||||
typedef unsigned int pkvm_handle_t;
|
||||
@@ -182,7 +183,7 @@ typedef unsigned int pkvm_handle_t;
|
||||
struct kvm_protected_vm {
|
||||
pkvm_handle_t handle;
|
||||
struct kvm_hyp_memcache teardown_mc;
|
||||
struct list_head pinned_pages;
|
||||
struct rb_root pinned_pages;
|
||||
gpa_t pvmfw_load_addr;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
@@ -200,6 +200,7 @@ static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 si
|
||||
static void pkvm_stage2_flush(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_pinned_page *ppage;
|
||||
struct rb_node *node;
|
||||
|
||||
/*
|
||||
* Contrary to stage2_apply_range(), we don't need to check
|
||||
@@ -207,7 +208,8 @@ static void pkvm_stage2_flush(struct kvm *kvm)
|
||||
* from a vcpu thread, and the list is only ever freed on VM
|
||||
* destroy (which only occurs when all vcpu are gone).
|
||||
*/
|
||||
list_for_each_entry(ppage, &kvm->arch.pkvm.pinned_pages, link) {
|
||||
for (node = rb_first(&kvm->arch.pkvm.pinned_pages); node; node = rb_next(node)) {
|
||||
ppage = rb_entry(node, struct kvm_pinned_page, node);
|
||||
__clean_dcache_guest_page(page_address(ppage->page), PAGE_SIZE);
|
||||
cond_resched_rwlock_write(&kvm->mmu_lock);
|
||||
}
|
||||
@@ -700,7 +702,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
|
||||
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||
mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
|
||||
kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
|
||||
INIT_LIST_HEAD(&kvm->arch.pkvm.pinned_pages);
|
||||
kvm->arch.pkvm.pinned_pages = RB_ROOT;
|
||||
mmu->arch = &kvm->arch;
|
||||
|
||||
if (is_protected_kvm_enabled())
|
||||
@@ -1181,6 +1183,26 @@ static int pkvm_host_map_guest(u64 pfn, u64 gfn)
|
||||
return (ret == -EPERM) ? -EAGAIN : ret;
|
||||
}
|
||||
|
||||
static int cmp_ppages(struct rb_node *node, const struct rb_node *parent)
|
||||
{
|
||||
struct kvm_pinned_page *a = container_of(node, struct kvm_pinned_page, node);
|
||||
struct kvm_pinned_page *b = container_of(parent, struct kvm_pinned_page, node);
|
||||
|
||||
if (a->ipa < b->ipa)
|
||||
return -1;
|
||||
if (a->ipa > b->ipa)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_ppage(struct kvm *kvm, struct kvm_pinned_page *ppage)
|
||||
{
|
||||
if (rb_find_add(&ppage->node, &kvm->arch.pkvm.pinned_pages, cmp_ppages))
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
unsigned long hva)
|
||||
{
|
||||
@@ -1245,8 +1267,8 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
}
|
||||
|
||||
ppage->page = page;
|
||||
INIT_LIST_HEAD(&ppage->link);
|
||||
list_add(&ppage->link, &kvm->arch.pkvm.pinned_pages);
|
||||
ppage->ipa = fault_ipa;
|
||||
WARN_ON(insert_ppage(kvm, ppage));
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -217,9 +217,9 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
|
||||
void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
|
||||
{
|
||||
struct kvm_pinned_page *ppage, *tmp;
|
||||
struct kvm_pinned_page *ppage;
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct list_head *ppages;
|
||||
struct rb_node *node;
|
||||
|
||||
if (host_kvm->arch.pkvm.handle) {
|
||||
WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm,
|
||||
@@ -229,15 +229,17 @@ void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
|
||||
host_kvm->arch.pkvm.handle = 0;
|
||||
free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
|
||||
|
||||
ppages = &host_kvm->arch.pkvm.pinned_pages;
|
||||
list_for_each_entry_safe(ppage, tmp, ppages, link) {
|
||||
node = rb_first(&host_kvm->arch.pkvm.pinned_pages);
|
||||
while (node) {
|
||||
ppage = rb_entry(node, struct kvm_pinned_page, node);
|
||||
WARN_ON(kvm_call_hyp_nvhe(__pkvm_host_reclaim_page,
|
||||
page_to_pfn(ppage->page)));
|
||||
cond_resched();
|
||||
|
||||
account_locked_vm(mm, 1, false);
|
||||
unpin_user_pages_dirty_lock(&ppage->page, 1, true);
|
||||
list_del(&ppage->link);
|
||||
node = rb_next(node);
|
||||
rb_erase(&ppage->node, &host_kvm->arch.pkvm.pinned_pages);
|
||||
kfree(ppage);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user