]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cddl/dev/dtrace/aarch64/dtrace_isa.c
dts: Update our copy for arm, arm64 and riscv dts to Linux 5.5
[FreeBSD/FreeBSD.git] / sys / cddl / dev / dtrace / aarch64 / dtrace_isa.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * $FreeBSD$
23  */
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/stack.h>
34 #include <sys/pcpu.h>
35
36 #include <machine/frame.h>
37 #include <machine/md_var.h>
38 #include <machine/reg.h>
39
40 #include <vm/vm.h>
41 #include <vm/vm_param.h>
42 #include <vm/pmap.h>
43
44 #include <machine/atomic.h>
45 #include <machine/db_machdep.h>
46 #include <machine/md_var.h>
47 #include <machine/stack.h>
48 #include <ddb/db_sym.h>
49 #include <ddb/ddb.h>
50 #include <sys/kdb.h>
51
52 #include "regset.h"
53
54 /*
55  * Wee need some reasonable default to prevent backtrace code
56  * from wandering too far
57  */
58 #define MAX_FUNCTION_SIZE 0x10000
59 #define MAX_PROLOGUE_SIZE 0x100
60 #define MAX_USTACK_DEPTH  2048
61
62 uint8_t dtrace_fuword8_nocheck(void *);
63 uint16_t dtrace_fuword16_nocheck(void *);
64 uint32_t dtrace_fuword32_nocheck(void *);
65 uint64_t dtrace_fuword64_nocheck(void *);
66
67 void
68 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
69     uint32_t *intrpc)
70 {
71         struct unwind_state state;
72         int scp_offset;
73         register_t sp, fp;
74         int depth;
75
76         depth = 0;
77
78         if (intrpc != 0) {
79                 pcstack[depth++] = (pc_t) intrpc;
80         }
81
82         aframes++;
83
84         __asm __volatile("mov %0, sp" : "=&r" (sp));
85
86         state.fp = (uint64_t)__builtin_frame_address(0);
87         state.sp = sp;
88         state.pc = (uint64_t)dtrace_getpcstack;
89
90         while (depth < pcstack_limit) {
91                 if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
92                         break;
93
94                 fp = state.fp;
95                 state.sp = fp + 0x10;
96                 /* FP to previous frame (X29) */
97                 state.fp = *(register_t *)(fp);
98                 /* LR (X30) */
99                 state.pc = *(register_t *)(fp + 8) - 4;
100
101                 /*
102                  * NB: Unlike some other architectures, we don't need to
103                  * explicitly insert cpu_dtrace_caller as it appears in the
104                  * normal kernel stack trace rather than a special trap frame.
105                  */
106                 if (aframes > 0) {
107                         aframes--;
108                 } else {
109                         pcstack[depth++] = state.pc;
110                 }
111
112         }
113
114         for (; depth < pcstack_limit; depth++) {
115                 pcstack[depth] = 0;
116         }
117 }
118
119 static int
120 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
121     uintptr_t fp)
122 {
123         volatile uint16_t *flags =
124             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
125         int ret = 0;
126         uintptr_t oldfp = fp;
127
128         ASSERT(pcstack == NULL || pcstack_limit > 0);
129
130         while (pc != 0) {
131                 /*
132                  * We limit the number of times we can go around this
133                  * loop to account for a circular stack.
134                  */
135                 if (ret++ >= MAX_USTACK_DEPTH) {
136                         *flags |= CPU_DTRACE_BADSTACK;
137                         cpu_core[curcpu].cpuc_dtrace_illval = fp;
138                         break;
139                 }
140
141                 if (pcstack != NULL) {
142                         *pcstack++ = (uint64_t)pc;
143                         pcstack_limit--;
144                         if (pcstack_limit <= 0)
145                                 break;
146                 }
147
148                 if (fp == 0)
149                         break;
150
151                 pc = dtrace_fuword64((void *)(fp +
152                     offsetof(struct arm64_frame, f_retaddr)));
153                 fp = dtrace_fuword64((void *)fp);
154
155                 if (fp == oldfp) {
156                         *flags |= CPU_DTRACE_BADSTACK;
157                         cpu_core[curcpu].cpuc_dtrace_illval = fp;
158                         break;
159                 }
160
161                 /*
162                  * ARM64TODO:
163                  *     This workaround might not be necessary. It needs to be
164                  *     revised and removed from all architectures if found
165                  *     unwanted. Leaving the original x86 comment for reference.
166                  *
167                  * This is totally bogus:  if we faulted, we're going to clear
168                  * the fault and break.  This is to deal with the apparently
169                  * broken Java stacks on x86.
170                  */
171                 if (*flags & CPU_DTRACE_FAULT) {
172                         *flags &= ~CPU_DTRACE_FAULT;
173                         break;
174                 }
175
176                 oldfp = fp;
177         }
178
179         return (ret);
180 }
181
182 void
183 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
184 {
185         proc_t *p = curproc;
186         struct trapframe *tf;
187         uintptr_t pc, sp, fp;
188         volatile uint16_t *flags =
189             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
190         int n;
191
192         if (*flags & CPU_DTRACE_FAULT)
193                 return;
194
195         if (pcstack_limit <= 0)
196                 return;
197
198         /*
199          * If there's no user context we still need to zero the stack.
200          */
201         if (p == NULL || (tf = curthread->td_frame) == NULL)
202                 goto zero;
203
204         *pcstack++ = (uint64_t)p->p_pid;
205         pcstack_limit--;
206
207         if (pcstack_limit <= 0)
208                 return;
209
210         pc = tf->tf_elr;
211         sp = tf->tf_sp;
212         fp = tf->tf_x[29];
213
214         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
215                 /*
216                  * In an entry probe.  The frame pointer has not yet been
217                  * pushed (that happens in the function prologue).  The
218                  * best approach is to add the current pc as a missing top
219                  * of stack and back the pc up to the caller, which is stored
220                  * at the current stack pointer address since the call
221                  * instruction puts it there right before the branch.
222                  */
223
224                 *pcstack++ = (uint64_t)pc;
225                 pcstack_limit--;
226                 if (pcstack_limit <= 0)
227                         return;
228
229                 pc = tf->tf_lr;
230         }
231
232         n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
233         ASSERT(n >= 0);
234         ASSERT(n <= pcstack_limit);
235
236         pcstack += n;
237         pcstack_limit -= n;
238
239 zero:
240         while (pcstack_limit-- > 0)
241                 *pcstack++ = 0;
242 }
243
244 int
245 dtrace_getustackdepth(void)
246 {
247
248         printf("IMPLEMENT ME: %s\n", __func__);
249
250         return (0);
251 }
252
253 void
254 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
255 {
256
257         printf("IMPLEMENT ME: %s\n", __func__);
258 }
259
260 /*ARGSUSED*/
261 uint64_t
262 dtrace_getarg(int arg, int aframes)
263 {
264
265         printf("IMPLEMENT ME: %s\n", __func__);
266
267         return (0);
268 }
269
270 int
271 dtrace_getstackdepth(int aframes)
272 {
273         struct unwind_state state;
274         int scp_offset;
275         register_t sp;
276         int depth;
277         int done;
278
279         depth = 1;
280         done = 0;
281
282         __asm __volatile("mov %0, sp" : "=&r" (sp));
283
284         state.fp = (uint64_t)__builtin_frame_address(0);
285         state.sp = sp;
286         state.pc = (uint64_t)dtrace_getstackdepth;
287
288         do {
289                 done = unwind_frame(&state);
290                 if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
291                         break;
292                 depth++;
293         } while (!done);
294
295         if (depth < aframes)
296                 return (0);
297         else
298                 return (depth - aframes);
299 }
300
301 ulong_t
302 dtrace_getreg(struct trapframe *rp, uint_t reg)
303 {
304
305         printf("IMPLEMENT ME: %s\n", __func__);
306
307         return (0);
308 }
309
310 static int
311 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
312 {
313
314         if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
315                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
316                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
317                 return (0);
318         }
319
320         return (1);
321 }
322
323 void
324 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
325     volatile uint16_t *flags)
326 {
327
328         if (dtrace_copycheck(uaddr, kaddr, size))
329                 dtrace_copy(uaddr, kaddr, size);
330 }
331
332 void
333 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
334     volatile uint16_t *flags)
335 {
336
337         if (dtrace_copycheck(uaddr, kaddr, size))
338                 dtrace_copy(kaddr, uaddr, size);
339 }
340
341 void
342 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
343     volatile uint16_t *flags)
344 {
345
346         if (dtrace_copycheck(uaddr, kaddr, size))
347                 dtrace_copystr(uaddr, kaddr, size, flags);
348 }
349
350 void
351 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
352     volatile uint16_t *flags)
353 {
354
355         if (dtrace_copycheck(uaddr, kaddr, size))
356                 dtrace_copystr(kaddr, uaddr, size, flags);
357 }
358
359 uint8_t
360 dtrace_fuword8(void *uaddr)
361 {
362
363         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
364                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
365                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
366                 return (0);
367         }
368
369         return (dtrace_fuword8_nocheck(uaddr));
370 }
371
372 uint16_t
373 dtrace_fuword16(void *uaddr)
374 {
375
376         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
377                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
378                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
379                 return (0);
380         }
381
382         return (dtrace_fuword16_nocheck(uaddr));
383 }
384
385 uint32_t
386 dtrace_fuword32(void *uaddr)
387 {
388
389         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
390                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
391                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
392                 return (0);
393         }
394
395         return (dtrace_fuword32_nocheck(uaddr));
396 }
397
398 uint64_t
399 dtrace_fuword64(void *uaddr)
400 {
401
402         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
403                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
404                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
405                 return (0);
406         }
407
408         return (dtrace_fuword64_nocheck(uaddr));
409 }