Print this page
11859 need swapgs mitigation
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/intel/amd64/sys/privregs.h
+++ new/usr/src/uts/intel/amd64/sys/privregs.h
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 +/*
28 + * Copyright 2019 Joyent, Inc.
29 + */
30 +
27 31 #ifndef _AMD64_SYS_PRIVREGS_H
28 32 #define _AMD64_SYS_PRIVREGS_H
29 33
30 34 #include <sys/ccompile.h>
31 35
32 36 #ifdef __cplusplus
33 37 extern "C" {
34 38 #endif
35 39
36 40 /*
37 41 * This file describes the cpu's privileged register set, and
38 42 * how the machine state is saved on the stack when a trap occurs.
39 43 */
40 44
41 45 #if !defined(__amd64)
42 46 #error "non-amd64 code depends on amd64 privileged header!"
43 47 #endif
44 48
45 49 #ifndef _ASM
46 50
47 51 /*
48 52 * This is NOT the structure to use for general purpose debugging;
49 53 * see /proc for that. This is NOT the structure to use to decode
50 54 * the ucontext or grovel about in a core file; see <sys/regset.h>.
51 55 */
52 56
53 57 struct regs {
54 58 /*
55 59 * Extra frame for mdb to follow through high level interrupts and
56 60 * system traps. Set them to 0 to terminate stacktrace.
57 61 */
58 62 greg_t r_savfp; /* a copy of %rbp */
59 63 greg_t r_savpc; /* a copy of %rip */
60 64
61 65 greg_t r_rdi; /* 1st arg to function */
62 66 greg_t r_rsi; /* 2nd arg to function */
63 67 greg_t r_rdx; /* 3rd arg to function, 2nd return register */
64 68 greg_t r_rcx; /* 4th arg to function */
65 69
66 70 greg_t r_r8; /* 5th arg to function */
67 71 greg_t r_r9; /* 6th arg to function */
68 72 greg_t r_rax; /* 1st return register, # SSE registers */
69 73 greg_t r_rbx; /* callee-saved, optional base pointer */
70 74
71 75 greg_t r_rbp; /* callee-saved, optional frame pointer */
72 76 greg_t r_r10; /* temporary register, static chain pointer */
73 77 greg_t r_r11; /* temporary register */
74 78 greg_t r_r12; /* callee-saved */
75 79
76 80 greg_t r_r13; /* callee-saved */
77 81 greg_t r_r14; /* callee-saved */
78 82 greg_t r_r15; /* callee-saved */
79 83
80 84 /*
81 85 * fsbase and gsbase are sampled on every exception in DEBUG kernels
82 86 * only. They remain in the non-DEBUG kernel to avoid any flag days.
83 87 */
84 88 greg_t __r_fsbase; /* no longer used in non-DEBUG builds */
85 89 greg_t __r_gsbase; /* no longer used in non-DEBUG builds */
86 90 greg_t r_ds;
87 91 greg_t r_es;
88 92 greg_t r_fs; /* %fs is *never* used by the kernel */
89 93 greg_t r_gs;
90 94
91 95 greg_t r_trapno;
92 96
93 97 /*
94 98 * (the rest of these are defined by the hardware)
95 99 */
96 100 greg_t r_err;
97 101 greg_t r_rip;
98 102 greg_t r_cs;
99 103 greg_t r_rfl;
100 104 greg_t r_rsp;
101 105 greg_t r_ss;
102 106 };
103 107
104 108 #define r_r0 r_rax /* r0 for portability */
105 109 #define r_r1 r_rdx /* r1 for portability */
106 110 #define r_fp r_rbp /* kernel frame pointer */
107 111 #define r_sp r_rsp /* user stack pointer */
108 112 #define r_pc r_rip /* user's instruction pointer */
109 113 #define r_ps r_rfl /* user's RFLAGS */
110 114
111 115 #ifdef _KERNEL
112 116 #define lwptoregs(lwp) ((struct regs *)((lwp)->lwp_regs))
113 117 #endif /* _KERNEL */
114 118
115 119 #else /* !_ASM */
116 120
117 121 #if defined(_MACHDEP)
118 122
119 123 #include <sys/machprivregs.h>
120 124 #include <sys/pcb.h>
121 125
122 126 /*
123 127 * We can not safely sample {fs,gs}base on the hypervisor. The rdmsr
124 128 * instruction triggers a #gp fault which is emulated in the hypervisor
125 129 * on behalf of the guest. This is normally ok but if the guest is in
126 130 * the special failsafe handler it must not fault again or the hypervisor
127 131 * will kill the domain. We could use something different than INTR_PUSH
128 132 * in xen_failsafe_callback but for now we will not sample them.
129 133 */
130 134 #if defined(DEBUG) && !defined(__xpv)
131 135 #define __SAVE_BASES \
132 136 movl $MSR_AMD_FSBASE, %ecx; \
133 137 rdmsr; \
134 138 movl %eax, REGOFF_FSBASE(%rsp); \
135 139 movl %edx, REGOFF_FSBASE+4(%rsp); \
136 140 movl $MSR_AMD_GSBASE, %ecx; \
137 141 rdmsr; \
138 142 movl %eax, REGOFF_GSBASE(%rsp); \
139 143 movl %edx, REGOFF_GSBASE+4(%rsp)
140 144 #else
141 145 #define __SAVE_BASES
142 146 #endif
143 147
144 148 /*
145 149 * Create a struct regs on the stack suitable for an
146 150 * interrupt trap.
147 151 *
148 152 * Assumes that the trap handler has already pushed an
149 153 * appropriate r_err and r_trapno
150 154 */
151 155 #define __SAVE_REGS \
152 156 movq %r15, REGOFF_R15(%rsp); \
153 157 movq %r14, REGOFF_R14(%rsp); \
154 158 movq %r13, REGOFF_R13(%rsp); \
155 159 movq %r12, REGOFF_R12(%rsp); \
156 160 movq %r11, REGOFF_R11(%rsp); \
157 161 movq %r10, REGOFF_R10(%rsp); \
158 162 movq %rbp, REGOFF_RBP(%rsp); \
159 163 movq %rbx, REGOFF_RBX(%rsp); \
160 164 movq %rax, REGOFF_RAX(%rsp); \
161 165 movq %r9, REGOFF_R9(%rsp); \
162 166 movq %r8, REGOFF_R8(%rsp); \
163 167 movq %rcx, REGOFF_RCX(%rsp); \
164 168 movq %rdx, REGOFF_RDX(%rsp); \
165 169 movq %rsi, REGOFF_RSI(%rsp); \
166 170 movq %rdi, REGOFF_RDI(%rsp); \
167 171 movq %rbp, REGOFF_SAVFP(%rsp); \
168 172 movq REGOFF_RIP(%rsp), %rcx; \
169 173 movq %rcx, REGOFF_SAVPC(%rsp); \
170 174 xorl %ecx, %ecx; \
171 175 movw %gs, %cx; \
172 176 movq %rcx, REGOFF_GS(%rsp); \
173 177 movw %fs, %cx; \
174 178 movq %rcx, REGOFF_FS(%rsp); \
175 179 movw %es, %cx; \
176 180 movq %rcx, REGOFF_ES(%rsp); \
177 181 movw %ds, %cx; \
178 182 movq %rcx, REGOFF_DS(%rsp); \
179 183 __SAVE_BASES
180 184
181 185 #define __RESTORE_REGS \
182 186 movq REGOFF_RDI(%rsp), %rdi; \
183 187 movq REGOFF_RSI(%rsp), %rsi; \
184 188 movq REGOFF_RDX(%rsp), %rdx; \
185 189 movq REGOFF_RCX(%rsp), %rcx; \
186 190 movq REGOFF_R8(%rsp), %r8; \
187 191 movq REGOFF_R9(%rsp), %r9; \
188 192 movq REGOFF_RAX(%rsp), %rax; \
189 193 movq REGOFF_RBX(%rsp), %rbx; \
190 194 movq REGOFF_RBP(%rsp), %rbp; \
191 195 movq REGOFF_R10(%rsp), %r10; \
192 196 movq REGOFF_R11(%rsp), %r11; \
193 197 movq REGOFF_R12(%rsp), %r12; \
194 198 movq REGOFF_R13(%rsp), %r13; \
195 199 movq REGOFF_R14(%rsp), %r14; \
196 200 movq REGOFF_R15(%rsp), %r15
197 201
198 202 /*
↓ open down ↓ |
162 lines elided |
↑ open up ↑ |
199 203 * Push register state onto the stack. If we've
200 204 * interrupted userland, do a swapgs as well.
201 205 */
202 206 #define INTR_PUSH \
203 207 subq $REGOFF_TRAPNO, %rsp; \
204 208 __SAVE_REGS; \
205 209 cmpw $KCS_SEL, REGOFF_CS(%rsp); \
206 210 je 6f; \
207 211 movq $0, REGOFF_SAVFP(%rsp); \
208 212 SWAPGS; \
209 -6: CLEAN_CS
213 +6: lfence; /* swapgs mitigation */ \
214 + CLEAN_CS
210 215
211 216 #define INTR_POP \
212 217 leaq sys_lcall32(%rip), %r11;\
213 218 cmpq %r11, REGOFF_RIP(%rsp); \
214 219 __RESTORE_REGS; \
215 220 je 5f; \
216 221 cmpw $KCS_SEL, REGOFF_CS(%rsp);\
217 222 je 8f; \
218 223 5: SWAPGS; \
219 -8: addq $REGOFF_RIP, %rsp
224 +8: lfence; /* swapgs mitigation */ \
225 + addq $REGOFF_RIP, %rsp
220 226
227 +/*
228 + * No need for swapgs mitigation: it's unconditional, and we're heading
229 + * back to userspace.
230 + */
221 231 #define USER_POP \
222 232 __RESTORE_REGS; \
223 233 SWAPGS; \
224 234 addq $REGOFF_RIP, %rsp /* Adjust %rsp to prepare for iretq */
225 235
226 236 #define USER32_POP \
227 237 movl REGOFF_RDI(%rsp), %edi; \
228 238 movl REGOFF_RSI(%rsp), %esi; \
229 239 movl REGOFF_RDX(%rsp), %edx; \
230 240 movl REGOFF_RCX(%rsp), %ecx; \
231 241 movl REGOFF_RAX(%rsp), %eax; \
232 242 movl REGOFF_RBX(%rsp), %ebx; \
233 243 movl REGOFF_RBP(%rsp), %ebp; \
234 244 SWAPGS; \
235 245 addq $REGOFF_RIP, %rsp /* Adjust %rsp to prepare for iretq */
236 246
237 247 #define DFTRAP_PUSH \
238 248 subq $REGOFF_TRAPNO, %rsp; \
239 249 __SAVE_REGS
240 250
241 251 #endif /* _MACHDEP */
242 252
243 253 /*
244 254 * Used to set rflags to known values at the head of an
245 255 * interrupt gate handler, i.e. interrupts are -already- disabled.
246 256 */
247 257 #define INTGATE_INIT_KERNEL_FLAGS \
248 258 pushq $F_OFF; \
249 259 popfq
250 260
251 261 #endif /* !_ASM */
252 262
253 263 #include <sys/controlregs.h>
254 264
255 265 #if defined(_KERNEL) && !defined(_ASM)
256 266 #if !defined(__lint) && defined(__GNUC__)
257 267
258 268 extern __GNU_INLINE ulong_t
259 269 getcr8(void)
260 270 {
261 271 uint64_t value;
262 272
263 273 __asm__ __volatile__(
264 274 "movq %%cr8, %0"
265 275 : "=r" (value));
266 276 return (value);
267 277 }
268 278
269 279 extern __GNU_INLINE void
270 280 setcr8(ulong_t value)
271 281 {
272 282 __asm__ __volatile__(
273 283 "movq %0, %%cr8"
274 284 : /* no output */
275 285 : "r" (value));
276 286 }
277 287
278 288 #else
279 289
280 290 extern ulong_t getcr8(void);
281 291 extern void setcr8(ulong_t);
282 292
283 293 #endif /* !defined(__lint) && defined(__GNUC__) */
284 294 #endif /* _KERNEL && !_ASM */
285 295
286 296 /* Control register layout for panic dump */
287 297
288 298 #define CREGSZ 0x68
289 299 #define CREG_GDT 0
290 300 #define CREG_IDT 0x10
291 301 #define CREG_LDT 0x20
292 302 #define CREG_TASKR 0x28
293 303 #define CREG_CR0 0x30
294 304 #define CREG_CR2 0x38
295 305 #define CREG_CR3 0x40
296 306 #define CREG_CR4 0x48
297 307 #define CREG_CR8 0x50
298 308 #define CREG_KGSBASE 0x58
299 309 #define CREG_EFER 0x60
300 310
301 311 #if !defined(_ASM) && defined(_INT64_TYPE)
302 312
303 313 typedef uint64_t creg64_t;
304 314 typedef upad128_t creg128_t;
305 315
306 316 struct cregs {
307 317 creg128_t cr_gdt;
308 318 creg128_t cr_idt;
309 319 creg64_t cr_ldt;
310 320 creg64_t cr_task;
311 321 creg64_t cr_cr0;
312 322 creg64_t cr_cr2;
313 323 creg64_t cr_cr3;
314 324 creg64_t cr_cr4;
315 325 creg64_t cr_cr8;
316 326 creg64_t cr_kgsbase;
317 327 creg64_t cr_efer;
318 328 };
319 329
320 330 #if defined(_KERNEL)
321 331 extern void getcregs(struct cregs *);
322 332 #endif /* _KERNEL */
323 333
324 334 #endif /* !_ASM && _INT64_TYPE */
325 335
326 336 #ifdef __cplusplus
327 337 }
328 338 #endif
329 339
330 340 #endif /* !_AMD64_SYS_PRIVREGS_H */
↓ open down ↓ |
100 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX