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
 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
 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 */