git: 6f0b2a235a13 - main - powerpc/pmap: Add pmap_sync_icache() for radix pmap

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Sun, 12 Mar 2023 15:52:01 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=6f0b2a235a133a381634ba9a7f5f477c64db9873

commit 6f0b2a235a133a381634ba9a7f5f477c64db9873
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2023-03-12 15:46:57 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2023-03-12 15:51:42 +0000

    powerpc/pmap: Add pmap_sync_icache() for radix pmap
    
    DTrace pid provider writes to user space to set breakpoints.  Failing to
    sync the icache can lead to SIGTRAP.  Radix pmap is the only one missing
    a pmap_sync_icache() method, so the pid provider would only potentially
    crash a process on a POWER9 or later system.
---
 sys/powerpc/aim/mmu_radix.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c
index 6e2203ccca45..1e7661ba8068 100644
--- a/sys/powerpc/aim/mmu_radix.c
+++ b/sys/powerpc/aim/mmu_radix.c
@@ -464,6 +464,7 @@ void mmu_radix_remove(pmap_t, vm_offset_t, vm_offset_t);
 void mmu_radix_remove_all(vm_page_t);
 void mmu_radix_remove_pages(pmap_t);
 void mmu_radix_remove_write(vm_page_t);
+void mmu_radix_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz);
 void mmu_radix_unwire(pmap_t, vm_offset_t, vm_offset_t);
 void mmu_radix_zero_page(vm_page_t);
 void mmu_radix_zero_page_area(vm_page_t, int, int);
@@ -542,6 +543,7 @@ static struct pmap_funcs mmu_radix_methods = {
 	.remove = mmu_radix_remove,
 	.remove_all = mmu_radix_remove_all,
 	.remove_write = mmu_radix_remove_write,
+	.sync_icache = mmu_radix_sync_icache,
 	.unwire = mmu_radix_unwire,
 	.zero_page = mmu_radix_zero_page,
 	.zero_page_area = mmu_radix_zero_page_area,
@@ -5921,6 +5923,25 @@ mmu_radix_unmapdev(void *p, vm_size_t size)
 	}
 }
 
+void
+mmu_radix_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz)
+{
+	vm_paddr_t pa = 0;
+	int sync_sz;
+
+	while (sz > 0) {
+		pa = pmap_extract(pm, va);
+		sync_sz = PAGE_SIZE - (va & PAGE_MASK);
+		sync_sz = min(sync_sz, sz);
+		if (pa != 0) {
+			pa += (va & PAGE_MASK);
+			__syncicache((void *)PHYS_TO_DMAP(pa), sync_sz);
+		}
+		va += sync_sz;
+		sz -= sync_sz;
+	}
+}
+
 static __inline void
 pmap_pte_attr(pt_entry_t *pte, uint64_t cache_bits, uint64_t mask)
 {