xref: /illumos-gate/usr/src/uts/intel/amd64/sys/privregs.h (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef _AMD64_SYS_PRIVREGS_H
28 #define	_AMD64_SYS_PRIVREGS_H
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #ifdef	__cplusplus
33 extern "C" {
34 #endif
35 
36 /*
37  * This file describes the cpu's privileged register set, and
38  * how the machine state is saved on the stack when a trap occurs.
39  */
40 
41 #if !defined(__amd64)
42 #error	"non-amd64 code depends on amd64 privileged header!"
43 #endif
44 
45 #ifndef	_ASM
46 
47 /*
48  * This is NOT the structure to use for general purpose debugging;
49  * see /proc for that.  This is NOT the structure to use to decode
50  * the ucontext or grovel about in a core file; see <sys/regset.h>.
51  */
52 
53 struct regs {
54 	/*
55 	 * Extra frame for mdb to follow through high level interrupts and
56 	 * system traps.  Set them to 0 to terminate stacktrace.
57 	 */
58 	greg_t	r_savfp;	/* a copy of %rbp */
59 	greg_t	r_savpc;	/* a copy of %rip */
60 
61 	greg_t	r_rdi;		/* 1st arg to function */
62 	greg_t	r_rsi;		/* 2nd arg to function */
63 	greg_t	r_rdx;		/* 3rd arg to function, 2nd return register */
64 	greg_t	r_rcx;		/* 4th arg to function */
65 
66 	greg_t	r_r8;		/* 5th arg to function */
67 	greg_t	r_r9;		/* 6th arg to function */
68 	greg_t	r_rax;		/* 1st return register, # SSE registers */
69 	greg_t	r_rbx;		/* callee-saved, optional base pointer */
70 
71 	greg_t	r_rbp;		/* callee-saved, optional frame pointer */
72 	greg_t	r_r10;		/* temporary register, static chain pointer */
73 	greg_t	r_r11;		/* temporary register */
74 	greg_t	r_r12;		/* callee-saved */
75 
76 	greg_t	r_r13;		/* callee-saved */
77 	greg_t	r_r14;		/* callee-saved */
78 	greg_t	r_r15;		/* callee-saved */
79 
80 	greg_t	r_fsbase;
81 	greg_t	r_gsbase;
82 	greg_t	r_ds;
83 	greg_t	r_es;
84 	greg_t	r_fs;		/* %fs is *never* used by the kernel */
85 	greg_t	r_gs;
86 
87 	greg_t	r_trapno;
88 
89 	/*
90 	 * (the rest of these are defined by the hardware)
91 	 */
92 	greg_t	r_err;
93 	greg_t	r_rip;
94 	greg_t	r_cs;
95 	greg_t	r_rfl;
96 	greg_t	r_rsp;
97 	greg_t	r_ss;
98 };
99 
100 #define	r_r0	r_rax	/* r0 for portability */
101 #define	r_r1	r_rdx	/* r1 for portability */
102 #define	r_fp	r_rbp	/* kernel frame pointer */
103 #define	r_sp	r_rsp	/* user stack pointer */
104 #define	r_pc	r_rip	/* user's instruction pointer */
105 #define	r_ps	r_rfl	/* user's RFLAGS */
106 
107 #ifdef _KERNEL
108 #define	lwptoregs(lwp)	((struct regs *)((lwp)->lwp_regs))
109 #endif	/* _KERNEL */
110 
111 #else	/* !_ASM */
112 
113 #define	TRAPERR_PUSH(err, trapno)	\
114 	pushq	$err;			\
115 	pushq	$trapno
116 
117 /*
118  * Create a struct regs on the stack suitable for an
119  * interrupt trap.
120  *
121  * The swapgs instruction is conditionalized to make sure that
122  * interrupts in kernel mode don't cause us to switch back to
123  * the user's gsbase!
124  *
125  * Assumes that the trap handler has already pushed an
126  * appropriate r_err and r_trapno
127  */
128 #define	__SAVE_REGS				\
129 	movq	%r15, REGOFF_R15(%rsp);		\
130 	movq	%r14, REGOFF_R14(%rsp);		\
131 	movq	%r13, REGOFF_R13(%rsp);		\
132 	movq	%r12, REGOFF_R12(%rsp);		\
133 	movq	%r11, REGOFF_R11(%rsp);		\
134 	movq	%r10, REGOFF_R10(%rsp);		\
135 	movq	%rbp, REGOFF_RBP(%rsp);		\
136 	movq	%rbx, REGOFF_RBX(%rsp);		\
137 	movq	%rax, REGOFF_RAX(%rsp);		\
138 	movq	%r9, REGOFF_R9(%rsp);		\
139 	movq	%r8, REGOFF_R8(%rsp);		\
140 	movq	%rcx, REGOFF_RCX(%rsp);		\
141 	movq	%rdx, REGOFF_RDX(%rsp);		\
142 	movq	%rsi, REGOFF_RSI(%rsp);		\
143 	movq	%rdi, REGOFF_RDI(%rsp);		\
144 	movq	%rbp, REGOFF_SAVFP(%rsp);	\
145 	movq	REGOFF_RIP(%rsp), %rcx;		\
146 	movq	%rcx, REGOFF_SAVPC(%rsp);	\
147 	xorl	%ecx, %ecx;			\
148 	movw	%gs, %cx;			\
149 	movq	%rcx, REGOFF_GS(%rsp);		\
150 	movw	%fs, %cx;			\
151 	movq	%rcx, REGOFF_FS(%rsp);		\
152 	movw	%es, %cx;			\
153 	movq	%rcx, REGOFF_ES(%rsp);		\
154 	movw	%ds, %cx;			\
155 	movq	%rcx, REGOFF_DS(%rsp);		\
156 	movl	$MSR_AMD_FSBASE, %ecx;		\
157 	rdmsr;					\
158 	movl	%eax, REGOFF_FSBASE(%rsp);	\
159 	movl	%edx, REGOFF_FSBASE+4(%rsp);	\
160 	movl	$MSR_AMD_GSBASE, %ecx;		\
161 	rdmsr;					\
162 	movl	%eax, REGOFF_GSBASE(%rsp);	\
163 	movl	%edx, REGOFF_GSBASE+4(%rsp)
164 
165 /*
166  * Push register state onto the stack. If we've
167  * interrupted userland, do a swapgs as well.
168  */
169 
170 #define	INTR_PUSH				\
171 	subq	$REGOFF_TRAPNO, %rsp;		\
172 	__SAVE_REGS;				\
173 	cmpw	$KCS_SEL, REGOFF_CS(%rsp);	\
174 	je	6f;				\
175 	movq	$0, REGOFF_SAVFP(%rsp);		\
176 	swapgs;					\
177 6:
178 
179 #define	TRAP_PUSH				\
180 	subq	$REGOFF_TRAPNO, %rsp;		\
181 	__SAVE_REGS;				\
182 	cmpw	$KCS_SEL, REGOFF_CS(%rsp);	\
183 	je	6f;				\
184 	movq	$0, REGOFF_SAVFP(%rsp);		\
185 	swapgs;					\
186 6:
187 
188 #define	DFTRAP_PUSH				\
189 	subq	$REGOFF_TRAPNO, %rsp;		\
190 	__SAVE_REGS
191 
192 #define	__RESTORE_REGS			\
193 	movq	REGOFF_RDI(%rsp),	%rdi;	\
194 	movq	REGOFF_RSI(%rsp),	%rsi;	\
195 	movq	REGOFF_RDX(%rsp),	%rdx;	\
196 	movq	REGOFF_RCX(%rsp),	%rcx;	\
197 	movq	REGOFF_R8(%rsp),	%r8;	\
198 	movq	REGOFF_R9(%rsp),	%r9;	\
199 	movq	REGOFF_RAX(%rsp),	%rax;	\
200 	movq	REGOFF_RBX(%rsp),	%rbx;	\
201 	movq	REGOFF_RBP(%rsp),	%rbp;	\
202 	movq	REGOFF_R10(%rsp),	%r10;	\
203 	movq	REGOFF_R11(%rsp),	%r11;	\
204 	movq	REGOFF_R12(%rsp),	%r12;	\
205 	movq	REGOFF_R13(%rsp),	%r13;	\
206 	movq	REGOFF_R14(%rsp),	%r14;	\
207 	movq	REGOFF_R15(%rsp),	%r15
208 
209 #define	INTR_POP			\
210 	leaq	sys_lcall32(%rip), %r11;\
211 	cmpq	%r11, REGOFF_RIP(%rsp);	\
212 	__RESTORE_REGS;			\
213 	je	5f;			\
214 	cmpw	$KCS_SEL, REGOFF_CS(%rsp);\
215 	je	8f;			\
216 5:	swapgs;				\
217 8:	addq	$REGOFF_RIP, %rsp
218 
219 #define	USER_POP			\
220 	__RESTORE_REGS;			\
221 	swapgs;				\
222 	addq	$REGOFF_RIP, %rsp	/* Adjust %rsp to prepare for iretq */
223 
224 #define	USER32_POP			\
225 	movl	REGOFF_RDI(%rsp), %edi;	\
226 	movl	REGOFF_RSI(%rsp), %esi;	\
227 	movl	REGOFF_RDX(%rsp), %edx;	\
228 	movl	REGOFF_RCX(%rsp), %ecx;	\
229 	movl	REGOFF_RAX(%rsp), %eax;	\
230 	movl	REGOFF_RBX(%rsp), %ebx;	\
231 	movl	REGOFF_RBP(%rsp), %ebp;	\
232 	swapgs;				\
233 	addq	$REGOFF_RIP, %rsp	/* Adjust %rsp to prepare for iretq */
234 
235 
236 /*
237  * Smaller versions of INTR_PUSH and INTR_POP for fast traps.
238  * The following registers have been pushed onto the stack by
239  * hardware at this point:
240  *
241  *	greg_t	r_rip;
242  *	greg_t	r_cs;
243  *	greg_t	r_rfl;
244  *	greg_t	r_rsp;
245  *	greg_t	r_ss;
246  *
247  * This handler is executed both by 32-bit and 64-bit applications.
248  * 64-bit applications allow us to treat the set (%rdi, %rsi, %rdx,
249  * %rcx, %r8, %r9, %r10, %r11, %rax) as volatile across function calls.
250  * However, 32-bit applications only expect (%eax, %edx, %ecx) to be volatile
251  * across a function call -- in particular, %esi and %edi MUST be saved!
252  *
253  * We could do this differently by making a FAST_INTR_PUSH32 for 32-bit
254  * programs, and FAST_INTR_PUSH for 64-bit programs, but it doesn't seem
255  * particularly worth it.
256  */
257 #define	FAST_INTR_PUSH			\
258 	subq	$REGOFF_RIP, %rsp;	\
259 	movq	%rsi, REGOFF_RSI(%rsp);	\
260 	movq	%rdi, REGOFF_RDI(%rsp);	\
261 	swapgs
262 
263 #define	FAST_INTR_POP			\
264 	swapgs;				\
265 	movq	REGOFF_RSI(%rsp), %rsi;	\
266 	movq	REGOFF_RDI(%rsp), %rdi;	\
267 	addq	$REGOFF_RIP, %rsp
268 
269 #define	DISABLE_INTR_FLAGS		\
270 	pushq	$F_OFF;			\
271 	popfq
272 
273 #define	ENABLE_INTR_FLAGS		\
274 	pushq	$F_ON;			\
275 	popfq
276 
277 #endif	/* !_ASM */
278 
279 #include <sys/controlregs.h>
280 
281 #if defined(_KERNEL) && !defined(_ASM)
282 #if !defined(__lint) && defined(__GNUC__)
283 
284 extern __inline__ ulong_t getcr8(void)
285 {
286 	uint64_t value;
287 
288 	__asm__ __volatile__(
289 		"movq %%cr8, %0"
290 		: "=r" (value));
291 	return (value);
292 }
293 
294 extern __inline__ void setcr8(ulong_t value)
295 {
296 	__asm__ __volatile__(
297 		"movq %0, %%cr8"
298 		: /* no output */
299 		: "r" (value));
300 }
301 
302 #else
303 
304 extern ulong_t getcr8(void);
305 extern void setcr8(ulong_t);
306 
307 #endif	/* !defined(__lint) && defined(__GNUC__) */
308 #endif	/* _KERNEL && !_ASM */
309 
310 /* Control register layout for panic dump */
311 
312 #define	CREGSZ		0x68
313 #define	CREG_GDT	0
314 #define	CREG_IDT	0x10
315 #define	CREG_LDT	0x20
316 #define	CREG_TASKR	0x28
317 #define	CREG_CR0	0x30
318 #define	CREG_CR2	0x38
319 #define	CREG_CR3	0x40
320 #define	CREG_CR4	0x48
321 #define	CREG_CR8	0x50
322 #define	CREG_KGSBASE	0x58
323 #define	CREG_EFER	0x60
324 
325 #if !defined(_ASM)
326 
327 typedef	uint64_t	creg64_t;
328 typedef	upad128_t	creg128_t;
329 
330 struct cregs {
331 	creg128_t	cr_gdt;
332 	creg128_t	cr_idt;
333 	creg64_t	cr_ldt;
334 	creg64_t	cr_task;
335 	creg64_t	cr_cr0;
336 	creg64_t	cr_cr2;
337 	creg64_t	cr_cr3;
338 	creg64_t	cr_cr4;
339 	creg64_t	cr_cr8;
340 	creg64_t	cr_kgsbase;
341 	creg64_t	cr_efer;
342 };
343 
344 #if defined(_KERNEL)
345 extern void getcregs(struct cregs *);
346 #endif	/* _KERNEL */
347 
348 #endif	/* _ASM */
349 
350 #ifdef	__cplusplus
351 }
352 #endif
353 
354 #endif	/* _AMD64_SYS_PRIVREGS_H */
355