1/*- 2 * Copyright (c) 2005,2008 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h>
|
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 184205 2008-10-23 15:53:51Z des $");
|
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 184802 2008-11-09 17:37:54Z jkoshy $"); |
33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/pmc.h> 37#include <sys/proc.h> 38#include <sys/systm.h> 39 40#include <machine/cpu.h> 41#include <machine/apicreg.h> 42#include <machine/pmc_mdep.h> 43#include <machine/md_var.h> 44 45#include <vm/vm.h> 46#include <vm/vm_param.h> 47#include <vm/pmap.h> 48 49extern volatile lapic_t *lapic; 50 51void 52pmc_x86_lapic_enable_pmc_interrupt(void) 53{ 54 uint32_t value; 55 56 value = lapic->lvt_pcint; 57 value &= ~APIC_LVT_M; 58 lapic->lvt_pcint = value; 59} 60 61/* 62 * Attempt to walk a user call stack using a too-simple algorithm. 63 * In the general case we need unwind information associated with 64 * the executable to be able to walk the user stack. 65 * 66 * We are handed a trap frame laid down at the time the PMC interrupt 67 * was taken. If the application is using frame pointers, the saved 68 * PC value could be: 69 * a. at the beginning of a function before the stack frame is laid 70 * down, 71 * b. just before a 'ret', after the stack frame has been taken off, 72 * c. somewhere else in the function with a valid stack frame being 73 * present, 74 * 75 * If the application is not using frame pointers, this algorithm will 76 * fail to yield an interesting call chain. 77 * 78 * TODO: figure out a way to use unwind information. 79 */ 80 81int 82pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf) 83{ 84 int n; 85 uint32_t instr; 86 uintptr_t fp, oldfp, pc, r, sp; 87 88 KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p", 89 __LINE__, (void *) tf)); 90 91 pc = PMC_TRAPFRAME_TO_PC(tf); 92 oldfp = fp = PMC_TRAPFRAME_TO_FP(tf); 93 sp = PMC_TRAPFRAME_TO_USER_SP(tf); 94 95 *cc++ = pc; n = 1; 96 97 r = fp + sizeof(uintptr_t); /* points to return address */ 98 99 if (!PMC_IN_USERSPACE(pc)) 100 return (n); 101 102 if (copyin((void *) pc, &instr, sizeof(instr)) != 0) 103 return (n); 104 105 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) || 106 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) { /* ret */ 107 if (copyin((void *) sp, &pc, sizeof(pc)) != 0) 108 return (n); 109 } else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) { 110 sp += sizeof(uintptr_t); 111 if (copyin((void *) sp, &pc, sizeof(pc)) != 0) 112 return (n); 113 } else if (copyin((void *) r, &pc, sizeof(pc)) != 0 || 114 copyin((void *) fp, &fp, sizeof(fp) != 0)) 115 return (n); 116 117 for (; n < nframes;) { 118 if (pc == 0 || !PMC_IN_USERSPACE(pc)) 119 break; 120 121 *cc++ = pc; n++; 122 123 if (fp < oldfp) 124 break; 125 126 r = fp + sizeof(uintptr_t); /* address of return address */ 127 oldfp = fp; 128 129 if (copyin((void *) r, &pc, sizeof(pc)) != 0 || 130 copyin((void *) fp, &fp, sizeof(fp)) != 0) 131 break; 132 } 133 134 return (n); 135} 136 137/* 138 * Walking the kernel call stack. 139 * 140 * We are handed the trap frame laid down at the time the PMC 141 * interrupt was taken. The saved PC could be: 142 * a. in the lowlevel trap handler, meaning that there isn't a C stack 143 * to traverse, 144 * b. at the beginning of a function before the stack frame is laid 145 * down, 146 * c. just before a 'ret', after the stack frame has been taken off, 147 * d. somewhere else in a function with a valid stack frame being 148 * present. 149 * 150 * In case (d), the previous frame pointer is at [%ebp]/[%rbp] and 151 * the return address is at [%ebp+4]/[%rbp+8]. 152 * 153 * For cases (b) and (c), the return address is at [%esp]/[%rsp] and 154 * the frame pointer doesn't need to be changed when going up one 155 * level in the stack. 156 * 157 * For case (a), we check if the PC lies in low-level trap handling 158 * code, and if so we terminate our trace. 159 */ 160 161int 162pmc_save_kernel_callchain(uintptr_t *cc, int nframes, struct trapframe *tf) 163{ 164 int n; 165 uint32_t instr; 166 uintptr_t fp, pc, r, sp, stackstart, stackend; 167 struct thread *td; 168 169 KASSERT(TRAPF_USERMODE(tf) == 0,("[x86,%d] not a kernel backtrace", 170 __LINE__)); 171 172 pc = PMC_TRAPFRAME_TO_PC(tf); 173 fp = PMC_TRAPFRAME_TO_FP(tf); 174 sp = PMC_TRAPFRAME_TO_KERNEL_SP(tf); 175 176 *cc++ = pc; 177 r = fp + sizeof(uintptr_t); /* points to return address */ 178 179 if ((td = curthread) == NULL) 180 return (1); 181 182 if (nframes <= 1) 183 return (1); 184 185 stackstart = (uintptr_t) td->td_kstack; 186 stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE; 187 188 if (PMC_IN_TRAP_HANDLER(pc) || 189 !PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL(r) || 190 !PMC_IN_KERNEL_STACK(sp, stackstart, stackend) || 191 !PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) 192 return (1); 193 194 instr = *(uint32_t *) pc; 195 196 /* 197 * Determine whether the interrupted function was in the 198 * processing of either laying down its stack frame or taking 199 * it off. 200 * 201 * If we haven't started laying down a stack frame, or are 202 * just about to return, then our caller's address is at 203 * *sp, and we don't have a frame to unwind. 204 */ 205 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) || 206 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) 207 pc = *(uintptr_t *) sp; 208 else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) { 209 /* 210 * The code was midway through laying down a frame. 211 * At this point sp[0] has a frame back pointer, 212 * and the caller's address is therefore at sp[1]. 213 */ 214 sp += sizeof(uintptr_t); 215 if (!PMC_IN_KERNEL_STACK(sp, stackstart, stackend)) 216 return (1); 217 pc = *(uintptr_t *) sp; 218 } else { 219 /* 220 * Not in the function prologue or epilogue. 221 */ 222 pc = *(uintptr_t *) r; 223 fp = *(uintptr_t *) fp; 224 } 225 226 for (n = 1; n < nframes; n++) { 227 *cc++ = pc; 228 229 if (PMC_IN_TRAP_HANDLER(pc)) 230 break; 231 232 r = fp + sizeof(uintptr_t); 233 if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend) || 234 !PMC_IN_KERNEL(r)) 235 break; 236 pc = *(uintptr_t *) r; 237 fp = *(uintptr_t *) fp; 238 } 239 240 return (n); 241} 242
|
243static struct pmc_mdep *
244pmc_intel_initialize(void)
245{
246 struct pmc_mdep *pmc_mdep;
247 enum pmc_cputype cputype;
248 int error, model;
249
250 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
251 ("[intel,%d] Initializing non-intel processor", __LINE__));
252
253 PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
254
255 cputype = -1;
256
257 switch (cpu_id & 0xF00) {
258#if defined(__i386__)
259 case 0x500: /* Pentium family processors */
260 cputype = PMC_CPU_INTEL_P5;
261 break;
262 case 0x600: /* Pentium Pro, Celeron, Pentium II & III */
263 switch ((cpu_id & 0xF0) >> 4) { /* model number field */
264 case 0x1:
265 cputype = PMC_CPU_INTEL_P6;
266 break;
267 case 0x3: case 0x5:
268 cputype = PMC_CPU_INTEL_PII;
269 break;
270 case 0x6:
271 cputype = PMC_CPU_INTEL_CL;
272 break;
273 case 0x7: case 0x8: case 0xA: case 0xB:
274 cputype = PMC_CPU_INTEL_PIII;
275 break;
276 case 0x9: case 0xD:
277 cputype = PMC_CPU_INTEL_PM;
278 break;
279 }
280 break;
281#endif
282#if defined(__i386__) || defined(__amd64__)
283 case 0xF00: /* P4 */
284 model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4);
285 if (model >= 0 && model <= 6) /* known models */
286 cputype = PMC_CPU_INTEL_PIV;
287 break;
288 }
289#endif
290
291 if ((int) cputype == -1) {
292 printf("pmc: Unknown Intel CPU.\n");
293 return NULL;
294 }
295
296 pmc_mdep = malloc(sizeof(struct pmc_mdep),
297 M_PMC, M_WAITOK|M_ZERO);
298
299 pmc_mdep->pmd_cputype = cputype;
300 pmc_mdep->pmd_nclass = 2;
301 pmc_mdep->pmd_classes[0].pm_class = PMC_CLASS_TSC;
302 pmc_mdep->pmd_classes[0].pm_caps = PMC_CAP_READ;
303 pmc_mdep->pmd_classes[0].pm_width = 64;
304 pmc_mdep->pmd_nclasspmcs[0] = 1;
305
306 error = 0;
307
308 switch (cputype) {
309
310#if defined(__i386__) || defined(__amd64__)
311
312 /*
313 * Intel Pentium 4 Processors, and P4/EMT64 processors.
314 */
315
316 case PMC_CPU_INTEL_PIV:
317 error = pmc_initialize_p4(pmc_mdep);
318 break;
319#endif
320
321#if defined(__i386__)
322 /*
323 * P6 Family Processors
324 */
325
326 case PMC_CPU_INTEL_P6:
327 case PMC_CPU_INTEL_CL:
328 case PMC_CPU_INTEL_PII:
329 case PMC_CPU_INTEL_PIII:
330 case PMC_CPU_INTEL_PM:
331
332 error = pmc_initialize_p6(pmc_mdep);
333 break;
334
335 /*
336 * Intel Pentium PMCs.
337 */
338
339 case PMC_CPU_INTEL_P5:
340 error = pmc_initialize_p5(pmc_mdep);
341 break;
342#endif
343
344 default:
345 KASSERT(0,("[intel,%d] Unknown CPU type", __LINE__));
346 }
347
348 if (error) {
349 free(pmc_mdep, M_PMC);
350 pmc_mdep = NULL;
351 }
352
353 return pmc_mdep;
354}
355
356
|
243/* 244 * Machine dependent initialization for x86 class platforms. 245 */ 246 247struct pmc_mdep * 248pmc_md_initialize() 249{ 250 int i; 251 struct pmc_mdep *md; 252 253 /* determine the CPU kind */ 254 md = NULL; 255 if (strcmp(cpu_vendor, "AuthenticAMD") == 0) 256 md = pmc_amd_initialize(); 257 else if (strcmp(cpu_vendor, "GenuineIntel") == 0) 258 md = pmc_intel_initialize();
|
259 else 260 KASSERT(0, ("[x86,%d] Unknown vendor", __LINE__)); |
261 262 /* disallow sampling if we do not have an LAPIC */ 263 if (md != NULL && lapic == NULL) 264 for (i = 1; i < md->pmd_nclass; i++)
|
377 md->pmd_classes[i].pm_caps &= ~PMC_CAP_INTERRUPT;
|
265 md->pmd_classdep[i].pcd_caps &= ~PMC_CAP_INTERRUPT; |
266
|
379 return md;
|
267 return (md); |
268}
|
269 270void 271pmc_md_finalize(struct pmc_mdep *md) 272{ 273 if (strcmp(cpu_vendor, "AuthenticAMD") == 0) 274 pmc_amd_finalize(md); 275 else if (strcmp(cpu_vendor, "GenuineIntel") == 0) 276 pmc_intel_finalize(md); 277 else 278 KASSERT(0, ("[x86,%d] Unknown vendor", __LINE__)); 279} |
|