1/* 2 * Copyright (C) 2000 Silicon Graphics, Inc. 3 * 4 * Written by Ulf Carlsson (ulfc@engr.sgi.com) 5 */ 6 7#ifndef _ASM_KERNPROF_H 8#define _ASM_KERNPROF_H 9 10#ifdef __KERNEL__ 11 12#include <asm/system.h> 13#include <asm/ptrace.h> 14#include <asm/processor.h> 15 16#define DFL_PC_RES 4 /* default PC resolution for this platform */ 17 18#define in_firmware(regs) 0 /* never in the PROM during normal execution */ 19 20extern char stext; 21extern char _etext; 22extern int prof_freq[]; 23 24extern int setup_profiling_timer(unsigned int); 25 26typedef struct frame_info frame_info_t; 27 28struct frame_info { 29 unsigned long ra; 30 unsigned long pc; 31 unsigned long sp; 32 unsigned long top; 33}; 34 35#define frame_get_pc(p) ((p)->pc) 36 37/* 38 * A function tests up its stack frame with the instructions 39 * 40 * addiu $sp,$sp,-stacksize 41 * sw $ra,stacksize-8($sp) 42 * 43 * The timer interrupt may arrive at any time including right at the moment 44 * that the new frame is being set up, so we need to distinguish a few cases. 45 */ 46static __inline__ void get_top_frame(struct pt_regs *regs, frame_info_t *p) 47{ 48 unsigned long pc = regs->cp0_epc; 49 50 pc = regs->cp0_epc; 51 52#ifndef CONFIG_SMP 53 { 54 extern unsigned long kernelsp; 55 p->top = kernelsp; 56 } 57#else 58 { 59 unsigned int lo, hi; 60 lo = read_32bit_cp0_register(CP0_WATCHLO); 61 hi = read_32bit_cp0_register(CP0_WATCHHI); 62 p->top = ((unsigned long) hi << 32) | lo; 63 } 64#endif 65 66 do { 67 unsigned int inst = *(unsigned int *)pc; 68 /* First we look for a ``addiu $sp,$sp,...'' and then we look 69 for a ``jr $ra'' in case this is a leaf function without 70 stack frame. */ 71 if ((inst & 0xffff0000) == 0x27bd0000) { 72 p->sp = regs->regs[29] - (short) (inst & 0xffff); 73 p->ra = *((unsigned long *)p->sp - 1); 74 p->pc = regs->cp0_epc; 75 return; 76 } else if (inst == 0x03e00008) { 77 /* N32 says that routines aren't restricted to a single 78 exit block. In that case we lose. The thing is 79 that the .mdebug format doesn't handle that either 80 so we should be pretty safe. */ 81 p->sp = regs->regs[29]; 82 p->ra = regs->regs[31]; 83 p->pc = regs->cp0_epc; 84 } 85 } while (--pc > (unsigned long) &stext); 86 87 BUG(); 88} 89 90static unsigned long this_pc(void) 91{ 92 return (unsigned long)return_address(); 93} 94 95/* Fabricate a stack frame that is sufficient to begin walking up the stack */ 96static __inline__ int build_fake_frame(frame_info_t *p) 97{ 98#ifndef CONFIG_SMP 99 { 100 extern unsigned long kernelsp; 101 p->top = kernelsp; 102 } 103#else 104 { 105 unsigned int lo, hi; 106 lo = read_32bit_cp0_register(CP0_WATCHLO); 107 hi = read_32bit_cp0_register(CP0_WATCHHI); 108 p->top = ((unsigned long) hi << 32) | lo; 109 } 110#endif 111 __asm__ __volatile__("sw\t$29,%0\t\n" : "=m" (p->sp)); 112 p->pc = this_pc(); 113 return 1; 114} 115 116static __inline__ int last_frame(frame_info_t *p) 117{ 118 if (p->sp < (unsigned long) current + sizeof(*current)) 119 BUG(); 120 121 return (p->sp < p->top); 122} 123 124static __inline__ int get_next_frame(frame_info_t *p) 125{ 126 unsigned int *sp = (unsigned int *)p->sp; 127 unsigned int *pc = (unsigned int *)p->pc; 128 129 if (last_frame(p)) 130 return 0; 131 132 /* 133 * First, scan backwards to find the stack-decrement that signals the 134 * beginning of this routine in which we're inlined. That tells us 135 * how to roll back the stack. 136 */ 137 do { 138 unsigned int inst = *pc; 139 /* Look for a ``addiu $sp,$sp,...'' */ 140 if ((inst & 0xffff0000) == 0x27bd0000) { 141 p->sp = (unsigned long)sp - (short) (inst & 0xffff); 142 break; 143 } 144 } while (--pc > (unsigned int *)&stext); 145 146 if (pc == (unsigned int *)&stext) 147 return 0; 148 149 /* 150 * Now scan forwards to find the $ra-save, so we can decode the 151 * instruction and retrieve the return address from the stack. 152 */ 153 pc++; 154 do { 155 unsigned int inst = *pc; 156 /* Look for a ``sw $ra,NN($sp)'' */ 157 if ((inst & 0xffff0000) == 0xafbf0000) { 158 p->pc = *(unsigned long *)((unsigned long)sp + (short)(inst & 0xffff)); 159 return 1; 160 } 161 } while (++pc <= (unsigned int *)&_etext); 162 163 return 0; 164} 165 166#define supports_call_graph prof_have_mcount 167 168#define get_prof_freq() prof_freq[0] 169 170/* No performance counters for the time being */ 171 172#define have_perfctr() 0 173#define valid_perfctr_event(e) 0 174#define valid_perfctr_freq(n) 0 175#define perfctr_reload(x) 176#define __perfctr_stop() 177#define __perfctr_commence(x,y) 178 179#endif /* __KERNEL__ */ 180 181#endif /* !_ASM_KERNPROF_H */ 182