]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Handle huge mappings for np-guest CMOs
authorVincent Donnefort <vdonnefort@google.com>
Wed, 21 May 2025 12:48:25 +0000 (13:48 +0100)
committerMarc Zyngier <maz@kernel.org>
Wed, 21 May 2025 13:33:51 +0000 (14:33 +0100)
clean_dcache_guest_page() and invalidate_icache_guest_page() accept a
size as an argument. But they also rely on fixmap, which can only map a
single PAGE_SIZE page.

With the upcoming stage-2 huge mappings for pKVM np-guests, those
callbacks will get size > PAGE_SIZE. Loop the CMOs on a PAGE_SIZE basis
until the whole range is done.

Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Link: https://lore.kernel.org/r/20250521124834.1070650-2-vdonnefort@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/hyp/nvhe/mem_protect.c

index 31173c6946951d404f5479e63c503c9507b7fb5b..be4f7c5612f8c27404c071597dedc90e7fd0ca95 100644 (file)
@@ -219,14 +219,32 @@ static void guest_s2_put_page(void *addr)
 
 static void clean_dcache_guest_page(void *va, size_t size)
 {
-       __clean_dcache_guest_page(hyp_fixmap_map(__hyp_pa(va)), size);
-       hyp_fixmap_unmap();
+       size += va - PTR_ALIGN_DOWN(va, PAGE_SIZE);
+       va = PTR_ALIGN_DOWN(va, PAGE_SIZE);
+       size = PAGE_ALIGN(size);
+
+       while (size) {
+               __clean_dcache_guest_page(hyp_fixmap_map(__hyp_pa(va)),
+                                         PAGE_SIZE);
+               hyp_fixmap_unmap();
+               va += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
 }
 
 static void invalidate_icache_guest_page(void *va, size_t size)
 {
-       __invalidate_icache_guest_page(hyp_fixmap_map(__hyp_pa(va)), size);
-       hyp_fixmap_unmap();
+       size += va - PTR_ALIGN_DOWN(va, PAGE_SIZE);
+       va = PTR_ALIGN_DOWN(va, PAGE_SIZE);
+       size = PAGE_ALIGN(size);
+
+       while (size) {
+               __invalidate_icache_guest_page(hyp_fixmap_map(__hyp_pa(va)),
+                                              PAGE_SIZE);
+               hyp_fixmap_unmap();
+               va += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
 }
 
 int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd)