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