xref: /illumos-gate/usr/src/uts/sun4v/ml/mach_xc.S (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include "assym.h"
27
28#include <sys/asm_linkage.h>
29#include <sys/privregs.h>
30#include <sys/x_call.h>
31#include <sys/xc_impl.h>
32#include <sys/machthread.h>
33#include <sys/hypervisor_api.h>
34
35#ifdef TRAPTRACE
36#include <sys/traptrace.h>
37#endif /* TRAPTRACE */
38
39
40/*
41 * Entered by the software trap (TT=ST_SELFXCALL, TL>0) thru send_self_xcall().
42 * Emulate the mondo handler - vec_interrupt().
43 *
44 * Global registers are the Alternate Globals.
45 * Arguments:
46 * 	%o0 - CPU
47 * 	ILP32 kernel:
48 * 		%o5 - function to call
49 * 		%o1, %o2, %o3, %o4  - arguments
50 * 	LP64 kernel:
51 * 		%o3 - function to call
52 * 		%o1, %o2 - arguments
53 */
54	ENTRY_NP(self_xcall)
55	!
56	! TL>0 handlers are expected to do "retry"
57	! prepare their return PC and nPC now
58	!
59	rdpr	%tnpc, %g1
60	wrpr	%g1, %tpc			!  PC <- TNPC[TL]
61 	add	%g1, 4, %g1
62	wrpr	%g1, %tnpc			! nPC <- TNPC[TL] + 4
63
64#ifdef TRAPTRACE
65	TRACE_PTR(%g4, %g6)
66	GET_TRACE_TICK(%g6, %g3)
67	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
68	rdpr	%tl, %g6
69	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
70	rdpr	%tt, %g6
71	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
72	stna	%o3, [%g4 + TRAP_ENT_TR]%asi ! pc of the TL>0 handler
73	rdpr	%tpc, %g6
74	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
75	rdpr	%tstate, %g6
76	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
77	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
78	stna	%o1, [%g4 + TRAP_ENT_F1]%asi ! arg 1
79	stna	%o2, [%g4 + TRAP_ENT_F2]%asi ! arg 2
80	stna	%g0, [%g4 + TRAP_ENT_F3]%asi
81	stna	%g0, [%g4 + TRAP_ENT_F4]%asi
82	TRACE_NEXT(%g4, %g6, %g3)
83#endif /* TRAPTRACE */
84	!
85	! Load the arguments for the fast trap handler.
86	!
87	mov	%o1, %g1
88	jmp	%o3				! call the fast trap handler
89	mov	%o2, %g2
90	/* Not Reached */
91	SET_SIZE(self_xcall)
92
93#ifdef  TRAPTRACE
94	ENTRY(xc_trace)
95	rdpr	%pstate, %g1
96	andn	%g1, PSTATE_IE | PSTATE_AM, %g2
97	wrpr	%g0, %g2, %pstate			/* disable interrupts */
98	TRACE_PTR(%g3, %g4)
99	GET_TRACE_TICK(%g6, %g4)
100	stxa	%g6, [%g3 + TRAP_ENT_TICK]%asi
101	stha	%g0, [%g3 + TRAP_ENT_TL]%asi
102	set	TT_XCALL, %g2
103	or	%o0, %g2, %g4
104	stha	%g4, [%g3 + TRAP_ENT_TT]%asi
105	stna	%o7, [%g3 + TRAP_ENT_TPC]%asi
106	ldn	[%o1], %g2
107	stna	%g2, [%g3 + TRAP_ENT_SP]%asi		/* sp = cpuset */
108	stna	%o2, [%g3 + TRAP_ENT_TR]%asi		/* tr = func */
109	stna	%o3, [%g3 + TRAP_ENT_F1]%asi		/* f1 = arg1 */
110	stna	%o4, [%g3 + TRAP_ENT_F2]%asi		/* f2 = arg2 */
111	stna	%g0, [%g3 + TRAP_ENT_F3]%asi		/* f3 = 0 */
112	stna	%i7, [%g3 + TRAP_ENT_F4]%asi		/* f4 = xcall caller */
113	stxa	%g1, [%g3 + TRAP_ENT_TSTATE]%asi	/* tstate = pstate */
114	TRACE_NEXT(%g2, %g3, %g4)
115/*
116 * In the case of a cpuset of greater size than a long we
117 * grab extra trace buffers just to store the cpuset.
118 * Seems like a waste but popular opinion opted for this
119 * rather than increase the size of the buffer.
120 */
121#if CPUSET_SIZE > CLONGSIZE
122	add	%o1, CPUSET_SIZE, %g5			/* end of cpuset */
123	clr	%o2
1241:
125	TRACE_PTR(%g3, %g4)
126	stha	%g0, [%g3 + TRAP_ENT_TL]%asi
127	set	TT_XCALL_CONT, %g2
128	or	%g2, %o2, %g2				/* continuation # */
129	stha	%g2, [%g3 + TRAP_ENT_TT]%asi
130	stxa	%g6, [%g3 + TRAP_ENT_TICK]%asi		/* same tick */
131	stna	%g0, [%g3 + TRAP_ENT_TPC]%asi		/* clr unused fields */
132	stna	%g0, [%g3 + TRAP_ENT_SP]%asi
133	stna	%g0, [%g3 + TRAP_ENT_TR]%asi
134	stxa	%g0, [%g3 + TRAP_ENT_TSTATE]%asi
135	stna	%g0, [%g3 + TRAP_ENT_F2]%asi
136	stna	%g0, [%g3 + TRAP_ENT_F3]%asi
137	stna	%g0, [%g3 + TRAP_ENT_F4]%asi
138	ldn	[%o1], %g2
139	stna	%g2, [%g3 + TRAP_ENT_F1]%asi
140	add	%o1, CLONGSIZE, %o1
141	cmp	%o1, %g5
142	bge	2f
143	ldn	[%o1], %g2
144	stna	%g2, [%g3 + TRAP_ENT_F2]%asi
145	add	%o1, CLONGSIZE, %o1
146	cmp	%o1, %g5
147	bge	2f
148	ldn	[%o1], %g2
149	stna	%g2, [%g3 + TRAP_ENT_F3]%asi
150	add	%o1, CLONGSIZE, %o1
151	cmp	%o1, %g5
152	bge	2f
153	ldn	[%o1], %g2
154	stna	%g2, [%g3 + TRAP_ENT_F4]%asi
155	add	%o1, CLONGSIZE, %o1
1562:
157	TRACE_NEXT(%g2, %g3, %g4)
158	cmp	%o1, %g5
159	bl	1b
160	inc	%o2
161#endif	/* CPUSET_SIZE */
162	retl
163	wrpr	%g0, %g1, %pstate			/* enable interrupts */
164	SET_SIZE(xc_trace)
165
166#endif	/* TRAPTRACE */
167
168/*
169 * Setup interrupt dispatch data registers
170 * Entry:
171 *	%o0 - function or inumber to call
172 *	%o1, %o2 - arguments (2 uint64_t's)
173 */
174	ENTRY(init_mondo)
175	ALTENTRY(init_mondo_nocheck)
176	CPU_ADDR(%g1, %g4)			! load CPU struct addr
177	add	%g1, CPU_MCPU, %g1
178	ldx	[%g1 + MCPU_MONDO_DATA], %g1
179	stx	%o0, [%g1]
180	stx	%o1, [%g1+8]
181	stx	%o2, [%g1+0x10]
182	stx	%g0, [%g1+0x18]
183	stx	%g0, [%g1+0x20]
184	stx	%g0, [%g1+0x28]
185	stx	%g0, [%g1+0x30]
186	stx	%g0, [%g1+0x38]
187	retl
188	membar	#Sync			! allowed to be in the delay slot
189	SET_SIZE(init_mondo)
190
191/*
192 * Ship mondo to cpuid
193 */
194	ENTRY_NP(shipit)
195	/* For now use dummy interface:  cpu# func arg1 arg2 */
196	CPU_ADDR(%g1, %g4)
197	add	%g1, CPU_MCPU, %g1
198	ldx	[%g1 + MCPU_MONDO_DATA_RA],	%o2
199	mov	HV_INTR_SEND, %o5
200	ta	FAST_TRAP
201	retl
202	membar	#Sync
203	SET_SIZE(shipit)
204
205/*
206 * Get cpu structure
207 * Entry:
208 *      %o0 - register for CPU_ADDR macro
209 *      %o1 - scratch for CPU_ADDR macro
210 */
211	ENTRY(get_cpuaddr)
212	CPU_ADDR(%o0, %o1)	! %o0 == CPU struct addr
213	retl
214	nop
215	SET_SIZE(get_cpuaddr)
216
217/*
218 * This is to ensure that previously called xtrap handlers have executed on
219 * sun4v. We zero out the byte corresponding to its cpuid in the
220 * array passed to us from xt_sync(), so the sender knows the previous
221 * mondo has been executed.
222 * Register:
223 *		%g1 - Addr of the cpu_sync array.
224 */
225	ENTRY_NP(xt_sync_tl1)
226	CPU_INDEX(%g3, %g4)		/* %g3 = cpu id */
227	stb	%g0, [%g1 + %g3]
228	retry
229	SET_SIZE(xt_sync_tl1)
230
231