]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/ppc/fasttrap_isa.c
xnu-1504.7.4.tar.gz
[apple/xnu.git] / bsd / dev / ppc / fasttrap_isa.c
CommitLineData
2d21ac55
A
1/*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * CDDL HEADER START
31 *
32 * The contents of this file are subject to the terms of the
33 * Common Development and Distribution License (the "License").
34 * You may not use this file except in compliance with the License.
35 *
36 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
37 * or http://www.opensolaris.org/os/licensing.
38 * See the License for the specific language governing permissions
39 * and limitations under the License.
40 *
41 * When distributing Covered Code, include this CDDL HEADER in each
42 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
43 * If applicable, add the following below this CDDL HEADER, with the
44 * fields enclosed by brackets "[]" replaced with your own identifying
45 * information: Portions Copyright [yyyy] [name of copyright owner]
46 *
47 * CDDL HEADER END
48 */
49
50/*
b0d623f7 51 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2d21ac55
A
52 * Use is subject to license terms.
53 */
54
55/*
b0d623f7 56 * #pragma ident "@(#)fasttrap_isa.c 1.27 08/04/09 SMI"
2d21ac55
A
57 */
58
59#ifdef KERNEL
60#ifndef _KERNEL
61#define _KERNEL /* Solaris vs. Darwin */
62#endif
63#endif
64
65#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
66#include <sys/fasttrap_isa.h>
67#include <sys/fasttrap_impl.h>
68#include <sys/dtrace.h>
69#include <sys/dtrace_impl.h>
70#include <sys/dtrace_ptss.h>
71#include <kern/debug.h>
72#include <ppc/decodePPC.h>
73#include <kern/task.h>
74#include <mach/vm_param.h>
75#include <mach/mach_vm.h>
76#include <mach/task.h>
77#include <vm/pmap.h>
78#include <vm/vm_map.h> /* All the bits we care about are guarded by MACH_KERNEL_PRIVATE :-( */
cf7d32b8 79extern dtrace_id_t dtrace_probeid_error;
2d21ac55 80
b0d623f7
A
81/* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
82#define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
2d21ac55
A
83
84static int32_t branchtaken(int32_t bo, int32_t bi, ppc_saved_state_t *sv);
85static int32_t dtrace_decode_ppc(uint32_t inst);
86int patchInst(task_t task, addr64_t vaddr, uint32_t inst);
87kern_return_t dtrace_user_probe(ppc_saved_state_t *sv);
88
89/*
90 * Lossless User-Land Tracing on PPC
91 * ---------------------------------
92 *
93 * PPC uses a different technique to emulate user-land instruction replaces by a probe
94 * trap than x86.
95 *
96 * Like x86, it will emulate all forms of branch instructions. We will not attempt
97 * to emulate any instruction that we know will cause an interruption or exception
98 * (system call, trap, privileged instruction, instruction that uses a privileged
99 * register).
100 *
101 * NOTE: I am thinking that we should punish tight loopers, e.g., branch-to-dot.
102 * Depending upon clock resolution and how fast we can process these guys, it is
103 * possible that its quantum will never decrease. Maybe we could just manually
104 * end the guy's quantum and let the next guy go...
105 *
106 * When fasttrap_tracepoint_init is called, we fetch the instruction and decode it.
107 * If we don't recognize it or find it is a "banned" instruction, we return -1,
108 * telling our caller to forget it. Otherwise we save the instruction image and
109 * enough of the decode to quickly handle it at probe time. We cram it into
110 * the fasttrap_machtp_t structure.
111 *
112 * When the probe hits, we verify that the PC is still a probe point and if not,
113 * we bail. Otherwise we have a bit more to do.
114 *
115 * If DTFTP_ENTRY is set, we have an entry probe and need to call dtrace_probe.
116 *
117 * If DTFTP_IS_ENABLED is set, all we need to do is to return a 1.
118 *
119 * If ftp_argmap is NULL, we call dtrace_probe
120 *
121 * Otherwise, we figure out what the arguments are and pass them to dtrace_probe
122 *
123 * Next, we need to set up to emulate the probed instruction and here is where we are
124 * the most different than the x86 code.
125 *
126 * Like x86, we first check to see if the instruction is any form of branch. If so,
127 * we emulate it completely within the kernel and are done.
128 *
129 * If it is anything else, we build a code stream within the kernel to execute the
130 * instruction. Note that this is very different from x86 which build the code in
131 * userland.
132 *
133 * The generated stream needs to be executed within the kernel's code space but with
134 * the user address space and registers. Because PPC allows different translation modes
135 * for instruction fetch and data fetch, this is not too difficult.
136 *
137 * There are two kinds streams needed: execute and continue, and execute and return,
138 * which are used for entry/offset and exit probes respectivily.
139 *
140 * The probe code will copy the instruction image into the current user savearea (which
141 * also contains the complete user state register context). A flag that requests either
142 * execute/continue or execute/return is also set in the savearea.
143 *
144 * We now exit the dtrace code and the marked context makes its way back to the point
145 * where it will be dispatched on the processor.
146 *
147 * The exception return code will start to restore the user context, including registers
148 * and address space. However, before dispatching the user, it will notice that the
149 * emulate flags are set. At this point the code will build a code stream
150 * in an area in the per_proc that consists of
151 * the original instruction followed by a trap instruction. It will set the new MSR (in
152 * SRR1) to have address translation enable for data, translation disabled for instruction
153 * fetches, interruptions disabled, and supervisor state.
154 *
155 * The new PC and MSR are loaded via a RFID and the generated stream is executed. If a
156 * synchronous fault occurs, it is either handled (PTE miss, FPU or vector unavailable),
157 * emulated (alignment or denorm), or passed on to the user.
158 *
159 * Assuming the emulated instruction completes, the trap will execute. When that happens,
160 * low-level trap handler will check its flags. If the trap corresponds to an
161 * execute/continue stream, the trap handler will adjust the PC and complete the
162 * transition into user space.
163 *
164 * If the trap corresponds to an execute/return stream, the handler will generate
165 * a T_DTRACE_RET exception and let the trap handler pass it along to dtrace_user_probe.
166 *
167 */
168
169
170static uint64_t
171fasttrap_anarg(ppc_saved_state_t *sv, int function_entry, int argno)
172{
173#pragma unused(function_entry)
174 uint32_t farg;
175 uint64_t value;
176
177 /* The first 8 arguments (argno 0-7) are in registers */
178 if (argno < 8) {
179 value = (&sv->save_r3)[argno];
180 } else {
181 if (sv->save_srr1 & 0x8000000000000000ULL) {
182 /* 64-bit */
183 /* Grab argument >= 8 from stack */
184 fasttrap_fuword64_noerr(sv->save_r1 + 48 + ((argno)* sizeof(uint64_t)), &value);
185 } else {
186 /* 32-bit */
187 /* Grab argument >= 8 from stack */
188 fasttrap_fuword32_noerr(sv->save_r1 + 24 + ((argno) * sizeof(uint32_t)), &farg);
189 value = (uint64_t)farg;
190 }
191 }
192
193 return (value);
194}
195
196/*ARGSUSED*/
197int
198fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
199 fasttrap_probe_type_t type)
200{
201#pragma unused(type)
202
203 uint32_t instr, testr1, testr2, testr3;
204 user_addr_t targpc;
205 int32_t target, optype;
206
207 /*
208 * Read the instruction at the given address out of the process's
209 * address space. We don't have to worry about a debugger
210 * changing this instruction before we overwrite it with our trap
211 * instruction since P_PR_LOCK is set. Since instructions can span
212 * pages, we potentially read the instruction in two parts. If the
213 * second part fails, we just zero out that part of the instruction.
214 */
215 /*
216 * APPLE NOTE: Of course, we do not have a P_PR_LOCK, so this is racey...
217 */
218
219 if (uread(p, &instr, 4, pc) != 0) return (-1); /* Grab instruction, return suddenly if read fails... */
220
221 optype = dtrace_decode_ppc(instr); /* See if we have an instruction we can probe */
222
223 tp->ftt_instr = instr; /* Save the instruction image */
224 testr1 = tp->ftt_bo = (uint8_t)((instr >> (31 - 10)) & 0x1F); /* Extract branch options */
225 testr2 = tp->ftt_bi = (uint8_t)((instr >> (31 - 15)) & 0x1F); /* Extract condition register bit */
226 testr3 = (instr >> (31 - 20)) & 0x1F; /* Get that last register */
227 tp->ftt_flgs = (uint8_t)(instr & 3); /* Set the absolute address and link flags */
228
229 switch(optype) { /* Do instruction specific decode */
230
231 case diCMN: /* Common instruction */
232 tp->ftt_type = ftmtCommon; /* Mark as common instruction */
233 break;
234
235 case diINV: /* Invalid */
236 case diTRP: /* Trap */
237 case diSC: /* System Call */
238 case diRFI: /* Return from interrupt */
239 case diPRV: /* Priviliged instruction */
240 return (-1); /* We will not emulate these... */
241 break;
242
243 case diB: /* Branch */
244 tp->ftt_type = ftmtB; /* Mark as branch instruction */
245 target = instr & 0x03FFFFFC; /* Extract address or offset */
246 if(target & 0x02000000) target |= 0xFC000000; /* Sign extend */
247 tp->ftt_trgt = target; /* Trim back down and save */
248
249 targpc = (user_addr_t)((int64_t)target); /* Generate a target address, hopefully we sign extend... */
250 if(!(tp->ftt_flgs & ftmtAbs)) { /* Are we dealing with an offset here? */
251 targpc = targpc + pc; /* Apply offset to get target address */
252 }
253
254 if(targpc == pc) return -1; /* Branching to self is a sin and is forbidden... */
255 break;
256
257 case diBC: /* Branch conditional */
258 tp->ftt_type = ftmtBC; /* Mark as branch conditional */
259 target = instr & 0x0000FFFC; /* Extract address or offset */
260 if(target & 0x00008000) target |= 0xFFFF0000; /* Sign extend */
261 tp->ftt_trgt = target; /* Trim back down and save */
262
263 targpc = (user_addr_t)((int64_t)target); /* Generate a target address, hopefully we sign extend... */
264 if(!(tp->ftt_flgs & ftmtAbs)) { /* Are we dealing with an offset here? */
265 targpc = targpc + pc; /* Apply offset to get target address */
266 }
267
268 if(targpc == pc) return -1; /* Branching to self is a sin and is forbidden... */
269 break;
270
271 case diBLR: /* Branch conditional to link register */
272 tp->ftt_type = ftmtBLR; /* Mark as branch conditional to link register */
273 break;
274
275 case diBCTR: /* Branch conditional to count register */
276 tp->ftt_type = ftmtBCTR; /* Mark as branch conditional to count register */
277 break;
278
279 case diOR: /* OR */
280 if((instr >> 26) == 24) { /* Is this the ORI nop? */
281 if((testr1 == testr2) && ((instr & 0x0000FFFF) == 0)) tp->ftt_type = ftmtNOP; /* Remember if this is a NOP instruction */
282 else tp->ftt_type = ftmtCommon; /* Otherwise it is a common ORI instruction */
283 }
284 else if((testr1 == testr2) && (testr1 == testr3)) tp->ftt_type = ftmtNOP; /* If all three registers are the same, this is a NOP */
285 else tp->ftt_type = ftmtCommon; /* Otherwise it is a common OR instruction */
286
287 break;
288
289 default:
290 panic("fasttrap_tracepoint_init: invalid branch decode, inst = %08X, optype = %d\n", instr, optype);
291 break;
292
293 }
294
295 return (0);
296}
297
298int
299fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
300{
301 return patchInst(p->task, tp->ftt_pc, FASTTRAP_INSTR); /* Patch the instruction and flush it */
302}
303
304extern void dbgTrace(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
305
306int
307fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
308{
309 uint32_t instr;
310
311 /*
312 * Distinguish between read or write failures and a changed
313 * instruction.
314 */
315 if (uread(p, &instr, 4, tp->ftt_pc) != 0) return (0); /* Get the instruction, but exit if not mapped */
316
317// dbgTrace(0x99999999, (uint32_t)tp->ftt_pc, tp->ftt_instr, instr, 0); /* (TRACE/DEBUG) */
318
319 if (instr != FASTTRAP_INSTR) return (0); /* Did someone change it? If so, just leave */
320
321 return patchInst(p->task, tp->ftt_pc, tp->ftt_instr); /* Patch the old instruction back in and flush it */
322}
323
324static void
325fasttrap_return_common(ppc_saved_state_t *sv, user_addr_t pc, pid_t pid, user_addr_t new_pc)
326{
327
328 fasttrap_tracepoint_t *tp;
329 fasttrap_bucket_t *bucket;
330 fasttrap_id_t *id;
331 lck_mtx_t *pid_mtx;
332
333 pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
334 lck_mtx_lock(pid_mtx);
335 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
336
337 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
338 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
b0d623f7 339 tp->ftt_proc->ftpc_acount != 0)
2d21ac55
A
340 break;
341 }
342
343 /*
344 * Don't sweat it if we can't find the tracepoint again. Unlike
345 * when we're in fasttrap_pid_probe(), finding the tracepoint here
346 * is not essential to the correct execution of the process.
347 */
348 if (tp == NULL) {
349 lck_mtx_unlock(pid_mtx);
350 return;
351 }
352
353 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
354 /*
355 * If there's a branch that could act as a return site, we
356 * need to trace it, and check here if the program counter is
357 * external to the function.
358 */
359 if((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize) /* Is target within the function? */
360 continue; /* Yeah, skip this one... */
361
362 DTRACE_CPUFLAG_SET(CPU_DTRACE_USTACK_FP);
cf7d32b8
A
363 if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
364 dtrace_probe(dtrace_probeid_error, 0 /* state */,
365 id->fti_probe->ftp_id, 1 /* ndx */, -1 /* offset */,
366 DTRACEFLT_UPRIV);
367 } else {
368 dtrace_probe(id->fti_probe->ftp_id,
369 pc - id->fti_probe->ftp_faddr,
370 sv->save_r3, sv->save_r4, 0, 0);
371 }
2d21ac55
A
372 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_USTACK_FP);
373 }
374
375 lck_mtx_unlock(pid_mtx);
376}
377
378static void
379fasttrap_usdt_args(fasttrap_probe_t *probe, ppc_saved_state_t *sv, int argc,
380 uint64_t *argv)
381{
382 int i, x, cap = MIN(argc, probe->ftp_nargs);
383 uint32_t farg;
384
385 for (i = 0; i < cap; i++) {
386 x = probe->ftp_argmap[i];
387
388 if (x <= 8) { /* Is this argument in a register? */
389 argv[i] = (&sv->save_r0)[x];
390 } else {
391 if(sv->save_srr1 & 0x8000000000000000ULL) { /* Are we running in 64-bit? */
392 fasttrap_fuword64_noerr(sv->save_r1 + 48 + (x * sizeof(uint64_t)), &argv[i]); /* Grab argument > 8 from stack */
393 }
394 else {
395 fasttrap_fuword32_noerr(sv->save_r1 + 24 + (x * sizeof(uint32_t)), &farg); /* Grab argument > 8 from stack */
396 argv[i] = (uint64_t)farg; /* Convert to 64-bit */
397 }
398 }
399 }
400
401 for (; i < argc; i++) {
402 argv[i] = 0;
403 }
404}
405
406int
407fasttrap_pid_probe(ppc_saved_state_t *sv)
408{
409 proc_t *p = current_proc();
410 fasttrap_bucket_t *bucket;
411 lck_mtx_t *pid_mtx;
412 fasttrap_tracepoint_t *tp, tp_local;
413 pid_t pid;
414 dtrace_icookie_t cookie;
415 uint_t is_enabled = 0;
416 user_addr_t new_pc = 0;
417 user_addr_t pc;
418 user_addr_t addrmask;
419
420 pc = sv->save_srr0; /* Remember the PC for later */
421 if(sv->save_srr1 & 0x8000000000000000ULL) addrmask = 0xFFFFFFFFFFFFFFFFULL; /* Set 64-bit addressing if enabled */
422 else addrmask = 0x00000000FFFFFFFFULL; /* Otherwise set 32-bit */
423
424 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
425
426 /*
427 * Clear all user tracing flags.
428 */
429 uthread->t_dtrace_ft = 0;
430
431 /*
432 * Treat a child created by a call to vfork(2) as if it were its
433 * parent. We know that there's only one thread of control in such a
434 * process: this one.
435 */
436 /*
437 * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal"
438 * FIXME: How do we assert this?
439 */
440 while (p->p_lflag & P_LINVFORK) p = p->p_pptr; /* Search the end */
441
442 pid = p->p_pid;
443 pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
444 lck_mtx_lock(pid_mtx);
445 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, sv->save_srr0)]; /* Get the bucket that corresponds to out PC */
446
447 /*
448 * Lookup the tracepoint that the process just hit.
449 */
450 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
451 if (pid == tp->ftt_pid && (sv->save_srr0 == tp->ftt_pc) &&
b0d623f7 452 tp->ftt_proc->ftpc_acount != 0)
2d21ac55
A
453 break;
454 }
455
456 /*
457 * If we couldn't find a matching tracepoint, either a tracepoint has
458 * been inserted without using the pid<pid> ioctl interface (see
459 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
460 */
461 if (tp == NULL) {
462 lck_mtx_unlock(pid_mtx);
463 return (-1);
464 }
465
466 if (tp->ftt_ids != NULL) {
467 fasttrap_id_t *id;
468
469 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
470 fasttrap_probe_t *probe = id->fti_probe;
471
cf7d32b8
A
472 if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
473 dtrace_probe(dtrace_probeid_error, 0 /* state */,
474 id->fti_probe->ftp_id, 1 /* ndx */, -1 /* offset */,
475 DTRACEFLT_UPRIV);
476 } else if (id->fti_ptype == DTFTP_ENTRY) {
2d21ac55
A
477 /*
478 * We note that this was an entry
479 * probe to help ustack() find the
480 * first caller.
481 */
482 cookie = dtrace_interrupt_disable();
483 DTRACE_CPUFLAG_SET(CPU_DTRACE_USTACK_FP | CPU_DTRACE_ENTRY);
484 dtrace_probe(probe->ftp_id, sv->save_r3, sv->save_r4, /* Call the main probe routine with the first 5 args */
485 sv->save_r5, sv->save_r6, sv->save_r7);
486 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_USTACK_FP | CPU_DTRACE_ENTRY);
487 dtrace_interrupt_enable(cookie);
488
489 } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
490 /*
491 * Note that in this case, we don't
492 * call dtrace_probe() since it's only
493 * an artificial probe meant to change
494 * the flow of control so that it
495 * encounters the true probe.
496 */
497 is_enabled = 1;
498
499 } else if (probe->ftp_argmap == NULL) {
500 DTRACE_CPUFLAG_SET(CPU_DTRACE_USTACK_FP);
501 dtrace_probe(probe->ftp_id, sv->save_r3, sv->save_r4, /* Call the main probe routine with the first 5 args */
502 sv->save_r5, sv->save_r6, sv->save_r7);
503 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_USTACK_FP);
504
505 } else {
506 uint64_t t[5];
507
508 fasttrap_usdt_args(probe, sv, 5, t); /* Grab 5 arguments */
509
510 DTRACE_CPUFLAG_SET(CPU_DTRACE_USTACK_FP);
511 dtrace_probe(probe->ftp_id, t[0], t[1],
512 t[2], t[3], t[4]);
513 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_USTACK_FP);
514 }
515
516 /* APPLE NOTE: Oneshot probes get one and only one chance... */
517 if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
518 fasttrap_tracepoint_remove(p, tp);
519 }
520 }
521 }
522
523 /*
524 * We're about to do a bunch of work so we cache a local copy of
525 * the tracepoint to emulate the instruction, and then find the
526 * tracepoint again later if we need to light up any return probes.
527 */
528 tp_local = *tp;
529 lck_mtx_unlock(pid_mtx);
530 tp = &tp_local;
531
532 /*
533 * If there's an is-enabled probe connected to this tracepoint it
534 * means that there was a 'xor r3,r3,r3'
535 * instruction that was placed there by DTrace when the binary was
536 * linked. As this probe is, in fact, enabled, we need to stuff 1
537 * into R3. Accordingly, we can bypass all the instruction
538 * emulation logic since we know the inevitable result. It's possible
539 * that a user could construct a scenario where the 'is-enabled'
540 * probe was on some other instruction, but that would be a rather
541 * exotic way to shoot oneself in the foot.
542 */
543 if (is_enabled) {
544 sv->save_r3 = 1; /* Set condition to true */
545 new_pc = (sv->save_srr0 + 4) & addrmask; /* Just fall through to the next instruction */
546 goto done;
547 }
548
549 /*
550 * We emulate certain types of instructions to ensure correctness
551 * (in the case of position dependent instructions) or optimize
552 * common cases. The rest we execute in the kernel, but with
553 * most of the user's context active.
554 */
555 switch (tp->ftt_type) {
556
557 case ftmtNOP: /* NOP */
558 new_pc = (sv->save_srr0 + 4) & addrmask; /* Just fall through to the next instruction */
559 break;
560
561 case ftmtB: /* Plain unconditional branch */
562 new_pc = (user_addr_t)((int64_t)tp->ftt_trgt); /* Assume target is absolute address for the moment */
563 if(!(tp->ftt_flgs & ftmtAbs)) new_pc = (new_pc + sv->save_srr0) & addrmask; /* We don't have absolute address, use as offset from instruction address */
564
565 if(tp->ftt_flgs & ftmtLink) sv->save_lr = (sv->save_srr0 + 4) & addrmask; /* Set the LR to the next instruction if needed */
566 break;
567
568 case ftmtBC: /* Conditional PC relative or absolute branch */
569 new_pc = (user_addr_t)((int64_t)tp->ftt_trgt); /* Assume target is absolute address for the moment */
570 if(!(tp->ftt_flgs & ftmtAbs)) new_pc = new_pc + sv->save_srr0; /* We don't have absolute address, use as offset from instruction address */
571
572 if(tp->ftt_flgs & ftmtLink) sv->save_lr = (sv->save_srr0 + 4) & addrmask; /* Set the LR to the next instruction if needed */
573 if(!branchtaken(tp->ftt_bo, tp->ftt_bi, sv)) new_pc = (sv->save_srr0 + 4) & addrmask; /* If branch was not taken, set PC to next address */
574 break;
575
576 case ftmtBLR: /* Conditional branch to LR */
577 new_pc = sv->save_lr; /* Branch target comes from the LR */
578
579 if(tp->ftt_flgs & ftmtLink) sv->save_lr = (sv->save_srr0 + 4) & addrmask; /* Set the LR to the next instruction if needed */
580 if(!branchtaken(tp->ftt_bo, tp->ftt_bi, sv)) new_pc = (sv->save_srr0 + 4) & addrmask; /* If branch was not taken, set PC to next address */
581 break;
582
583 case ftmtBCTR: /* Conditional branch to CTR */
584 new_pc = sv->save_ctr; /* Branch target comes from the CTR */
585
586 if(tp->ftt_flgs & ftmtLink) sv->save_lr = (sv->save_srr0 + 4) & addrmask; /* Set the LR to the next instruction if needed */
587 if(!branchtaken(tp->ftt_bo, tp->ftt_bi, sv)) new_pc = (sv->save_srr0 + 4) & addrmask; /* If branch was not taken, set PC to next address */
588 break;
589
590 case ftmtCommon: /* Common, non-in-kernel emulated instruction */
591 sv->save_instr[0] = 1; /* We only have one instruction to inject */
592 sv->save_instr[1] = tp->ftt_instr; /* Set the instruction */
593 sv->save_hdr.save_flags = sv->save_hdr.save_flags | SAVinject; /* Tell low-level exception return to inject the instruction */
594 uthread->t_dtrace_step = 1; /* Let it be known that a trace return is imminent */
595 return 0; /* Go and don't dome back until you are done... */
596
597 default:
598 panic("fasttrap_pid_probe: invalid ftt_type = %08X\n", tp->ftt_type); /* Huh, wha happened? */
599 break;
600 }
601
602
603done:
604
605 /*
606 * If there were no return probes when we first found the tracepoint,
607 * we should feel no obligation to honor any return probes that were
608 * subsequently enabled -- they'll just have to wait until the next
609 * time around.
610 */
611 sv->save_srr0 = new_pc; /* Set the new PC */
612 if (tp->ftt_retids != NULL) fasttrap_return_common(sv, pc, pid, new_pc);
613
614 return (0);
615}
616
617
618int
619fasttrap_return_probe(ppc_saved_state_t *sv)
620{
621
622 user_addr_t pc, npc;
623
624 proc_t *p = current_proc();
625
626
627 /*
628 * Treat a child created by a call to vfork(2) as if it were its
629 * parent. We know that there's only one thread of control in such a
630 * process: this one.
631 */
632 /*
633 * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal"
634 * How do we assert this?
635 */
636 while (p->p_lflag & P_LINVFORK) {
637 p = p->p_pptr;
638 }
639
640 pc = sv->save_srr0; /* Get the PC of the probed instruction */
641 npc = pc + 4; /* Get next PC */
642 if(!(sv->save_srr1 & 0x8000000000000000ULL)) npc &= 0x00000000FFFFFFFF; /* Wrap new PC if running 32-bit */
643 fasttrap_return_common(sv, pc, p->p_pid, npc);
644
645 return (0);
646}
647
648uint64_t
649fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
650 int aframes)
651{
652#pragma unused(arg, id, parg, aframes)
653 return (fasttrap_anarg((ppc_saved_state_t *)find_user_regs(current_thread()), 1, argno));
654}
655
656uint64_t
657fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
658 int aframes)
659{
660#pragma unused(arg, id, parg, aframes)
661 return (fasttrap_anarg((ppc_saved_state_t *)find_user_regs(current_thread()), 0, argno));
662}
663
664
665static int32_t branchtaken(int32_t bo, int32_t bi, ppc_saved_state_t *sv) {
666 int32_t bcond, czero, crmatch;
667 uint64_t ctr;
668
669 if((bo & 0x14) == 0x14) return 1; /* If this is a branch always, exit with true... */
670
671 czero = 0; /* Assume that we have not just decremented the CTR to 0 */
672
673 if(!(bo & 4)) { /* Skip the next bit if we do NOT muck with the CTR */
674 ctr = sv->save_ctr = sv->save_ctr - 1; /* Decrement the CTR */
675 if(!(sv->save_srr1 & 0x8000000000000000ULL)) ctr &= 0x00000000FFFFFFFF; /* Only look at the bottom 32 bits if 32-bit mode */
676 czero = (ctr == 0); /* Remember if we just hit zero */
677 }
678
679 bcond = (bo >> 3); /* If 1, branch if CR flag is 1. If 0, branch if 0 */
680 crmatch = bo >> 4; /* If bo[0] is set, do not check CR flag */
681 crmatch = crmatch | (((sv->save_cr >> (31 - bi)) ^ bcond) ^ 1); /* Low bit is now set if CR flag matches or CR is not checked. Other bits are trash. */
682
683// dbgTrace(0x77777777, bo, bi, sv->save_cr, ((czero | crmatch) & 1)); /* (TRACE/DEBUG) */
684
685 return ((czero | crmatch) & 1); /* Return 1 if branch taken, 0 if not... */
686}
687
688static int32_t dtrace_decode_ppc(uint32_t inst) {
689
690 int32_t curdcd, lastmask, newmask, spr, bit, bito, word;
691 uint16_t xop = 0;
692 dcdtab *dcd;
693
694 curdcd = inst >> 26; /* Isolate major op code to start decode */
695 lastmask = 99; /* Always force a new xop at the start */
696
697 while(1) { /* Loop until we find instruction or fail */
698 dcd = &insts[curdcd]; /* Point to the current decode table entry */
699 if(dcd->dcdFlgs & dcdJump) { /* Should we jump to a new spot in the decode table? */
700 curdcd = dcd->dcdMatch; /* Jump */
701 continue;
702 }
703
704 newmask = dcd->dcdFlgs & dcdMask; /* Isolate the mask index */
705 if(lastmask != newmask) { /* Are we changing masks? */
706 if(!newmask) break; /* If the mask is 0, we match everything and succeed... (note: lastmask can never be 0) */
707 xop = inst & masktab[newmask]; /* Clear all extra bits to make match */
708 lastmask = newmask; /* Remember */
709 }
710
711 if(xop == dcd->dcdMatch) break; /* We found our guy! */
712
713 if(!(dcd->dcdFlgs & dcdStep)) { /* No stepping, we failed */
714 dcd = &dcdfail; /* Point to a failure entry */
715 break; /* Leave... */
716 }
717
718 curdcd = curdcd + 1; /* Step to the next decode entry */
719 }
720
721 if(dcd->dcdType != diSPR) return (int32_t)(dcd->dcdType); /* Return what we found */
722
723 spr = (inst >> (31 - 20)) & 0x3FF; /* Get the source */
724 spr = ((spr << 5) & 0x3E0) | ((spr >> 5) & 0x1F); /* Flip to right order */
725
726 word = spr >> 5; /* Get word index into table */
727 bito = spr & 0x1F; /* Get bit offset into entry */
728 bit = 0x80000000 >> bito; /* Position bit for a test */
729
730 if(!(sprtbl[word] & bit)) return (diINV); /* Bogus SPR so whole instruction is invalid... */
731
732 if(spr & 0x10) return (diPRV); /* This is a priviliged SPR so instruction is priviliged... */
733 return (diCMN); /* Just a common SPR so instruction is the same... */
734}