Home | History | Annotate | Line # | Download | only in arm
      1  1.5    simonb /*	$NetBSD: dtrace_subr.c,v 1.5 2021/04/06 12:48:59 simonb Exp $	*/
      2  1.2     ozaki 
      3  1.1  christos /*
      4  1.1  christos  * CDDL HEADER START
      5  1.1  christos  *
      6  1.1  christos  * The contents of this file are subject to the terms of the
      7  1.1  christos  * Common Development and Distribution License, Version 1.0 only
      8  1.1  christos  * (the "License").  You may not use this file except in compliance
      9  1.1  christos  * with the License.
     10  1.1  christos  *
     11  1.1  christos  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     12  1.1  christos  * or http://www.opensolaris.org/os/licensing.
     13  1.1  christos  * See the License for the specific language governing permissions
     14  1.1  christos  * and limitations under the License.
     15  1.1  christos  *
     16  1.1  christos  * When distributing Covered Code, include this CDDL HEADER in each
     17  1.1  christos  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     18  1.1  christos  * If applicable, add the following below this CDDL HEADER, with the
     19  1.1  christos  * fields enclosed by brackets "[]" replaced with your own identifying
     20  1.1  christos  * information: Portions Copyright [yyyy] [name of copyright owner]
     21  1.1  christos  *
     22  1.1  christos  * CDDL HEADER END
     23  1.1  christos  *
     24  1.4       chs  * $FreeBSD: head/sys/cddl/dev/dtrace/arm/dtrace_subr.c 308457 2016-11-08 23:59:41Z bdrewery $
     25  1.1  christos  *
     26  1.1  christos  */
     27  1.1  christos /*
     28  1.1  christos  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     29  1.1  christos  * Use is subject to license terms.
     30  1.1  christos  */
     31  1.1  christos 
     32  1.1  christos #include <sys/param.h>
     33  1.1  christos #include <sys/systm.h>
     34  1.1  christos #include <sys/types.h>
     35  1.1  christos #include <sys/kernel.h>
     36  1.1  christos #include <sys/malloc.h>
     37  1.1  christos #include <sys/kmem.h>
     38  1.2     ozaki #include <sys/xcall.h>
     39  1.2     ozaki #include <sys/cpu.h>
     40  1.2     ozaki #include <sys/cpuvar.h>
     41  1.1  christos #include <sys/dtrace_impl.h>
     42  1.1  christos #include <sys/dtrace_bsd.h>
     43  1.2     ozaki #include <machine/cpu.h>
     44  1.1  christos #include <machine/frame.h>
     45  1.2     ozaki #include <machine/vmparam.h>
     46  1.2     ozaki #include <uvm/uvm_pglist.h>
     47  1.2     ozaki #include <uvm/uvm_prot.h>
     48  1.2     ozaki #include <uvm/uvm_pmap.h>
     49  1.1  christos 
     50  1.4       chs #define FAULT_ALIGN	FAULT_ALIGN_0
     51  1.2     ozaki extern uintptr_t 	kernelbase;
     52  1.1  christos extern uintptr_t 	dtrace_in_probe_addr;
     53  1.1  christos extern int		dtrace_in_probe;
     54  1.4       chs 
     55  1.4       chs void dtrace_gethrtime_init(void *arg);
     56  1.4       chs 
     57  1.4       chs #define	DELAYBRANCH(x)	((int)(x) < 0)
     58  1.4       chs 
     59  1.4       chs #define	BIT_PC		15
     60  1.4       chs #define	BIT_LR		14
     61  1.4       chs #define	BIT_SP		13
     62  1.4       chs 
     63  1.1  christos extern dtrace_id_t	dtrace_probeid_error;
     64  1.4       chs extern int (*dtrace_invop_jump_addr)(struct trapframe *);
     65  1.4       chs extern void dtrace_getnanotime(struct timespec *tsp);
     66  1.1  christos 
     67  1.3       chs int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
     68  1.4       chs void dtrace_invop_init(void);
     69  1.4       chs void dtrace_invop_uninit(void);
     70  1.1  christos 
     71  1.1  christos typedef struct dtrace_invop_hdlr {
     72  1.3       chs 	int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
     73  1.1  christos 	struct dtrace_invop_hdlr *dtih_next;
     74  1.1  christos } dtrace_invop_hdlr_t;
     75  1.1  christos 
     76  1.1  christos dtrace_invop_hdlr_t *dtrace_invop_hdlr;
     77  1.1  christos 
     78  1.1  christos int
     79  1.3       chs dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
     80  1.1  christos {
     81  1.1  christos 	dtrace_invop_hdlr_t *hdlr;
     82  1.1  christos 	int rval;
     83  1.1  christos 
     84  1.1  christos 	for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
     85  1.3       chs 		if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
     86  1.1  christos 			return (rval);
     87  1.1  christos 
     88  1.1  christos 	return (0);
     89  1.1  christos }
     90  1.1  christos 
     91  1.4       chs 
     92  1.2     ozaki void
     93  1.3       chs dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
     94  1.2     ozaki {
     95  1.2     ozaki 	dtrace_invop_hdlr_t *hdlr;
     96  1.2     ozaki 
     97  1.5    simonb 	hdlr = kmem_alloc(sizeof(*hdlr), KM_SLEEP);
     98  1.2     ozaki 	hdlr->dtih_func = func;
     99  1.2     ozaki 	hdlr->dtih_next = dtrace_invop_hdlr;
    100  1.2     ozaki 	dtrace_invop_hdlr = hdlr;
    101  1.2     ozaki }
    102  1.2     ozaki 
    103  1.2     ozaki void
    104  1.3       chs dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
    105  1.2     ozaki {
    106  1.2     ozaki 	dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
    107  1.2     ozaki 
    108  1.2     ozaki 	for (;;) {
    109  1.2     ozaki 		if (hdlr == NULL)
    110  1.2     ozaki 			panic("attempt to remove non-existent invop handler");
    111  1.2     ozaki 
    112  1.2     ozaki 		if (hdlr->dtih_func == func)
    113  1.2     ozaki 			break;
    114  1.2     ozaki 
    115  1.2     ozaki 		prev = hdlr;
    116  1.2     ozaki 		hdlr = hdlr->dtih_next;
    117  1.2     ozaki 	}
    118  1.2     ozaki 
    119  1.2     ozaki 	if (prev == NULL) {
    120  1.2     ozaki 		ASSERT(dtrace_invop_hdlr == hdlr);
    121  1.2     ozaki 		dtrace_invop_hdlr = hdlr->dtih_next;
    122  1.2     ozaki 	} else {
    123  1.2     ozaki 		ASSERT(dtrace_invop_hdlr != hdlr);
    124  1.2     ozaki 		prev->dtih_next = hdlr->dtih_next;
    125  1.2     ozaki 	}
    126  1.2     ozaki 
    127  1.5    simonb 	kmem_free(hdlr, sizeof(*hdlr));
    128  1.2     ozaki }
    129  1.1  christos 
    130  1.4       chs /*ARGSUSED*/
    131  1.1  christos void
    132  1.1  christos dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
    133  1.1  christos {
    134  1.2     ozaki 	(*func)(0, kernelbase);
    135  1.2     ozaki }
    136  1.2     ozaki 
    137  1.2     ozaki static void
    138  1.2     ozaki xcall_func(void *arg0, void *arg1)
    139  1.2     ozaki {
    140  1.2     ozaki     	dtrace_xcall_t func = arg0;
    141  1.2     ozaki 
    142  1.2     ozaki     	(*func)(arg1);
    143  1.1  christos }
    144  1.1  christos 
    145  1.1  christos void
    146  1.1  christos dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
    147  1.1  christos {
    148  1.2     ozaki 	uint64_t where;
    149  1.1  christos 
    150  1.2     ozaki 	if (cpu == DTRACE_CPUALL) {
    151  1.2     ozaki 		where = xc_broadcast(0, xcall_func, func, arg);
    152  1.2     ozaki 	} else {
    153  1.2     ozaki 		struct cpu_info *cinfo = cpu_lookup(cpu);
    154  1.1  christos 
    155  1.2     ozaki 		KASSERT(cinfo != NULL);
    156  1.2     ozaki 		where = xc_unicast(0, xcall_func, func, arg, cinfo);
    157  1.2     ozaki 	}
    158  1.2     ozaki 	xc_wait(where);
    159  1.2     ozaki 
    160  1.2     ozaki 	/* XXX Q. Do we really need the other cpus to wait also?
    161  1.2     ozaki 	 * (see solaris:xc_sync())
    162  1.2     ozaki 	 */
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos static void
    166  1.1  christos dtrace_sync_func(void)
    167  1.1  christos {
    168  1.1  christos }
    169  1.1  christos 
    170  1.1  christos void
    171  1.1  christos dtrace_sync(void)
    172  1.1  christos {
    173  1.4       chs 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
    174  1.1  christos }
    175  1.1  christos 
    176  1.1  christos /*
    177  1.1  christos  * DTrace needs a high resolution time function which can
    178  1.1  christos  * be called from a probe context and guaranteed not to have
    179  1.1  christos  * instrumented with probes itself.
    180  1.1  christos  *
    181  1.1  christos  * Returns nanoseconds since boot.
    182  1.1  christos  */
    183  1.1  christos uint64_t
    184  1.4       chs dtrace_gethrtime(void)
    185  1.1  christos {
    186  1.4       chs 	struct	timespec curtime;
    187  1.1  christos 
    188  1.1  christos 	nanouptime(&curtime);
    189  1.1  christos 
    190  1.1  christos 	return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
    191  1.1  christos }
    192  1.1  christos 
    193  1.1  christos uint64_t
    194  1.1  christos dtrace_gethrestime(void)
    195  1.1  christos {
    196  1.4       chs 	struct timespec current_time;
    197  1.1  christos 
    198  1.4       chs 	dtrace_getnanotime(&current_time);
    199  1.1  christos 
    200  1.4       chs 	return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec);
    201  1.1  christos }
    202  1.1  christos 
    203  1.2     ozaki /* Function to handle DTrace traps during probes. Not used on ARM yet */
    204  1.1  christos int
    205  1.1  christos dtrace_trap(struct trapframe *frame, u_int type)
    206  1.1  christos {
    207  1.4       chs 	cpuid_t curcpu_id = cpu_number();	/* current cpu id */
    208  1.2     ozaki 
    209  1.1  christos 	/*
    210  1.1  christos 	 * A trap can occur while DTrace executes a probe. Before
    211  1.1  christos 	 * executing the probe, DTrace blocks re-scheduling and sets
    212  1.4       chs 	 * a flag in its per-cpu flags to indicate that it doesn't
    213  1.1  christos 	 * want to fault. On returning from the probe, the no-fault
    214  1.1  christos 	 * flag is cleared and finally re-scheduling is enabled.
    215  1.1  christos 	 *
    216  1.1  christos 	 * Check if DTrace has enabled 'no-fault' mode:
    217  1.1  christos 	 *
    218  1.1  christos 	 */
    219  1.2     ozaki 
    220  1.4       chs 	if ((cpu_core[curcpu_id].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
    221  1.1  christos 		/*
    222  1.1  christos 		 * There are only a couple of trap types that are expected.
    223  1.1  christos 		 * All the rest will be handled in the usual way.
    224  1.1  christos 		 */
    225  1.1  christos 		switch (type) {
    226  1.1  christos 		/* Page fault. */
    227  1.4       chs 		case FAULT_ALIGN:
    228  1.1  christos 			/* Flag a bad address. */
    229  1.4       chs 			cpu_core[curcpu_id].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
    230  1.4       chs 			cpu_core[curcpu_id].cpuc_dtrace_illval = 0;
    231  1.1  christos 
    232  1.1  christos 			/*
    233  1.1  christos 			 * Offset the instruction pointer to the instruction
    234  1.1  christos 			 * following the one causing the fault.
    235  1.1  christos 			 */
    236  1.4       chs 			frame->tf_pc += sizeof(int);
    237  1.1  christos 			return (1);
    238  1.1  christos 		default:
    239  1.1  christos 			/* Handle all other traps in the usual way. */
    240  1.1  christos 			break;
    241  1.1  christos 		}
    242  1.1  christos 	}
    243  1.1  christos 
    244  1.1  christos 	/* Handle the trap in the usual way. */
    245  1.1  christos 	return (0);
    246  1.1  christos }
    247  1.1  christos 
    248  1.1  christos void
    249  1.1  christos dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
    250  1.1  christos     int fault, int fltoffs, uintptr_t illval)
    251  1.1  christos {
    252  1.1  christos 
    253  1.1  christos 	dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
    254  1.1  christos 	    (uintptr_t)epid,
    255  1.1  christos 	    (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
    256  1.1  christos }
    257  1.2     ozaki 
    258  1.2     ozaki void
    259  1.2     ozaki dtrace_gethrtime_init(void *arg)
    260  1.2     ozaki {
    261  1.2     ozaki 	/* FIXME */
    262  1.2     ozaki }
    263  1.4       chs 
    264  1.4       chs static uint32_t
    265  1.4       chs dtrace_expand_imm(uint32_t imm12)
    266  1.4       chs {
    267  1.4       chs 	uint32_t unrot = imm12 & 0xff;
    268  1.4       chs 	int amount = 2 * (imm12 >> 8);
    269  1.4       chs 
    270  1.4       chs 	if (amount)
    271  1.4       chs 		return (unrot >> amount) | (unrot << (32 - amount));
    272  1.4       chs 	else
    273  1.4       chs 		return unrot;
    274  1.4       chs }
    275  1.4       chs 
    276  1.4       chs static uint32_t
    277  1.4       chs dtrace_add_with_carry(uint32_t x, uint32_t y, int carry_in,
    278  1.4       chs 	int *carry_out, int *overflow)
    279  1.4       chs {
    280  1.4       chs 	uint32_t result;
    281  1.4       chs 	uint64_t unsigned_sum = x + y + (uint32_t)carry_in;
    282  1.4       chs 	int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
    283  1.4       chs 	KASSERT(carry_in == 1);
    284  1.4       chs 
    285  1.4       chs 	result = (uint32_t)(unsigned_sum & 0xffffffff);
    286  1.4       chs 	*carry_out = ((uint64_t)result == unsigned_sum) ? 1 : 0;
    287  1.4       chs 	*overflow = ((int64_t)result == signed_sum) ? 0 : 1;
    288  1.4       chs 
    289  1.4       chs 	return result;
    290  1.4       chs }
    291  1.4       chs 
    292  1.4       chs static void
    293  1.4       chs dtrace_invop_emulate(int invop, struct trapframe *frame)
    294  1.4       chs {
    295  1.4       chs 	uint32_t op = invop;
    296  1.4       chs #if 1
    297  1.4       chs 	/* nbsd encoding */
    298  1.4       chs 	uint32_t code = op >> 28;
    299  1.4       chs 	uint32_t data = op;
    300  1.4       chs #else
    301  1.4       chs 	/* fbsd encoding */
    302  1.4       chs 	uint32_t code = op & DTRACE_INVOP_MASK;
    303  1.4       chs 	uint32_t data = DTRACE_INVOP_DATA(invop);
    304  1.4       chs #endif
    305  1.4       chs 
    306  1.4       chs 	switch (code) {
    307  1.4       chs 	case DTRACE_INVOP_MOV_IP_SP:
    308  1.4       chs 		/* mov ip, sp */
    309  1.4       chs 		frame->tf_ip = frame->tf_svc_sp;
    310  1.4       chs 		frame->tf_pc += 4;
    311  1.4       chs 		break;
    312  1.4       chs 	case DTRACE_INVOP_BX_LR:
    313  1.4       chs 		/* bx lr */
    314  1.4       chs 		frame->tf_pc = frame->tf_svc_lr;
    315  1.4       chs 		break;
    316  1.4       chs 	case DTRACE_INVOP_MOV_PC_LR:
    317  1.4       chs 		/* mov pc, lr */
    318  1.4       chs 		frame->tf_pc = frame->tf_svc_lr;
    319  1.4       chs 		break;
    320  1.4       chs 	case DTRACE_INVOP_LDM:
    321  1.4       chs 		/* ldm sp, {..., pc} */
    322  1.4       chs 		/* FALLTHRU */
    323  1.4       chs 	case DTRACE_INVOP_POPM: {
    324  1.4       chs 		/* ldmib sp, {..., pc} */
    325  1.4       chs 		uint32_t register_list = (op & 0xffff);
    326  1.4       chs 		uint32_t *sp = (uint32_t *)(intptr_t)frame->tf_svc_sp;
    327  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    328  1.4       chs 		int i;
    329  1.4       chs 
    330  1.4       chs 		/* POPM */
    331  1.4       chs 		if (code == DTRACE_INVOP_POPM)
    332  1.4       chs 			sp++;
    333  1.4       chs 
    334  1.4       chs 		for (i = 0; i <= 12; i++) {
    335  1.4       chs 			if (register_list & (1 << i))
    336  1.4       chs 				regs[i] = *sp++;
    337  1.4       chs 		}
    338  1.4       chs 		if (register_list & (1 << 13))
    339  1.4       chs 			frame->tf_svc_sp = *sp++;
    340  1.4       chs 		if (register_list & (1 << 14))
    341  1.4       chs 			frame->tf_svc_lr = *sp++;
    342  1.4       chs 		frame->tf_pc = *sp;
    343  1.4       chs 		break;
    344  1.4       chs 	}
    345  1.4       chs 	case DTRACE_INVOP_LDR_IMM: {
    346  1.4       chs 		/* ldr r?, [{pc,r?}, #?] */
    347  1.4       chs 		uint32_t rt = (op >> 12) & 0xf;
    348  1.4       chs 		uint32_t rn = (op >> 16) & 0xf;
    349  1.4       chs 		uint32_t imm = op & 0xfff;
    350  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    351  1.4       chs 		KDASSERT(rt <= 12);
    352  1.4       chs 		KDASSERT(rn == 15 || rn <= 12);
    353  1.4       chs 		if (rn == 15)
    354  1.4       chs 			regs[rt] = *((uint32_t *)(intptr_t)(frame->tf_pc + 8 + imm));
    355  1.4       chs 		else
    356  1.4       chs 			regs[rt] = *((uint32_t *)(intptr_t)(regs[rn] + imm));
    357  1.4       chs 		frame->tf_pc += 4;
    358  1.4       chs 		break;
    359  1.4       chs 	}
    360  1.4       chs 	case DTRACE_INVOP_MOVW: {
    361  1.4       chs 		/* movw r?, #? */
    362  1.4       chs 		uint32_t rd = (op >> 12) & 0xf;
    363  1.4       chs 		uint32_t imm = (op & 0xfff) | ((op & 0xf0000) >> 4);
    364  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    365  1.4       chs 		KDASSERT(rd <= 12);
    366  1.4       chs 		regs[rd] = imm;
    367  1.4       chs 		frame->tf_pc += 4;
    368  1.4       chs 		break;
    369  1.4       chs 	}
    370  1.4       chs 	case DTRACE_INVOP_MOV_IMM: {
    371  1.4       chs 		/* mov r?, #? */
    372  1.4       chs 		uint32_t rd = (op >> 12) & 0xf;
    373  1.4       chs 		uint32_t imm = dtrace_expand_imm(op & 0xfff);
    374  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    375  1.4       chs 		KDASSERT(rd <= 12);
    376  1.4       chs 		regs[rd] = imm;
    377  1.4       chs 		frame->tf_pc += 4;
    378  1.4       chs 		break;
    379  1.4       chs 	}
    380  1.4       chs 	case DTRACE_INVOP_CMP_IMM: {
    381  1.4       chs 		/* cmp r?, #? */
    382  1.4       chs 		uint32_t rn = (op >> 16) & 0xf;
    383  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    384  1.4       chs 		uint32_t imm = dtrace_expand_imm(op & 0xfff);
    385  1.4       chs 		uint32_t spsr = frame->tf_spsr;
    386  1.4       chs 		uint32_t result;
    387  1.4       chs 		int carry;
    388  1.4       chs 		int overflow;
    389  1.4       chs 		/*
    390  1.4       chs 		 * (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), 1);
    391  1.4       chs 		 * APSR.N = result<31>;
    392  1.4       chs 		 * APSR.Z = IsZeroBit(result);
    393  1.4       chs 		 * APSR.C = carry;
    394  1.4       chs 		 * APSR.V = overflow;
    395  1.4       chs 		 */
    396  1.4       chs 		KDASSERT(rn <= 12);
    397  1.4       chs 		result = dtrace_add_with_carry(regs[rn], ~imm, 1, &carry, &overflow);
    398  1.4       chs 		if (result & 0x80000000)
    399  1.4       chs 			spsr |= PSR_N_bit;
    400  1.4       chs 		else
    401  1.4       chs 			spsr &= ~PSR_N_bit;
    402  1.4       chs 		if (result == 0)
    403  1.4       chs 			spsr |= PSR_Z_bit;
    404  1.4       chs 		else
    405  1.4       chs 			spsr &= ~PSR_Z_bit;
    406  1.4       chs 		if (carry)
    407  1.4       chs 			spsr |= PSR_C_bit;
    408  1.4       chs 		else
    409  1.4       chs 			spsr &= ~PSR_C_bit;
    410  1.4       chs 		if (overflow)
    411  1.4       chs 			spsr |= PSR_V_bit;
    412  1.4       chs 		else
    413  1.4       chs 			spsr &= ~PSR_V_bit;
    414  1.4       chs 
    415  1.4       chs #if 0
    416  1.4       chs 		aprint_normal("pc=%x Rn=%x imm=%x %c%c%c%c\n", frame->tf_pc, regs[rn], imm,
    417  1.4       chs 		    (spsr & PSR_N_bit) ? 'N' : 'n',
    418  1.4       chs 		    (spsr & PSR_Z_bit) ? 'Z' : 'z',
    419  1.4       chs 		    (spsr & PSR_C_bit) ? 'C' : 'c',
    420  1.4       chs 		    (spsr & PSR_V_bit) ? 'V' : 'v');
    421  1.4       chs #endif
    422  1.4       chs 		frame->tf_spsr = spsr;
    423  1.4       chs 		frame->tf_pc += 4;
    424  1.4       chs 		break;
    425  1.4       chs 	}
    426  1.4       chs 	case DTRACE_INVOP_B: {
    427  1.4       chs 		/* b ??? */
    428  1.4       chs 		uint32_t imm = (op & 0x00ffffff) << 2;
    429  1.4       chs 		int32_t diff;
    430  1.4       chs 		/* SignExtend(imm26, 32) */
    431  1.4       chs 		if (imm & 0x02000000)
    432  1.4       chs 			imm |= 0xfc000000;
    433  1.4       chs 		diff = (int32_t)imm;
    434  1.4       chs 		frame->tf_pc += 8 + diff;
    435  1.4       chs 		break;
    436  1.4       chs 	}
    437  1.4       chs 	case DTRACE_INVOP_PUSHM: {
    438  1.4       chs 		/* push {...} */
    439  1.4       chs 		uint32_t register_list = (op & 0xffff);
    440  1.4       chs 		uint32_t *sp = (uint32_t *)(intptr_t)frame->tf_svc_sp;
    441  1.4       chs 		uint32_t *regs = &frame->tf_r0;
    442  1.4       chs 		int i;
    443  1.4       chs 		int count = 0;
    444  1.4       chs 
    445  1.4       chs #if 0
    446  1.4       chs 		if ((op & 0x0fff0fff) == 0x052d0004) {
    447  1.4       chs 			/* A2: str r4, [sp, #-4]! */
    448  1.4       chs 			*(sp - 1) = regs[4];
    449  1.4       chs 			frame->tf_pc += 4;
    450  1.4       chs 			break;
    451  1.4       chs 		}
    452  1.4       chs #endif
    453  1.4       chs 
    454  1.4       chs 		for (i = 0; i < 16; i++) {
    455  1.4       chs 			if (register_list & (1 << i))
    456  1.4       chs 				count++;
    457  1.4       chs 		}
    458  1.4       chs 		sp -= count;
    459  1.4       chs 
    460  1.4       chs 		for (i = 0; i <= 12; i++) {
    461  1.4       chs 			if (register_list & (1 << i))
    462  1.4       chs 				*sp++ = regs[i];
    463  1.4       chs 		}
    464  1.4       chs 		if (register_list & (1 << 13))
    465  1.4       chs 			*sp++ = frame->tf_svc_sp;
    466  1.4       chs 		if (register_list & (1 << 14))
    467  1.4       chs 			*sp++ = frame->tf_svc_lr;
    468  1.4       chs 		if (register_list & (1 << 15))
    469  1.4       chs 			*sp = frame->tf_pc + 8;
    470  1.4       chs 
    471  1.4       chs 		/* make sure the caches and memory are in sync */
    472  1.4       chs 		cpu_dcache_wbinv_range(frame->tf_svc_sp, count * 4);
    473  1.4       chs 
    474  1.4       chs 		/* In case the current page tables have been modified ... */
    475  1.4       chs 		cpu_tlb_flushID();
    476  1.4       chs 		cpu_cpwait();
    477  1.4       chs 
    478  1.4       chs 		frame->tf_svc_sp -= count * 4;
    479  1.4       chs 		frame->tf_pc += 4;
    480  1.4       chs 
    481  1.4       chs 		break;
    482  1.4       chs 	}
    483  1.4       chs 	default:
    484  1.4       chs 		KDASSERTMSG(0, "invop 0x%08x code %u tf %p", invop, code, frame);
    485  1.4       chs 	}
    486  1.4       chs }
    487  1.4       chs 
    488  1.4       chs static int
    489  1.4       chs dtrace_invop_start(struct trapframe *frame)
    490  1.4       chs {
    491  1.4       chs #if 0
    492  1.4       chs 	register_t *r0, *sp;
    493  1.4       chs 	int data, invop, reg, update_sp;
    494  1.4       chs #endif
    495  1.4       chs 	int invop;
    496  1.4       chs 
    497  1.4       chs 	invop = dtrace_invop(frame->tf_pc, frame, frame->tf_r0);
    498  1.4       chs 
    499  1.4       chs 	dtrace_invop_emulate(invop, frame);
    500  1.4       chs 
    501  1.4       chs #if 0
    502  1.4       chs 	switch (invop & DTRACE_INVOP_MASK) {
    503  1.4       chs 	case DTRACE_INVOP_PUSHM:
    504  1.4       chs 		sp = (register_t *)frame->tf_svc_sp;
    505  1.4       chs 		r0 = &frame->tf_r0;
    506  1.4       chs 		data = DTRACE_INVOP_DATA(invop);
    507  1.4       chs 
    508  1.4       chs 		/*
    509  1.4       chs 		 * Store the pc, lr, and sp. These have their own
    510  1.4       chs 		 * entries in the struct.
    511  1.4       chs 		 */
    512  1.4       chs 		if (data & (1 << BIT_PC)) {
    513  1.4       chs 			sp--;
    514  1.4       chs 			*sp = frame->tf_pc;
    515  1.4       chs 		}
    516  1.4       chs 		if (data & (1 << BIT_LR)) {
    517  1.4       chs 			sp--;
    518  1.4       chs 			*sp = frame->tf_svc_lr;
    519  1.4       chs 		}
    520  1.4       chs 		if (data & (1 << BIT_SP)) {
    521  1.4       chs 			sp--;
    522  1.4       chs 			*sp = frame->tf_svc_sp;
    523  1.4       chs 		}
    524  1.4       chs 
    525  1.4       chs 		/* Store the general registers */
    526  1.4       chs 		for (reg = 12; reg >= 0; reg--) {
    527  1.4       chs 			if (data & (1 << reg)) {
    528  1.4       chs 				sp--;
    529  1.4       chs 				*sp = r0[reg];
    530  1.4       chs 			}
    531  1.4       chs 		}
    532  1.4       chs 
    533  1.4       chs 		/* Update the stack pointer and program counter to continue */
    534  1.4       chs 		frame->tf_svc_sp = (register_t)sp;
    535  1.4       chs 		frame->tf_pc += 4;
    536  1.4       chs 		break;
    537  1.4       chs 	case DTRACE_INVOP_POPM:
    538  1.4       chs 		sp = (register_t *)frame->tf_svc_sp;
    539  1.4       chs 		r0 = &frame->tf_r0;
    540  1.4       chs 		data = DTRACE_INVOP_DATA(invop);
    541  1.4       chs 
    542  1.4       chs 		/* Read the general registers */
    543  1.4       chs 		for (reg = 0; reg <= 12; reg++) {
    544  1.4       chs 			if (data & (1 << reg)) {
    545  1.4       chs 				r0[reg] = *sp;
    546  1.4       chs 				sp++;
    547  1.4       chs 			}
    548  1.4       chs 		}
    549  1.4       chs 
    550  1.4       chs 		/*
    551  1.4       chs 		 * Set the stack pointer. If we don't update it here we will
    552  1.4       chs 		 * need to update it at the end as the instruction would do
    553  1.4       chs 		 */
    554  1.4       chs 		update_sp = 1;
    555  1.4       chs 		if (data & (1 << BIT_SP)) {
    556  1.4       chs 			frame->tf_svc_sp = *sp;
    557  1.4       chs 			*sp++;
    558  1.4       chs 			update_sp = 0;
    559  1.4       chs 		}
    560  1.4       chs 
    561  1.4       chs 		/* Update the link register, we need to use the correct copy */
    562  1.4       chs 		if (data & (1 << BIT_LR)) {
    563  1.4       chs 			frame->tf_svc_lr = *sp;
    564  1.4       chs 			*sp++;
    565  1.4       chs 		}
    566  1.4       chs 		/*
    567  1.4       chs 		 * And the program counter. If it's not in the list skip over
    568  1.4       chs 		 * it when we return so to not hit this again.
    569  1.4       chs 		 */
    570  1.4       chs 		if (data & (1 << BIT_PC)) {
    571  1.4       chs 			frame->tf_pc = *sp;
    572  1.4       chs 			*sp++;
    573  1.4       chs 		} else
    574  1.4       chs 			frame->tf_pc += 4;
    575  1.4       chs 
    576  1.4       chs 		/* Update the stack pointer if we haven't already done so */
    577  1.4       chs 		if (update_sp)
    578  1.4       chs 			frame->tf_svc_sp = (register_t)sp;
    579  1.4       chs 		break;
    580  1.4       chs 	case DTRACE_INVOP_B:
    581  1.4       chs 		data = DTRACE_INVOP_DATA(invop) & 0x00ffffff;
    582  1.4       chs 		/* Sign extend the data */
    583  1.4       chs 		if ((data & (1 << 23)) != 0)
    584  1.4       chs 			data |= 0xff000000;
    585  1.4       chs 		/* The data is the number of 4-byte words to change the pc */
    586  1.4       chs 		data *= 4;
    587  1.4       chs 		data += 8;
    588  1.4       chs 		frame->tf_pc += data;
    589  1.4       chs 		break;
    590  1.4       chs 
    591  1.4       chs 	default:
    592  1.4       chs 		return (-1);
    593  1.4       chs 		break;
    594  1.4       chs 	}
    595  1.4       chs #endif
    596  1.4       chs 
    597  1.4       chs 	return (0);
    598  1.4       chs }
    599  1.4       chs 
    600  1.4       chs void dtrace_invop_init(void)
    601  1.4       chs {
    602  1.4       chs 	dtrace_invop_jump_addr = dtrace_invop_start;
    603  1.4       chs }
    604  1.4       chs 
    605  1.4       chs void dtrace_invop_uninit(void)
    606  1.4       chs {
    607  1.4       chs 	dtrace_invop_jump_addr = 0;
    608  1.4       chs }
    609