1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #ifndef _SYS_TRAPTRACE_H 27 #define _SYS_TRAPTRACE_H 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 #define TRAP_TENABLE_ALL -1 /* enable all hv traptracing */ 34 #define TRAP_TDISABLE_ALL 0 /* disable all hv traptracing */ 35 #define TRAP_TFREEZE_ALL -1 /* freeze all hv traptracing */ 36 #define TRAP_TUNFREEZE_ALL 0 /* unfreeze all hv traptracing */ 37 38 /* 39 * Trap tracing. If TRAPTRACE is defined, every trap records info 40 * in a circular buffer. Define TRAPTRACE in Makefile.$ARCH. 41 * 42 * Trap trace records are TRAP_ENT_SIZE bytes, consisting of the 43 * %tick, %tl, %tt, %tpc, %tstate, %sp, and a few other words: 44 * 45 * struct trap_trace_record { 46 * ushort_t tl, tt; 47 * long pc; 48 * int64_t tstate, tick; 49 * long sp, tr, f1, f2, f3, f4; 50 * }; 51 * 52 * Note that for UltraSparc III and beyond %stick is used in place of %tick 53 * unless compiled with TRAPTRACE_FORCE_TICK. 54 * 55 * Auxilliary entries (not of just a trap), have obvious non-%tt values in 56 * the TRAP_ENT_TT field 57 */ 58 59 #define TRAP_TBUF (2 * PAGESIZE) /* default size is two pages */ 60 61 #ifndef _ASM 62 63 /* 64 * HV Trap trace header 65 */ 66 typedef struct htrap_trace_hdr { 67 uint64_t last_offset; /* most recently completed entry */ 68 uint64_t offset; /* next entry to be written */ 69 uint64_t dummy1; 70 uint64_t dummy2; 71 uint64_t dummy3; 72 uint64_t dummy4; 73 uint64_t dummy5; 74 uint64_t dummy6; 75 } htrap_trace_hdr_t; 76 77 /* 78 * HV Trap trace record 79 */ 80 struct htrap_trace_record { 81 uint8_t tt_ty; /* Indicates HV or Guest entry */ 82 uint8_t tt_hpstate; /* Hyper-privilege State */ 83 uint8_t tt_tl; /* Trap level */ 84 uint8_t tt_gl; /* Global register level */ 85 uint16_t tt_tt; /* Trap type */ 86 uint16_t tt_tag; /* Extended Trap Indentifier */ 87 uint64_t tt_tstate; /* Trap state */ 88 uint64_t tt_tick; /* Tick */ 89 uint64_t tt_tpc; /* Trap PC */ 90 uint64_t tt_f1; /* Entry specific */ 91 uint64_t tt_f2; /* Entry specific */ 92 uint64_t tt_f3; /* Entry specific */ 93 uint64_t tt_f4; /* Entry specific */ 94 }; 95 96 /* 97 * Kernel Trap trace record 98 */ 99 struct trap_trace_record { 100 uint8_t tt_tl; 101 uint8_t tt_gl; 102 uint16_t tt_tt; 103 uintptr_t tt_tpc; 104 uint64_t tt_tstate; 105 uint64_t tt_tick; 106 uintptr_t tt_sp; 107 uintptr_t tt_tr; 108 uintptr_t tt_f1; 109 uintptr_t tt_f2; 110 uintptr_t tt_f3; 111 uintptr_t tt_f4; 112 }; 113 114 #define TRAP_TSIZE ((TRAP_TBUF / sizeof (struct trap_trace_record)) * \ 115 sizeof (struct trap_trace_record)) 116 117 /* Rounding not needed, done for consistency */ 118 #define HTRAP_TSIZE ((TRAP_TBUF / sizeof (struct htrap_trace_record)) * \ 119 sizeof (struct htrap_trace_record)) 120 121 #else 122 123 #define TRAP_TSIZE ((TRAP_TBUF / TRAP_ENT_SIZE) * TRAP_ENT_SIZE) 124 #define HTRAP_TSIZE ((TRAP_TBUF / HTRAP_ENT_SIZE) * HTRAP_ENT_SIZE) 125 126 #endif 127 128 /* 129 * Trap tracing buffer header. 130 */ 131 132 #ifndef _ASM 133 134 /* 135 * Example buffer header stored in locore.s: 136 * 137 * (the actual implementation could be .skip TRAPTR_SIZE*NCPU) 138 */ 139 typedef union { 140 struct { 141 caddr_t vaddr_base; /* virtual address of top of buffer */ 142 uint64_t paddr_base; /* physical address of buffer */ 143 uint_t last_offset; /* to "know" what trace completed */ 144 uint_t offset; /* current index into buffer (bytes) */ 145 uint_t limit; /* upper limit on index */ 146 uchar_t asi; /* cache for real asi */ 147 caddr_t hvaddr_base; /* HV virtual addr of top of buffer */ 148 uint64_t hpaddr_base; /* HV physical addr of buffer */ 149 uint_t hlimit; /* HV upper limit on index */ 150 } d; 151 char cache_linesize[64]; 152 } TRAP_TRACE_CTL; 153 154 #ifdef _KERNEL 155 156 extern TRAP_TRACE_CTL trap_trace_ctl[]; /* allocated in locore.s */ 157 extern int trap_trace_bufsize; /* default buffer size */ 158 extern char trap_tr0[]; /* prealloc buf for boot cpu */ 159 extern int trap_freeze; /* freeze the trap trace */ 160 extern caddr_t ttrace_buf; /* kmem64 buffer */ 161 extern int ttrace_index; /* index used */ 162 extern size_t calc_traptrace_sz(void); 163 164 extern int htrap_trace_bufsize; /* default hv buffer size */ 165 extern int mach_htraptrace_enable; 166 extern void mach_htraptrace_setup(int); 167 extern void mach_htraptrace_configure(int); 168 extern void mach_htraptrace_cleanup(int); 169 170 #endif 171 172 /* 173 * freeze the trap trace 174 */ 175 #define TRAPTRACE_FREEZE trap_freeze = 1; 176 #define TRAPTRACE_UNFREEZE trap_freeze = 0; 177 178 #else /* _ASM */ 179 180 #include <sys/machthread.h> 181 #include <sys/machclock.h> 182 183 /* 184 * Offsets of words in trap_trace_ctl: 185 */ 186 /* 187 * XXX This should be done with genassym 188 */ 189 #define TRAPTR_VBASE 0 /* virtual address of buffer */ 190 #define TRAPTR_LAST_OFFSET 16 /* last completed trace entry */ 191 #define TRAPTR_OFFSET 20 /* next trace entry pointer */ 192 #define TRAPTR_LIMIT 24 /* pointer past end of buffer */ 193 #define TRAPTR_PBASE 8 /* start of buffer */ 194 #define TRAPTR_ASIBUF 28 /* cache of current asi */ 195 196 #define TRAPTR_HVBASE 32 /* HV virtual address of buffer */ 197 #define TRAPTR_HPBASE 40 /* HV start of buffer */ 198 #define TRAPTR_HLIMIT 48 /* HV pointer past end of buffer */ 199 200 #define TRAPTR_SIZE_SHIFT 6 /* shift count -- per CPU indexing */ 201 #define TRAPTR_SIZE (1<<TRAPTR_SIZE_SHIFT) 202 203 #define TRAPTR_ASI ASI_MEM /* ASI to use for TRAPTR access */ 204 205 /* 206 * Use new %stick register for UltraSparc III and beyond for 207 * sane debugging of mixed speed CPU systems. Use TRAPTRACE_FORCE_TICK 208 * for finer granularity on same speed systems. Note that traptrace 209 * %tick or %stick reads use the NO_SUSPEND_CHECK version of the 210 * register read macros. This requires fewer registers and a few less 211 * instructions to execute. As a result, if a suspend operation occurs 212 * while traptrace is executing GET_TRACE_TICK between the time that 213 * the counter offset variable is read and the hardware register is read, 214 * this traptrace entry in the log will have an incorrect %tick value 215 * since it is derived from a pre-suspend offset variable and a post- 216 * suspend hardware counter. 217 */ 218 #ifdef TRAPTRACE_FORCE_TICK 219 #define GET_TRACE_TICK(reg, scr) \ 220 RD_TICK_NO_SUSPEND_CHECK(reg, scr); 221 #else 222 #define GET_TRACE_TICK(reg, scr) \ 223 RD_TICKSTICK_FLAG(reg, scr, traptrace_use_stick); 224 #endif 225 226 /* 227 * TRACE_PTR(ptr, scr1) - get trap trace entry physical pointer. 228 * ptr is the register to receive the trace pointer. 229 * scr1 is a different register to be used as scratch. 230 * TRACING now needs a known processor state. Hence the assertion. 231 * NOTE: this caches and resets %asi 232 */ 233 #define TRACE_PTR(ptr, scr1) \ 234 sethi %hi(trap_freeze), ptr; \ 235 ld [ptr + %lo(trap_freeze)], ptr; \ 236 /* CSTYLED */ \ 237 brnz,pn ptr, .+20; /* skip assertion */ \ 238 rdpr %pstate, scr1; \ 239 andcc scr1, PSTATE_IE | PSTATE_AM, scr1; \ 240 /* CSTYLED */ \ 241 bne,a,pn %icc, trace_ptr_panic; \ 242 rd %pc, %g1; \ 243 CPU_INDEX(scr1, ptr); \ 244 sll scr1, TRAPTR_SIZE_SHIFT, scr1; \ 245 set trap_trace_ctl, ptr; \ 246 add ptr, scr1, scr1; \ 247 rd %asi, ptr; \ 248 stb ptr, [scr1 + TRAPTR_ASIBUF]; \ 249 sethi %hi(trap_freeze), ptr; \ 250 ld [ptr + %lo(trap_freeze)], ptr; \ 251 /* CSTYLED */ \ 252 brnz,pn ptr, .+20; /* skip assertion */ \ 253 ld [scr1 + TRAPTR_LIMIT], ptr; \ 254 tst ptr; \ 255 /* CSTYLED */ \ 256 be,a,pn %icc, trace_ptr_panic; \ 257 rd %pc, %g1; \ 258 ldx [scr1 + TRAPTR_PBASE], ptr; \ 259 ld [scr1 + TRAPTR_OFFSET], scr1; \ 260 wr %g0, TRAPTR_ASI, %asi; \ 261 add ptr, scr1, ptr; 262 263 /* 264 * TRACE_NEXT(scr1, scr2, scr3) - advance the trap trace pointer. 265 * scr1, scr2, scr3 are scratch registers. 266 * This routine will skip updating the trap pointers if the 267 * global freeze register is set (e.g. in panic). 268 * (we also restore the asi register) 269 */ 270 #define TRACE_NEXT(scr1, scr2, scr3) \ 271 CPU_INDEX(scr2, scr1); \ 272 sll scr2, TRAPTR_SIZE_SHIFT, scr2; \ 273 set trap_trace_ctl, scr1; \ 274 add scr1, scr2, scr2; \ 275 ldub [scr2 + TRAPTR_ASIBUF], scr1; \ 276 wr %g0, scr1, %asi; \ 277 sethi %hi(trap_freeze), scr1; \ 278 ld [scr1 + %lo(trap_freeze)], scr1; \ 279 /* CSTYLED */ \ 280 brnz scr1, .+36; /* skip update on freeze */ \ 281 ld [scr2 + TRAPTR_OFFSET], scr1; \ 282 ld [scr2 + TRAPTR_LIMIT], scr3; \ 283 st scr1, [scr2 + TRAPTR_LAST_OFFSET]; \ 284 add scr1, TRAP_ENT_SIZE, scr1; \ 285 sub scr3, TRAP_ENT_SIZE, scr3; \ 286 cmp scr1, scr3; \ 287 movge %icc, 0, scr1; \ 288 st scr1, [scr2 + TRAPTR_OFFSET]; 289 290 /* 291 * macro to save %tl, %gl to trap trace record at addr 292 */ 293 #define TRACE_SAVE_TL_GL_REGS(addr, scr1) \ 294 rdpr %tl, scr1; \ 295 stba scr1, [addr + TRAP_ENT_TL]%asi; \ 296 rdpr %gl, scr1; \ 297 stba scr1, [addr + TRAP_ENT_GL]%asi 298 299 /* 300 * macro to save tl to trap trace record at addr 301 */ 302 #define TRACE_SAVE_TL_VAL(addr, tl) \ 303 stba tl, [addr + TRAP_ENT_TL]%asi 304 305 /* 306 * macro to save gl to trap trace record at addr 307 */ 308 #define TRACE_SAVE_GL_VAL(addr, gl) \ 309 stba gl, [addr + TRAP_ENT_GL]%asi 310 311 312 /* 313 * Trace macro for sys_trap return entries: 314 * prom_rtt, priv_rtt, and user_rtt 315 * %l7 - regs 316 * %l6 - trap %pil for prom_rtt and priv_rtt; THREAD_REG for user_rtt 317 */ 318 #define TRACE_RTT(code, scr1, scr2, scr3, scr4) \ 319 rdpr %pstate, scr4; \ 320 andn scr4, PSTATE_IE | PSTATE_AM, scr3; \ 321 wrpr %g0, scr3, %pstate; \ 322 TRACE_PTR(scr1, scr2); \ 323 GET_TRACE_TICK(scr2, scr3); \ 324 stxa scr2, [scr1 + TRAP_ENT_TICK]%asi; \ 325 TRACE_SAVE_TL_GL_REGS(scr1, scr2); \ 326 set code, scr2; \ 327 stha scr2, [scr1 + TRAP_ENT_TT]%asi; \ 328 ldn [%l7 + PC_OFF], scr2; \ 329 stna scr2, [scr1 + TRAP_ENT_TPC]%asi; \ 330 ldx [%l7 + TSTATE_OFF], scr2; \ 331 stxa scr2, [scr1 + TRAP_ENT_TSTATE]%asi; \ 332 stna %sp, [scr1 + TRAP_ENT_SP]%asi; \ 333 stna %l6, [scr1 + TRAP_ENT_TR]%asi; \ 334 stna %l7, [scr1 + TRAP_ENT_F1]%asi; \ 335 ldn [THREAD_REG + T_CPU], scr2; \ 336 ld [scr2 + CPU_BASE_SPL], scr2; \ 337 stna scr2, [scr1 + TRAP_ENT_F2]%asi; \ 338 stna %g0, [scr1 + TRAP_ENT_F3]%asi; \ 339 rdpr %cwp, scr2; \ 340 stna scr2, [scr1 + TRAP_ENT_F4]%asi; \ 341 TRACE_NEXT(scr1, scr2, scr3); \ 342 wrpr %g0, scr4, %pstate 343 344 /* 345 * Trace macro for spill and fill trap handlers 346 * tl and tt fields indicate which spill handler is entered 347 */ 348 #define TRACE_WIN_INFO(code, scr1, scr2, scr3) \ 349 TRACE_PTR(scr1, scr2); \ 350 GET_TRACE_TICK(scr2, scr3); \ 351 stxa scr2, [scr1 + TRAP_ENT_TICK]%asi; \ 352 TRACE_SAVE_TL_GL_REGS(scr1, scr2); \ 353 rdpr %tt, scr2; \ 354 set code, scr3; \ 355 or scr2, scr3, scr2; \ 356 stha scr2, [scr1 + TRAP_ENT_TT]%asi; \ 357 rdpr %tstate, scr2; \ 358 stxa scr2, [scr1 + TRAP_ENT_TSTATE]%asi; \ 359 stna %sp, [scr1 + TRAP_ENT_SP]%asi; \ 360 rdpr %tpc, scr2; \ 361 stna scr2, [scr1 + TRAP_ENT_TPC]%asi; \ 362 set TT_FSPILL_DEBUG, scr2; \ 363 stna scr2, [scr1 + TRAP_ENT_TR]%asi; \ 364 rdpr %pstate, scr2; \ 365 stna scr2, [scr1 + TRAP_ENT_F1]%asi; \ 366 rdpr %cwp, scr2; \ 367 sll scr2, 24, scr2; \ 368 rdpr %cansave, scr3; \ 369 sll scr3, 16, scr3; \ 370 or scr2, scr3, scr2; \ 371 rdpr %canrestore, scr3; \ 372 or scr2, scr3, scr2; \ 373 stna scr2, [scr1 + TRAP_ENT_F2]%asi; \ 374 rdpr %otherwin, scr2; \ 375 sll scr2, 24, scr2; \ 376 rdpr %cleanwin, scr3; \ 377 sll scr3, 16, scr3; \ 378 or scr2, scr3, scr2; \ 379 rdpr %wstate, scr3; \ 380 or scr2, scr3, scr2; \ 381 stna scr2, [scr1 + TRAP_ENT_F3]%asi; \ 382 stna %o7, [scr1 + TRAP_ENT_F4]%asi; \ 383 TRACE_NEXT(scr1, scr2, scr3) 384 385 #ifdef TRAPTRACE 386 387 #define FAULT_WINTRACE(scr1, scr2, scr3, type) \ 388 TRACE_PTR(scr1, scr2); \ 389 GET_TRACE_TICK(scr2, scr3); \ 390 stxa scr2, [scr1 + TRAP_ENT_TICK]%asi; \ 391 TRACE_SAVE_TL_GL_REGS(scr1, scr2); \ 392 set type, scr2; \ 393 stha scr2, [scr1 + TRAP_ENT_TT]%asi; \ 394 rdpr %tpc, scr2; \ 395 stna scr2, [scr1 + TRAP_ENT_TPC]%asi; \ 396 rdpr %tstate, scr2; \ 397 stxa scr2, [scr1 + TRAP_ENT_TSTATE]%asi; \ 398 stna %sp, [scr1 + TRAP_ENT_SP]%asi; \ 399 stna %g0, [scr1 + TRAP_ENT_TR]%asi; \ 400 stna %g0, [scr1 + TRAP_ENT_F1]%asi; \ 401 stna %g4, [scr1 + TRAP_ENT_F2]%asi; \ 402 rdpr %pil, scr2; \ 403 stna scr2, [scr1 + TRAP_ENT_F3]%asi; \ 404 stna %g0, [scr1 + TRAP_ENT_F4]%asi; \ 405 TRACE_NEXT(scr1, scr2, scr3) 406 407 #define SYSTRAP_TT 0x1300 408 409 #define SYSTRAP_TRACE(scr1, scr2, scr3) \ 410 TRACE_PTR(scr1, scr2); \ 411 GET_TRACE_TICK(scr2, scr3); \ 412 stxa scr2, [scr1 + TRAP_ENT_TICK]%asi; \ 413 TRACE_SAVE_TL_GL_REGS(scr1, scr2); \ 414 set SYSTRAP_TT, scr3; \ 415 rdpr %tt, scr2; \ 416 or scr3, scr2, scr2; \ 417 stha scr2, [scr1 + TRAP_ENT_TT]%asi; \ 418 rdpr %tpc, scr2; \ 419 stna scr2, [scr1 + TRAP_ENT_TPC]%asi; \ 420 rdpr %tstate, scr2; \ 421 stxa scr2, [scr1 + TRAP_ENT_TSTATE]%asi; \ 422 stna %g1, [scr1 + TRAP_ENT_SP]%asi; \ 423 stna %g2, [scr1 + TRAP_ENT_TR]%asi; \ 424 stna %g3, [scr1 + TRAP_ENT_F1]%asi; \ 425 stna %g4, [scr1 + TRAP_ENT_F2]%asi; \ 426 rdpr %pil, scr2; \ 427 stna scr2, [scr1 + TRAP_ENT_F3]%asi; \ 428 rdpr %cwp, scr2; \ 429 stna scr2, [scr1 + TRAP_ENT_F4]%asi; \ 430 TRACE_NEXT(scr1, scr2, scr3) 431 432 #else /* TRAPTRACE */ 433 434 #define FAULT_WINTRACE(scr1, scr2, scr3, type) 435 #define SYSTRAP_TRACE(scr1, scr2, scr3) 436 437 #endif /* TRAPTRACE */ 438 439 #endif /* _ASM */ 440 441 /* 442 * Trap trace codes used in place of a %tbr value when more than one 443 * entry is made by a trap. The general scheme is that the trap-type is 444 * in the same position as in the TT, and the low-order bits indicate 445 * which precise entry is being made. 446 */ 447 448 #define TT_F32_SN0 0x1084 449 #define TT_F64_SN0 0x1088 450 #define TT_F32_NT0 0x1094 451 #define TT_F64_NT0 0x1098 452 #define TT_F32_SO0 0x10A4 453 #define TT_F64_SO0 0x10A8 454 #define TT_F32_FN0 0x10C4 455 #define TT_F64_FN0 0x10C8 456 #define TT_F32_SN1 0x1284 457 #define TT_F64_SN1 0x1288 458 #define TT_F32_NT1 0x1294 459 #define TT_F64_NT1 0x1298 460 #define TT_F32_SO1 0x12A4 461 #define TT_F64_SO1 0x12A8 462 #define TT_F32_FN1 0x12C4 463 #define TT_F64_FN1 0x12C8 464 #define TT_RTT_FN1 0x12DD 465 466 #define TT_SC_ENTR 0x880 /* enter system call */ 467 #define TT_SC_RET 0x881 /* system call normal return */ 468 469 #define TT_SYS_RTT_PROM 0x5555 /* return from trap to prom */ 470 #define TT_SYS_RTT_PRIV 0x6666 /* return from trap to privilege */ 471 #define TT_SYS_RTT_USER 0x7777 /* return from trap to user */ 472 473 #define TT_INTR_EXIT 0x8888 /* interrupt thread exit (no pinned thread) */ 474 #define TT_FSPILL_DEBUG 0x9999 /* fill/spill debugging */ 475 476 #define TT_SERVE_INTR 0x6000 /* SERVE_INTR */ 477 #define TT_XCALL 0xd000 /* xcall/xtrap */ 478 #define TT_XCALL_CONT 0xdc00 /* continuation of an xcall/xtrap record */ 479 480 #define TT_MMU_MISS 0x200 /* or'd into %tt to indicate a miss */ 481 #define TT_MMU_EXEC 0x400 /* or'd into %tt to indicate exec_fault */ 482 483 484 #ifdef __cplusplus 485 } 486 #endif 487 488 #endif /* _SYS_TRAPTRACE_H */ 489