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