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