From bc31899f7c6041235ee17e0147e1019157cf84c9 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Mon, 23 Jun 2025 13:39:53 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Always unmap the pvmfw region at stage-2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The donation of the pvmfw region to pKVM is currently done transparently as part of fix_host_ownership(). However, this function only runs over PA ranges covered by the memblock list, although there is no guarantee for the pvmfw region to be advertised in a memory node in DT. In this case, the pKVM init will appear to succeed while silently keeping valid host stage-2 mappings to the pvmfw region. Fix this by forcefully registering the pvmfw region in the pKVM memblock list. Bug: 357781595 Bug: 424382332 Reported-by: Bartłomiej Grzesik Suggested-by: Will Deacon Change-Id: I8f5498df25debb432b7dffd1e40a8910bcec7b49 Signed-off-by: Quentin Perret --- arch/arm64/kvm/pkvm.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index ae260ef9368b..6953ce7ba429 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -85,6 +85,7 @@ static void __init sort_memblock_regions(void) static int __init register_memblock_regions(void) { struct memblock_region *reg; + bool pvmfw_in_mem = false; for_each_mem_region(reg) { if (*hyp_memblock_nr_ptr >= HYP_MEMBLOCK_REGIONS) @@ -92,6 +93,26 @@ static int __init register_memblock_regions(void) hyp_memory[*hyp_memblock_nr_ptr] = *reg; (*hyp_memblock_nr_ptr)++; + + if (!pvmfw_size || pvmfw_in_mem || + !memblock_addrs_overlap(reg->base, reg->size, pvmfw_base, pvmfw_size)) + continue; + /* If the pvmfw region overlaps a memblock, it must be a subset */ + if (pvmfw_base < reg->base || (pvmfw_base + pvmfw_size) > (reg->base + reg->size)) + return -EINVAL; + pvmfw_in_mem = true; + } + + if (pvmfw_size && !pvmfw_in_mem) { + if (*hyp_memblock_nr_ptr >= HYP_MEMBLOCK_REGIONS) + return -ENOMEM; + + hyp_memory[*hyp_memblock_nr_ptr] = (struct memblock_region) { + .base = pvmfw_base, + .size = pvmfw_size, + .flags = MEMBLOCK_NOMAP, + }; + (*hyp_memblock_nr_ptr)++; } sort_memblock_regions();