xref: /freebsd-11-stable/sys/dev/hwpmc/hwpmc_mips.c (revision 4ab2e064d7950be84256d671a7ae93f87cc6aa36)
1 /*-
2  * Copyright (c) 2010, George V. Neville-Neil <gnn@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include "opt_hwpmc_hooks.h"
32 
33 #include <sys/param.h>
34 #include <sys/pmc.h>
35 #include <sys/pmckern.h>
36 #include <sys/systm.h>
37 
38 #include <machine/pmc_mdep.h>
39 #include <machine/md_var.h>
40 #include <machine/mips_opcode.h>
41 #include <machine/vmparam.h>
42 
43 int mips_npmcs;
44 
45 /*
46  * Per-processor information.
47  */
48 struct mips_cpu {
49 	struct pmc_hw	*pc_mipspmcs;
50 };
51 
52 static struct mips_cpu **mips_pcpu;
53 
54 #if defined(__mips_n64)
55 #	define	MIPS_IS_VALID_KERNELADDR(reg)	((((reg) & 3) == 0) && \
56 					((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
57 #else
58 #	define	MIPS_IS_VALID_KERNELADDR(reg)	((((reg) & 3) == 0) && \
59 					((vm_offset_t)(reg) >= MIPS_KSEG0_START))
60 #endif
61 
62 /*
63  * We need some reasonable default to prevent backtrace code
64  * from wandering too far
65  */
66 #define	MAX_FUNCTION_SIZE 0x10000
67 #define	MAX_PROLOGUE_SIZE 0x100
68 
69 static int
mips_allocate_pmc(int cpu,int ri,struct pmc * pm,const struct pmc_op_pmcallocate * a)70 mips_allocate_pmc(int cpu, int ri, struct pmc *pm,
71   const struct pmc_op_pmcallocate *a)
72 {
73 	enum pmc_event pe;
74 	uint32_t caps, config, counter;
75 	uint32_t event;
76 	int i;
77 
78 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
79 	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
80 	KASSERT(ri >= 0 && ri < mips_npmcs,
81 	    ("[mips,%d] illegal row index %d", __LINE__, ri));
82 
83 	caps = a->pm_caps;
84 	if (a->pm_class != mips_pmc_spec.ps_cpuclass)
85 		return (EINVAL);
86 	pe = a->pm_ev;
87 	counter = MIPS_CTR_ALL;
88 	event = 0;
89 	for (i = 0; i < mips_event_codes_size; i++) {
90 		if (mips_event_codes[i].pe_ev == pe) {
91 			event = mips_event_codes[i].pe_code;
92 			counter =  mips_event_codes[i].pe_counter;
93 			break;
94 		}
95 	}
96 
97 	if (i == mips_event_codes_size)
98 		return (EINVAL);
99 
100 	if ((counter != MIPS_CTR_ALL) && (counter != ri))
101 		return (EINVAL);
102 
103 	config = mips_get_perfctl(cpu, ri, event, caps);
104 
105 	pm->pm_md.pm_mips_evsel = config;
106 
107 	PMCDBG2(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri, config);
108 
109 	return 0;
110 }
111 
112 
113 static int
mips_read_pmc(int cpu,int ri,pmc_value_t * v)114 mips_read_pmc(int cpu, int ri, pmc_value_t *v)
115 {
116 	struct pmc *pm;
117 	pmc_value_t tmp;
118 
119 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
120 	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
121 	KASSERT(ri >= 0 && ri < mips_npmcs,
122 	    ("[mips,%d] illegal row index %d", __LINE__, ri));
123 
124 	pm  = mips_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
125 	tmp = mips_pmcn_read(ri);
126 	PMCDBG2(MDP,REA,2,"mips-read id=%d -> %jd", ri, tmp);
127 
128 	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
129 		*v = tmp - (1UL << (mips_pmc_spec.ps_counter_width - 1));
130 	else
131 		*v = tmp;
132 
133 	return 0;
134 }
135 
136 static int
mips_write_pmc(int cpu,int ri,pmc_value_t v)137 mips_write_pmc(int cpu, int ri, pmc_value_t v)
138 {
139 	struct pmc *pm;
140 
141 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
142 	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
143 	KASSERT(ri >= 0 && ri < mips_npmcs,
144 	    ("[mips,%d] illegal row-index %d", __LINE__, ri));
145 
146 	pm  = mips_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
147 
148 	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
149 		v = (1UL << (mips_pmc_spec.ps_counter_width - 1)) - v;
150 
151 	PMCDBG3(MDP,WRI,1,"mips-write cpu=%d ri=%d v=%jx", cpu, ri, v);
152 
153 	mips_pmcn_write(ri, v);
154 
155 	return 0;
156 }
157 
158 static int
mips_config_pmc(int cpu,int ri,struct pmc * pm)159 mips_config_pmc(int cpu, int ri, struct pmc *pm)
160 {
161 	struct pmc_hw *phw;
162 
163 	PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
164 
165 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
166 	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
167 	KASSERT(ri >= 0 && ri < mips_npmcs,
168 	    ("[mips,%d] illegal row-index %d", __LINE__, ri));
169 
170 	phw = &mips_pcpu[cpu]->pc_mipspmcs[ri];
171 
172 	KASSERT(pm == NULL || phw->phw_pmc == NULL,
173 	    ("[mips,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
174 	    __LINE__, pm, phw->phw_pmc));
175 
176 	phw->phw_pmc = pm;
177 
178 	return 0;
179 }
180 
181 static int
mips_start_pmc(int cpu,int ri)182 mips_start_pmc(int cpu, int ri)
183 {
184 	uint32_t config;
185         struct pmc *pm;
186         struct pmc_hw *phw;
187 
188 	phw    = &mips_pcpu[cpu]->pc_mipspmcs[ri];
189 	pm     = phw->phw_pmc;
190 	config = pm->pm_md.pm_mips_evsel;
191 
192 	/* Enable the PMC. */
193 	switch (ri) {
194 	case 0:
195 		mips_wr_perfcnt0(config);
196 		break;
197 	case 1:
198 		mips_wr_perfcnt2(config);
199 		break;
200 	default:
201 		break;
202 	}
203 
204 	return 0;
205 }
206 
207 static int
mips_stop_pmc(int cpu,int ri)208 mips_stop_pmc(int cpu, int ri)
209 {
210         struct pmc *pm;
211         struct pmc_hw *phw;
212 
213 	phw    = &mips_pcpu[cpu]->pc_mipspmcs[ri];
214 	pm     = phw->phw_pmc;
215 
216 	/*
217 	 * Disable the PMCs.
218 	 *
219 	 * Clearing the entire register turns the counter off as well
220 	 * as removes the previously sampled event.
221 	 */
222 	switch (ri) {
223 	case 0:
224 		mips_wr_perfcnt0(0);
225 		break;
226 	case 1:
227 		mips_wr_perfcnt2(0);
228 		break;
229 	default:
230 		break;
231 	}
232 	return 0;
233 }
234 
235 static int
mips_release_pmc(int cpu,int ri,struct pmc * pmc)236 mips_release_pmc(int cpu, int ri, struct pmc *pmc)
237 {
238 	struct pmc_hw *phw;
239 
240 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
241 	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
242 	KASSERT(ri >= 0 && ri < mips_npmcs,
243 	    ("[mips,%d] illegal row-index %d", __LINE__, ri));
244 
245 	phw = &mips_pcpu[cpu]->pc_mipspmcs[ri];
246 	KASSERT(phw->phw_pmc == NULL,
247 	    ("[mips,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
248 
249 	return 0;
250 }
251 
252 static int
mips_pmc_intr(int cpu,struct trapframe * tf)253 mips_pmc_intr(int cpu, struct trapframe *tf)
254 {
255 	int error;
256 	int retval, ri;
257 	struct pmc *pm;
258 	struct mips_cpu *pc;
259 	uint32_t r0, r2;
260 	pmc_value_t r;
261 
262 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
263 	    ("[mips,%d] CPU %d out of range", __LINE__, cpu));
264 
265 	retval = 0;
266 	pc = mips_pcpu[cpu];
267 
268 	/* Stop PMCs without clearing the counter */
269 	r0 = mips_rd_perfcnt0();
270 	mips_wr_perfcnt0(r0 & ~(0x1f));
271 	r2 = mips_rd_perfcnt2();
272 	mips_wr_perfcnt2(r2 & ~(0x1f));
273 
274 	for (ri = 0; ri < mips_npmcs; ri++) {
275 		pm = mips_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
276 		if (pm == NULL)
277 			continue;
278 		if (! PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
279 			continue;
280 
281 		r = mips_pmcn_read(ri);
282 
283 		/* If bit 31 is set, the counter has overflowed */
284 		if ((r & (1UL << (mips_pmc_spec.ps_counter_width - 1))) == 0)
285 			continue;
286 
287 		retval = 1;
288 		if (pm->pm_state != PMC_STATE_RUNNING)
289 			continue;
290 		error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
291 		    TRAPF_USERMODE(tf));
292 		if (error) {
293 			/* Clear/disable the relevant counter */
294 			if (ri == 0)
295 				r0 = 0;
296 			else if (ri == 1)
297 				r2 = 0;
298 			mips_stop_pmc(cpu, ri);
299 		}
300 
301 		/* Reload sampling count */
302 		mips_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount);
303 	}
304 
305 	/*
306 	 * Re-enable the PMC counters where they left off.
307 	 *
308 	 * Any counter which overflowed will have its sample count
309 	 * reloaded in the loop above.
310 	 */
311 	mips_wr_perfcnt0(r0);
312 	mips_wr_perfcnt2(r2);
313 
314 	return retval;
315 }
316 
317 static int
mips_describe(int cpu,int ri,struct pmc_info * pi,struct pmc ** ppmc)318 mips_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
319 {
320 	int error;
321 	struct pmc_hw *phw;
322 	char mips_name[PMC_NAME_MAX];
323 
324 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
325 	    ("[mips,%d], illegal CPU %d", __LINE__, cpu));
326 	KASSERT(ri >= 0 && ri < mips_npmcs,
327 	    ("[mips,%d] row-index %d out of range", __LINE__, ri));
328 
329 	phw = &mips_pcpu[cpu]->pc_mipspmcs[ri];
330 	snprintf(mips_name, sizeof(mips_name), "MIPS-%d", ri);
331 	if ((error = copystr(mips_name, pi->pm_name, PMC_NAME_MAX,
332 	    NULL)) != 0)
333 		return error;
334 	pi->pm_class = mips_pmc_spec.ps_cpuclass;
335 	if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
336 		pi->pm_enabled = TRUE;
337 		*ppmc          = phw->phw_pmc;
338 	} else {
339 		pi->pm_enabled = FALSE;
340 		*ppmc	       = NULL;
341 	}
342 
343 	return (0);
344 }
345 
346 static int
mips_get_config(int cpu,int ri,struct pmc ** ppm)347 mips_get_config(int cpu, int ri, struct pmc **ppm)
348 {
349 	*ppm = mips_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
350 
351 	return 0;
352 }
353 
354 /*
355  * XXX don't know what we should do here.
356  */
357 static int
mips_pmc_switch_in(struct pmc_cpu * pc,struct pmc_process * pp)358 mips_pmc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
359 {
360 	return 0;
361 }
362 
363 static int
mips_pmc_switch_out(struct pmc_cpu * pc,struct pmc_process * pp)364 mips_pmc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
365 {
366 	return 0;
367 }
368 
369 static int
mips_pcpu_init(struct pmc_mdep * md,int cpu)370 mips_pcpu_init(struct pmc_mdep *md, int cpu)
371 {
372 	int first_ri, i;
373 	struct pmc_cpu *pc;
374 	struct mips_cpu *pac;
375 	struct pmc_hw  *phw;
376 
377 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
378 	    ("[mips,%d] wrong cpu number %d", __LINE__, cpu));
379 	PMCDBG1(MDP,INI,1,"mips-init cpu=%d", cpu);
380 
381 	mips_pcpu[cpu] = pac = malloc(sizeof(struct mips_cpu), M_PMC,
382 	    M_WAITOK|M_ZERO);
383 	pac->pc_mipspmcs = malloc(sizeof(struct pmc_hw) * mips_npmcs,
384 	    M_PMC, M_WAITOK|M_ZERO);
385 	pc = pmc_pcpu[cpu];
386 	first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS].pcd_ri;
387 	KASSERT(pc != NULL, ("[mips,%d] NULL per-cpu pointer", __LINE__));
388 
389 	for (i = 0, phw = pac->pc_mipspmcs; i < mips_npmcs; i++, phw++) {
390 		phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
391 		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
392 		phw->phw_pmc      = NULL;
393 		pc->pc_hwpmcs[i + first_ri] = phw;
394 	}
395 
396 	/*
397 	 * Clear the counter control register which has the effect
398 	 * of disabling counting.
399 	 */
400 	for (i = 0; i < mips_npmcs; i++)
401 		mips_pmcn_write(i, 0);
402 
403 	return 0;
404 }
405 
406 static int
mips_pcpu_fini(struct pmc_mdep * md,int cpu)407 mips_pcpu_fini(struct pmc_mdep *md, int cpu)
408 {
409 	return 0;
410 }
411 
412 struct pmc_mdep *
pmc_mips_initialize()413 pmc_mips_initialize()
414 {
415 	struct pmc_mdep *pmc_mdep;
416 	struct pmc_classdep *pcd;
417 
418 	/*
419 	 * TODO: Use More bit of PerfCntlX register to detect actual
420 	 * number of counters
421 	 */
422 	mips_npmcs = 2;
423 
424 	PMCDBG1(MDP,INI,1,"mips-init npmcs=%d", mips_npmcs);
425 
426 	/*
427 	 * Allocate space for pointers to PMC HW descriptors and for
428 	 * the MDEP structure used by MI code.
429 	 */
430 	mips_pcpu = malloc(sizeof(struct mips_cpu *) * pmc_cpu_max(), M_PMC,
431 			   M_WAITOK|M_ZERO);
432 
433 	/* Just one class */
434 	pmc_mdep = pmc_mdep_alloc(1);
435 
436 	pmc_mdep->pmd_cputype = mips_pmc_spec.ps_cputype;
437 
438 	pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS];
439 	pcd->pcd_caps  = mips_pmc_spec.ps_capabilities;
440 	pcd->pcd_class = mips_pmc_spec.ps_cpuclass;
441 	pcd->pcd_num   = mips_npmcs;
442 	pcd->pcd_ri    = pmc_mdep->pmd_npmc;
443 	pcd->pcd_width = mips_pmc_spec.ps_counter_width;
444 
445 	pcd->pcd_allocate_pmc   = mips_allocate_pmc;
446 	pcd->pcd_config_pmc     = mips_config_pmc;
447 	pcd->pcd_pcpu_fini      = mips_pcpu_fini;
448 	pcd->pcd_pcpu_init      = mips_pcpu_init;
449 	pcd->pcd_describe       = mips_describe;
450 	pcd->pcd_get_config	= mips_get_config;
451 	pcd->pcd_read_pmc       = mips_read_pmc;
452 	pcd->pcd_release_pmc    = mips_release_pmc;
453 	pcd->pcd_start_pmc      = mips_start_pmc;
454 	pcd->pcd_stop_pmc       = mips_stop_pmc;
455  	pcd->pcd_write_pmc      = mips_write_pmc;
456 
457 	pmc_mdep->pmd_intr       = mips_pmc_intr;
458 	pmc_mdep->pmd_switch_in  = mips_pmc_switch_in;
459 	pmc_mdep->pmd_switch_out = mips_pmc_switch_out;
460 
461 	pmc_mdep->pmd_npmc   += mips_npmcs;
462 
463 	return (pmc_mdep);
464 }
465 
466 void
pmc_mips_finalize(struct pmc_mdep * md)467 pmc_mips_finalize(struct pmc_mdep *md)
468 {
469 	(void) md;
470 }
471 
472 #ifdef	HWPMC_MIPS_BACKTRACE
473 
474 static int
pmc_next_frame(register_t * pc,register_t * sp)475 pmc_next_frame(register_t *pc, register_t *sp)
476 {
477 	InstFmt i;
478 	uintptr_t va;
479 	uint32_t instr, mask;
480 	int more, stksize;
481 	register_t ra = 0;
482 
483 	/* Jump here after a nonstandard (interrupt handler) frame */
484 	stksize = 0;
485 
486 	/* check for bad SP: could foul up next frame */
487 	if (!MIPS_IS_VALID_KERNELADDR(*sp)) {
488 		goto error;
489 	}
490 
491 	/* check for bad PC */
492 	if (!MIPS_IS_VALID_KERNELADDR(*pc)) {
493 		goto error;
494 	}
495 
496 	/*
497 	 * Find the beginning of the current subroutine by scanning
498 	 * backwards from the current PC for the end of the previous
499 	 * subroutine.
500 	 */
501 	va = *pc - sizeof(int);
502 	while (1) {
503 		instr = *((uint32_t *)va);
504 
505 		/* [d]addiu sp,sp,-X */
506 		if (((instr & 0xffff8000) == 0x27bd8000)
507 		    || ((instr & 0xffff8000) == 0x67bd8000))
508 			break;
509 
510 		/* jr	ra */
511 		if (instr == 0x03e00008) {
512 			/* skip over branch-delay slot instruction */
513 			va += 2 * sizeof(int);
514 			break;
515 		}
516 
517 		va -= sizeof(int);
518 	}
519 
520 	/* skip over nulls which might separate .o files */
521 	while ((instr = *((uint32_t *)va)) == 0)
522 		va += sizeof(int);
523 
524 	/* scan forwards to find stack size and any saved registers */
525 	stksize = 0;
526 	more = 3;
527 	mask = 0;
528 	for (; more; va += sizeof(int),
529 	    more = (more == 3) ? 3 : more - 1) {
530 		/* stop if hit our current position */
531 		if (va >= *pc)
532 			break;
533 		instr = *((uint32_t *)va);
534 		i.word = instr;
535 		switch (i.JType.op) {
536 		case OP_SPECIAL:
537 			switch (i.RType.func) {
538 			case OP_JR:
539 			case OP_JALR:
540 				more = 2;	/* stop after next instruction */
541 				break;
542 
543 			case OP_SYSCALL:
544 			case OP_BREAK:
545 				more = 1;	/* stop now */
546 			}
547 			break;
548 
549 		case OP_BCOND:
550 		case OP_J:
551 		case OP_JAL:
552 		case OP_BEQ:
553 		case OP_BNE:
554 		case OP_BLEZ:
555 		case OP_BGTZ:
556 			more = 2;	/* stop after next instruction */
557 			break;
558 
559 		case OP_COP0:
560 		case OP_COP1:
561 		case OP_COP2:
562 		case OP_COP3:
563 			switch (i.RType.rs) {
564 			case OP_BCx:
565 			case OP_BCy:
566 				more = 2;	/* stop after next instruction */
567 			}
568 			break;
569 
570 		case OP_SW:
571 		case OP_SD:
572 			/*
573 			 * SP is being saved using S8(FP). Most likely it indicates
574 			 * that SP is modified in the function and we can't get
575 			 * its value safely without emulating code backward
576 			 * So just bail out on functions like this
577 			 */
578 			if ((i.IType.rs == 30) && (i.IType.rt = 29))
579 				return (-1);
580 
581 			/* look for saved registers on the stack */
582 			if (i.IType.rs != 29)
583 				break;
584 			/* only restore the first one */
585 			if (mask & (1 << i.IType.rt))
586 				break;
587 			mask |= (1 << i.IType.rt);
588 			if (i.IType.rt == 31)
589 				ra = *((register_t *)(*sp + (short)i.IType.imm));
590 			break;
591 
592 		case OP_ADDI:
593 		case OP_ADDIU:
594 		case OP_DADDI:
595 		case OP_DADDIU:
596 			/* look for stack pointer adjustment */
597 			if (i.IType.rs != 29 || i.IType.rt != 29)
598 				break;
599 			stksize = -((short)i.IType.imm);
600 		}
601 	}
602 
603 	if (!MIPS_IS_VALID_KERNELADDR(ra))
604 		return (-1);
605 
606 	*pc = ra;
607 	*sp += stksize;
608 
609 	return (0);
610 
611 error:
612 	return (-1);
613 }
614 
615 static int
pmc_next_uframe(register_t * pc,register_t * sp,register_t * ra)616 pmc_next_uframe(register_t *pc, register_t *sp, register_t *ra)
617 {
618 	int offset, registers_on_stack;
619 	uint32_t opcode, mask;
620 	register_t function_start;
621 	int stksize;
622 	InstFmt i;
623 
624 	registers_on_stack = 0;
625 	mask = 0;
626 	function_start = 0;
627 	offset = 0;
628 	stksize = 0;
629 
630 	while (offset < MAX_FUNCTION_SIZE) {
631 		opcode = fuword32((void *)(*pc - offset));
632 
633 		/* [d]addiu sp, sp, -X*/
634 		if (((opcode & 0xffff8000) == 0x27bd8000)
635 		    || ((opcode & 0xffff8000) == 0x67bd8000)) {
636 			function_start = *pc - offset;
637 			registers_on_stack = 1;
638 			break;
639 		}
640 
641 		/* lui gp, X */
642 		if ((opcode & 0xffff8000) == 0x3c1c0000) {
643 			/*
644 			 * Function might start with this instruction
645 			 * Keep an eye on "jr ra" and sp correction
646 			 * with positive value further on
647 			 */
648 			function_start = *pc - offset;
649 		}
650 
651 		if (function_start) {
652 			/*
653 			 * Stop looking further. Possible end of
654 			 * function instruction: it means there is no
655 			 * stack modifications, sp is unchanged
656 			 */
657 
658 			/* [d]addiu sp,sp,X */
659 			if (((opcode & 0xffff8000) == 0x27bd0000)
660 			    || ((opcode & 0xffff8000) == 0x67bd0000))
661 				break;
662 
663 			if (opcode == 0x03e00008)
664 				break;
665 		}
666 
667 		offset += sizeof(int);
668 	}
669 
670 	if (!function_start)
671 		return (-1);
672 
673 	if (registers_on_stack) {
674 		offset = 0;
675 		while ((offset < MAX_PROLOGUE_SIZE)
676 		    && ((function_start + offset) < *pc)) {
677 			i.word = fuword32((void *)(function_start + offset));
678 			switch (i.JType.op) {
679 			case OP_SW:
680 				/* look for saved registers on the stack */
681 				if (i.IType.rs != 29)
682 					break;
683 				/* only restore the first one */
684 				if (mask & (1 << i.IType.rt))
685 					break;
686 				mask |= (1 << i.IType.rt);
687 				if (i.IType.rt == 31)
688 					*ra = fuword32((void *)(*sp + (short)i.IType.imm));
689 				break;
690 
691 #if defined(__mips_n64)
692 			case OP_SD:
693 				/* look for saved registers on the stack */
694 				if (i.IType.rs != 29)
695 					break;
696 				/* only restore the first one */
697 				if (mask & (1 << i.IType.rt))
698 					break;
699 				mask |= (1 << i.IType.rt);
700 				/* ra */
701 				if (i.IType.rt == 31)
702 					*ra = fuword64((void *)(*sp + (short)i.IType.imm));
703 			break;
704 #endif
705 
706 			case OP_ADDI:
707 			case OP_ADDIU:
708 			case OP_DADDI:
709 			case OP_DADDIU:
710 				/* look for stack pointer adjustment */
711 				if (i.IType.rs != 29 || i.IType.rt != 29)
712 					break;
713 				stksize = -((short)i.IType.imm);
714 			}
715 
716 			offset += sizeof(int);
717 		}
718 	}
719 
720 	/*
721 	 * We reached the end of backtrace
722 	 */
723 	if (*pc == *ra)
724 		return (-1);
725 
726 	*pc = *ra;
727 	*sp += stksize;
728 
729 	return (0);
730 }
731 
732 #endif /* HWPMC_MIPS_BACKTRACE */
733 
734 struct pmc_mdep *
pmc_md_initialize()735 pmc_md_initialize()
736 {
737 	return pmc_mips_initialize();
738 }
739 
740 void
pmc_md_finalize(struct pmc_mdep * md)741 pmc_md_finalize(struct pmc_mdep *md)
742 {
743 	return pmc_mips_finalize(md);
744 }
745 
746 int
pmc_save_kernel_callchain(uintptr_t * cc,int nframes,struct trapframe * tf)747 pmc_save_kernel_callchain(uintptr_t *cc, int nframes,
748     struct trapframe *tf)
749 {
750 	register_t pc, ra, sp;
751 	int frames = 0;
752 
753 	pc = tf->pc;
754 	sp = tf->sp;
755 	ra = tf->ra;
756 
757 	cc[frames++] = pc;
758 
759 #ifdef	HWPMC_MIPS_BACKTRACE
760 	/*
761 	 * Unwind, and unwind, and unwind
762 	 */
763 	while (1) {
764 		if (frames >= nframes)
765 			break;
766 
767 		if (pmc_next_frame(&pc, &sp) < 0)
768 			break;
769 
770 		cc[frames++] = pc;
771 	}
772 #endif
773 
774 	return (frames);
775 }
776 
777 int
pmc_save_user_callchain(uintptr_t * cc,int nframes,struct trapframe * tf)778 pmc_save_user_callchain(uintptr_t *cc, int nframes,
779     struct trapframe *tf)
780 {
781 	register_t pc, ra, sp;
782 	int frames = 0;
783 
784 	pc = tf->pc;
785 	sp = tf->sp;
786 	ra = tf->ra;
787 
788 	cc[frames++] = pc;
789 
790 #ifdef	HWPMC_MIPS_BACKTRACE
791 
792 	/*
793 	 * Unwind, and unwind, and unwind
794 	 */
795 	while (1) {
796 		if (frames >= nframes)
797 			break;
798 
799 		if (pmc_next_uframe(&pc, &sp, &ra) < 0)
800 			break;
801 
802 		cc[frames++] = pc;
803 	}
804 #endif
805 
806 	return (frames);
807 }
808