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