mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
ANDROID: KVM: arm64: Add protected_hyp_mem VM statistic
When using nVHE in protected mode, the host allocates memory for the hypervisor to store shadow structures and the stage-2 page tables. This has been proven to be an interesting value to follow, for debug and health purpose. Account for those allocations in bytes, in a newly created VM statistic "protected_hyp_mem". It is expected, on VM teardown to reclaim all that memory. Raise a warning if not all the donations are recovered. Bug: 222044477 Change-Id: I18657d275f2ced67ceb6d0e4bd5ce41cf1d41dc8 Signed-off-by: Vincent Donnefort <vdonnefort@google.com> Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
committed by
Quentin Perret
parent
059a19c4ef
commit
b75ae68d19
@@ -127,7 +127,7 @@ static inline void __free_hyp_memcache(struct kvm_hyp_memcache *mc,
|
||||
free_fn(pop_hyp_memcache(mc, to_va), arg);
|
||||
}
|
||||
|
||||
void free_hyp_memcache(struct kvm_hyp_memcache *mc);
|
||||
void free_hyp_memcache(struct kvm_hyp_memcache *mc, struct kvm *kvm);
|
||||
int topup_hyp_memcache(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_vmid {
|
||||
@@ -821,6 +821,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
||||
|
||||
struct kvm_vm_stat {
|
||||
struct kvm_vm_stat_generic generic;
|
||||
atomic64_t protected_hyp_mem;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_stat {
|
||||
|
||||
@@ -212,6 +212,10 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
||||
|
||||
kvm_destroy_vcpus(kvm);
|
||||
|
||||
if (atomic64_read(&kvm->stat.protected_hyp_mem))
|
||||
pr_warn("%lluB of donations to the nVHE hyp are missing\n",
|
||||
atomic64_read(&kvm->stat.protected_hyp_mem));
|
||||
|
||||
kvm_unshare_hyp(kvm, kvm + 1);
|
||||
}
|
||||
|
||||
@@ -459,7 +463,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
static_branch_dec(&userspace_irqchip_in_use);
|
||||
|
||||
if (is_protected_kvm_enabled())
|
||||
free_hyp_memcache(&vcpu->arch.pkvm_memcache);
|
||||
free_hyp_memcache(&vcpu->arch.pkvm_memcache, vcpu->kvm);
|
||||
else
|
||||
kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
#include "trace.h"
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS()
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_ICOUNTER(VM, protected_hyp_mem),
|
||||
};
|
||||
|
||||
const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
|
||||
@@ -871,22 +871,54 @@ static void *hyp_mc_alloc_fn(void *unused)
|
||||
return (void *)__get_free_page(GFP_KERNEL_ACCOUNT);
|
||||
}
|
||||
|
||||
void free_hyp_memcache(struct kvm_hyp_memcache *mc)
|
||||
static void account_hyp_memcache(struct kvm_hyp_memcache *mc,
|
||||
unsigned long prev_nr_pages,
|
||||
struct kvm *kvm)
|
||||
{
|
||||
if (is_protected_kvm_enabled())
|
||||
__free_hyp_memcache(mc, hyp_mc_free_fn,
|
||||
kvm_host_va, NULL);
|
||||
unsigned long nr_pages = mc->nr_pages;
|
||||
|
||||
if (prev_nr_pages == nr_pages)
|
||||
return;
|
||||
|
||||
if (nr_pages > prev_nr_pages) {
|
||||
atomic64_add((nr_pages - prev_nr_pages) << PAGE_SHIFT,
|
||||
&kvm->stat.protected_hyp_mem);
|
||||
} else {
|
||||
atomic64_sub((prev_nr_pages - nr_pages) << PAGE_SHIFT,
|
||||
&kvm->stat.protected_hyp_mem);
|
||||
}
|
||||
}
|
||||
|
||||
void free_hyp_memcache(struct kvm_hyp_memcache *mc, struct kvm *kvm)
|
||||
{
|
||||
unsigned long prev_nr_pages;
|
||||
|
||||
if (!is_protected_kvm_enabled())
|
||||
return;
|
||||
|
||||
prev_nr_pages = mc->nr_pages;
|
||||
__free_hyp_memcache(mc, hyp_mc_free_fn, kvm_host_va, NULL);
|
||||
account_hyp_memcache(mc, prev_nr_pages, kvm);
|
||||
}
|
||||
|
||||
int topup_hyp_memcache(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_hyp_memcache *mc = &vcpu->arch.pkvm_memcache;
|
||||
unsigned long prev_nr_pages;
|
||||
int err;
|
||||
|
||||
if (!is_protected_kvm_enabled())
|
||||
return 0;
|
||||
|
||||
return __topup_hyp_memcache(&vcpu->arch.pkvm_memcache,
|
||||
kvm_mmu_cache_min_pages(vcpu->kvm),
|
||||
hyp_mc_alloc_fn,
|
||||
kvm_host_pa, NULL);
|
||||
prev_nr_pages = mc->nr_pages;
|
||||
|
||||
err = __topup_hyp_memcache(mc, kvm_mmu_cache_min_pages(vcpu->kvm),
|
||||
hyp_mc_alloc_fn,
|
||||
kvm_host_pa, NULL);
|
||||
if (!err)
|
||||
account_hyp_memcache(mc, prev_nr_pages, vcpu->kvm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,7 +117,7 @@ void __init kvm_hyp_reserve(void)
|
||||
*/
|
||||
static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
{
|
||||
size_t pgd_sz, hyp_vm_sz, hyp_vcpu_sz, last_ran_sz;
|
||||
size_t pgd_sz, hyp_vm_sz, hyp_vcpu_sz, last_ran_sz, total_sz;
|
||||
struct kvm_vcpu *host_vcpu;
|
||||
pkvm_handle_t handle;
|
||||
void *pgd, *hyp_vm, *last_ran;
|
||||
@@ -165,6 +165,8 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
|
||||
host_kvm->arch.pkvm.handle = handle;
|
||||
|
||||
total_sz = hyp_vm_sz + last_ran_sz + pgd_sz;
|
||||
|
||||
/* Donate memory for the vcpus at hyp and initialize it. */
|
||||
hyp_vcpu_sz = PAGE_ALIGN(PKVM_HYP_VCPU_SIZE);
|
||||
kvm_for_each_vcpu(idx, host_vcpu, host_kvm) {
|
||||
@@ -182,6 +184,8 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
goto destroy_vm;
|
||||
}
|
||||
|
||||
total_sz += hyp_vcpu_sz;
|
||||
|
||||
ret = kvm_call_hyp_nvhe(__pkvm_init_vcpu, handle, host_vcpu,
|
||||
hyp_vcpu);
|
||||
if (ret) {
|
||||
@@ -190,6 +194,8 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
}
|
||||
}
|
||||
|
||||
atomic64_set(&host_kvm->stat.protected_hyp_mem, total_sz);
|
||||
|
||||
return 0;
|
||||
|
||||
destroy_vm:
|
||||
@@ -228,7 +234,7 @@ void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
|
||||
}
|
||||
|
||||
host_kvm->arch.pkvm.handle = 0;
|
||||
free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
|
||||
free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc, host_kvm);
|
||||
|
||||
node = rb_first(&host_kvm->arch.pkvm.pinned_pages);
|
||||
while (node) {
|
||||
|
||||
Reference in New Issue
Block a user