162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020 - Google LLC 462306a36Sopenharmony_ci * Author: Quentin Perret <qperret@google.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#ifndef __ARM64_KVM_PKVM_H__ 762306a36Sopenharmony_ci#define __ARM64_KVM_PKVM_H__ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/arm_ffa.h> 1062306a36Sopenharmony_ci#include <linux/memblock.h> 1162306a36Sopenharmony_ci#include <linux/scatterlist.h> 1262306a36Sopenharmony_ci#include <asm/kvm_pgtable.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* Maximum number of VMs that can co-exist under pKVM. */ 1562306a36Sopenharmony_ci#define KVM_MAX_PVMS 255 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define HYP_MEMBLOCK_REGIONS 128 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciint pkvm_init_host_vm(struct kvm *kvm); 2062306a36Sopenharmony_ciint pkvm_create_hyp_vm(struct kvm *kvm); 2162306a36Sopenharmony_civoid pkvm_destroy_hyp_vm(struct kvm *kvm); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciextern struct memblock_region kvm_nvhe_sym(hyp_memory)[]; 2462306a36Sopenharmony_ciextern unsigned int kvm_nvhe_sym(hyp_memblock_nr); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic inline unsigned long 2762306a36Sopenharmony_cihyp_vmemmap_memblock_size(struct memblock_region *reg, size_t vmemmap_entry_size) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci unsigned long nr_pages = reg->size >> PAGE_SHIFT; 3062306a36Sopenharmony_ci unsigned long start, end; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci start = (reg->base >> PAGE_SHIFT) * vmemmap_entry_size; 3362306a36Sopenharmony_ci end = start + nr_pages * vmemmap_entry_size; 3462306a36Sopenharmony_ci start = ALIGN_DOWN(start, PAGE_SIZE); 3562306a36Sopenharmony_ci end = ALIGN(end, PAGE_SIZE); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return end - start; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline unsigned long hyp_vmemmap_pages(size_t vmemmap_entry_size) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci unsigned long res = 0, i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < kvm_nvhe_sym(hyp_memblock_nr); i++) { 4562306a36Sopenharmony_ci res += hyp_vmemmap_memblock_size(&kvm_nvhe_sym(hyp_memory)[i], 4662306a36Sopenharmony_ci vmemmap_entry_size); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return res >> PAGE_SHIFT; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline unsigned long hyp_vm_table_pages(void) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci return PAGE_ALIGN(KVM_MAX_PVMS * sizeof(void *)) >> PAGE_SHIFT; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci unsigned long total = 0, i; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Provision the worst case scenario */ 6262306a36Sopenharmony_ci for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) { 6362306a36Sopenharmony_ci nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE); 6462306a36Sopenharmony_ci total += nr_pages; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return total; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline unsigned long __hyp_pgtable_total_pages(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned long res = 0, i; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Cover all of memory with page-granularity */ 7562306a36Sopenharmony_ci for (i = 0; i < kvm_nvhe_sym(hyp_memblock_nr); i++) { 7662306a36Sopenharmony_ci struct memblock_region *reg = &kvm_nvhe_sym(hyp_memory)[i]; 7762306a36Sopenharmony_ci res += __hyp_pgtable_max_pages(reg->size >> PAGE_SHIFT); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return res; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic inline unsigned long hyp_s1_pgtable_pages(void) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned long res; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci res = __hyp_pgtable_total_pages(); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Allow 1 GiB for private mappings */ 9062306a36Sopenharmony_ci res += __hyp_pgtable_max_pages(SZ_1G >> PAGE_SHIFT); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return res; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline unsigned long host_s2_pgtable_pages(void) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci unsigned long res; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* 10062306a36Sopenharmony_ci * Include an extra 16 pages to safely upper-bound the worst case of 10162306a36Sopenharmony_ci * concatenated pgds. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci res = __hyp_pgtable_total_pages() + 16; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Allow 1 GiB for MMIO mappings */ 10662306a36Sopenharmony_ci res += __hyp_pgtable_max_pages(SZ_1G >> PAGE_SHIFT); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return res; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define KVM_FFA_MBOX_NR_PAGES 1 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline unsigned long hyp_ffa_proxy_pages(void) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci size_t desc_max; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* 11862306a36Sopenharmony_ci * The hypervisor FFA proxy needs enough memory to buffer a fragmented 11962306a36Sopenharmony_ci * descriptor returned from EL3 in response to a RETRIEVE_REQ call. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci desc_max = sizeof(struct ffa_mem_region) + 12262306a36Sopenharmony_ci sizeof(struct ffa_mem_region_attributes) + 12362306a36Sopenharmony_ci sizeof(struct ffa_composite_mem_region) + 12462306a36Sopenharmony_ci SG_MAX_SEGMENTS * sizeof(struct ffa_mem_region_addr_range); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Plus a page each for the hypervisor's RX and TX mailboxes. */ 12762306a36Sopenharmony_ci return (2 * KVM_FFA_MBOX_NR_PAGES) + DIV_ROUND_UP(desc_max, PAGE_SIZE); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#endif /* __ARM64_KVM_PKVM_H__ */ 131