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(¤t_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