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