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