Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-9]: src Pull up following revision(s) (requested by riastradh in ...
details: https://anonhg.NetBSD.org/src/rev/0d540c963a7e
branches: netbsd-9
changeset: 744785:0d540c963a7e
user: martin <martin%NetBSD.org@localhost>
date: Wed Feb 12 19:55:56 2020 +0000
description:
Pull up following revision(s) (requested by riastradh in ticket #701):
external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c: revision 1.2
external/cddl/osnet/dist/lib/libdtrace/common/dt_open.c: revision 1.17
external/cddl/osnet/dist/lib/libdtrace/common/dt_module.c: revision 1.18
sys/modules/cyclic/Makefile: revision 1.5
external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c: revision 1.2
external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c: revision 1.3
sys/arch/aarch64/aarch64/vectors.S: revision 1.10
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c: revision 1.2
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c: revision 1.3
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c: revision 1.4
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c: revision 1.5
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c: revision 1.6
sys/arch/aarch64/include/cpu.h: revision 1.20
external/cddl/osnet/dist/lib/libdtrace/common/dt_impl.h: revision 1.9
Create a buffer space of 512 bytes before the trapframe.
dtrace fbt needs enough space to emulate an
stp x29, x30, [sp,#-FRAMESIZE]!
instruction in a function prologue. In the aarch64 instruction
encoding, FRAMESIZE can be as large as 512 bytes, so reserve this
much space when KDTRACE_HOOKS is enabled.
Use db_write_bytes to overwrite kernel text.
Tidy up a bit. No functional change intended.
aarch64 fbt_invop doesn't actually use the argument, but it would
make more sense for it to be the return value and/or first argument
register. Certainly it's not `eax'!
Tidy up a bit: don't set things we won't use; assert nonzeroness.
Use /dev/ksyms, not /netbsd, for the running kernel's symbols.
Teach dtrace about el1_trap_exit frames on aarch64.
Implement dtrace_getarg and dtrace_getreg while here.
Count the number of artificial frames in aarch64 fbt probe correctly.
Change the address ranges that aarch64 considers toxic for dtrace.
`Toxic' means dtrace forbids D scripts from even attempting to read
or write at them.
Previously we considered [0, VM_MIN_KERNEL_ADDRESS) toxic, but
VM_MIN_KERNEL_ADDRESS is only the minimum address of the kernel map;
the direct-mapped region lies below it, and with PMAP_MAP_POOLPAGE we
allocate virtual pages for pool backing directly from physical pages
through the direct-mapped region. Also, this did not consider I/O
mappings to be toxic, which they probably should be.
Instead, treat:
[0, AARCH64_KSEG_START)
and
[VM_KERNEL_IO_ADDRESS, 0xfff...ff)
as toxic. (The upper bound for 0xfff...ff ought to be inclusive, not
exclusive, but I think we'll need another mechanism for expressing
that to dtrace!)
Switch from db_write_bytes to using direct-mapping.
This way there's no dependency on ddb.
Define the MULTIPROCESSOR cpu_number() for modules too.
Modules should work whether the main kernel is multiprocessor or not.
In particular, dtrace should not think cpu_number() is 0 while
cpu_index(curcpu()) and curcpu()->ci_index are nonzero, leading to
rather spectacularly bogus results...
cyclic.kmod needs -Wno-sign-compare for aarch64 CPU_INFO_FOREACH.
Provisional workaround; feel free to fix.
diffstat:
external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c | 170 ++++++++-----
external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c | 11 +-
external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c | 43 ++-
external/cddl/osnet/dist/lib/libdtrace/common/dt_impl.h | 2 -
external/cddl/osnet/dist/lib/libdtrace/common/dt_module.c | 5 +-
external/cddl/osnet/dist/lib/libdtrace/common/dt_open.c | 20 +-
sys/arch/aarch64/aarch64/vectors.S | 18 +-
sys/arch/aarch64/include/cpu.h | 4 +-
sys/modules/cyclic/Makefile | 2 +-
9 files changed, 166 insertions(+), 109 deletions(-)
diffs (truncated from 524 to 300 lines):
diff -r 587cea43e0c9 -r 0d540c963a7e external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c
--- a/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Wed Feb 12 19:44:27 2020 +0000
+++ b/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Wed Feb 12 19:55:56 2020 +0000
@@ -89,52 +89,60 @@
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
uint32_t *intrpc)
{
- struct unwind_state state;
- int scp_offset;
- register_t sp, fp;
- int depth;
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ int i = 0;
- depth = 0;
-
- if (intrpc != 0) {
- pcstack[depth++] = (pc_t) intrpc;
+ if (intrpc) {
+ if (i < pcstack_limit)
+ pcstack[i++] = (pc_t)intrpc;
}
- aframes++;
-
- __asm __volatile("mov %0, sp" : "=&r" (sp));
-
- state.fp = (uint64_t)__builtin_frame_address(0);
- state.sp = sp;
- state.pc = (uint64_t)dtrace_getpcstack;
-
- while (depth < pcstack_limit) {
- if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
- break;
+ /*
+ * fp[0] = x29 (saved frame pointer)
+ * fp[1] = x30 (saved link register == return address)
+ */
+ fp = __builtin_frame_address(0);
+ while (i < pcstack_limit && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ /* Skip the specified number of artificial frames. */
+ if (aframes > 0)
+ aframes--;
+ else
+ pcstack[i++] = fp[1];
- fp = state.fp;
- state.sp = fp + 0x10;
- /* FP to previous frame (X29) */
- state.fp = *(register_t *)(fp);
- /* LR (X30) */
- state.pc = *(register_t *)(fp + 8) - 4;
-
- /*
- * NB: Unlike some other architectures, we don't need to
- * explicitly insert cpu_dtrace_caller as it appears in the
- * normal kernel stack trace rather than a special trap frame.
- */
- if (aframes > 0) {
- aframes--;
+ /* Check whether this frame is handling a trap. */
+ if (fp[1] == (register_t)el1_trap_exit) {
+ /*
+ * Trap from kernel. The trapframe is the
+ * saved frame pointer of the call to the trap
+ * handler whose return address is
+ * el1_trap_exit. The frame pointer of the
+ * interrupted code is in x29 stashed in the
+ * trapframe, alongside its pc.
+ */
+ const struct trapframe *tf = (const void *)fp[0];
+ /* x29 = frame pointer */
+ fp = (const void *)tf->tf_regs.r_reg[29];
+ if (INKERNEL(tf->tf_pc)) {
+ if (i >= pcstack_limit)
+ break;
+ if (aframes > 0)
+ aframes--;
+ else
+ pcstack[i++] = tf->tf_pc;
+ }
} else {
- pcstack[depth++] = state.pc;
+ /*
+ * Not a trap. Keep going with fp[0] as the
+ * parent frame pointer.
+ */
+ fp = (const void *)fp[0];
}
-
}
- for (; depth < pcstack_limit; depth++) {
- pcstack[depth] = 0;
- }
+ /* Zero the rest of the return address stack. (Paranoia?) */
+ while (i < pcstack_limit)
+ pcstack[i++] = 0;
}
static int
@@ -282,48 +290,78 @@
uint64_t
dtrace_getarg(int arg, int aframes)
{
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ const struct trapframe *tf = NULL;
+ int i = 0;
- printf("IMPLEMENT ME: %s\n", __func__);
+ /*
+ * The first arguments are passed in x0,...,x7. The rest are
+ * on the stack, too much trouble to figure out.
+ *
+ * XXX Shouldn't we ask ctf or dwarf or something to figure
+ * this stuff out for us?
+ */
+ KASSERT(arg >= 0);
+ if (arg >= 8)
+ return 0;
- return (0);
+ fp = __builtin_frame_address(0);
+ while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ if (fp[1] == (register_t)el1_trap_exit) {
+ tf = (const void *)fp[0];
+ break;
+ } else {
+ fp = (const void *)fp[0];
+ }
+ }
+
+ /* If we didn't find a trap frame, give up. */
+ if (tf == NULL)
+ return 0;
+
+ /* Arg0, arg1, ..., arg7 are in registers x0, x1, ..., x7. */
+ return tf->tf_regs.r_reg[arg];
}
int
dtrace_getstackdepth(int aframes)
{
- struct unwind_state state;
- int scp_offset;
- register_t sp;
- int depth;
- int done;
-
- depth = 1;
- done = 0;
-
- __asm __volatile("mov %0, sp" : "=&r" (sp));
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ int i = 0;
- state.fp = (uint64_t)__builtin_frame_address(0);
- state.sp = sp;
- state.pc = (uint64_t)dtrace_getstackdepth;
+ fp = __builtin_frame_address(0);
+ while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ if (fp[1] == (register_t)el1_trap_exit) {
+ const struct trapframe *tf = (const void *)fp[0];
+ fp = (const void *)tf->tf_regs.r_reg[29];
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ } else {
+ fp = (const void *)fp[0];
+ }
+ }
- do {
- done = unwind_frame(&state);
- if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
- break;
- depth++;
- } while (!done);
-
- if (depth < aframes)
- return (0);
- else
- return (depth - aframes);
+ return i;
}
ulong_t
-dtrace_getreg(struct trapframe *rp, uint_t reg)
+dtrace_getreg(struct trapframe *tf, uint_t reg)
{
- printf("IMPLEMENT ME: %s\n", __func__);
+ if (reg < 32)
+ return tf->tf_regs.r_reg[reg];
return (0);
}
diff -r 587cea43e0c9 -r 0d540c963a7e external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c
--- a/external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c Wed Feb 12 19:44:27 2020 +0000
+++ b/external/cddl/osnet/dev/dtrace/aarch64/dtrace_subr.c Wed Feb 12 19:55:56 2020 +0000
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dtrace_subr.c,v 1.1.2.2 2019/12/09 15:19:30 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dtrace_subr.c,v 1.1.2.3 2020/02/12 19:55:56 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -69,13 +69,13 @@
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
-dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
+dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t r0)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
- if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
+ if ((rval = hdlr->dtih_func(addr, frame, r0)) != 0)
return (rval);
return (0);
@@ -128,7 +128,8 @@
dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
{
- (*func)(0, (uintptr_t)VM_MIN_KERNEL_ADDRESS);
+ (*func)(0, (uintptr_t)AARCH64_KSEG_START);
+ (*func)((uintptr_t)VM_KERNEL_IO_ADDRESS, ~(uintptr_t)0);
}
static void
@@ -263,7 +264,7 @@
int tmp;
int i;
- invop = dtrace_invop(frame->tf_pc, frame, frame->tf_pc);
+ invop = dtrace_invop(frame->tf_pc, frame, frame->tf_regs.r_reg[0]);
tmp = (invop & LDP_STP_MASK);
if (tmp == STP_64 || tmp == LDP_64) {
diff -r 587cea43e0c9 -r 0d540c963a7e external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c
--- a/external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c Wed Feb 12 19:44:27 2020 +0000
+++ b/external/cddl/osnet/dev/fbt/aarch64/fbt_isa.c Wed Feb 12 19:55:56 2020 +0000
@@ -36,6 +36,11 @@
#include <sys/cpu.h>
#include <sys/module.h>
#include <sys/kmem.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/mm.h>
+
#include <machine/cpufunc.h>
#include <sys/dtrace.h>
@@ -49,8 +54,19 @@
#define FBT_ENTRY "entry"
#define FBT_RETURN "return"
+/*
+ * How many artificial frames appear between dtrace_probe and the
+ * interrupted function call?
+ *
+ * fbt_invop
+ * dtrace_invop
+ * dtrace_invop_start
+ * el1_trap_exit
+ */
+#define FBT_AFRAMES 4
+
int
-fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
+fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t r0)
{
solaris_cpu_t *cpu;
fbt_probe_t *fbt;
@@ -67,6 +83,7 @@
frame->tf_regs.r_reg[3], frame->tf_regs.r_reg[4]);
cpu->cpu_dtrace_caller = 0;
+ KASSERT(fbt->fbtp_savedval != 0);
return (fbt->fbtp_savedval);
}
}
Home |
Main Index |
Thread Index |
Old Index