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 /*
23 * Copyright 2007 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 #include <sys/ccompile.h>
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 /*
81 * fsbase and gsbase are sampled on every exception in DEBUG kernels
82 * only. They remain in the non-DEBUG kernel to avoid any flag days.
83 */
84 greg_t __r_fsbase; /* no longer used in non-DEBUG builds */
85 greg_t __r_gsbase; /* no longer used in non-DEBUG builds */
86 greg_t r_ds;
87 greg_t r_es;
88 greg_t r_fs; /* %fs is *never* used by the kernel */
89 greg_t r_gs;
90
91 greg_t r_trapno;
92
93 /*
94 * (the rest of these are defined by the hardware)
95 */
96 greg_t r_err;
97 greg_t r_rip;
98 greg_t r_cs;
99 greg_t r_rfl;
100 greg_t r_rsp;
101 greg_t r_ss;
102 };
103
104 #define r_r0 r_rax /* r0 for portability */
105 #define r_r1 r_rdx /* r1 for portability */
106 #define r_fp r_rbp /* kernel frame pointer */
107 #define r_sp r_rsp /* user stack pointer */
108 #define r_pc r_rip /* user's instruction pointer */
109 #define r_ps r_rfl /* user's RFLAGS */
110
111 #ifdef _KERNEL
112 #define lwptoregs(lwp) ((struct regs *)((lwp)->lwp_regs))
113 #endif /* _KERNEL */
114
115 #else /* !_ASM */
116
117 #if defined(_MACHDEP)
118
119 #include <sys/machprivregs.h>
120 #include <sys/pcb.h>
121
122 /*
123 * We can not safely sample {fs,gs}base on the hypervisor. The rdmsr
124 * instruction triggers a #gp fault which is emulated in the hypervisor
125 * on behalf of the guest. This is normally ok but if the guest is in
126 * the special failsafe handler it must not fault again or the hypervisor
127 * will kill the domain. We could use something different than INTR_PUSH
128 * in xen_failsafe_callback but for now we will not sample them.
129 */
130 #if defined(DEBUG) && !defined(__xpv)
131 #define __SAVE_BASES \
132 movl $MSR_AMD_FSBASE, %ecx; \
133 rdmsr; \
134 movl %eax, REGOFF_FSBASE(%rsp); \
135 movl %edx, REGOFF_FSBASE+4(%rsp); \
136 movl $MSR_AMD_GSBASE, %ecx; \
137 rdmsr; \
138 movl %eax, REGOFF_GSBASE(%rsp); \
139 movl %edx, REGOFF_GSBASE+4(%rsp)
140 #else
141 #define __SAVE_BASES
142 #endif
143
144 /*
145 * Create a struct regs on the stack suitable for an
146 * interrupt trap.
147 *
148 * Assumes that the trap handler has already pushed an
149 * appropriate r_err and r_trapno
150 */
151 #define __SAVE_REGS \
152 movq %r15, REGOFF_R15(%rsp); \
153 movq %r14, REGOFF_R14(%rsp); \
154 movq %r13, REGOFF_R13(%rsp); \
155 movq %r12, REGOFF_R12(%rsp); \
156 movq %r11, REGOFF_R11(%rsp); \
157 movq %r10, REGOFF_R10(%rsp); \
158 movq %rbp, REGOFF_RBP(%rsp); \
159 movq %rbx, REGOFF_RBX(%rsp); \
160 movq %rax, REGOFF_RAX(%rsp); \
161 movq %r9, REGOFF_R9(%rsp); \
162 movq %r8, REGOFF_R8(%rsp); \
163 movq %rcx, REGOFF_RCX(%rsp); \
164 movq %rdx, REGOFF_RDX(%rsp); \
165 movq %rsi, REGOFF_RSI(%rsp); \
166 movq %rdi, REGOFF_RDI(%rsp); \
167 movq %rbp, REGOFF_SAVFP(%rsp); \
168 movq REGOFF_RIP(%rsp), %rcx; \
169 movq %rcx, REGOFF_SAVPC(%rsp); \
170 xorl %ecx, %ecx; \
171 movw %gs, %cx; \
172 movq %rcx, REGOFF_GS(%rsp); \
173 movw %fs, %cx; \
174 movq %rcx, REGOFF_FS(%rsp); \
175 movw %es, %cx; \
176 movq %rcx, REGOFF_ES(%rsp); \
177 movw %ds, %cx; \
178 movq %rcx, REGOFF_DS(%rsp); \
179 __SAVE_BASES
180
181 #define __RESTORE_REGS \
182 movq REGOFF_RDI(%rsp), %rdi; \
183 movq REGOFF_RSI(%rsp), %rsi; \
184 movq REGOFF_RDX(%rsp), %rdx; \
185 movq REGOFF_RCX(%rsp), %rcx; \
186 movq REGOFF_R8(%rsp), %r8; \
187 movq REGOFF_R9(%rsp), %r9; \
188 movq REGOFF_RAX(%rsp), %rax; \
189 movq REGOFF_RBX(%rsp), %rbx; \
190 movq REGOFF_RBP(%rsp), %rbp; \
191 movq REGOFF_R10(%rsp), %r10; \
192 movq REGOFF_R11(%rsp), %r11; \
193 movq REGOFF_R12(%rsp), %r12; \
194 movq REGOFF_R13(%rsp), %r13; \
195 movq REGOFF_R14(%rsp), %r14; \
196 movq REGOFF_R15(%rsp), %r15
197
198 /*
199 * Push register state onto the stack. If we've
200 * interrupted userland, do a swapgs as well.
201 */
202 #define INTR_PUSH \
203 subq $REGOFF_TRAPNO, %rsp; \
204 __SAVE_REGS; \
205 cmpw $KCS_SEL, REGOFF_CS(%rsp); \
206 je 6f; \
207 movq $0, REGOFF_SAVFP(%rsp); \
208 SWAPGS; \
209 6: CLEAN_CS
210
211 #define INTR_POP \
212 leaq sys_lcall32(%rip), %r11;\
213 cmpq %r11, REGOFF_RIP(%rsp); \
214 __RESTORE_REGS; \
215 je 5f; \
216 cmpw $KCS_SEL, REGOFF_CS(%rsp);\
217 je 8f; \
218 5: SWAPGS; \
219 8: addq $REGOFF_RIP, %rsp
220
221 #define USER_POP \
222 __RESTORE_REGS; \
223 SWAPGS; \
224 addq $REGOFF_RIP, %rsp /* Adjust %rsp to prepare for iretq */
225
226 #define USER32_POP \
227 movl REGOFF_RDI(%rsp), %edi; \
228 movl REGOFF_RSI(%rsp), %esi; \
229 movl REGOFF_RDX(%rsp), %edx; \
230 movl REGOFF_RCX(%rsp), %ecx; \
231 movl REGOFF_RAX(%rsp), %eax; \
232 movl REGOFF_RBX(%rsp), %ebx; \
233 movl REGOFF_RBP(%rsp), %ebp; \
234 SWAPGS; \
235 addq $REGOFF_RIP, %rsp /* Adjust %rsp to prepare for iretq */
236
237 #define DFTRAP_PUSH \
238 subq $REGOFF_TRAPNO, %rsp; \
239 __SAVE_REGS
240
241 #endif /* _MACHDEP */
242
243 /*
244 * Used to set rflags to known values at the head of an
245 * interrupt gate handler, i.e. interrupts are -already- disabled.
246 */
247 #define INTGATE_INIT_KERNEL_FLAGS \
248 pushq $F_OFF; \
249 popfq
250
251 #endif /* !_ASM */
252
253 #include <sys/controlregs.h>
254
255 #if defined(_KERNEL) && !defined(_ASM)
256 #if !defined(__lint) && defined(__GNUC__)
257
258 extern __GNU_INLINE ulong_t
getcr8(void)259 getcr8(void)
260 {
261 uint64_t value;
262
263 __asm__ __volatile__(
264 "movq %%cr8, %0"
265 : "=r" (value));
266 return (value);
267 }
268
269 extern __GNU_INLINE void
setcr8(ulong_t value)270 setcr8(ulong_t value)
271 {
272 __asm__ __volatile__(
273 "movq %0, %%cr8"
274 : /* no output */
275 : "r" (value));
276 }
277
278 #else
279
280 extern ulong_t getcr8(void);
281 extern void setcr8(ulong_t);
282
283 #endif /* !defined(__lint) && defined(__GNUC__) */
284 #endif /* _KERNEL && !_ASM */
285
286 /* Control register layout for panic dump */
287
288 #define CREGSZ 0x68
289 #define CREG_GDT 0
290 #define CREG_IDT 0x10
291 #define CREG_LDT 0x20
292 #define CREG_TASKR 0x28
293 #define CREG_CR0 0x30
294 #define CREG_CR2 0x38
295 #define CREG_CR3 0x40
296 #define CREG_CR4 0x48
297 #define CREG_CR8 0x50
298 #define CREG_KGSBASE 0x58
299 #define CREG_EFER 0x60
300
301 #if !defined(_ASM) && defined(_INT64_TYPE)
302
303 typedef uint64_t creg64_t;
304 typedef upad128_t creg128_t;
305
306 struct cregs {
307 creg128_t cr_gdt;
308 creg128_t cr_idt;
309 creg64_t cr_ldt;
310 creg64_t cr_task;
311 creg64_t cr_cr0;
312 creg64_t cr_cr2;
313 creg64_t cr_cr3;
314 creg64_t cr_cr4;
315 creg64_t cr_cr8;
316 creg64_t cr_kgsbase;
317 creg64_t cr_efer;
318 };
319
320 #if defined(_KERNEL)
321 extern void getcregs(struct cregs *);
322 #endif /* _KERNEL */
323
324 #endif /* !_ASM && _INT64_TYPE */
325
326 #ifdef __cplusplus
327 }
328 #endif
329
330 #endif /* !_AMD64_SYS_PRIVREGS_H */
331