]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
Merge lld trunk r366426, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / cddl / dev / dtrace / powerpc / 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  * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org>
23  *
24  * $FreeBSD$
25  */
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 #include <sys/cdefs.h>
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/stack.h>
36 #include <sys/sysent.h>
37 #include <sys/pcpu.h>
38
39 #include <machine/frame.h>
40 #include <machine/md_var.h>
41 #include <machine/psl.h>
42 #include <machine/reg.h>
43 #include <machine/stack.h>
44
45 #include <vm/vm.h>
46 #include <vm/vm_param.h>
47 #include <vm/pmap.h>
48
49 #include "regset.h"
50
51 /* Offset to the LR Save word (ppc32) */
52 #define RETURN_OFFSET   4
53 /* Offset to LR Save word (ppc64).  CR Save area sits between back chain and LR */
54 #define RETURN_OFFSET64 16
55
56 #ifdef __powerpc64__
57 #define OFFSET 4 /* Account for the TOC reload slot */
58 #define FRAME_OFFSET    48
59 #else
60 #define OFFSET 0
61 #define FRAME_OFFSET    8
62 #endif
63
64 #define INKERNEL(x)     (((x) <= VM_MAX_KERNEL_ADDRESS && \
65                 (x) >= VM_MIN_KERNEL_ADDRESS) || \
66                 (PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \
67                  (x) <= DMAP_MAX_ADDRESS))
68
69 static __inline int
70 dtrace_sp_inkernel(uintptr_t sp)
71 {
72         struct trapframe *frame;
73         vm_offset_t callpc;
74
75         /* Not within the kernel, or not aligned. */
76         if (!INKERNEL(sp) || (sp & 0xf) != 0)
77                 return (0);
78 #ifdef __powerpc64__
79         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
80 #else
81         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
82 #endif
83         if ((callpc & 3) || (callpc < 0x100))
84                 return (0);
85
86         /*
87          * trapexit() and asttrapexit() are sentinels
88          * for kernel stack tracing.
89          */
90         if (callpc + OFFSET == (vm_offset_t) &trapexit ||
91             callpc + OFFSET == (vm_offset_t) &asttrapexit) {
92                 frame = (struct trapframe *)(sp + FRAME_OFFSET);
93
94                 return ((frame->srr1 & PSL_PR) == 0);
95         }
96
97         return (1);
98 }
99
100 static __inline void
101 dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
102 {
103         vm_offset_t callpc;
104         struct trapframe *frame;
105
106 #ifdef __powerpc64__
107         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
108 #else
109         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
110 #endif
111
112         /*
113          * trapexit() and asttrapexit() are sentinels
114          * for kernel stack tracing.
115          */
116         if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
117             callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
118                 /* Access the trap frame */
119                 frame = (struct trapframe *)(sp + FRAME_OFFSET);
120
121                 if (nsp != NULL)
122                         *nsp = frame->fixreg[1];
123                 if (pc != NULL)
124                         *pc = frame->srr0;
125                 return;
126         }
127
128         if (nsp != NULL)
129                 *nsp = *(uintptr_t *)sp;
130         if (pc != NULL)
131                 *pc = callpc;
132 }
133
134 void
135 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
136     uint32_t *intrpc)
137 {
138         int depth = 0;
139         uintptr_t osp, sp;
140         vm_offset_t callpc;
141         pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
142
143         osp = PAGE_SIZE;
144         if (intrpc != 0)
145                 pcstack[depth++] = (pc_t) intrpc;
146
147         aframes++;
148
149         sp = (uintptr_t)__builtin_frame_address(0);
150
151         while (depth < pcstack_limit) {
152                 if (sp <= osp)
153                         break;
154
155                 if (!dtrace_sp_inkernel(sp))
156                         break;
157                 osp = sp;
158                 dtrace_next_sp_pc(osp, &sp, &callpc);
159
160                 if (aframes > 0) {
161                         aframes--;
162                         if ((aframes == 0) && (caller != 0)) {
163                                 pcstack[depth++] = caller;
164                         }
165                 }
166                 else {
167                         pcstack[depth++] = callpc;
168                 }
169         }
170
171         for (; depth < pcstack_limit; depth++) {
172                 pcstack[depth] = 0;
173         }
174 }
175
176 static int
177 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
178     uintptr_t sp)
179 {
180         proc_t *p = curproc;
181         int ret = 0;
182
183         ASSERT(pcstack == NULL || pcstack_limit > 0);
184
185         while (pc != 0) {
186                 ret++;
187                 if (pcstack != NULL) {
188                         *pcstack++ = (uint64_t)pc;
189                         pcstack_limit--;
190                         if (pcstack_limit <= 0)
191                                 break;
192                 }
193
194                 if (sp == 0)
195                         break;
196
197                 if (SV_PROC_FLAG(p, SV_ILP32)) {
198                         pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
199                         sp = dtrace_fuword32((void *)sp);
200                 }
201                 else {
202                         pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
203                         sp = dtrace_fuword64((void *)sp);
204                 }
205         }
206
207         return (ret);
208 }
209
210 void
211 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
212 {
213         proc_t *p = curproc;
214         struct trapframe *tf;
215         uintptr_t pc, sp;
216         volatile uint16_t *flags =
217             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
218         int n;
219
220         if (*flags & CPU_DTRACE_FAULT)
221                 return;
222
223         if (pcstack_limit <= 0)
224                 return;
225
226         /*
227          * If there's no user context we still need to zero the stack.
228          */
229         if (p == NULL || (tf = curthread->td_frame) == NULL)
230                 goto zero;
231
232         *pcstack++ = (uint64_t)p->p_pid;
233         pcstack_limit--;
234
235         if (pcstack_limit <= 0)
236                 return;
237
238         pc = tf->srr0;
239         sp = tf->fixreg[1];
240
241         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
242                 /* 
243                  * In an entry probe.  The frame pointer has not yet been
244                  * pushed (that happens in the function prologue).  The
245                  * best approach is to add the current pc as a missing top
246                  * of stack and back the pc up to the caller, which is stored
247                  * at the current stack pointer address since the call 
248                  * instruction puts it there right before the branch.
249                  */
250
251                 *pcstack++ = (uint64_t)pc;
252                 pcstack_limit--;
253                 if (pcstack_limit <= 0)
254                         return;
255
256                 pc = tf->lr;
257         }
258
259         n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
260         ASSERT(n >= 0);
261         ASSERT(n <= pcstack_limit);
262
263         pcstack += n;
264         pcstack_limit -= n;
265
266 zero:
267         while (pcstack_limit-- > 0)
268                 *pcstack++ = 0;
269 }
270
271 int
272 dtrace_getustackdepth(void)
273 {
274         proc_t *p = curproc;
275         struct trapframe *tf;
276         uintptr_t pc, sp;
277         int n = 0;
278
279         if (p == NULL || (tf = curthread->td_frame) == NULL)
280                 return (0);
281
282         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
283                 return (-1);
284
285         pc = tf->srr0;
286         sp = tf->fixreg[1];
287
288         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
289                 /* 
290                  * In an entry probe.  The frame pointer has not yet been
291                  * pushed (that happens in the function prologue).  The
292                  * best approach is to add the current pc as a missing top
293                  * of stack and back the pc up to the caller, which is stored
294                  * at the current stack pointer address since the call 
295                  * instruction puts it there right before the branch.
296                  */
297
298                 if (SV_PROC_FLAG(p, SV_ILP32)) {
299                         pc = dtrace_fuword32((void *) sp);
300                 }
301                 else
302                         pc = dtrace_fuword64((void *) sp);
303                 n++;
304         }
305
306         n += dtrace_getustack_common(NULL, 0, pc, sp);
307
308         return (n);
309 }
310
311 void
312 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
313 {
314         proc_t *p = curproc;
315         struct trapframe *tf;
316         uintptr_t pc, sp;
317         volatile uint16_t *flags =
318             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
319 #ifdef notyet   /* XXX signal stack */
320         uintptr_t oldcontext;
321         size_t s1, s2;
322 #endif
323
324         if (*flags & CPU_DTRACE_FAULT)
325                 return;
326
327         if (pcstack_limit <= 0)
328                 return;
329
330         /*
331          * If there's no user context we still need to zero the stack.
332          */
333         if (p == NULL || (tf = curthread->td_frame) == NULL)
334                 goto zero;
335
336         *pcstack++ = (uint64_t)p->p_pid;
337         pcstack_limit--;
338
339         if (pcstack_limit <= 0)
340                 return;
341
342         pc = tf->srr0;
343         sp = tf->fixreg[1];
344
345 #ifdef notyet /* XXX signal stack */
346         oldcontext = lwp->lwp_oldcontext;
347         s1 = sizeof (struct xframe) + 2 * sizeof (long);
348         s2 = s1 + sizeof (siginfo_t);
349 #endif
350
351         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
352                 *pcstack++ = (uint64_t)pc;
353                 *fpstack++ = 0;
354                 pcstack_limit--;
355                 if (pcstack_limit <= 0)
356                         return;
357
358                 if (SV_PROC_FLAG(p, SV_ILP32)) {
359                         pc = dtrace_fuword32((void *)sp);
360                 }
361                 else {
362                         pc = dtrace_fuword64((void *)sp);
363                 }
364         }
365
366         while (pc != 0) {
367                 *pcstack++ = (uint64_t)pc;
368                 *fpstack++ = sp;
369                 pcstack_limit--;
370                 if (pcstack_limit <= 0)
371                         break;
372
373                 if (sp == 0)
374                         break;
375
376 #ifdef notyet /* XXX signal stack */
377                 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
378                         ucontext_t *ucp = (ucontext_t *)oldcontext;
379                         greg_t *gregs = ucp->uc_mcontext.gregs;
380
381                         sp = dtrace_fulword(&gregs[REG_FP]);
382                         pc = dtrace_fulword(&gregs[REG_PC]);
383
384                         oldcontext = dtrace_fulword(&ucp->uc_link);
385                 } else
386 #endif /* XXX */
387                 {
388                         if (SV_PROC_FLAG(p, SV_ILP32)) {
389                                 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
390                                 sp = dtrace_fuword32((void *)sp);
391                         }
392                         else {
393                                 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
394                                 sp = dtrace_fuword64((void *)sp);
395                         }
396                 }
397
398                 /*
399                  * This is totally bogus:  if we faulted, we're going to clear
400                  * the fault and break.  This is to deal with the apparently
401                  * broken Java stacks on x86.
402                  */
403                 if (*flags & CPU_DTRACE_FAULT) {
404                         *flags &= ~CPU_DTRACE_FAULT;
405                         break;
406                 }
407         }
408
409 zero:
410         while (pcstack_limit-- > 0)
411                 *pcstack++ = 0;
412 }
413
414 /*ARGSUSED*/
415 uint64_t
416 dtrace_getarg(int arg, int aframes)
417 {
418         uintptr_t val;
419         uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0);
420         uintptr_t *stack;
421         int i;
422
423         /*
424          * A total of 8 arguments are passed via registers; any argument with
425          * index of 7 or lower is therefore in a register.
426          */
427         int inreg = 7;
428
429         for (i = 1; i <= aframes; i++) {
430                 fp = (uintptr_t *)*fp;
431
432                 /*
433                  * On ppc32 trapexit() is the immediately following label.  On
434                  * ppc64 AIM trapexit() follows a nop.
435                  */
436 #ifdef __powerpc64__
437                 if ((long)(fp[2]) + 4 == (long)trapexit) {
438 #else
439                 if ((long)(fp[1]) == (long)trapexit) {
440 #endif
441                         /*
442                          * In the case of powerpc, we will use the pointer to the regs
443                          * structure that was pushed when we took the trap.  To get this
444                          * structure, we must increment beyond the frame structure.  If the
445                          * argument that we're seeking is passed on the stack, we'll pull
446                          * the true stack pointer out of the saved registers and decrement
447                          * our argument by the number of arguments passed in registers; if
448                          * the argument we're seeking is passed in regsiters, we can just
449                          * load it directly.
450                          */
451 #ifdef __powerpc64__
452                         struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
453 #else
454                         struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
455 #endif
456
457                         if (arg <= inreg) {
458                                 stack = &rp->fixreg[3];
459                         } else {
460                                 stack = (uintptr_t *)(rp->fixreg[1]);
461                                 arg -= inreg;
462                         }
463                         goto load;
464                 }
465
466         }
467
468         /*
469          * We know that we did not come through a trap to get into
470          * dtrace_probe() -- the provider simply called dtrace_probe()
471          * directly.  As this is the case, we need to shift the argument
472          * that we're looking for:  the probe ID is the first argument to
473          * dtrace_probe(), so the argument n will actually be found where
474          * one would expect to find argument (n + 1).
475          */
476         arg++;
477
478         if (arg <= inreg) {
479                 /*
480                  * This shouldn't happen.  If the argument is passed in a
481                  * register then it should have been, well, passed in a
482                  * register...
483                  */
484                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
485                 return (0);
486         }
487
488         arg -= (inreg + 1);
489         stack = fp + 2;
490
491 load:
492         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
493         val = stack[arg];
494         DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
495
496         return (val);
497 }
498
499 int
500 dtrace_getstackdepth(int aframes)
501 {
502         int depth = 0;
503         uintptr_t osp, sp;
504         vm_offset_t callpc;
505
506         osp = PAGE_SIZE;
507         sp = (uintptr_t)__builtin_frame_address(0);
508         for(;;) {
509                 if (sp <= osp)
510                         break;
511
512                 if (!dtrace_sp_inkernel(sp))
513                         break;
514
515                 depth++;
516                 osp = sp;
517                 dtrace_next_sp_pc(sp, &sp, NULL);
518         }
519         if (depth < aframes)
520                 return (0);
521
522         return (depth - aframes);
523 }
524
525 ulong_t
526 dtrace_getreg(struct trapframe *rp, uint_t reg)
527 {
528         if (reg < 32)
529                 return (rp->fixreg[reg]);
530
531         switch (reg) {
532         case 32:
533                 return (rp->lr);
534         case 33:
535                 return (rp->cr);
536         case 34:
537                 return (rp->xer);
538         case 35:
539                 return (rp->ctr);
540         case 36:
541                 return (rp->srr0);
542         case 37:
543                 return (rp->srr1);
544         case 38:
545                 return (rp->exc);
546         default:
547                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
548                 return (0);
549         }
550 }
551
552 static int
553 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
554 {
555         ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
556
557         if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
558                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
559                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
560                 return (0);
561         }
562
563         return (1);
564 }
565
566 void
567 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
568     volatile uint16_t *flags)
569 {
570         if (dtrace_copycheck(uaddr, kaddr, size))
571                 if (copyin((const void *)uaddr, (void *)kaddr, size)) {
572                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
573                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
574                 }
575 }
576
577 void
578 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
579     volatile uint16_t *flags)
580 {
581         if (dtrace_copycheck(uaddr, kaddr, size)) {
582                 if (copyout((const void *)kaddr, (void *)uaddr, size)) {
583                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
584                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
585                 }
586         }
587 }
588
589 void
590 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
591     volatile uint16_t *flags)
592 {
593         size_t actual;
594         int    error;
595
596         if (dtrace_copycheck(uaddr, kaddr, size)) {
597                 error = copyinstr((const void *)uaddr, (void *)kaddr,
598                     size, &actual);
599                 
600                 /* ENAMETOOLONG is not a fault condition. */
601                 if (error && error != ENAMETOOLONG) {
602                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
603                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
604                 }
605         }
606 }
607
608 /*
609  * The bulk of this function could be replaced to match dtrace_copyinstr() 
610  * if we ever implement a copyoutstr().
611  */
612 void
613 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
614     volatile uint16_t *flags)
615 {
616         size_t len;
617
618         if (dtrace_copycheck(uaddr, kaddr, size)) {
619                 len = strlen((const char *)kaddr);
620                 if (len > size)
621                         len = size;
622
623                 if (copyout((const void *)kaddr, (void *)uaddr, len)) {
624                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
625                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
626                 }
627         }
628 }
629
630 uint8_t
631 dtrace_fuword8(void *uaddr)
632 {
633         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
634                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
635                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
636                 return (0);
637         }
638         return (fubyte(uaddr));
639 }
640
641 uint16_t
642 dtrace_fuword16(void *uaddr)
643 {
644         uint16_t ret = 0;
645
646         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
647                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
648                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
649                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
650                 }
651         }
652         return ret;
653 }
654
655 uint32_t
656 dtrace_fuword32(void *uaddr)
657 {
658         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
659                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
660                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
661                 return (0);
662         }
663         return (fuword32(uaddr));
664 }
665
666 uint64_t
667 dtrace_fuword64(void *uaddr)
668 {
669         uint64_t ret = 0;
670
671         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
672                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
673                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
674                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
675                 }
676         }
677         return ret;
678 }
679
680 uintptr_t
681 dtrace_fulword(void *uaddr)
682 {
683         uintptr_t ret = 0;
684
685         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
686                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
687                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
688                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
689                 }
690         }
691         return ret;
692 }