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