xref: /titanic_51/usr/src/uts/sun4v/ml/wbuf.s (revision f875b4ebb1dd9fdbeb043557cab38ab3bf7f6e01)
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_PADDR(%g5, %g6)
109	mov	ASI_MEM, %asi
110	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
111	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
112	stna	%sp, [%g6 + MPCB_SPBUF]%asi
113	SAVE_V8WINDOW_ASI(%g5)
114	mov	1, %g5
115	sta	%g5, [%g6 + MPCB_WBCNT]%asi
116	saved
117	set	sys_trap, %g5
118	wrpr	%g5, %tnpc
119	done
120	SET_SIZE(fault_32bit_sn1)
121
122	ENTRY_NP(fault_32bit_so0)
123	!
124	FAULT_WINTRACE(%g5, %g6, %g1, TT_F32_SO0)
125	!
126	! Spill other tl0 fault.
127	! This happens when the kernel spills a user window and that
128	! user's stack has been unmapped.
129	! We handle it by spilling the window into the user's wbuf.
130	!
131	! find lwp & increment wbcnt
132	!
133	CPU_ADDR(%g5, %g6)
134	ldn	[%g5 + CPU_MPCB], %g1
135	ld	[%g1 + MPCB_WBCNT], %g2
136	add	%g2, 1, %g3
137	st	%g3, [%g1 + MPCB_WBCNT]
138	!
139	! use previous wbcnt to spill new spbuf & wbuf
140	!
141	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
142	add	%g1, MPCB_SPBUF, %g3
143	stn	%sp, [%g3 + %g4]
144	sll	%g2, RWIN32SHIFT, %g4
145	ldn	[%g1 + MPCB_WBUF], %g3
146	add	%g3, %g4, %g3
147	SAVE_V8WINDOW(%g3)
148	saved
149	retry
150	SET_SIZE(fault_32bit_so0)
151
152	!
153	! Spill other tl1 fault.
154	! This happens when priv_trap spills a user window and that
155	! user's stack has been unmapped.
156	! We handle it by spilling the window to the wbuf and retrying
157	! the save.
158	!
159	ENTRY_NP(fault_32bit_so1)
160	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SO1)
161	CPU_PADDR(%g5, %g6)
162	!
163	! find lwp & increment wbcnt
164	!
165	mov	ASI_MEM, %asi
166	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
167	lda	[%g6 + MPCB_WBCNT]%asi, %g5
168	add	%g5, 1, %g7
169	sta	%g7, [%g6 + MPCB_WBCNT]%asi
170	!
171	! use previous wbcnt to spill new spbuf & wbuf
172	!
173	sll	%g5, CPTRSHIFT, %g7		! spbuf size is sizeof (caddr_t)
174	add	%g6, %g7, %g7
175	stna	%sp, [%g7 + MPCB_SPBUF]%asi
176	sll	%g5, RWIN32SHIFT, %g7
177	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
178	add	%g5, %g7, %g7
179	SAVE_V8WINDOW_ASI(%g7)
180	saved
181	set	sys_trap, %g5
182	wrpr	%g5, %tnpc
183	done
184	SET_SIZE(fault_32bit_so1)
185
186	ENTRY_NP(fault_64bit_sn0)
187	!
188	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_SN0)
189	!
190	! Spill normal tl0 fault.
191	! This happens when a user tries to spill to an unmapped or
192	! misaligned stack. We handle an unmapped stack by simulating
193	! a pagefault at the trap pc and a misaligned stack by generating
194	! a user alignment trap.
195	!
196	! spill the window into wbuf slot 0
197	! (we know wbuf is empty since we came from user mode)
198	!
199	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
200	! sfar (g5 == T_ALIGNMENT)
201	!
202	CPU_ADDR(%g4, %g1)
203	ldn	[%g4 + CPU_MPCB], %g1
204	stn	%sp, [%g1 + MPCB_SPBUF]
205	ldn	[%g1 + MPCB_WBUF], %g2
206	SAVE_V9WINDOW(%g2)
207	mov	1, %g2
208	st	%g2, [%g1 + MPCB_WBCNT]
209	saved
210	!
211	! setup user_trap args
212	!
213	set	sfmmu_tsbmiss_exception, %g1
214	mov	%g6, %g2			! arg2 = tagaccess
215	mov	%g5, %g3			! arg3 = traptype
216	cmp	%g5, T_ALIGNMENT
217	bne	%icc, 1f
218	nop
219	set	trap, %g1
220	mov	T_ALIGNMENT, %g3
2211:
222	sub	%g0, 1, %g4
223	!
224	! spill traps increment %cwp by 2,
225	! but user_trap wants the trap %cwp
226	!
227	rdpr	%tstate, %g5
228	and	%g5, TSTATE_CWP, %g5
229	ba,pt	%xcc, user_trap
230	  wrpr	%g0, %g5, %cwp
231	SET_SIZE(fault_64bit_sn0)
232
233	!
234	! Spill normal tl1 fault.
235	! This happens when sys_trap's save spills to an unmapped stack.
236	! We handle it by spilling the window to the wbuf and trying
237	! sys_trap again.
238	!
239	! spill the window into wbuf slot 0
240	! (we know wbuf is empty since we came from user mode)
241	!
242	ENTRY_NP(fault_64bit_sn1)
243	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SN1)
244	CPU_PADDR(%g5, %g6)
245	mov	ASI_MEM, %asi
246	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
247	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
248	stna	%sp, [%g6 + MPCB_SPBUF]%asi
249	SAVE_V9WINDOW_ASI(%g5)
250	mov	1, %g5
251	sta	%g5, [%g6 + MPCB_WBCNT]%asi
252	saved
253	set	sys_trap, %g5
254	wrpr	%g5, %tnpc
255	done
256	SET_SIZE(fault_64bit_sn1)
257
258	!
259	! Spill normal kernel tl1.
260	!
261	! spill the kernel window into kwbuf
262	!
263	ENTRY_NP(fault_32bit_sk)
264	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_NT1)
265	CPU_PADDR(%g5, %g6)
266	set	CPU_KWBUF_SP, %g6
267	add	%g5, %g6, %g6
268	mov	ASI_MEM, %asi
269	stna	%sp, [%g6]%asi
270	set	CPU_KWBUF, %g6
271	add	%g5, %g6, %g6
272	SAVE_V8WINDOW_ASI(%g6)
273	mov	1, %g6
274	add	%g5, CPU_MCPU, %g5
275#ifdef DEBUG
276	lda	[%g5 + MCPU_KWBUF_FULL]%asi, %g7
277	tst	%g7
278	bnz,a,pn %icc, ptl1_panic
279	  mov	PTL1_BAD_WTRAP, %g1
280#endif /* DEBUG */
281	sta	%g6, [%g5 + MCPU_KWBUF_FULL]%asi
282	saved
283	retry
284	SET_SIZE(fault_32bit_sk)
285
286	!
287	! Spill normal kernel tl1.
288	!
289	! spill the kernel window into kwbuf
290	!
291	ENTRY_NP(fault_64bit_sk)
292	!
293	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_NT1)
294	CPU_PADDR(%g5, %g6)
295	set	CPU_KWBUF_SP, %g6
296	add	%g5, %g6, %g6
297	mov	ASI_MEM, %asi
298	stna	%sp, [%g6]%asi
299	set	CPU_KWBUF, %g6
300	add	%g5, %g6, %g6
301	SAVE_V9WINDOW_ASI(%g6)
302	mov	1, %g6
303	add	%g5, CPU_MCPU, %g5
304#ifdef DEBUG
305	lda	[%g5 + MCPU_KWBUF_FULL]%asi, %g7
306	tst	%g7
307	bnz,a,pn %icc, ptl1_panic
308	  mov	PTL1_BAD_WTRAP, %g1
309#endif /* DEBUG */
310	sta	%g6, [%g5 + MCPU_KWBUF_FULL]%asi
311	saved
312	retry
313	SET_SIZE(fault_64bit_sk)
314
315	ENTRY_NP(fault_64bit_so0)
316	!
317	FAULT_WINTRACE(%g5, %g6, %g1, TT_F64_SO0)
318	!
319	! Spill other tl0 fault.
320	! This happens when the kernel spills a user window and that
321	! user's stack has been unmapped.
322	! We handle it by spilling the window into the user's wbuf.
323	!
324	! find lwp & increment wbcnt
325	!
326	CPU_ADDR(%g5, %g6)
327	ldn	[%g5 + CPU_MPCB], %g1
328	ld	[%g1 + MPCB_WBCNT], %g2
329	add	%g2, 1, %g3
330	st	%g3, [%g1 + MPCB_WBCNT]
331	!
332	! use previous wbcnt to spill new spbuf & wbuf
333	!
334	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
335	add	%g1, MPCB_SPBUF, %g3
336	stn	%sp, [%g3 + %g4]
337	sll	%g2, RWIN64SHIFT, %g4
338	ldn	[%g1 + MPCB_WBUF], %g3
339	add	%g3, %g4, %g3
340	SAVE_V9WINDOW(%g3)
341	saved
342	retry
343	SET_SIZE(fault_64bit_so0)
344
345	!
346	! Spill other tl1 fault.
347	! This happens when priv_trap spills a user window and that
348	! user's stack has been unmapped.
349	! We handle it by spilling the window to the wbuf and retrying
350	! the save.
351	!
352	ENTRY_NP(fault_64bit_so1)
353	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SO1)
354	CPU_PADDR(%g5, %g6)
355	!
356	! find lwp & increment wbcnt
357	!
358	mov	ASI_MEM, %asi
359	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
360	lda	[%g6 + MPCB_WBCNT]%asi, %g5
361	add	%g5, 1, %g7
362	sta	%g7, [%g6 + MPCB_WBCNT]%asi
363	!
364	! use previous wbcnt to spill new spbuf & wbuf
365	!
366	sll	%g5, CPTRSHIFT, %g7		! spbuf size is sizeof (caddr_t)
367	add	%g6, %g7, %g7
368	stna	%sp, [%g7 + MPCB_SPBUF]%asi
369	sll	%g5, RWIN64SHIFT, %g7
370	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
371	add	%g5, %g7, %g7
372	SAVE_V9WINDOW_ASI(%g7)
373	saved
374	set	sys_trap, %g5
375	wrpr	%g5, %tnpc
376	done
377	SET_SIZE(fault_64bit_so1)
378
379	/*
380	 * Fill fault handlers
381	 *   fn0 - fill normal tl 0
382	 *   fn1 - fill normal tl 1
383	 */
384
385	ENTRY_NP(fault_32bit_fn0)
386	!
387	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN0)
388	!
389.fault_fn0_common:
390	!
391	! Fill normal tl0 fault.
392	! This happens when a user tries to fill to an unmapped or
393	! misaligned stack. We handle an unmapped stack by simulating
394	! a pagefault at the trap pc and a misaligned stack by generating
395	! a user alignment trap.
396	!
397	! setup user_trap args
398	!
399	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
400	! sfar (g5 == T_ALIGNMENT)
401	!
402	set	sfmmu_tsbmiss_exception, %g1
403	mov	%g6, %g2			! arg2 = tagaccess
404	mov	T_WIN_UNDERFLOW, %g3
405	cmp	%g5, T_ALIGNMENT
406	bne	%icc, 1f
407	nop
408	set	trap, %g1
409	mov	T_ALIGNMENT, %g3
4101:
411	sub	%g0, 1, %g4
412	!
413	! sys_trap wants %cwp to be the same as when the trap occured,
414	! so set it from %tstate
415	!
416	rdpr	%tstate, %g5
417	and	%g5, TSTATE_CWP, %g5
418	ba,pt	%xcc, user_trap
419	wrpr	%g0, %g5, %cwp
420	SET_SIZE(fault_32bit_fn0)
421
422	ENTRY_NP(fault_32bit_fn1)
423	!
424	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN1)
425	!
426	wrpr	%g0, 1, %gl
427	srl	%sp, 0, %g7
428	!
429.fault_fn1_common:
430	!
431	! Fill normal tl1 fault.
432	! This happens when user_rtt's restore fills from an unmapped or
433	! misaligned stack. We handle an unmapped stack by simulating
434	! a pagefault at user_rtt and a misaligned stack by generating
435	! a RTT alignment trap.
436	!
437	! save fault addr & fix %cwp
438	!
439	rdpr	%tstate, %g1
440	and	%g1, TSTATE_CWP, %g1
441	wrpr	%g0, %g1, %cwp
442	!
443	! fake tl1 traps regs so that after pagefault runs, we
444	! re-execute at user_rtt.
445	!
446	wrpr	%g0, 1, %tl
447	set	TSTATE_KERN | TSTATE_IE, %g1
448	wrpr	%g0, %g1, %tstate
449	set	user_rtt, %g1
450	wrpr	%g0, %g1, %tpc
451	add	%g1, 4, %g1
452	wrpr	%g0, %g1, %tnpc
453	!
454	! setup sys_trap args
455	!
456	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
457	! sfar (g5 == T_ALIGNMENT)
458	!
459	set	sfmmu_tsbmiss_exception, %g1
460	mov	%g6, %g2			! arg2 = tagaccess
461	set	T_USER | T_SYS_RTT_PAGE, %g3	! arg3 = traptype
462	cmp	%g5, T_ALIGNMENT
463	bne	%icc, 1f
464	nop
465	set	trap, %g1
466	set	T_USER | T_SYS_RTT_ALIGN, %g3
4671:
468	sub	%g0, 1, %g4
469	!
470	! setup to run kernel again by setting THREAD_REG, %wstate
471	! and the mmu to their kernel values.
472	!
473	! sun4v cannot safely lower %gl then raise it again
474	! so ktl0 must restore THREAD_REG
475	rdpr	%wstate, %l1
476	sllx	%l1, WSTATE_SHIFT, %l1
477	wrpr	%l1, WSTATE_K64, %wstate
478	mov	KCONTEXT, %g5
479	mov	MMU_PCONTEXT, %g6
480	stxa	%g5, [%g6]ASI_MMU_CTX
481	membar	#Sync
482
483	ba,pt	%xcc, priv_trap
484	nop
485	SET_SIZE(fault_32bit_fn1)
486
487	ENTRY_NP(fault_64bit_fn0)
488	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN0)
489	b	.fault_fn0_common
490	  nop
491	SET_SIZE(fault_64bit_fn0)
492
493	ENTRY_NP(fault_64bit_fn1)
494	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN1)
495	wrpr	%g0, 1, %gl
496	b	.fault_fn1_common
497	  nop
498	SET_SIZE(fault_64bit_fn1)
499
500	ENTRY_NP(fault_rtt_fn1)
501	FAULT_WINTRACE(%g1, %g2, %g3, TT_RTT_FN1)
502	wrpr	%g0, 1, %gl
503	b	.fault_fn1_common
504	  nop
505	SET_SIZE(fault_rtt_fn1)
506
507	/*
508	 * Kernel fault handlers
509	 */
510	ENTRY_NP(fault_32bit_not)
511	ENTRY_NP(fault_64bit_not)
512	ba,pt	%xcc, ptl1_panic
513	mov	PTL1_BAD_WTRAP, %g1
514	SET_SIZE(fault_32bit_not)
515	SET_SIZE(fault_64bit_not)
516#endif /* !lint */
517