From 9d79c30f82f87357cd15798d5e80def8a0407502 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Tue, 13 Dec 2022 09:13:39 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Keep the pKVM private range under 1GiB The hypervisor memory pool is sized to allow mapping up to 1GiB of data in the 'private' range of the hypervisor. However, this is currently not enforced in any way, which might become a problem as private range mappings are used more and more (e.g. from pKVM modules). Enforce the 1GiB limit at allocation time, and while at it, rename __io_map_base to __private_range_base for consistency. Bug: 244543039 Change-Id: I32c9145ba331309b49428ff461a41c94ea0c1512 Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pkvm.h | 5 +++-- arch/arm64/kvm/hyp/nvhe/mm.c | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index 6cd974fc584f..2c7652bfe362 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -320,14 +320,15 @@ static inline unsigned long __hyp_pgtable_moveable_regs_pages(void) return res; } +#define __PKVM_PRIVATE_SZ SZ_1G + static inline unsigned long hyp_s1_pgtable_pages(void) { unsigned long res; res = __hyp_pgtable_moveable_regs_pages(); - /* Allow 1 GiB for private mappings */ - res += __hyp_pgtable_max_pages(SZ_1G >> PAGE_SHIFT); + res += __hyp_pgtable_max_pages(__PKVM_PRIVATE_SZ >> PAGE_SHIFT); return res; } diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 6ed9bf0819bc..58ddd7d1711e 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -25,7 +25,8 @@ hyp_spinlock_t pkvm_pgd_lock; struct memblock_region hyp_memory[HYP_MEMBLOCK_REGIONS]; unsigned int hyp_memblock_nr; -static u64 __io_map_base; +static u64 __private_range_base; +static u64 __private_range_cur; struct hyp_fixmap_slot { u64 addr; @@ -50,29 +51,29 @@ static int __pkvm_create_mappings(unsigned long start, unsigned long size, * @size: The size of the VA range to reserve. * @haddr: The hypervisor virtual start address of the allocation. * - * The private virtual address (VA) range is allocated above __io_map_base + * The private virtual address (VA) range is allocated above __private_range_base * and aligned based on the order of @size. * * Return: 0 on success or negative error code on failure. */ int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr) { - unsigned long base, addr; + unsigned long cur, addr; int ret = 0; hyp_spin_lock(&pkvm_pgd_lock); /* Align the allocation based on the order of its size */ - addr = ALIGN(__io_map_base, PAGE_SIZE << get_order(size)); + addr = ALIGN(__private_range_cur, PAGE_SIZE << get_order(size)); /* The allocated size is always a multiple of PAGE_SIZE */ - base = addr + PAGE_ALIGN(size); + cur = addr + PAGE_ALIGN(size); - /* Are we overflowing on the vmemmap ? */ - if (!addr || base > __hyp_vmemmap) + /* Has the private range grown too large ? */ + if (!addr || cur > __hyp_vmemmap || (cur - __private_range_base) > __PKVM_PRIVATE_SZ) { ret = -ENOMEM; - else { - __io_map_base = base; + } else { + __private_range_cur = cur; *haddr = addr; } @@ -386,9 +387,10 @@ int hyp_create_idmap(u32 hyp_va_bits) * with the idmap to place the IOs and the vmemmap. IOs use the lower * half of the quarter and the vmemmap the upper half. */ - __io_map_base = start & BIT(hyp_va_bits - 2); - __io_map_base ^= BIT(hyp_va_bits - 2); - __hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3); + __private_range_base = start & BIT(hyp_va_bits - 2); + __private_range_base ^= BIT(hyp_va_bits - 2); + __private_range_cur = __private_range_base; + __hyp_vmemmap = __private_range_base | BIT(hyp_va_bits - 3); return __pkvm_create_mappings(start, end - start, start, PAGE_HYP_EXEC); }