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
45void
46xen_failsafe_callback(void)
47{}
48
49void
50xen_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 */
250