162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020 Google LLC 462306a36Sopenharmony_ci * Author: Quentin Perret <qperret@google.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kvm_host.h> 862306a36Sopenharmony_ci#include <asm/kvm_hyp.h> 962306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 1062306a36Sopenharmony_ci#include <asm/kvm_pgtable.h> 1162306a36Sopenharmony_ci#include <asm/kvm_pkvm.h> 1262306a36Sopenharmony_ci#include <asm/spectre.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <nvhe/early_alloc.h> 1562306a36Sopenharmony_ci#include <nvhe/gfp.h> 1662306a36Sopenharmony_ci#include <nvhe/memory.h> 1762306a36Sopenharmony_ci#include <nvhe/mem_protect.h> 1862306a36Sopenharmony_ci#include <nvhe/mm.h> 1962306a36Sopenharmony_ci#include <nvhe/spinlock.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct kvm_pgtable pkvm_pgtable; 2262306a36Sopenharmony_cihyp_spinlock_t pkvm_pgd_lock; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct memblock_region hyp_memory[HYP_MEMBLOCK_REGIONS]; 2562306a36Sopenharmony_ciunsigned int hyp_memblock_nr; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic u64 __io_map_base; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct hyp_fixmap_slot { 3062306a36Sopenharmony_ci u64 addr; 3162306a36Sopenharmony_ci kvm_pte_t *ptep; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct hyp_fixmap_slot, fixmap_slots); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int __pkvm_create_mappings(unsigned long start, unsigned long size, 3662306a36Sopenharmony_ci unsigned long phys, enum kvm_pgtable_prot prot) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int err; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci hyp_spin_lock(&pkvm_pgd_lock); 4162306a36Sopenharmony_ci err = kvm_pgtable_hyp_map(&pkvm_pgtable, start, size, phys, prot); 4262306a36Sopenharmony_ci hyp_spin_unlock(&pkvm_pgd_lock); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return err; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int __pkvm_alloc_private_va_range(unsigned long start, size_t size) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci unsigned long cur; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci hyp_assert_lock_held(&pkvm_pgd_lock); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (!start || start < __io_map_base) 5462306a36Sopenharmony_ci return -EINVAL; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* The allocated size is always a multiple of PAGE_SIZE */ 5762306a36Sopenharmony_ci cur = start + PAGE_ALIGN(size); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Are we overflowing on the vmemmap ? */ 6062306a36Sopenharmony_ci if (cur > __hyp_vmemmap) 6162306a36Sopenharmony_ci return -ENOMEM; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci __io_map_base = cur; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/** 6962306a36Sopenharmony_ci * pkvm_alloc_private_va_range - Allocates a private VA range. 7062306a36Sopenharmony_ci * @size: The size of the VA range to reserve. 7162306a36Sopenharmony_ci * @haddr: The hypervisor virtual start address of the allocation. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * The private virtual address (VA) range is allocated above __io_map_base 7462306a36Sopenharmony_ci * and aligned based on the order of @size. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Return: 0 on success or negative error code on failure. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ciint pkvm_alloc_private_va_range(size_t size, unsigned long *haddr) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned long addr; 8162306a36Sopenharmony_ci int ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci hyp_spin_lock(&pkvm_pgd_lock); 8462306a36Sopenharmony_ci addr = __io_map_base; 8562306a36Sopenharmony_ci ret = __pkvm_alloc_private_va_range(addr, size); 8662306a36Sopenharmony_ci hyp_spin_unlock(&pkvm_pgd_lock); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci *haddr = addr; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return ret; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciint __pkvm_create_private_mapping(phys_addr_t phys, size_t size, 9462306a36Sopenharmony_ci enum kvm_pgtable_prot prot, 9562306a36Sopenharmony_ci unsigned long *haddr) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci unsigned long addr; 9862306a36Sopenharmony_ci int err; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci size = PAGE_ALIGN(size + offset_in_page(phys)); 10162306a36Sopenharmony_ci err = pkvm_alloc_private_va_range(size, &addr); 10262306a36Sopenharmony_ci if (err) 10362306a36Sopenharmony_ci return err; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = __pkvm_create_mappings(addr, size, phys, prot); 10662306a36Sopenharmony_ci if (err) 10762306a36Sopenharmony_ci return err; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci *haddr = addr + offset_in_page(phys); 11062306a36Sopenharmony_ci return err; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint pkvm_create_mappings_locked(void *from, void *to, enum kvm_pgtable_prot prot) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci unsigned long start = (unsigned long)from; 11662306a36Sopenharmony_ci unsigned long end = (unsigned long)to; 11762306a36Sopenharmony_ci unsigned long virt_addr; 11862306a36Sopenharmony_ci phys_addr_t phys; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci hyp_assert_lock_held(&pkvm_pgd_lock); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci start = start & PAGE_MASK; 12362306a36Sopenharmony_ci end = PAGE_ALIGN(end); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (virt_addr = start; virt_addr < end; virt_addr += PAGE_SIZE) { 12662306a36Sopenharmony_ci int err; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci phys = hyp_virt_to_phys((void *)virt_addr); 12962306a36Sopenharmony_ci err = kvm_pgtable_hyp_map(&pkvm_pgtable, virt_addr, PAGE_SIZE, 13062306a36Sopenharmony_ci phys, prot); 13162306a36Sopenharmony_ci if (err) 13262306a36Sopenharmony_ci return err; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint pkvm_create_mappings(void *from, void *to, enum kvm_pgtable_prot prot) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci int ret; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hyp_spin_lock(&pkvm_pgd_lock); 14362306a36Sopenharmony_ci ret = pkvm_create_mappings_locked(from, to, prot); 14462306a36Sopenharmony_ci hyp_spin_unlock(&pkvm_pgd_lock); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciint hyp_back_vmemmap(phys_addr_t back) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci unsigned long i, start, size, end = 0; 15262306a36Sopenharmony_ci int ret; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (i = 0; i < hyp_memblock_nr; i++) { 15562306a36Sopenharmony_ci start = hyp_memory[i].base; 15662306a36Sopenharmony_ci start = ALIGN_DOWN((u64)hyp_phys_to_page(start), PAGE_SIZE); 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * The begining of the hyp_vmemmap region for the current 15962306a36Sopenharmony_ci * memblock may already be backed by the page backing the end 16062306a36Sopenharmony_ci * the previous region, so avoid mapping it twice. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci start = max(start, end); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci end = hyp_memory[i].base + hyp_memory[i].size; 16562306a36Sopenharmony_ci end = PAGE_ALIGN((u64)hyp_phys_to_page(end)); 16662306a36Sopenharmony_ci if (start >= end) 16762306a36Sopenharmony_ci continue; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci size = end - start; 17062306a36Sopenharmony_ci ret = __pkvm_create_mappings(start, size, back, PAGE_HYP); 17162306a36Sopenharmony_ci if (ret) 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci memset(hyp_phys_to_virt(back), 0, size); 17562306a36Sopenharmony_ci back += size; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void *__hyp_bp_vect_base; 18262306a36Sopenharmony_ciint pkvm_cpu_set_vector(enum arm64_hyp_spectre_vector slot) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci void *vector; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci switch (slot) { 18762306a36Sopenharmony_ci case HYP_VECTOR_DIRECT: { 18862306a36Sopenharmony_ci vector = __kvm_hyp_vector; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci case HYP_VECTOR_SPECTRE_DIRECT: { 19262306a36Sopenharmony_ci vector = __bp_harden_hyp_vecs; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci case HYP_VECTOR_INDIRECT: 19662306a36Sopenharmony_ci case HYP_VECTOR_SPECTRE_INDIRECT: { 19762306a36Sopenharmony_ci vector = (void *)__hyp_bp_vect_base; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci default: 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci vector = __kvm_vector_slot2addr(vector, slot); 20562306a36Sopenharmony_ci *this_cpu_ptr(&kvm_hyp_vector) = (unsigned long)vector; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciint hyp_map_vectors(void) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci phys_addr_t phys; 21362306a36Sopenharmony_ci unsigned long bp_base; 21462306a36Sopenharmony_ci int ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (!kvm_system_needs_idmapped_vectors()) { 21762306a36Sopenharmony_ci __hyp_bp_vect_base = __bp_harden_hyp_vecs; 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci phys = __hyp_pa(__bp_harden_hyp_vecs); 22262306a36Sopenharmony_ci ret = __pkvm_create_private_mapping(phys, __BP_HARDEN_HYP_VECS_SZ, 22362306a36Sopenharmony_ci PAGE_HYP_EXEC, &bp_base); 22462306a36Sopenharmony_ci if (ret) 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci __hyp_bp_vect_base = (void *)bp_base; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_civoid *hyp_fixmap_map(phys_addr_t phys) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct hyp_fixmap_slot *slot = this_cpu_ptr(&fixmap_slots); 23562306a36Sopenharmony_ci kvm_pte_t pte, *ptep = slot->ptep; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pte = *ptep; 23862306a36Sopenharmony_ci pte &= ~kvm_phys_to_pte(KVM_PHYS_INVALID); 23962306a36Sopenharmony_ci pte |= kvm_phys_to_pte(phys) | KVM_PTE_VALID; 24062306a36Sopenharmony_ci WRITE_ONCE(*ptep, pte); 24162306a36Sopenharmony_ci dsb(ishst); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return (void *)slot->addr; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void fixmap_clear_slot(struct hyp_fixmap_slot *slot) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci kvm_pte_t *ptep = slot->ptep; 24962306a36Sopenharmony_ci u64 addr = slot->addr; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci WRITE_ONCE(*ptep, *ptep & ~KVM_PTE_VALID); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * Irritatingly, the architecture requires that we use inner-shareable 25562306a36Sopenharmony_ci * broadcast TLB invalidation here in case another CPU speculates 25662306a36Sopenharmony_ci * through our fixmap and decides to create an "amalagamation of the 25762306a36Sopenharmony_ci * values held in the TLB" due to the apparent lack of a 25862306a36Sopenharmony_ci * break-before-make sequence. 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci dsb(ishst); 26362306a36Sopenharmony_ci __tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1)); 26462306a36Sopenharmony_ci dsb(ish); 26562306a36Sopenharmony_ci isb(); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_civoid hyp_fixmap_unmap(void) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci fixmap_clear_slot(this_cpu_ptr(&fixmap_slots)); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx, 27462306a36Sopenharmony_ci enum kvm_pgtable_walk_flags visit) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci slot->addr = ctx->addr; 28262306a36Sopenharmony_ci slot->ptep = ctx->ptep; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * Clear the PTE, but keep the page-table page refcount elevated to 28662306a36Sopenharmony_ci * prevent it from ever being freed. This lets us manipulate the PTEs 28762306a36Sopenharmony_ci * by hand safely without ever needing to allocate memory. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci fixmap_clear_slot(slot); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int create_fixmap_slot(u64 addr, u64 cpu) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct kvm_pgtable_walker walker = { 29762306a36Sopenharmony_ci .cb = __create_fixmap_slot_cb, 29862306a36Sopenharmony_ci .flags = KVM_PGTABLE_WALK_LEAF, 29962306a36Sopenharmony_ci .arg = (void *)cpu, 30062306a36Sopenharmony_ci }; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return kvm_pgtable_walk(&pkvm_pgtable, addr, PAGE_SIZE, &walker); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciint hyp_create_pcpu_fixmap(void) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci unsigned long addr, i; 30862306a36Sopenharmony_ci int ret; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (i = 0; i < hyp_nr_cpus; i++) { 31162306a36Sopenharmony_ci ret = pkvm_alloc_private_va_range(PAGE_SIZE, &addr); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ret = kvm_pgtable_hyp_map(&pkvm_pgtable, addr, PAGE_SIZE, 31662306a36Sopenharmony_ci __hyp_pa(__hyp_bss_start), PAGE_HYP); 31762306a36Sopenharmony_ci if (ret) 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ret = create_fixmap_slot(addr, i); 32162306a36Sopenharmony_ci if (ret) 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ciint hyp_create_idmap(u32 hyp_va_bits) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci unsigned long start, end; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci start = hyp_virt_to_phys((void *)__hyp_idmap_text_start); 33362306a36Sopenharmony_ci start = ALIGN_DOWN(start, PAGE_SIZE); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci end = hyp_virt_to_phys((void *)__hyp_idmap_text_end); 33662306a36Sopenharmony_ci end = ALIGN(end, PAGE_SIZE); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * One half of the VA space is reserved to linearly map portions of 34062306a36Sopenharmony_ci * memory -- see va_layout.c for more details. The other half of the VA 34162306a36Sopenharmony_ci * space contains the trampoline page, and needs some care. Split that 34262306a36Sopenharmony_ci * second half in two and find the quarter of VA space not conflicting 34362306a36Sopenharmony_ci * with the idmap to place the IOs and the vmemmap. IOs use the lower 34462306a36Sopenharmony_ci * half of the quarter and the vmemmap the upper half. 34562306a36Sopenharmony_ci */ 34662306a36Sopenharmony_ci __io_map_base = start & BIT(hyp_va_bits - 2); 34762306a36Sopenharmony_ci __io_map_base ^= BIT(hyp_va_bits - 2); 34862306a36Sopenharmony_ci __hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return __pkvm_create_mappings(start, end - start, start, PAGE_HYP_EXEC); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciint pkvm_create_stack(phys_addr_t phys, unsigned long *haddr) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci unsigned long addr, prev_base; 35662306a36Sopenharmony_ci size_t size; 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci hyp_spin_lock(&pkvm_pgd_lock); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci prev_base = __io_map_base; 36262306a36Sopenharmony_ci /* 36362306a36Sopenharmony_ci * Efficient stack verification using the PAGE_SHIFT bit implies 36462306a36Sopenharmony_ci * an alignment of our allocation on the order of the size. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci size = PAGE_SIZE * 2; 36762306a36Sopenharmony_ci addr = ALIGN(__io_map_base, size); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = __pkvm_alloc_private_va_range(addr, size); 37062306a36Sopenharmony_ci if (!ret) { 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * Since the stack grows downwards, map the stack to the page 37362306a36Sopenharmony_ci * at the higher address and leave the lower guard page 37462306a36Sopenharmony_ci * unbacked. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Any valid stack address now has the PAGE_SHIFT bit as 1 37762306a36Sopenharmony_ci * and addresses corresponding to the guard page have the 37862306a36Sopenharmony_ci * PAGE_SHIFT bit as 0 - this is used for overflow detection. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci ret = kvm_pgtable_hyp_map(&pkvm_pgtable, addr + PAGE_SIZE, 38162306a36Sopenharmony_ci PAGE_SIZE, phys, PAGE_HYP); 38262306a36Sopenharmony_ci if (ret) 38362306a36Sopenharmony_ci __io_map_base = prev_base; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci hyp_spin_unlock(&pkvm_pgd_lock); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci *haddr = addr + size; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void *admit_host_page(void *arg) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct kvm_hyp_memcache *host_mc = arg; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!host_mc->nr_pages) 39762306a36Sopenharmony_ci return NULL; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* 40062306a36Sopenharmony_ci * The host still owns the pages in its memcache, so we need to go 40162306a36Sopenharmony_ci * through a full host-to-hyp donation cycle to change it. Fortunately, 40262306a36Sopenharmony_ci * __pkvm_host_donate_hyp() takes care of races for us, so if it 40362306a36Sopenharmony_ci * succeeds we're good to go. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci if (__pkvm_host_donate_hyp(hyp_phys_to_pfn(host_mc->head), 1)) 40662306a36Sopenharmony_ci return NULL; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return pop_hyp_memcache(host_mc, hyp_phys_to_virt); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/* Refill our local memcache by poping pages from the one provided by the host. */ 41262306a36Sopenharmony_ciint refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, 41362306a36Sopenharmony_ci struct kvm_hyp_memcache *host_mc) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct kvm_hyp_memcache tmp = *host_mc; 41662306a36Sopenharmony_ci int ret; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = __topup_hyp_memcache(mc, min_pages, admit_host_page, 41962306a36Sopenharmony_ci hyp_virt_to_phys, &tmp); 42062306a36Sopenharmony_ci *host_mc = tmp; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return ret; 42362306a36Sopenharmony_ci} 424