xref: /titanic_50/usr/src/uts/sun4u/ml/wbuf.s (revision 25cf1a301a396c38e8adf52c15f537b80d2483f7)
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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 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/machthread.h>
31#include <sys/privregs.h>
32#include <sys/machasi.h>
33#include <sys/trap.h>
34#include <sys/mmu.h>
35#include <sys/machparam.h>
36#include <sys/machtrap.h>
37#include <sys/traptrace.h>
38
39#if !defined(lint)
40#include "assym.h"
41
42	/*
43	 * Spill fault handlers
44	 *   sn0 - spill normal tl 0
45	 *   sn1 - spill normal tl >0
46	 *   so0 - spill other tl 0
47	 *   so1 - spill other tl >0
48	 */
49
50	ENTRY_NP(fault_32bit_sn0)
51	!
52	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_SN0)
53	!
54	! Spill normal tl0 fault.
55	! This happens when a user tries to spill to an unmapped or
56	! misaligned stack. We handle an unmapped stack by simulating
57	! a pagefault at the trap pc and a misaligned stack by generating
58	! a user alignment trap.
59	!
60	! spill the window into wbuf slot 0
61	! (we know wbuf is empty since we came from user mode)
62	!
63	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
64	! sfar (g5 == T_ALIGNMENT)
65	!
66	CPU_ADDR(%g4, %g1)
67	ldn	[%g4 + CPU_MPCB], %g1
68	stn	%sp, [%g1 + MPCB_SPBUF]
69	ldn	[%g1 + MPCB_WBUF], %g2
70	SAVE_V8WINDOW(%g2)
71	mov	1, %g2
72	st	%g2, [%g1 + MPCB_WBCNT]
73	saved
74	!
75	! setup user_trap args
76	!
77	set	sfmmu_tsbmiss_exception, %g1
78	mov	%g6, %g2			! arg2 = tagaccess
79	mov	T_WIN_OVERFLOW, %g3		! arg3 = traptype
80	cmp	%g5, T_ALIGNMENT
81	bne	%icc, 1f
82	nop
83	set	trap, %g1
84	mov	T_ALIGNMENT, %g3
851:
86	sub	%g0, 1, %g4
87	!
88	! spill traps increment %cwp by 2,
89	! but user_trap wants the trap %cwp
90	!
91	rdpr	%tstate, %g5
92	and	%g5, TSTATE_CWP, %g5
93	ba,pt	%xcc, user_trap
94	wrpr	%g0, %g5, %cwp
95	SET_SIZE(fault_32bit_sn0)
96
97	!
98	! Spill normal tl1 fault.
99	! This happens when sys_trap's save spills to an unmapped stack.
100	! We handle it by spilling the window to the wbuf and trying
101	! sys_trap again.
102	!
103	! spill the window into wbuf slot 0
104	! (we know wbuf is empty since we came from user mode)
105	!
106	ENTRY_NP(fault_32bit_sn1)
107	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SN1)
108	CPU_ADDR(%g5, %g6)
109	ldn	[%g5 + CPU_MPCB], %g6
110	stn	%sp, [%g6 + MPCB_SPBUF]
111	ldn	[%g6 + MPCB_WBUF], %g5
112	SAVE_V8WINDOW(%g5)
113	mov	1, %g5
114	st	%g5, [%g6 + MPCB_WBCNT]
115	saved
116	set	sys_trap, %g5
117	wrpr	%g5, %tnpc
118	done
119	SET_SIZE(fault_32bit_sn1)
120
121	ENTRY_NP(fault_32bit_so0)
122	!
123	FAULT_WINTRACE(%g5, %g6, %g1, TT_F32_SO0)
124	!
125	! Spill other tl0 fault.
126	! This happens when the kernel spills a user window and that
127	! user's stack has been unmapped.
128	! We handle it by spilling the window into the user's wbuf.
129	!
130	! find lwp & increment wbcnt
131	!
132	CPU_ADDR(%g5, %g6)
133	ldn	[%g5 + CPU_MPCB], %g1
134	ld	[%g1 + MPCB_WBCNT], %g2
135	add	%g2, 1, %g3
136	st	%g3, [%g1 + MPCB_WBCNT]
137	!
138	! use previous wbcnt to spill new spbuf & wbuf
139	!
140	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
141	add	%g1, MPCB_SPBUF, %g3
142	stn	%sp, [%g3 + %g4]
143	sll	%g2, RWIN32SHIFT, %g4
144	ldn	[%g1 + MPCB_WBUF], %g3
145	add	%g3, %g4, %g3
146	SAVE_V8WINDOW(%g3)
147	saved
148	retry
149	SET_SIZE(fault_32bit_so0)
150
151	!
152	! Spill other tl1 fault.
153	! This happens when priv_trap spills a user window and that
154	! user's stack has been unmapped.
155	! We handle it by spilling the window to the wbuf and retrying
156	! the save.
157	!
158	ENTRY_NP(fault_32bit_so1)
159	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SO1)
160	CPU_ADDR(%g5, %g6)
161	!
162	! find lwp & increment wbcnt
163	!
164	ldn	[%g5 + CPU_MPCB], %g6
165	ld	[%g6 + MPCB_WBCNT], %g5
166	add	%g5, 1, %g7
167	st	%g7, [%g6 + MPCB_WBCNT]
168	!
169	! use previous wbcnt to spill new spbuf & wbuf
170	!
171	sll	%g5, CPTRSHIFT, %g7		! spbuf size is sizeof (caddr_t)
172	add	%g6, %g7, %g7
173	stn	%sp, [%g7 + MPCB_SPBUF]
174	sll	%g5, RWIN32SHIFT, %g7
175	ldn	[%g6 + MPCB_WBUF], %g5
176	add	%g5, %g7, %g7
177	SAVE_V8WINDOW(%g7)
178	saved
179	set	sys_trap, %g5
180	wrpr	%g5, %tnpc
181	done
182	SET_SIZE(fault_32bit_so1)
183
184	ENTRY_NP(fault_64bit_sn0)
185	!
186	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_SN0)
187	!
188	! Spill normal tl0 fault.
189	! This happens when a user tries to spill to an unmapped or
190	! misaligned stack. We handle an unmapped stack by simulating
191	! a pagefault at the trap pc and a misaligned stack by generating
192	! a user alignment trap.
193	!
194	! spill the window into wbuf slot 0
195	! (we know wbuf is empty since we came from user mode)
196	!
197	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
198	! sfar (g5 == T_ALIGNMENT)
199	!
200	CPU_ADDR(%g4, %g1)
201	ldn	[%g4 + CPU_MPCB], %g1
202	stn	%sp, [%g1 + MPCB_SPBUF]
203	ldn	[%g1 + MPCB_WBUF], %g2
204	SAVE_V9WINDOW(%g2)
205	mov	1, %g2
206	st	%g2, [%g1 + MPCB_WBCNT]
207	saved
208	!
209	! setup user_trap args
210	!
211	set	sfmmu_tsbmiss_exception, %g1
212	mov	%g6, %g2			! arg2 = tagaccess
213	mov	%g5, %g3			! arg3 = traptype
214	cmp	%g5, T_ALIGNMENT
215	bne	%icc, 1f
216	nop
217	set	trap, %g1
218	mov	T_ALIGNMENT, %g3
2191:
220	sub	%g0, 1, %g4
221	!
222	! spill traps increment %cwp by 2,
223	! but user_trap wants the trap %cwp
224	!
225	rdpr	%tstate, %g5
226	and	%g5, TSTATE_CWP, %g5
227	ba,pt	%xcc, user_trap
228	  wrpr	%g0, %g5, %cwp
229	SET_SIZE(fault_64bit_sn0)
230
231	!
232	! Spill normal tl1 fault.
233	! This happens when sys_trap's save spills to an unmapped stack.
234	! We handle it by spilling the window to the wbuf and trying
235	! sys_trap again.
236	!
237	! spill the window into wbuf slot 0
238	! (we know wbuf is empty since we came from user mode)
239	!
240	ENTRY_NP(fault_64bit_sn1)
241	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SN1)
242	CPU_ADDR(%g5, %g6)
243	ldn	[%g5 + CPU_MPCB], %g6
244	stn	%sp, [%g6 + MPCB_SPBUF]
245	ldn	[%g6 + MPCB_WBUF], %g5
246	SAVE_V9WINDOW(%g5)
247	mov	1, %g5
248	st	%g5, [%g6 + MPCB_WBCNT]
249	saved
250	set	sys_trap, %g5
251	wrpr	%g5, %tnpc
252	done
253	SET_SIZE(fault_64bit_sn1)
254
255	ENTRY_NP(fault_64bit_so0)
256	!
257	FAULT_WINTRACE(%g5, %g6, %g1, TT_F64_SO0)
258	!
259	! Spill other tl0 fault.
260	! This happens when the kernel spills a user window and that
261	! user's stack has been unmapped.
262	! We handle it by spilling the window into the user's wbuf.
263	!
264	! find lwp & increment wbcnt
265	!
266	CPU_ADDR(%g5, %g6)
267	ldn	[%g5 + CPU_MPCB], %g1
268	ld	[%g1 + MPCB_WBCNT], %g2
269	add	%g2, 1, %g3
270	st	%g3, [%g1 + MPCB_WBCNT]
271	!
272	! use previous wbcnt to spill new spbuf & wbuf
273	!
274	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
275	add	%g1, MPCB_SPBUF, %g3
276	stn	%sp, [%g3 + %g4]
277	sll	%g2, RWIN64SHIFT, %g4
278	ldn	[%g1 + MPCB_WBUF], %g3
279	add	%g3, %g4, %g3
280	SAVE_V9WINDOW(%g3)
281	saved
282	retry
283	SET_SIZE(fault_64bit_so0)
284
285	!
286	! Spill other tl1 fault.
287	! This happens when priv_trap spills a user window and that
288	! user's stack has been unmapped.
289	! We handle it by spilling the window to the wbuf and retrying
290	! the save.
291	!
292	ENTRY_NP(fault_64bit_so1)
293	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SO1)
294	CPU_ADDR(%g5, %g6)
295	!
296	! find lwp & increment wbcnt
297	!
298	ldn	[%g5 + CPU_MPCB], %g6
299	ld	[%g6 + MPCB_WBCNT], %g5
300	add	%g5, 1, %g7
301	st	%g7, [%g6 + MPCB_WBCNT]
302	!
303	! use previous wbcnt to spill new spbuf & wbuf
304	!
305	sll	%g5, CPTRSHIFT, %g7		! spbuf size is sizeof (caddr_t)
306	add	%g6, %g7, %g7
307	stn	%sp, [%g7 + MPCB_SPBUF]
308	sll	%g5, RWIN64SHIFT, %g7
309	ldn	[%g6 + MPCB_WBUF], %g5
310	add	%g5, %g7, %g7
311	SAVE_V9WINDOW(%g7)
312	saved
313	set	sys_trap, %g5
314	wrpr	%g5, %tnpc
315	done
316	SET_SIZE(fault_64bit_so1)
317
318	/*
319	 * Fill fault handlers
320	 *   fn0 - fill normal tl 0
321	 *   fn1 - fill normal tl 1
322	 */
323
324	ENTRY_NP(fault_32bit_fn0)
325	!
326	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN0)
327	!
328.fault_fn0_common:
329	!
330	! Fill normal tl0 fault.
331	! This happens when a user tries to fill to an unmapped or
332	! misaligned stack. We handle an unmapped stack by simulating
333	! a pagefault at the trap pc and a misaligned stack by generating
334	! a user alignment trap.
335	!
336	! setup user_trap args
337	!
338	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
339	! sfar (g5 == T_ALIGNMENT)
340	!
341	set	sfmmu_tsbmiss_exception, %g1
342	mov	%g6, %g2			! arg2 = tagaccess
343	mov	T_WIN_UNDERFLOW, %g3
344	cmp	%g5, T_ALIGNMENT
345	bne	%icc, 1f
346	nop
347	set	trap, %g1
348	mov	T_ALIGNMENT, %g3
3491:
350	sub	%g0, 1, %g4
351	!
352	! sys_trap wants %cwp to be the same as when the trap occured,
353	! so set it from %tstate
354	!
355	rdpr	%tstate, %g5
356	and	%g5, TSTATE_CWP, %g5
357	ba,pt	%xcc, user_trap
358	wrpr	%g0, %g5, %cwp
359	SET_SIZE(fault_32bit_fn0)
360
361	ENTRY_NP(fault_32bit_fn1)
362	!
363	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN1)
364	!
365	srl	%sp, 0, %g7
366	!
367.fault_fn1_common:
368	!
369	! Fill normal tl1 fault.
370	! This happens when user_rtt's restore fills from an unmapped or
371	! misaligned stack. We handle an unmapped stack by simulating
372	! a pagefault at user_rtt and a misaligned stack by generating
373	! a RTT alignment trap.
374	!
375	! save fault addr & fix %cwp
376	!
377	rdpr	%tstate, %g1
378	and	%g1, TSTATE_CWP, %g1
379	wrpr	%g0, %g1, %cwp
380	!
381	! fake tl1 traps regs so that after pagefault runs, we
382	! re-execute at user_rtt.
383	!
384	wrpr	%g0, 1, %tl
385	set	TSTATE_KERN | TSTATE_IE, %g1
386	wrpr	%g0, %g1, %tstate
387	set	user_rtt, %g1
388	wrpr	%g0, %g1, %tpc
389	add	%g1, 4, %g1
390	wrpr	%g0, %g1, %tnpc
391	!
392	! setup sys_trap args
393	!
394	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
395	! sfar (g5 == T_ALIGNMENT)
396	!
397	set	sfmmu_tsbmiss_exception, %g1
398	mov	%g6, %g2			! arg2 = tagaccess
399	set	T_USER | T_SYS_RTT_PAGE, %g3	! arg3 = traptype
400	cmp	%g5, T_ALIGNMENT
401	bne	%icc, 1f
402	nop
403	set	trap, %g1
404	set	T_USER | T_SYS_RTT_ALIGN, %g3
4051:
406	sub	%g0, 1, %g4
407	!
408	! setup to run kernel again by setting THREAD_REG, %wstate
409	! and the mmu to their kernel values.
410	!
411	rdpr	%pstate, %l1
412	wrpr	%l1, PSTATE_AG, %pstate
413	mov	%l6, THREAD_REG			! %l6 is user_rtt's thread
414	wrpr	%g0, %l1, %pstate
415	rdpr	%wstate, %l1
416	sllx	%l1, WSTATE_SHIFT, %l1
417	wrpr	%l1, WSTATE_K64, %wstate
418	sethi   %hi(kcontextreg), %g5           ! mov   KCONTEXT, %g5
419        ldx     [%g5 + %lo(kcontextreg)], %g5
420	mov	MMU_PCONTEXT, %g6
421	stxa	%g5, [%g6]ASI_MMU_CTX
422	sethi   %hi(FLUSH_ADDR), %g5
423	flush   %g5
424
425	ba,pt	%xcc, priv_trap
426	nop
427	SET_SIZE(fault_32bit_fn1)
428
429	ENTRY_NP(fault_64bit_fn0)
430	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN0)
431	b	.fault_fn0_common
432	  nop
433	SET_SIZE(fault_64bit_fn0)
434
435	ENTRY_NP(fault_64bit_fn1)
436	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN1)
437	b	.fault_fn1_common
438	  nop
439	SET_SIZE(fault_64bit_fn1)
440
441	/*
442	 * Kernel fault handlers
443	 */
444	ENTRY_NP(fault_32bit_not)
445	ENTRY_NP(fault_64bit_not)
446	ba,pt	%xcc, ptl1_panic
447	mov	PTL1_BAD_WTRAP, %g1
448	SET_SIZE(fault_32bit_not)
449	SET_SIZE(fault_64bit_not)
450#endif /* !lint */
451