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 _IA32_SYS_TRAPTRACE_H 27 #define _IA32_SYS_TRAPTRACE_H 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 #include <sys/privregs.h> 34 35 /* 36 * Trap tracing. If TRAPTRACE is defined, an entry is recorded every time 37 * the CPU jumps through the Interrupt Descriptor Table (IDT). One exception 38 * is the Double Fault handler, which does not record a traptrace entry. 39 * 40 * There are facilities to (conditionally) interleave tracing of related 41 * facilities e.h. x-calls. 42 */ 43 44 /* 45 * Note: non-assembler files that include this file must include 46 * <sys/systm.h> before it, for the typedef of pc_t to be visible. 47 */ 48 49 #define TTR_STACK_DEPTH 10 50 51 #ifndef _ASM 52 53 #define TTR_PAD1_SIZE (sizeof (long) - 1) 54 55 typedef struct { 56 uintptr_t ttc_next; 57 uintptr_t ttc_first; 58 uintptr_t ttc_limit; 59 uintptr_t ttc_current; 60 } trap_trace_ctl_t; 61 62 typedef struct { 63 struct regs ttr_regs; 64 greg_t ttr_cr2; 65 union _ttr_info { 66 struct _idt_entry { 67 short vector; 68 uchar_t ipl; 69 uchar_t spl; 70 uchar_t pri; 71 } idt_entry; 72 struct _gate_entry { 73 int sysnum; 74 } gate_entry; 75 } ttr_info; 76 uintptr_t ttr_curthread; 77 uchar_t ttr_pad[TTR_PAD1_SIZE]; 78 uchar_t ttr_marker; 79 hrtime_t ttr_stamp; 80 int ttr_sdepth; 81 pc_t ttr_stack[TTR_STACK_DEPTH]; 82 } trap_trace_rec_t; 83 84 #define ttr_vector ttr_info.idt_entry.vector 85 #define ttr_ipl ttr_info.idt_entry.ipl 86 #define ttr_spl ttr_info.idt_entry.spl 87 #define ttr_pri ttr_info.idt_entry.pri 88 #define ttr_sysnum ttr_info.gate_entry.sysnum 89 90 #define TRAPTR_NENT 128 91 92 extern trap_trace_ctl_t trap_trace_ctl[NCPU]; /* Allocated in locore.s */ 93 extern size_t trap_trace_bufsize; 94 extern int trap_trace_freeze; 95 extern trap_trace_rec_t trap_trace_postmort; /* Entry used after death */ 96 97 #define TRAPTRACE_FREEZE trap_trace_freeze = 1; 98 #define TRAPTRACE_UNFREEZE trap_trace_freeze = 0; 99 100 #else /* _ASM */ 101 102 /* 103 * ptr -- will be set to a TRAPTRACE entry. 104 * scr1 -- scratch 105 * scr1_32 -- 32-bit version of scr1 106 * scr2 -- scratch 107 * marker -- register containing byte to store in marker field of entry 108 * 109 * Note that this macro defines labels "8" and "9". 110 */ 111 #ifdef TRAPTRACE 112 113 #if defined(__amd64) 114 115 #define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker) \ 116 leaq trap_trace_postmort(%rip), ptr; \ 117 cmpl $0, trap_trace_freeze(%rip); \ 118 jne 9f; \ 119 LOADCPU(ptr); \ 120 movl CPU_ID(ptr), scr1_32; \ 121 shlq $TRAPTR_SIZE_SHIFT, scr1; \ 122 leaq trap_trace_ctl(%rip), scr2; \ 123 addq scr2, scr1; \ 124 movq TRAPTR_NEXT(scr1), ptr; \ 125 leaq TRAP_ENT_SIZE(ptr), scr2; \ 126 cmpq TRAPTR_LIMIT(scr1), scr2; \ 127 jl 8f; \ 128 movq TRAPTR_FIRST(scr1), scr2; \ 129 8: movq scr2, TRAPTR_NEXT(scr1); \ 130 9: movb marker, TTR_MARKER(ptr); 131 132 #elif defined(__i386) 133 134 #define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker) \ 135 movl $trap_trace_postmort, ptr; \ 136 cmpl $0, trap_trace_freeze; \ 137 jne 9f; \ 138 LOADCPU(ptr); \ 139 movl CPU_ID(ptr), scr1_32; \ 140 shll $TRAPTR_SIZE_SHIFT, scr1; \ 141 addl $trap_trace_ctl, scr1; \ 142 movl TRAPTR_NEXT(scr1), ptr; \ 143 leal TRAP_ENT_SIZE(ptr), scr2; \ 144 cmpl TRAPTR_LIMIT(scr1), scr2; \ 145 jl 8f; \ 146 movl TRAPTR_FIRST(scr1), scr2; \ 147 8: movl scr2, TRAPTR_NEXT(scr1); \ 148 9: movb marker, TTR_MARKER(ptr); 149 150 #endif /* __i386 */ 151 152 /* 153 * ptr -- pointer to the current TRAPTRACE entry. 154 * reg -- pointer to the stored registers; must be on the stack 155 * scr1 -- scratch used as array index 156 * scr2 -- scratch used as temporary 157 * 158 * Note that this macro defines label "9". 159 * Also captures curthread on exit of loop. 160 */ 161 #if defined(__xpv) 162 #define __GETCR2(_mov, reg) \ 163 _mov %gs:CPU_VCPU_INFO, reg; \ 164 _mov VCPU_INFO_ARCH_CR2(reg), reg 165 #else 166 #define __GETCR2(_mov, reg) \ 167 _mov %cr2, reg 168 #endif 169 170 #if defined(__amd64) 171 172 #define TRACE_REGS(ptr, reg, scr1, scr2) \ 173 xorq scr1, scr1; \ 174 /*CSTYLED*/ \ 175 9: movq (reg, scr1, 1), scr2; \ 176 movq scr2, (ptr, scr1, 1); \ 177 addq $CLONGSIZE, scr1; \ 178 cmpq $REGSIZE, scr1; \ 179 jl 9b; \ 180 movq %gs:CPU_THREAD, scr2; \ 181 movq scr2, TTR_CURTHREAD(ptr); \ 182 __GETCR2(movq, scr2); \ 183 movq scr2, TTR_CR2(ptr) 184 185 #elif defined(__i386) 186 187 #define TRACE_REGS(ptr, reg, scr1, scr2) \ 188 xorl scr1, scr1; \ 189 /*CSTYLED*/ \ 190 9: movl (reg, scr1, 1), scr2; \ 191 movl scr2, (ptr, scr1, 1); \ 192 addl $CLONGSIZE, scr1; \ 193 cmpl $REGSIZE, scr1; \ 194 jl 9b; \ 195 movl %gs:CPU_THREAD, scr2; \ 196 movl scr2, TTR_CURTHREAD(ptr); \ 197 __GETCR2(movl, scr2); \ 198 movl scr2, TTR_CR2(ptr) 199 200 #endif /* __i386 */ 201 202 /* 203 * The time stamp macro records a high-resolution time stamp for the 204 * given TRAPTRACE entry. Note that %eax and %edx are plowed by this 205 * macro; if they are to be preserved, it's up to the caller of the macro. 206 */ 207 208 #if defined(__amd64) 209 210 #define TRACE_STAMP(reg) \ 211 rdtsc; \ 212 movl %eax, TTR_STAMP(reg); \ 213 movl %edx, TTR_STAMP+4(reg) 214 215 /* 216 * %rbp should be set before invoking this macro. 217 */ 218 219 #define TRACE_STACK(tt) \ 220 pushq %rdi; \ 221 pushq %rsi; \ 222 pushq %rdx; \ 223 pushq %rcx; \ 224 pushq %r8; \ 225 pushq %r9; \ 226 pushq %rax; \ 227 pushq %r12; \ 228 movq tt, %r12; \ 229 leaq TTR_STACK(%r12), %rdi; \ 230 movl $TTR_STACK_DEPTH, %esi; \ 231 call getpcstack; \ 232 movl %eax, TTR_SDEPTH(%r12); \ 233 popq %r12; \ 234 popq %rax; \ 235 popq %r9; \ 236 popq %r8; \ 237 popq %rcx; \ 238 popq %rdx; \ 239 popq %rsi; \ 240 popq %rdi 241 242 #elif defined(__i386) 243 244 #define TRACE_STAMP(reg) \ 245 xorl %eax, %eax; \ 246 xorl %edx, %edx; \ 247 testl $X86_TSC, x86_feature; \ 248 jz 9f; \ 249 rdtsc; \ 250 9: movl %eax, TTR_STAMP(reg); \ 251 movl %edx, TTR_STAMP+4(reg) 252 253 #define TRACE_STACK(tt) \ 254 pushl %eax; \ 255 pushl %ecx; \ 256 pushl %edx; \ 257 pushl %ebx; \ 258 pushl $TTR_STACK_DEPTH; \ 259 movl tt, %ebx; \ 260 leal TTR_STACK(%ebx), %eax; \ 261 pushl %eax; \ 262 call getpcstack; \ 263 addl $8, %esp; \ 264 movl %eax, TTR_SDEPTH(%ebx); \ 265 popl %ebx; \ 266 popl %edx; \ 267 popl %ecx; \ 268 popl %eax 269 270 #endif /* __i386 */ 271 272 #else 273 274 #define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker) 275 #define TRACE_REGS(ptr, reg, scr1, scr2) 276 #define TRACE_STAMP(reg) 277 #define TRACE_STACK(reg) 278 279 #endif /* TRAPTRACE */ 280 281 #endif /* _ASM */ 282 283 #define TT_SYSCALL 0xaa /* system call via lcall */ 284 #define TT_SYSENTER 0xab /* system call via sysenter */ 285 #define TT_SYSC 0xad /* system call via syscall (32-bit) */ 286 #define TT_SYSC64 0xae /* system call via syscall (64-bit) */ 287 #define TT_INTERRUPT 0xbb 288 #define TT_TRAP 0xcc 289 #define TT_INTTRAP 0xdd 290 #define TT_EVENT 0xee /* hypervisor event */ 291 292 #ifdef __cplusplus 293 } 294 #endif 295 296 #endif /* _IA32_SYS_TRAPTRACE_H */ 297