xref: /illumos-gate/usr/src/uts/sun4v/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, 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#include <sys/asm_linkage.h>
28#include <sys/machthread.h>
29#include <sys/privregs.h>
30#include <sys/machasi.h>
31#include <sys/trap.h>
32#include <sys/mmu.h>
33#include <sys/machparam.h>
34#include <sys/machtrap.h>
35#include <sys/traptrace.h>
36
37#include "assym.h"
38
39	/*
40	 * Spill fault handlers
41	 *   sn0 - spill normal tl 0
42	 *   sn1 - spill normal tl >0
43	 *   so0 - spill other tl 0
44	 *   so1 - spill other tl >0
45	 */
46
47	ENTRY_NP(fault_32bit_sn0)
48	!
49	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_SN0)
50	!
51	! Spill normal tl0 fault.
52	! This happens when a user tries to spill to an unmapped or
53	! misaligned stack. We handle an unmapped stack by simulating
54	! a pagefault at the trap pc and a misaligned stack by generating
55	! a user alignment trap.
56	!
57	! spill the window into wbuf slot 0
58	! (we know wbuf is empty since we came from user mode)
59	!
60	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
61	! sfar (g5 == T_ALIGNMENT)
62	!
63	CPU_ADDR(%g4, %g1)
64	ldn	[%g4 + CPU_MPCB], %g1
65	stn	%sp, [%g1 + MPCB_SPBUF]
66	ldn	[%g1 + MPCB_WBUF], %g2
67	SAVE_V8WINDOW(%g2)
68	mov	1, %g2
69	st	%g2, [%g1 + MPCB_WBCNT]
70	saved
71	!
72	! setup user_trap args
73	!
74	set	sfmmu_tsbmiss_exception, %g1
75	mov	%g6, %g2			! arg2 = tagaccess
76	mov	T_WIN_OVERFLOW, %g3		! arg3 = traptype
77	cmp	%g5, T_ALIGNMENT
78	bne	%icc, 1f
79	nop
80	set	trap, %g1
81	mov	T_ALIGNMENT, %g3
821:
83	sub	%g0, 1, %g4
84	!
85	! spill traps increment %cwp by 2,
86	! but user_trap wants the trap %cwp
87	!
88	rdpr	%tstate, %g5
89	and	%g5, TSTATE_CWP, %g5
90	ba,pt	%xcc, user_trap
91	wrpr	%g0, %g5, %cwp
92	SET_SIZE(fault_32bit_sn0)
93
94	!
95	! Spill normal tl1 fault.
96	! This happens when sys_trap's save spills to an unmapped stack.
97	! We handle it by spilling the window to the wbuf and trying
98	! sys_trap again.
99	!
100	! spill the window into wbuf slot 0
101	! (we know wbuf is empty since we came from user mode)
102	!
103	ENTRY_NP(fault_32bit_sn1)
104	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SN1)
105	CPU_PADDR(%g5, %g6)
106	mov	ASI_MEM, %asi
107	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
108	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
109	stna	%sp, [%g6 + MPCB_SPBUF]%asi
110	SAVE_V8WINDOW_ASI(%g5)
111	mov	1, %g5
112	sta	%g5, [%g6 + MPCB_WBCNT]%asi
113	saved
114	set	sys_trap, %g5
115	wrpr	%g5, %tnpc
116	done
117	SET_SIZE(fault_32bit_sn1)
118
119	ENTRY_NP(fault_32bit_so0)
120	!
121	FAULT_WINTRACE(%g5, %g6, %g1, TT_F32_SO0)
122	!
123	! Spill other tl0 fault.
124	! This happens when the kernel spills a user window and that
125	! user's stack has been unmapped.
126	! We handle it by spilling the window into the user's wbuf.
127	!
128	! find lwp & increment wbcnt
129	!
130	CPU_ADDR(%g5, %g6)
131	ldn	[%g5 + CPU_MPCB], %g1
132	ld	[%g1 + MPCB_WBCNT], %g2
133	add	%g2, 1, %g3
134	st	%g3, [%g1 + MPCB_WBCNT]
135	!
136	! use previous wbcnt to spill new spbuf & wbuf
137	!
138	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
139	add	%g1, MPCB_SPBUF, %g3
140	stn	%sp, [%g3 + %g4]
141	sll	%g2, RWIN32SHIFT, %g4
142	ldn	[%g1 + MPCB_WBUF], %g3
143	add	%g3, %g4, %g3
144	SAVE_V8WINDOW(%g3)
145	saved
146	retry
147	SET_SIZE(fault_32bit_so0)
148
149	!
150	! Spill other tl1 fault.
151	! This happens when priv_trap spills a user window and that
152	! user's stack has been unmapped.
153	! We handle it by spilling the window to the wbuf and retrying
154	! the save.
155	!
156	ENTRY_NP(fault_32bit_so1)
157	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SO1)
158	CPU_PADDR(%g5, %g6)
159	!
160	! find lwp & increment wbcnt
161	!
162	mov	ASI_MEM, %asi
163	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
164	lda	[%g6 + MPCB_WBCNT]%asi, %g5
165	add	%g5, 1, %g7
166	sta	%g7, [%g6 + MPCB_WBCNT]%asi
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	stna	%sp, [%g7 + MPCB_SPBUF]%asi
173	sll	%g5, RWIN32SHIFT, %g7
174	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
175	add	%g5, %g7, %g7
176	SAVE_V8WINDOW_ASI(%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_PADDR(%g5, %g6)
242	mov	ASI_MEM, %asi
243	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
244	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
245	stna	%sp, [%g6 + MPCB_SPBUF]%asi
246	SAVE_V9WINDOW_ASI(%g5)
247	mov	1, %g5
248	sta	%g5, [%g6 + MPCB_WBCNT]%asi
249	saved
250	set	sys_trap, %g5
251	wrpr	%g5, %tnpc
252	done
253	SET_SIZE(fault_64bit_sn1)
254
255	!
256	! Spill normal kernel tl1.
257	!
258	! spill the kernel window into kwbuf
259	!
260	ENTRY_NP(fault_32bit_sk)
261	FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_NT1)
262	CPU_PADDR(%g5, %g6)
263	set	CPU_KWBUF_SP, %g6
264	add	%g5, %g6, %g6
265	mov	ASI_MEM, %asi
266	stna	%sp, [%g6]%asi
267	set	CPU_KWBUF, %g6
268	add	%g5, %g6, %g6
269	SAVE_V8WINDOW_ASI(%g6)
270	mov	1, %g6
271	add	%g5, CPU_MCPU, %g5
272#ifdef DEBUG
273	lda	[%g5 + MCPU_KWBUF_FULL]%asi, %g7
274	tst	%g7
275	bnz,a,pn %icc, ptl1_panic
276	  mov	PTL1_BAD_WTRAP, %g1
277#endif /* DEBUG */
278	sta	%g6, [%g5 + MCPU_KWBUF_FULL]%asi
279	saved
280	retry
281	SET_SIZE(fault_32bit_sk)
282
283	!
284	! Spill normal kernel tl1.
285	!
286	! spill the kernel window into kwbuf
287	!
288	ENTRY_NP(fault_64bit_sk)
289	!
290	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_NT1)
291	CPU_PADDR(%g5, %g6)
292	set	CPU_KWBUF_SP, %g6
293	add	%g5, %g6, %g6
294	mov	ASI_MEM, %asi
295	stna	%sp, [%g6]%asi
296	set	CPU_KWBUF, %g6
297	add	%g5, %g6, %g6
298	SAVE_V9WINDOW_ASI(%g6)
299	mov	1, %g6
300	add	%g5, CPU_MCPU, %g5
301#ifdef DEBUG
302	lda	[%g5 + MCPU_KWBUF_FULL]%asi, %g7
303	tst	%g7
304	bnz,a,pn %icc, ptl1_panic
305	  mov	PTL1_BAD_WTRAP, %g1
306#endif /* DEBUG */
307	sta	%g6, [%g5 + MCPU_KWBUF_FULL]%asi
308	saved
309	retry
310	SET_SIZE(fault_64bit_sk)
311
312	ENTRY_NP(fault_64bit_so0)
313	!
314	FAULT_WINTRACE(%g5, %g6, %g1, TT_F64_SO0)
315	!
316	! Spill other tl0 fault.
317	! This happens when the kernel spills a user window and that
318	! user's stack has been unmapped.
319	! We handle it by spilling the window into the user's wbuf.
320	!
321	! find lwp & increment wbcnt
322	!
323	CPU_ADDR(%g5, %g6)
324	ldn	[%g5 + CPU_MPCB], %g1
325	ld	[%g1 + MPCB_WBCNT], %g2
326	add	%g2, 1, %g3
327	st	%g3, [%g1 + MPCB_WBCNT]
328	!
329	! use previous wbcnt to spill new spbuf & wbuf
330	!
331	sll	%g2, CPTRSHIFT, %g4		! spbuf size is sizeof (caddr_t)
332	add	%g1, MPCB_SPBUF, %g3
333	stn	%sp, [%g3 + %g4]
334	sll	%g2, RWIN64SHIFT, %g4
335	ldn	[%g1 + MPCB_WBUF], %g3
336	add	%g3, %g4, %g3
337	SAVE_V9WINDOW(%g3)
338	saved
339	retry
340	SET_SIZE(fault_64bit_so0)
341
342	!
343	! Spill other tl1 fault.
344	! This happens when priv_trap spills a user window and that
345	! user's stack has been unmapped.
346	! We handle it by spilling the window to the wbuf and retrying
347	! the save.
348	!
349	ENTRY_NP(fault_64bit_so1)
350	FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SO1)
351	CPU_PADDR(%g5, %g6)
352	!
353	! find lwp & increment wbcnt
354	!
355	mov	ASI_MEM, %asi
356	ldxa	[%g5 + CPU_MPCB_PA]%asi, %g6
357	lda	[%g6 + MPCB_WBCNT]%asi, %g5
358	add	%g5, 1, %g7
359	sta	%g7, [%g6 + MPCB_WBCNT]%asi
360	!
361	! use previous wbcnt to spill new spbuf & wbuf
362	!
363	sll	%g5, CPTRSHIFT, %g7		! spbuf size is sizeof (caddr_t)
364	add	%g6, %g7, %g7
365	stna	%sp, [%g7 + MPCB_SPBUF]%asi
366	sll	%g5, RWIN64SHIFT, %g7
367	ldxa	[%g6 + MPCB_WBUF_PA]%asi, %g5
368	add	%g5, %g7, %g7
369	SAVE_V9WINDOW_ASI(%g7)
370	saved
371	set	sys_trap, %g5
372	wrpr	%g5, %tnpc
373	done
374	SET_SIZE(fault_64bit_so1)
375
376	/*
377	 * Fill fault handlers
378	 *   fn0 - fill normal tl 0
379	 *   fn1 - fill normal tl 1
380	 */
381
382	ENTRY_NP(fault_32bit_fn0)
383	!
384	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN0)
385	!
386.fault_fn0_common:
387	!
388	! Fill normal tl0 fault.
389	! This happens when a user tries to fill to an unmapped or
390	! misaligned stack. We handle an unmapped stack by simulating
391	! a pagefault at the trap pc and a misaligned stack by generating
392	! a user alignment trap.
393	!
394	! setup user_trap args
395	!
396	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
397	! sfar (g5 == T_ALIGNMENT)
398	!
399	set	sfmmu_tsbmiss_exception, %g1
400	mov	%g6, %g2			! arg2 = tagaccess
401	mov	T_WIN_UNDERFLOW, %g3
402	cmp	%g5, T_ALIGNMENT
403	bne	%icc, 1f
404	nop
405	set	trap, %g1
406	mov	T_ALIGNMENT, %g3
4071:
408	sub	%g0, 1, %g4
409	!
410	! sys_trap wants %cwp to be the same as when the trap occured,
411	! so set it from %tstate
412	!
413	rdpr	%tstate, %g5
414	and	%g5, TSTATE_CWP, %g5
415	ba,pt	%xcc, user_trap
416	wrpr	%g0, %g5, %cwp
417	SET_SIZE(fault_32bit_fn0)
418
419	ENTRY_NP(fault_32bit_fn1)
420	!
421	FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN1)
422	!
423	wrpr	%g0, 1, %gl
424	srl	%sp, 0, %g7
425	!
426.fault_fn1_common:
427	!
428	! Fill normal tl1 fault.
429	! This happens when user_rtt's restore fills from an unmapped or
430	! misaligned stack. We handle an unmapped stack by simulating
431	! a pagefault at user_rtt and a misaligned stack by generating
432	! a RTT alignment trap.
433	!
434	! save fault addr & fix %cwp
435	!
436	rdpr	%tstate, %g1
437	and	%g1, TSTATE_CWP, %g1
438	wrpr	%g0, %g1, %cwp
439	!
440	! fake tl1 traps regs so that after pagefault runs, we
441	! re-execute at user_rtt.
442	!
443	wrpr	%g0, 1, %tl
444	set	TSTATE_KERN | TSTATE_IE, %g1
445	wrpr	%g0, %g1, %tstate
446	set	user_rtt, %g1
447	wrpr	%g0, %g1, %tpc
448	add	%g1, 4, %g1
449	wrpr	%g0, %g1, %tnpc
450	!
451	! setup sys_trap args
452	!
453	! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or
454	! sfar (g5 == T_ALIGNMENT)
455	!
456	set	sfmmu_tsbmiss_exception, %g1
457	mov	%g6, %g2			! arg2 = tagaccess
458	set	T_USER | T_SYS_RTT_PAGE, %g3	! arg3 = traptype
459	cmp	%g5, T_ALIGNMENT
460	bne	%icc, 1f
461	nop
462	set	trap, %g1
463	set	T_USER | T_SYS_RTT_ALIGN, %g3
4641:
465	sub	%g0, 1, %g4
466	!
467	! setup to run kernel again by setting THREAD_REG, %wstate
468	! and the mmu to their kernel values.
469	!
470	! sun4v cannot safely lower %gl then raise it again
471	! so ktl0 must restore THREAD_REG
472	rdpr	%wstate, %l1
473	sllx	%l1, WSTATE_SHIFT, %l1
474	wrpr	%l1, WSTATE_K64, %wstate
475	mov	KCONTEXT, %g5
476	mov	MMU_PCONTEXT, %g6
477	stxa	%g5, [%g6]ASI_MMU_CTX
478	membar	#Sync
479
480	ba,pt	%xcc, priv_trap
481	nop
482	SET_SIZE(fault_32bit_fn1)
483
484	ENTRY_NP(fault_64bit_fn0)
485	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN0)
486	b	.fault_fn0_common
487	  nop
488	SET_SIZE(fault_64bit_fn0)
489
490	ENTRY_NP(fault_64bit_fn1)
491	FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN1)
492	wrpr	%g0, 1, %gl
493	b	.fault_fn1_common
494	  nop
495	SET_SIZE(fault_64bit_fn1)
496
497	ENTRY_NP(fault_rtt_fn1)
498	FAULT_WINTRACE(%g1, %g2, %g3, TT_RTT_FN1)
499	wrpr	%g0, 1, %gl
500	b	.fault_fn1_common
501	  nop
502	SET_SIZE(fault_rtt_fn1)
503
504	/*
505	 * Kernel fault handlers
506	 */
507	ENTRY_NP(fault_32bit_not)
508	ENTRY_NP(fault_64bit_not)
509	ba,pt	%xcc, ptl1_panic
510	mov	PTL1_BAD_WTRAP, %g1
511	SET_SIZE(fault_32bit_not)
512	SET_SIZE(fault_64bit_not)
513