xref: /illumos-gate/usr/src/uts/intel/sys/traptrace.h (revision f0089e391b2bc4be2755f1a1b51fb4cd9b8f3988)
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) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #ifndef _SYS_TRAPTRACE_H
26 #define	_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 	btl	$X86FSET_TSC, x86_featureset;	\
249 	jnc	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	/* _SYS_TRAPTRACE_H */
298