git: 3d2533f5c29f - main - Allow ddb and dtrace use the DMAP region on arm64
Andrew Turner
andrew at FreeBSD.org
Fri Oct 1 10:27:58 UTC 2021
The branch main has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=3d2533f5c29fbf6e63c5e408ba13c2294a7612fd
commit 3d2533f5c29fbf6e63c5e408ba13c2294a7612fd
Author: Andrew Turner <andrew at FreeBSD.org>
AuthorDate: 2021-09-21 17:10:57 +0000
Commit: Andrew Turner <andrew at FreeBSD.org>
CommitDate: 2021-10-01 10:27:33 +0000
Allow ddb and dtrace use the DMAP region on arm64
When writing to memory on arm64 we may be trying to be accessing a
read-only page. In this case try to access via the DMAP region to
get a writable location.
While here simplify writing data in DDB and stop trashing the size as
it is passed into the cache handling functions.
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D32053
---
sys/arm64/arm64/db_interface.c | 33 +++++++++------------------------
sys/arm64/arm64/machdep.c | 36 ++++++++++++++++++++++++++++++++++++
sys/arm64/include/cpufunc.h | 1 +
sys/cddl/dev/fbt/aarch64/fbt_isa.c | 6 +++++-
4 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/sys/arm64/arm64/db_interface.c b/sys/arm64/arm64/db_interface.c
index d8ae79715a19..dc0fa8ac5e1e 100644
--- a/sys/arm64/arm64/db_interface.c
+++ b/sys/arm64/arm64/db_interface.c
@@ -153,39 +153,24 @@ db_write_bytes(vm_offset_t addr, size_t size, char *data)
jmp_buf jb;
void *prev_jb;
char *dst;
+ size_t i;
int ret;
- uint64_t tmp64;
- uint32_t tmp32;
- uint16_t tmp16;
prev_jb = kdb_jmpbuf(jb);
ret = setjmp(jb);
if (ret == 0) {
- if (size == 8 && (addr & 7) == 0) {
- dst = (char *)&tmp64;
- while (size-- > 0)
- *dst++ = *data++;
- *((uint64_t *)addr) = tmp64;
- } else if (size == 4 && (addr & 3) == 0) {
- dst = (char *)&tmp32;
- while (size-- > 0)
- *dst++ = *data++;
- *((uint32_t *)addr) = tmp32;
- } else if (size == 2 && (addr & 1) == 0) {
- dst = (char *)&tmp16;
- while (size-- > 0)
- *dst++ = *data++;
- *((uint32_t *)addr) = tmp16;
+ if (!arm64_get_writable_addr(addr, &addr)) {
+ ret = 1;
} else {
dst = (char *)addr;
- while (size-- > 0)
+ for (i = 0; i < size; i++)
*dst++ = *data++;
- }
- dsb(ish);
+ dsb(ish);
- /* Clean D-cache and invalidate I-cache */
- cpu_dcache_wb_range(addr, (vm_size_t)size);
- cpu_icache_sync_range(addr, (vm_size_t)size);
+ /* Clean D-cache and invalidate I-cache */
+ cpu_dcache_wb_range(addr, (vm_size_t)size);
+ cpu_icache_sync_range(addr, (vm_size_t)size);
+ }
}
(void)kdb_jmpbuf(prev_jb);
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 89c4f21134f8..30f07bce5551 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -942,6 +942,42 @@ init_proc0(vm_offset_t kstack)
serror_enable();
}
+/*
+ * Get an address to be used to write to kernel data that may be mapped
+ * read-only, e.g. to patch kernel code.
+ */
+bool
+arm64_get_writable_addr(vm_offset_t addr, vm_offset_t *out)
+{
+ vm_paddr_t pa;
+
+ /* Check if the page is writable */
+ if (PAR_SUCCESS(arm64_address_translate_s1e1w(addr))) {
+ *out = addr;
+ return (true);
+ }
+
+ /*
+ * Find the physical address of the given page.
+ */
+ if (!pmap_klookup(addr, &pa)) {
+ return (false);
+ }
+
+ /*
+ * If it is within the DMAP region and is writable use that.
+ */
+ if (PHYS_IN_DMAP(pa)) {
+ addr = PHYS_TO_DMAP(pa);
+ if (PAR_SUCCESS(arm64_address_translate_s1e1w(addr))) {
+ *out = addr;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
typedef struct {
uint32_t type;
uint64_t phys_start;
diff --git a/sys/arm64/include/cpufunc.h b/sys/arm64/include/cpufunc.h
index 94af62380de3..16133903841f 100644
--- a/sys/arm64/include/cpufunc.h
+++ b/sys/arm64/include/cpufunc.h
@@ -246,6 +246,7 @@ int arm64_icache_sync_range_checked(vm_offset_t, vm_size_t);
void arm64_dcache_wbinv_range(vm_offset_t, vm_size_t);
void arm64_dcache_inv_range(vm_offset_t, vm_size_t);
void arm64_dcache_wb_range(vm_offset_t, vm_size_t);
+bool arm64_get_writable_addr(vm_offset_t, vm_offset_t *);
#endif /* _KERNEL */
#endif /* _MACHINE_CPUFUNC_H_ */
diff --git a/sys/cddl/dev/fbt/aarch64/fbt_isa.c b/sys/cddl/dev/fbt/aarch64/fbt_isa.c
index f9b99febe8d1..4d22f1d584d3 100644
--- a/sys/cddl/dev/fbt/aarch64/fbt_isa.c
+++ b/sys/cddl/dev/fbt/aarch64/fbt_isa.c
@@ -74,8 +74,12 @@ fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
void
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
{
+ vm_offset_t addr;
- *fbt->fbtp_patchpoint = val;
+ if (!arm64_get_writable_addr((vm_offset_t)fbt->fbtp_patchpoint, &addr))
+ panic("%s: Unable to write new instruction", __func__);
+
+ *(fbt_patchval_t *)addr = val;
cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
}
More information about the dev-commits-src-all
mailing list