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