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 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <sys/asm_linkage.h>
  30 #include <sys/hypervisor.h>
  31 #include <sys/privregs.h>
  32 #include <sys/segments.h>
  33 #include <sys/traptrace.h>
  34 #include <sys/trap.h>
  35 #include <sys/psw.h>
  36 #include <sys/x86_archext.h>
  37 #include <sys/asm_misc.h>
  38 
  39 #if !defined(__lint)
  40 #include "assym.h"
  41 #endif
  42 
  43 #if defined(__lint)
  44 
  45 void
  46 xen_failsafe_callback(void)
  47 {}
  48 
  49 void
  50 xen_callback(void)
  51 {}
  52 
  53 #else   /* __lint */
  54 
  55         /*
  56          * The stack frame for events is exactly that of an x86 hardware
  57          * interrupt.
  58          *
  59          * The stack frame for a failsafe callback is augmented with saved
  60          * values for segment registers:
  61          *
  62          * i386
  63          *      %ds, %es, %fs, %gs, %eip, %cs, %eflags [, %oldesp, %oldss ]
  64          *
  65          * On amd64 the stack frame for events is exactly that of an hardware
  66          * interrupt with the addition of rcx and r11.
  67          * 
  68          * The stack frame for a failsafe callback is augmented with saved
  69          * values for segment registers:
  70          * 
  71          * amd64
  72          *      %rcx, %r11, %ds, %es, %fs, %gs, %rip, %cs, %rflags,
  73          *      [, %oldrsp, %oldss ]
  74          *
  75          * The hypervisor  does this to allow the guest OS to handle returns
  76          * to processes which have bad segment registers.
  77          *
  78          * [See comments in xen/arch/x86/[x86_64,x86_32]/entry.S]
  79          *
  80          * We will construct a fully fledged 'struct regs' and call trap
  81          * with a #gp fault.
  82          */
  83 
  84 #if defined(__amd64)
  85 
  86         ENTRY(xen_failsafe_callback)
  87 
  88         /*
  89          * The saved values of rcx and r11 are on the top of the stack.
  90          * pop them and let INTR_PUSH save them. We drop ds, es, fs and
  91          * gs since the hypervisor will have already loaded these for us.
  92          * If any were bad and faulted the hypervisor would have loaded
  93          * them with the null selctor.
  94          */
  95         XPV_TRAP_POP    /* rcx, r11 */
  96 
  97         /*
  98          * XXPV
  99          * If the current segregs are provided for us on the stack by
 100          * the hypervisor then we should simply move them into their proper
 101          * location in the regs struct?
 102          */
 103         addq    $_CONST(_MUL(4, CLONGSIZE)), %rsp
 104 
 105         /*
 106          * XXPV
 107          * It would be nice to somehow figure out which selector caused
 108          * #gp fault.
 109          */
 110 
 111         pushq   $0      /* dummy error */
 112         pushq   $T_GPFLT
 113 
 114         INTR_PUSH
 115         INTGATE_INIT_KERNEL_FLAGS
 116 
 117         /*
 118          * We're here because HYPERVISOR_IRET to userland failed due to a
 119          * bad %cs value. Rewrite %cs, %ss and %rip on the stack so trap
 120          * will know to handle this with kern_gpfault and kill the currently
 121          * running process.
 122          */
 123         movq    $KCS_SEL, REGOFF_CS(%rsp)
 124         movq    $KDS_SEL, REGOFF_SS(%rsp)
 125         leaq    nopop_sys_rtt_syscall(%rip), %rdi
 126         movq    %rdi, REGOFF_RIP(%rsp)
 127 
 128         TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_EVENT) /* Uses labels 8 and 9 */
 129         TRACE_REGS(%rdi, %rsp, %rbx, %rcx)      /* Uses label 9 */
 130         TRACE_STAMP(%rdi)               /* Clobbers %eax, %edx, uses 9 */
 131 
 132         movq    %rsp, %rbp
 133 
 134         TRACE_STACK(%rdi)
 135 
 136         movq    %rbp, %rdi
 137 
 138         ENABLE_INTR_FLAGS
 139 
 140         movq    %rbp, %rdi
 141         xorl    %esi, %esi
 142         movl    %gs:CPU_ID, %edx
 143         call    trap            /* trap(rp, addr, cpuid) handles all trap */
 144         jmp     _sys_rtt
 145         SET_SIZE(xen_failsafe_callback)
 146 
 147 #elif defined(__i386)
 148 
 149         ENTRY(xen_failsafe_callback)
 150 
 151         /*
 152          * drop ds, es, fs and gs
 153          */
 154         addl    $_CONST(_MUL(4, CLONGSIZE)), %esp /* see comment for 64-bit */
 155 
 156         pushl   $0      /* dummy error (see comment for 64-bit) */
 157         pushl   $T_GPFLT
 158 
 159         INTR_PUSH
 160         INTGATE_INIT_KERNEL_FLAGS       /* (set kernel flag values) */
 161 
 162         /*
 163          * The fact were here is because HYPERVISOR_IRET to userland
 164          * failed due to a bad %cs value. Rewrite %cs, %ss and %eip
 165          * on the stack so trap will know to handle this with
 166          * kern_gpfault and kill the currently running process.
 167          */
 168         movl    $KCS_SEL, REGOFF_CS(%esp)
 169         movl    $KDS_SEL, REGOFF_SS(%esp)
 170         leal    nopop_sys_rtt_syscall, %edi
 171         movl    %edi, REGOFF_EIP(%esp)
 172 
 173         TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_EVENT) /* Uses labels 8 and 9 */
 174         TRACE_REGS(%edi, %esp, %ebx, %ecx)      /* Uses label 9 */
 175         TRACE_STAMP(%edi)               /* Clobbers %eax, %edx, uses 9 */
 176 
 177         movl    %esp, %ebp
 178 
 179         TRACE_STACK(%edi)
 180 
 181         ENABLE_INTR_FLAGS
 182 
 183         pushl   %gs:CPU_ID
 184         pushl   $0
 185         pushl   %ebp
 186         call    trap            /* trap(rp, addr, cpuid) handles all traps */
 187         addl    $12, %esp
 188         jmp     _sys_rtt
 189         SET_SIZE(xen_failsafe_callback)
 190 
 191 #endif  /* __i386 */
 192 
 193 #if defined(__amd64)
 194 
 195         ENTRY(xen_callback)
 196         XPV_TRAP_POP
 197 
 198         pushq   $0                      /* dummy error */
 199         pushq   $T_AST
 200 
 201         INTR_PUSH
 202         INTGATE_INIT_KERNEL_FLAGS       /* (set kernel flag values) */
 203 
 204         TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_EVENT) /* Uses labels 8 and 9 */
 205         TRACE_REGS(%rdi, %rsp, %rbx, %rcx)      /* Uses label 9 */
 206         TRACE_STAMP(%rdi)               /* Clobbers %eax, %edx, uses 9 */
 207 
 208         movq    %rsp, %rbp
 209 
 210         TRACE_STACK(%rdi)
 211 
 212         movq    %rdi, %rsi              /* rsi = trap trace recode pointer */
 213         movq    %rbp, %rdi              /* rdi = struct regs pointer */
 214         call    xen_callback_handler
 215 
 216         jmp     _sys_rtt_ints_disabled
 217         /*NOTREACHED*/
 218 
 219         SET_SIZE(xen_callback)
 220 
 221 #elif defined(__i386)
 222 
 223         ENTRY(xen_callback)
 224         pushl   $0                      /* dummy error */
 225         pushl   $T_AST
 226 
 227         INTR_PUSH
 228         INTGATE_INIT_KERNEL_FLAGS       /* (set kernel flag values) */
 229 
 230         TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_EVENT) /* Uses labels 8 and 9 */
 231         TRACE_REGS(%edi, %esp, %ebx, %ecx)      /* Uses label 9 */
 232         TRACE_STAMP(%edi)               /* Clobbers %eax, %edx, uses 9 */
 233 
 234         movl    %esp, %ebp
 235 
 236         TRACE_STACK(%edi)
 237 
 238         pushl   %edi                    /* pass trap trace record pointer */
 239         pushl   %ebp                    /* pass struct regs pointer */
 240         call    xen_callback_handler
 241         addl    $8, %esp
 242 
 243         jmp     _sys_rtt_ints_disabled
 244         /*NOTREACHED*/
 245 
 246         SET_SIZE(xen_callback)
 247 
 248 #endif  /* __i386 */
 249 #endif  /* __lint */