de-linting of .s files
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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include "assym.h"
27 #include <sys/asm_linkage.h>
28 #include <sys/privregs.h>
29 #include <sys/sun4asi.h>
30 #include <sys/spitregs.h>
31 #include <sys/cheetahregs.h>
32 #include <sys/machtrap.h>
33 #include <sys/machthread.h>
34 #include <sys/machbrand.h>
35 #include <sys/pcb.h>
36 #include <sys/pte.h>
37 #include <sys/mmu.h>
38 #include <sys/machpcb.h>
39 #include <sys/async.h>
40 #include <sys/intreg.h>
41 #include <sys/scb.h>
42 #include <sys/psr_compat.h>
43 #include <sys/syscall.h>
44 #include <sys/machparam.h>
45 #include <sys/traptrace.h>
46 #include <vm/hat_sfmmu.h>
47 #include <sys/archsystm.h>
48 #include <sys/utrap.h>
49 #include <sys/clock.h>
50 #include <sys/intr.h>
51 #include <sys/fpu/fpu_simulator.h>
52 #include <vm/seg_spt.h>
53
54 /*
55 * WARNING: If you add a fast trap handler which can be invoked by a
56 * non-privileged user, you may have to use the FAST_TRAP_DONE macro
57 * instead of "done" instruction to return back to the user mode. See
58 * comments for the "fast_trap_done" entry point for more information.
59 *
60 * An alternate FAST_TRAP_DONE_CHK_INTR macro should be used for the
61 * cases where you always want to process any pending interrupts before
62 * returning back to the user mode.
63 */
64 #define FAST_TRAP_DONE \
65 ba,a fast_trap_done
66
67 #define FAST_TRAP_DONE_CHK_INTR \
68 ba,a fast_trap_done_chk_intr
69
70 /*
71 * SPARC V9 Trap Table
72 *
73 * Most of the trap handlers are made from common building
74 * blocks, and some are instantiated multiple times within
75 * the trap table. So, I build a bunch of macros, then
76 * populate the table using only the macros.
77 *
78 * Many macros branch to sys_trap. Its calling convention is:
79 * %g1 kernel trap handler
80 * %g2, %g3 args for above
81 * %g4 desire %pil
82 */
83
84 #ifdef TRAPTRACE
85
86 /*
87 * Tracing macro. Adds two instructions if TRAPTRACE is defined.
88 */
89 #define TT_TRACE(label) \
90 ba label ;\
91 rd %pc, %g7
92 #define TT_TRACE_INS 2
93
94 #define TT_TRACE_L(label) \
95 ba label ;\
96 rd %pc, %l4 ;\
97 clr %l4
98 #define TT_TRACE_L_INS 3
99
100 #else
101
102 #define TT_TRACE(label)
103 #define TT_TRACE_INS 0
104
105 #define TT_TRACE_L(label)
106 #define TT_TRACE_L_INS 0
107
108 #endif
109
110 /*
111 * This first set are funneled to trap() with %tt as the type.
112 * Trap will then either panic or send the user a signal.
113 */
114 /*
115 * NOT is used for traps that just shouldn't happen.
116 * It comes in both single and quadruple flavors.
117 */
118 .global trap
119 #define NOT \
120 TT_TRACE(trace_gen) ;\
121 set trap, %g1 ;\
122 rdpr %tt, %g3 ;\
123 ba,pt %xcc, sys_trap ;\
124 sub %g0, 1, %g4 ;\
125 .align 32
126 #define NOT4 NOT; NOT; NOT; NOT
127 /*
128 * RED is for traps that use the red mode handler.
129 * We should never see these either.
130 */
131 #define RED NOT
132 /*
133 * BAD is used for trap vectors we don't have a kernel
134 * handler for.
135 * It also comes in single and quadruple versions.
136 */
137 #define BAD NOT
138 #define BAD4 NOT4
139
140 #define DONE \
141 done; \
142 .align 32
143
144 /*
145 * TRAP vectors to the trap() function.
146 * It's main use is for user errors.
147 */
148 .global trap
149 #define TRAP(arg) \
150 TT_TRACE(trace_gen) ;\
151 set trap, %g1 ;\
152 mov arg, %g3 ;\
153 ba,pt %xcc, sys_trap ;\
154 sub %g0, 1, %g4 ;\
155 .align 32
156
157 /*
158 * SYSCALL is used for unsupported syscall interfaces (with 'which'
159 * set to 'nosys') and legacy support of old SunOS 4.x syscalls (with
160 * 'which' set to 'syscall_trap32').
161 *
162 * The SYSCALL_TRAP* macros are used for syscall entry points.
163 * SYSCALL_TRAP is used to support LP64 syscalls and SYSCALL_TRAP32
164 * is used to support ILP32. Each macro can only be used once
165 * since they each define a symbol. The symbols are used as hot patch
166 * points by the brand infrastructure to dynamically enable and disable
167 * brand syscall interposition. See the comments around BRAND_CALLBACK
168 * and brand_plat_interposition_enable() for more information.
169 */
170 #define SYSCALL_NOTT(which) \
171 set (which), %g1 ;\
172 ba,pt %xcc, sys_trap ;\
173 sub %g0, 1, %g4 ;\
174 .align 32
175
176 #define SYSCALL(which) \
177 TT_TRACE(trace_gen) ;\
178 SYSCALL_NOTT(which)
179
180 #define SYSCALL_TRAP32 \
181 TT_TRACE(trace_gen) ;\
182 ALTENTRY(syscall_trap32_patch_point) \
183 SYSCALL_NOTT(syscall_trap32)
184
185 #define SYSCALL_TRAP \
186 TT_TRACE(trace_gen) ;\
187 ALTENTRY(syscall_trap_patch_point) \
188 SYSCALL_NOTT(syscall_trap)
189
190 #define FLUSHW(h_name) \
191 .global h_name ;\
192 h_name: ;\
193 set trap, %g1 ;\
194 mov T_FLUSHW, %g3 ;\
195 sub %g0, 1, %g4 ;\
196 save ;\
197 flushw ;\
198 restore ;\
199 FAST_TRAP_DONE ;\
200 .align 32
201
202 /*
203 * GOTO just jumps to a label.
204 * It's used for things that can be fixed without going thru sys_trap.
205 */
206 #define GOTO(label) \
207 .global label ;\
208 ba,a label ;\
209 .empty ;\
210 .align 32
211
212 /*
213 * GOTO_TT just jumps to a label.
214 * correctable ECC error traps at level 0 and 1 will use this macro.
215 * It's used for things that can be fixed without going thru sys_trap.
216 */
217 #define GOTO_TT(label, ttlabel) \
218 .global label ;\
219 TT_TRACE(ttlabel) ;\
220 ba,a label ;\
221 .empty ;\
222 .align 32
223
224 /*
225 * Privileged traps
226 * Takes breakpoint if privileged, calls trap() if not.
227 */
228 #define PRIV(label) \
229 rdpr %tstate, %g1 ;\
230 btst TSTATE_PRIV, %g1 ;\
231 bnz label ;\
232 rdpr %tt, %g3 ;\
233 set trap, %g1 ;\
234 ba,pt %xcc, sys_trap ;\
235 sub %g0, 1, %g4 ;\
236 .align 32
237
238
239 /*
240 * DTrace traps.
241 */
242 #define DTRACE_PID \
243 .global dtrace_pid_probe ;\
244 set dtrace_pid_probe, %g1 ;\
245 ba,pt %xcc, user_trap ;\
246 sub %g0, 1, %g4 ;\
247 .align 32
248
249 #define DTRACE_RETURN \
250 .global dtrace_return_probe ;\
251 set dtrace_return_probe, %g1 ;\
252 ba,pt %xcc, user_trap ;\
253 sub %g0, 1, %g4 ;\
254 .align 32
255
256 /*
257 * REGISTER WINDOW MANAGEMENT MACROS
258 */
259
260 /*
261 * various convenient units of padding
262 */
263 #define SKIP(n) .skip 4*(n)
264
265 /*
266 * CLEAN_WINDOW is the simple handler for cleaning a register window.
267 */
268 #define CLEAN_WINDOW \
269 TT_TRACE_L(trace_win) ;\
270 rdpr %cleanwin, %l0; inc %l0; wrpr %l0, %cleanwin ;\
271 clr %l0; clr %l1; clr %l2; clr %l3 ;\
272 clr %l4; clr %l5; clr %l6; clr %l7 ;\
273 clr %o0; clr %o1; clr %o2; clr %o3 ;\
274 clr %o4; clr %o5; clr %o6; clr %o7 ;\
275 retry; .align 128
276
277 /*
278 * If we get an unresolved tlb miss while in a window handler, the fault
279 * handler will resume execution at the last instruction of the window
280 * hander, instead of delivering the fault to the kernel. Spill handlers
281 * use this to spill windows into the wbuf.
282 *
283 * The mixed handler works by checking %sp, and branching to the correct
284 * handler. This is done by branching back to label 1: for 32b frames,
285 * or label 2: for 64b frames; which implies the handler order is: 32b,
286 * 64b, mixed. The 1: and 2: labels are offset into the routines to
287 * allow the branchs' delay slots to contain useful instructions.
288 */
289
290 /*
291 * SPILL_32bit spills a 32-bit-wide kernel register window. It
292 * assumes that the kernel context and the nucleus context are the
293 * same. The stack pointer is required to be eight-byte aligned even
294 * though this code only needs it to be four-byte aligned.
295 */
296 #define SPILL_32bit(tail) \
297 srl %sp, 0, %sp ;\
298 1: st %l0, [%sp + 0] ;\
299 st %l1, [%sp + 4] ;\
300 st %l2, [%sp + 8] ;\
301 st %l3, [%sp + 12] ;\
302 st %l4, [%sp + 16] ;\
303 st %l5, [%sp + 20] ;\
304 st %l6, [%sp + 24] ;\
305 st %l7, [%sp + 28] ;\
306 st %i0, [%sp + 32] ;\
307 st %i1, [%sp + 36] ;\
308 st %i2, [%sp + 40] ;\
309 st %i3, [%sp + 44] ;\
310 st %i4, [%sp + 48] ;\
311 st %i5, [%sp + 52] ;\
312 st %i6, [%sp + 56] ;\
313 st %i7, [%sp + 60] ;\
314 TT_TRACE_L(trace_win) ;\
315 saved ;\
316 retry ;\
317 SKIP(31-19-TT_TRACE_L_INS) ;\
318 ba,a,pt %xcc, fault_32bit_/**/tail ;\
319 .empty
320
321 /*
322 * SPILL_32bit_asi spills a 32-bit-wide register window into a 32-bit
323 * wide address space via the designated asi. It is used to spill
324 * non-kernel windows. The stack pointer is required to be eight-byte
325 * aligned even though this code only needs it to be four-byte
326 * aligned.
327 */
328 #define SPILL_32bit_asi(asi_num, tail) \
329 srl %sp, 0, %sp ;\
330 1: sta %l0, [%sp + %g0]asi_num ;\
331 mov 4, %g1 ;\
332 sta %l1, [%sp + %g1]asi_num ;\
333 mov 8, %g2 ;\
334 sta %l2, [%sp + %g2]asi_num ;\
335 mov 12, %g3 ;\
336 sta %l3, [%sp + %g3]asi_num ;\
337 add %sp, 16, %g4 ;\
338 sta %l4, [%g4 + %g0]asi_num ;\
339 sta %l5, [%g4 + %g1]asi_num ;\
340 sta %l6, [%g4 + %g2]asi_num ;\
341 sta %l7, [%g4 + %g3]asi_num ;\
342 add %g4, 16, %g4 ;\
343 sta %i0, [%g4 + %g0]asi_num ;\
344 sta %i1, [%g4 + %g1]asi_num ;\
345 sta %i2, [%g4 + %g2]asi_num ;\
346 sta %i3, [%g4 + %g3]asi_num ;\
347 add %g4, 16, %g4 ;\
348 sta %i4, [%g4 + %g0]asi_num ;\
349 sta %i5, [%g4 + %g1]asi_num ;\
350 sta %i6, [%g4 + %g2]asi_num ;\
351 sta %i7, [%g4 + %g3]asi_num ;\
352 TT_TRACE_L(trace_win) ;\
353 saved ;\
354 retry ;\
355 SKIP(31-25-TT_TRACE_L_INS) ;\
356 ba,a,pt %xcc, fault_32bit_/**/tail ;\
357 .empty
358
359 /*
360 * SPILL_32bit_tt1 spills a 32-bit-wide register window into a 32-bit
361 * wide address space via the designated asi. It is used to spill
362 * windows at tl>1 where performance isn't the primary concern and
363 * where we don't want to use unnecessary registers. The stack
364 * pointer is required to be eight-byte aligned even though this code
365 * only needs it to be four-byte aligned.
366 */
367 #define SPILL_32bit_tt1(asi_num, tail) \
368 mov asi_num, %asi ;\
369 1: srl %sp, 0, %sp ;\
370 sta %l0, [%sp + 0]%asi ;\
371 sta %l1, [%sp + 4]%asi ;\
372 sta %l2, [%sp + 8]%asi ;\
373 sta %l3, [%sp + 12]%asi ;\
374 sta %l4, [%sp + 16]%asi ;\
375 sta %l5, [%sp + 20]%asi ;\
376 sta %l6, [%sp + 24]%asi ;\
377 sta %l7, [%sp + 28]%asi ;\
378 sta %i0, [%sp + 32]%asi ;\
379 sta %i1, [%sp + 36]%asi ;\
380 sta %i2, [%sp + 40]%asi ;\
381 sta %i3, [%sp + 44]%asi ;\
382 sta %i4, [%sp + 48]%asi ;\
383 sta %i5, [%sp + 52]%asi ;\
384 sta %i6, [%sp + 56]%asi ;\
385 sta %i7, [%sp + 60]%asi ;\
386 TT_TRACE_L(trace_win) ;\
387 saved ;\
388 retry ;\
389 SKIP(31-20-TT_TRACE_L_INS) ;\
390 ba,a,pt %xcc, fault_32bit_/**/tail ;\
391 .empty
392
393
394 /*
395 * FILL_32bit fills a 32-bit-wide kernel register window. It assumes
396 * that the kernel context and the nucleus context are the same. The
397 * stack pointer is required to be eight-byte aligned even though this
398 * code only needs it to be four-byte aligned.
399 */
400 #define FILL_32bit(tail) \
401 srl %sp, 0, %sp ;\
402 1: TT_TRACE_L(trace_win) ;\
403 ld [%sp + 0], %l0 ;\
404 ld [%sp + 4], %l1 ;\
405 ld [%sp + 8], %l2 ;\
406 ld [%sp + 12], %l3 ;\
407 ld [%sp + 16], %l4 ;\
408 ld [%sp + 20], %l5 ;\
409 ld [%sp + 24], %l6 ;\
410 ld [%sp + 28], %l7 ;\
411 ld [%sp + 32], %i0 ;\
412 ld [%sp + 36], %i1 ;\
413 ld [%sp + 40], %i2 ;\
414 ld [%sp + 44], %i3 ;\
415 ld [%sp + 48], %i4 ;\
416 ld [%sp + 52], %i5 ;\
417 ld [%sp + 56], %i6 ;\
418 ld [%sp + 60], %i7 ;\
419 restored ;\
420 retry ;\
421 SKIP(31-19-TT_TRACE_L_INS) ;\
422 ba,a,pt %xcc, fault_32bit_/**/tail ;\
423 .empty
424
425 /*
426 * FILL_32bit_asi fills a 32-bit-wide register window from a 32-bit
427 * wide address space via the designated asi. It is used to fill
428 * non-kernel windows. The stack pointer is required to be eight-byte
429 * aligned even though this code only needs it to be four-byte
430 * aligned.
431 */
432 #define FILL_32bit_asi(asi_num, tail) \
433 srl %sp, 0, %sp ;\
434 1: TT_TRACE_L(trace_win) ;\
435 mov 4, %g1 ;\
436 lda [%sp + %g0]asi_num, %l0 ;\
437 mov 8, %g2 ;\
438 lda [%sp + %g1]asi_num, %l1 ;\
439 mov 12, %g3 ;\
440 lda [%sp + %g2]asi_num, %l2 ;\
441 lda [%sp + %g3]asi_num, %l3 ;\
442 add %sp, 16, %g4 ;\
443 lda [%g4 + %g0]asi_num, %l4 ;\
444 lda [%g4 + %g1]asi_num, %l5 ;\
445 lda [%g4 + %g2]asi_num, %l6 ;\
446 lda [%g4 + %g3]asi_num, %l7 ;\
447 add %g4, 16, %g4 ;\
448 lda [%g4 + %g0]asi_num, %i0 ;\
449 lda [%g4 + %g1]asi_num, %i1 ;\
450 lda [%g4 + %g2]asi_num, %i2 ;\
451 lda [%g4 + %g3]asi_num, %i3 ;\
452 add %g4, 16, %g4 ;\
453 lda [%g4 + %g0]asi_num, %i4 ;\
454 lda [%g4 + %g1]asi_num, %i5 ;\
455 lda [%g4 + %g2]asi_num, %i6 ;\
456 lda [%g4 + %g3]asi_num, %i7 ;\
457 restored ;\
458 retry ;\
459 SKIP(31-25-TT_TRACE_L_INS) ;\
460 ba,a,pt %xcc, fault_32bit_/**/tail ;\
461 .empty
462
463 /*
464 * FILL_32bit_tt1 fills a 32-bit-wide register window from a 32-bit
465 * wide address space via the designated asi. It is used to fill
466 * windows at tl>1 where performance isn't the primary concern and
467 * where we don't want to use unnecessary registers. The stack
468 * pointer is required to be eight-byte aligned even though this code
469 * only needs it to be four-byte aligned.
470 */
471 #define FILL_32bit_tt1(asi_num, tail) \
472 mov asi_num, %asi ;\
473 1: srl %sp, 0, %sp ;\
474 TT_TRACE_L(trace_win) ;\
475 lda [%sp + 0]%asi, %l0 ;\
476 lda [%sp + 4]%asi, %l1 ;\
477 lda [%sp + 8]%asi, %l2 ;\
478 lda [%sp + 12]%asi, %l3 ;\
479 lda [%sp + 16]%asi, %l4 ;\
480 lda [%sp + 20]%asi, %l5 ;\
481 lda [%sp + 24]%asi, %l6 ;\
482 lda [%sp + 28]%asi, %l7 ;\
483 lda [%sp + 32]%asi, %i0 ;\
484 lda [%sp + 36]%asi, %i1 ;\
485 lda [%sp + 40]%asi, %i2 ;\
486 lda [%sp + 44]%asi, %i3 ;\
487 lda [%sp + 48]%asi, %i4 ;\
488 lda [%sp + 52]%asi, %i5 ;\
489 lda [%sp + 56]%asi, %i6 ;\
490 lda [%sp + 60]%asi, %i7 ;\
491 restored ;\
492 retry ;\
493 SKIP(31-20-TT_TRACE_L_INS) ;\
494 ba,a,pt %xcc, fault_32bit_/**/tail ;\
495 .empty
496
497
498 /*
499 * SPILL_64bit spills a 64-bit-wide kernel register window. It
500 * assumes that the kernel context and the nucleus context are the
501 * same. The stack pointer is required to be eight-byte aligned.
502 */
503 #define SPILL_64bit(tail) \
504 2: stx %l0, [%sp + V9BIAS64 + 0] ;\
505 stx %l1, [%sp + V9BIAS64 + 8] ;\
506 stx %l2, [%sp + V9BIAS64 + 16] ;\
507 stx %l3, [%sp + V9BIAS64 + 24] ;\
508 stx %l4, [%sp + V9BIAS64 + 32] ;\
509 stx %l5, [%sp + V9BIAS64 + 40] ;\
510 stx %l6, [%sp + V9BIAS64 + 48] ;\
511 stx %l7, [%sp + V9BIAS64 + 56] ;\
512 stx %i0, [%sp + V9BIAS64 + 64] ;\
513 stx %i1, [%sp + V9BIAS64 + 72] ;\
514 stx %i2, [%sp + V9BIAS64 + 80] ;\
515 stx %i3, [%sp + V9BIAS64 + 88] ;\
516 stx %i4, [%sp + V9BIAS64 + 96] ;\
517 stx %i5, [%sp + V9BIAS64 + 104] ;\
518 stx %i6, [%sp + V9BIAS64 + 112] ;\
519 stx %i7, [%sp + V9BIAS64 + 120] ;\
520 TT_TRACE_L(trace_win) ;\
521 saved ;\
522 retry ;\
523 SKIP(31-18-TT_TRACE_L_INS) ;\
524 ba,a,pt %xcc, fault_64bit_/**/tail ;\
525 .empty
526
527 /*
528 * SPILL_64bit_asi spills a 64-bit-wide register window into a 64-bit
529 * wide address space via the designated asi. It is used to spill
530 * non-kernel windows. The stack pointer is required to be eight-byte
531 * aligned.
532 */
533 #define SPILL_64bit_asi(asi_num, tail) \
534 mov 0 + V9BIAS64, %g1 ;\
535 2: stxa %l0, [%sp + %g1]asi_num ;\
536 mov 8 + V9BIAS64, %g2 ;\
537 stxa %l1, [%sp + %g2]asi_num ;\
538 mov 16 + V9BIAS64, %g3 ;\
539 stxa %l2, [%sp + %g3]asi_num ;\
540 mov 24 + V9BIAS64, %g4 ;\
541 stxa %l3, [%sp + %g4]asi_num ;\
542 add %sp, 32, %g5 ;\
543 stxa %l4, [%g5 + %g1]asi_num ;\
544 stxa %l5, [%g5 + %g2]asi_num ;\
545 stxa %l6, [%g5 + %g3]asi_num ;\
546 stxa %l7, [%g5 + %g4]asi_num ;\
547 add %g5, 32, %g5 ;\
548 stxa %i0, [%g5 + %g1]asi_num ;\
549 stxa %i1, [%g5 + %g2]asi_num ;\
550 stxa %i2, [%g5 + %g3]asi_num ;\
551 stxa %i3, [%g5 + %g4]asi_num ;\
552 add %g5, 32, %g5 ;\
553 stxa %i4, [%g5 + %g1]asi_num ;\
554 stxa %i5, [%g5 + %g2]asi_num ;\
555 stxa %i6, [%g5 + %g3]asi_num ;\
556 stxa %i7, [%g5 + %g4]asi_num ;\
557 TT_TRACE_L(trace_win) ;\
558 saved ;\
559 retry ;\
560 SKIP(31-25-TT_TRACE_L_INS) ;\
561 ba,a,pt %xcc, fault_64bit_/**/tail ;\
562 .empty
563
564 /*
565 * SPILL_64bit_tt1 spills a 64-bit-wide register window into a 64-bit
566 * wide address space via the designated asi. It is used to spill
567 * windows at tl>1 where performance isn't the primary concern and
568 * where we don't want to use unnecessary registers. The stack
569 * pointer is required to be eight-byte aligned.
570 */
571 #define SPILL_64bit_tt1(asi_num, tail) \
572 mov asi_num, %asi ;\
573 2: stxa %l0, [%sp + V9BIAS64 + 0]%asi ;\
574 stxa %l1, [%sp + V9BIAS64 + 8]%asi ;\
575 stxa %l2, [%sp + V9BIAS64 + 16]%asi ;\
576 stxa %l3, [%sp + V9BIAS64 + 24]%asi ;\
577 stxa %l4, [%sp + V9BIAS64 + 32]%asi ;\
578 stxa %l5, [%sp + V9BIAS64 + 40]%asi ;\
579 stxa %l6, [%sp + V9BIAS64 + 48]%asi ;\
580 stxa %l7, [%sp + V9BIAS64 + 56]%asi ;\
581 stxa %i0, [%sp + V9BIAS64 + 64]%asi ;\
582 stxa %i1, [%sp + V9BIAS64 + 72]%asi ;\
583 stxa %i2, [%sp + V9BIAS64 + 80]%asi ;\
584 stxa %i3, [%sp + V9BIAS64 + 88]%asi ;\
585 stxa %i4, [%sp + V9BIAS64 + 96]%asi ;\
586 stxa %i5, [%sp + V9BIAS64 + 104]%asi ;\
587 stxa %i6, [%sp + V9BIAS64 + 112]%asi ;\
588 stxa %i7, [%sp + V9BIAS64 + 120]%asi ;\
589 TT_TRACE_L(trace_win) ;\
590 saved ;\
591 retry ;\
592 SKIP(31-19-TT_TRACE_L_INS) ;\
593 ba,a,pt %xcc, fault_64bit_/**/tail ;\
594 .empty
595
596
597 /*
598 * FILL_64bit fills a 64-bit-wide kernel register window. It assumes
599 * that the kernel context and the nucleus context are the same. The
600 * stack pointer is required to be eight-byte aligned.
601 */
602 #define FILL_64bit(tail) \
603 2: TT_TRACE_L(trace_win) ;\
604 ldx [%sp + V9BIAS64 + 0], %l0 ;\
605 ldx [%sp + V9BIAS64 + 8], %l1 ;\
606 ldx [%sp + V9BIAS64 + 16], %l2 ;\
607 ldx [%sp + V9BIAS64 + 24], %l3 ;\
608 ldx [%sp + V9BIAS64 + 32], %l4 ;\
609 ldx [%sp + V9BIAS64 + 40], %l5 ;\
610 ldx [%sp + V9BIAS64 + 48], %l6 ;\
611 ldx [%sp + V9BIAS64 + 56], %l7 ;\
612 ldx [%sp + V9BIAS64 + 64], %i0 ;\
613 ldx [%sp + V9BIAS64 + 72], %i1 ;\
614 ldx [%sp + V9BIAS64 + 80], %i2 ;\
615 ldx [%sp + V9BIAS64 + 88], %i3 ;\
616 ldx [%sp + V9BIAS64 + 96], %i4 ;\
617 ldx [%sp + V9BIAS64 + 104], %i5 ;\
618 ldx [%sp + V9BIAS64 + 112], %i6 ;\
619 ldx [%sp + V9BIAS64 + 120], %i7 ;\
620 restored ;\
621 retry ;\
622 SKIP(31-18-TT_TRACE_L_INS) ;\
623 ba,a,pt %xcc, fault_64bit_/**/tail ;\
624 .empty
625
626 /*
627 * FILL_64bit_asi fills a 64-bit-wide register window from a 64-bit
628 * wide address space via the designated asi. It is used to fill
629 * non-kernel windows. The stack pointer is required to be eight-byte
630 * aligned.
631 */
632 #define FILL_64bit_asi(asi_num, tail) \
633 mov V9BIAS64 + 0, %g1 ;\
634 2: TT_TRACE_L(trace_win) ;\
635 ldxa [%sp + %g1]asi_num, %l0 ;\
636 mov V9BIAS64 + 8, %g2 ;\
637 ldxa [%sp + %g2]asi_num, %l1 ;\
638 mov V9BIAS64 + 16, %g3 ;\
639 ldxa [%sp + %g3]asi_num, %l2 ;\
640 mov V9BIAS64 + 24, %g4 ;\
641 ldxa [%sp + %g4]asi_num, %l3 ;\
642 add %sp, 32, %g5 ;\
643 ldxa [%g5 + %g1]asi_num, %l4 ;\
644 ldxa [%g5 + %g2]asi_num, %l5 ;\
645 ldxa [%g5 + %g3]asi_num, %l6 ;\
646 ldxa [%g5 + %g4]asi_num, %l7 ;\
647 add %g5, 32, %g5 ;\
648 ldxa [%g5 + %g1]asi_num, %i0 ;\
649 ldxa [%g5 + %g2]asi_num, %i1 ;\
650 ldxa [%g5 + %g3]asi_num, %i2 ;\
651 ldxa [%g5 + %g4]asi_num, %i3 ;\
652 add %g5, 32, %g5 ;\
653 ldxa [%g5 + %g1]asi_num, %i4 ;\
654 ldxa [%g5 + %g2]asi_num, %i5 ;\
655 ldxa [%g5 + %g3]asi_num, %i6 ;\
656 ldxa [%g5 + %g4]asi_num, %i7 ;\
657 restored ;\
658 retry ;\
659 SKIP(31-25-TT_TRACE_L_INS) ;\
660 ba,a,pt %xcc, fault_64bit_/**/tail ;\
661 .empty
662
663 /*
664 * FILL_64bit_tt1 fills a 64-bit-wide register window from a 64-bit
665 * wide address space via the designated asi. It is used to fill
666 * windows at tl>1 where performance isn't the primary concern and
667 * where we don't want to use unnecessary registers. The stack
668 * pointer is required to be eight-byte aligned.
669 */
670 #define FILL_64bit_tt1(asi_num, tail) \
671 mov asi_num, %asi ;\
672 TT_TRACE_L(trace_win) ;\
673 ldxa [%sp + V9BIAS64 + 0]%asi, %l0 ;\
674 ldxa [%sp + V9BIAS64 + 8]%asi, %l1 ;\
675 ldxa [%sp + V9BIAS64 + 16]%asi, %l2 ;\
676 ldxa [%sp + V9BIAS64 + 24]%asi, %l3 ;\
677 ldxa [%sp + V9BIAS64 + 32]%asi, %l4 ;\
678 ldxa [%sp + V9BIAS64 + 40]%asi, %l5 ;\
679 ldxa [%sp + V9BIAS64 + 48]%asi, %l6 ;\
680 ldxa [%sp + V9BIAS64 + 56]%asi, %l7 ;\
681 ldxa [%sp + V9BIAS64 + 64]%asi, %i0 ;\
682 ldxa [%sp + V9BIAS64 + 72]%asi, %i1 ;\
683 ldxa [%sp + V9BIAS64 + 80]%asi, %i2 ;\
684 ldxa [%sp + V9BIAS64 + 88]%asi, %i3 ;\
685 ldxa [%sp + V9BIAS64 + 96]%asi, %i4 ;\
686 ldxa [%sp + V9BIAS64 + 104]%asi, %i5 ;\
687 ldxa [%sp + V9BIAS64 + 112]%asi, %i6 ;\
688 ldxa [%sp + V9BIAS64 + 120]%asi, %i7 ;\
689 restored ;\
690 retry ;\
691 SKIP(31-19-TT_TRACE_L_INS) ;\
692 ba,a,pt %xcc, fault_64bit_/**/tail ;\
693 .empty
694
695 /*
696 * SPILL_mixed spills either size window, depending on
697 * whether %sp is even or odd, to a 32-bit address space.
698 * This may only be used in conjunction with SPILL_32bit/
699 * SPILL_64bit. New versions of SPILL_mixed_{tt1,asi} would be
700 * needed for use with SPILL_{32,64}bit_{tt1,asi}. Particular
701 * attention should be paid to the instructions that belong
702 * in the delay slots of the branches depending on the type
703 * of spill handler being branched to.
704 * Clear upper 32 bits of %sp if it is odd.
705 * We won't need to clear them in 64 bit kernel.
706 */
707 #define SPILL_mixed \
708 btst 1, %sp ;\
709 bz,a,pt %xcc, 1b ;\
710 srl %sp, 0, %sp ;\
711 ba,pt %xcc, 2b ;\
712 nop ;\
713 .align 128
714
715 /*
716 * FILL_mixed(ASI) fills either size window, depending on
717 * whether %sp is even or odd, from a 32-bit address space.
718 * This may only be used in conjunction with FILL_32bit/
719 * FILL_64bit. New versions of FILL_mixed_{tt1,asi} would be
720 * needed for use with FILL_{32,64}bit_{tt1,asi}. Particular
721 * attention should be paid to the instructions that belong
722 * in the delay slots of the branches depending on the type
723 * of fill handler being branched to.
724 * Clear upper 32 bits of %sp if it is odd.
725 * We won't need to clear them in 64 bit kernel.
726 */
727 #define FILL_mixed \
728 btst 1, %sp ;\
729 bz,a,pt %xcc, 1b ;\
730 srl %sp, 0, %sp ;\
731 ba,pt %xcc, 2b ;\
732 nop ;\
733 .align 128
734
735
736 /*
737 * SPILL_32clean/SPILL_64clean spill 32-bit and 64-bit register windows,
738 * respectively, into the address space via the designated asi. The
739 * unbiased stack pointer is required to be eight-byte aligned (even for
740 * the 32-bit case even though this code does not require such strict
741 * alignment).
742 *
743 * With SPARC v9 the spill trap takes precedence over the cleanwin trap
744 * so when cansave == 0, canrestore == 6, and cleanwin == 6 the next save
745 * will cause cwp + 2 to be spilled but will not clean cwp + 1. That
746 * window may contain kernel data so in user_rtt we set wstate to call
747 * these spill handlers on the first user spill trap. These handler then
748 * spill the appropriate window but also back up a window and clean the
749 * window that didn't get a cleanwin trap.
750 */
751 #define SPILL_32clean(asi_num, tail) \
752 srl %sp, 0, %sp ;\
753 sta %l0, [%sp + %g0]asi_num ;\
754 mov 4, %g1 ;\
755 sta %l1, [%sp + %g1]asi_num ;\
756 mov 8, %g2 ;\
757 sta %l2, [%sp + %g2]asi_num ;\
758 mov 12, %g3 ;\
759 sta %l3, [%sp + %g3]asi_num ;\
760 add %sp, 16, %g4 ;\
761 sta %l4, [%g4 + %g0]asi_num ;\
762 sta %l5, [%g4 + %g1]asi_num ;\
763 sta %l6, [%g4 + %g2]asi_num ;\
764 sta %l7, [%g4 + %g3]asi_num ;\
765 add %g4, 16, %g4 ;\
766 sta %i0, [%g4 + %g0]asi_num ;\
767 sta %i1, [%g4 + %g1]asi_num ;\
768 sta %i2, [%g4 + %g2]asi_num ;\
769 sta %i3, [%g4 + %g3]asi_num ;\
770 add %g4, 16, %g4 ;\
771 sta %i4, [%g4 + %g0]asi_num ;\
772 sta %i5, [%g4 + %g1]asi_num ;\
773 sta %i6, [%g4 + %g2]asi_num ;\
774 sta %i7, [%g4 + %g3]asi_num ;\
775 TT_TRACE_L(trace_win) ;\
776 b .spill_clean ;\
777 mov WSTATE_USER32, %g7 ;\
778 SKIP(31-25-TT_TRACE_L_INS) ;\
779 ba,a,pt %xcc, fault_32bit_/**/tail ;\
780 .empty
781
782 #define SPILL_64clean(asi_num, tail) \
783 mov 0 + V9BIAS64, %g1 ;\
784 stxa %l0, [%sp + %g1]asi_num ;\
785 mov 8 + V9BIAS64, %g2 ;\
786 stxa %l1, [%sp + %g2]asi_num ;\
787 mov 16 + V9BIAS64, %g3 ;\
788 stxa %l2, [%sp + %g3]asi_num ;\
789 mov 24 + V9BIAS64, %g4 ;\
790 stxa %l3, [%sp + %g4]asi_num ;\
791 add %sp, 32, %g5 ;\
792 stxa %l4, [%g5 + %g1]asi_num ;\
793 stxa %l5, [%g5 + %g2]asi_num ;\
794 stxa %l6, [%g5 + %g3]asi_num ;\
795 stxa %l7, [%g5 + %g4]asi_num ;\
796 add %g5, 32, %g5 ;\
797 stxa %i0, [%g5 + %g1]asi_num ;\
798 stxa %i1, [%g5 + %g2]asi_num ;\
799 stxa %i2, [%g5 + %g3]asi_num ;\
800 stxa %i3, [%g5 + %g4]asi_num ;\
801 add %g5, 32, %g5 ;\
802 stxa %i4, [%g5 + %g1]asi_num ;\
803 stxa %i5, [%g5 + %g2]asi_num ;\
804 stxa %i6, [%g5 + %g3]asi_num ;\
805 stxa %i7, [%g5 + %g4]asi_num ;\
806 TT_TRACE_L(trace_win) ;\
807 b .spill_clean ;\
808 mov WSTATE_USER64, %g7 ;\
809 SKIP(31-25-TT_TRACE_L_INS) ;\
810 ba,a,pt %xcc, fault_64bit_/**/tail ;\
811 .empty
812
813
814 /*
815 * Floating point disabled.
816 */
817 #define FP_DISABLED_TRAP \
818 TT_TRACE(trace_gen) ;\
819 ba,pt %xcc,.fp_disabled ;\
820 nop ;\
821 .align 32
822
823 /*
824 * Floating point exceptions.
825 */
826 #define FP_IEEE_TRAP \
827 TT_TRACE(trace_gen) ;\
828 ba,pt %xcc,.fp_ieee_exception ;\
829 nop ;\
830 .align 32
831
832 #define FP_TRAP \
833 TT_TRACE(trace_gen) ;\
834 ba,pt %xcc,.fp_exception ;\
835 nop ;\
836 .align 32
837
838 /*
839 * asynchronous traps at level 0 and level 1
840 *
841 * The first instruction must be a membar for UltraSPARC-III
842 * to stop RED state entry if the store queue has many
843 * pending bad stores (PRM, Chapter 11).
844 */
845 #define ASYNC_TRAP(ttype, ttlabel, table_name)\
846 .global table_name ;\
847 table_name: ;\
848 membar #Sync ;\
849 TT_TRACE(ttlabel) ;\
850 ba async_err ;\
851 mov ttype, %g5 ;\
852 .align 32
853
854 /*
855 * Defaults to BAD entry, but establishes label to be used for
856 * architecture-specific overwrite of trap table entry.
857 */
858 #define LABELED_BAD(table_name) \
859 .global table_name ;\
860 table_name: ;\
861 BAD
862
863 /*
864 * illegal instruction trap
865 */
866 #define ILLTRAP_INSTR \
867 membar #Sync ;\
868 TT_TRACE(trace_gen) ;\
869 or %g0, P_UTRAP4, %g2 ;\
870 or %g0, T_UNIMP_INSTR, %g3 ;\
871 sethi %hi(.check_v9utrap), %g4 ;\
872 jmp %g4 + %lo(.check_v9utrap) ;\
873 nop ;\
874 .align 32
875
876 /*
877 * tag overflow trap
878 */
879 #define TAG_OVERFLOW \
880 TT_TRACE(trace_gen) ;\
881 or %g0, P_UTRAP10, %g2 ;\
882 or %g0, T_TAG_OVERFLOW, %g3 ;\
883 sethi %hi(.check_v9utrap), %g4 ;\
884 jmp %g4 + %lo(.check_v9utrap) ;\
885 nop ;\
886 .align 32
887
888 /*
889 * divide by zero trap
890 */
891 #define DIV_BY_ZERO \
892 TT_TRACE(trace_gen) ;\
893 or %g0, P_UTRAP11, %g2 ;\
894 or %g0, T_IDIV0, %g3 ;\
895 sethi %hi(.check_v9utrap), %g4 ;\
896 jmp %g4 + %lo(.check_v9utrap) ;\
897 nop ;\
898 .align 32
899
900 /*
901 * trap instruction for V9 user trap handlers
902 */
903 #define TRAP_INSTR \
904 TT_TRACE(trace_gen) ;\
905 or %g0, T_SOFTWARE_TRAP, %g3 ;\
906 sethi %hi(.check_v9utrap), %g4 ;\
907 jmp %g4 + %lo(.check_v9utrap) ;\
908 nop ;\
909 .align 32
910 #define TRP4 TRAP_INSTR; TRAP_INSTR; TRAP_INSTR; TRAP_INSTR
911
912 /*
913 * LEVEL_INTERRUPT is for level N interrupts.
914 * VECTOR_INTERRUPT is for the vector trap.
915 */
916 #define LEVEL_INTERRUPT(level) \
917 .global tt_pil/**/level ;\
918 tt_pil/**/level: ;\
919 ba,pt %xcc, pil_interrupt ;\
920 mov level, %g4 ;\
921 .align 32
922
923 #define LEVEL14_INTERRUPT \
924 ba pil14_interrupt ;\
925 mov PIL_14, %g4 ;\
926 .align 32
927
928 #define LEVEL15_INTERRUPT \
929 ba pil15_interrupt ;\
930 mov PIL_15, %g4 ;\
931 .align 32
932
933 #define VECTOR_INTERRUPT \
934 ldxa [%g0]ASI_INTR_RECEIVE_STATUS, %g1 ;\
935 btst IRSR_BUSY, %g1 ;\
936 bnz,pt %xcc, vec_interrupt ;\
937 nop ;\
938 ba,a,pt %xcc, vec_intr_spurious ;\
939 .empty ;\
940 .align 32
941
942 /*
943 * MMU Trap Handlers.
944 */
945 #define SWITCH_GLOBALS /* mmu->alt, alt->mmu */ \
946 rdpr %pstate, %g5 ;\
947 wrpr %g5, PSTATE_MG | PSTATE_AG, %pstate
948
949 #define IMMU_EXCEPTION \
950 membar #Sync ;\
951 SWITCH_GLOBALS ;\
952 wr %g0, ASI_IMMU, %asi ;\
953 rdpr %tpc, %g2 ;\
954 ldxa [MMU_SFSR]%asi, %g3 ;\
955 ba,pt %xcc, .mmu_exception_end ;\
956 mov T_INSTR_EXCEPTION, %g1 ;\
957 .align 32
958
959 #define DMMU_EXCEPTION \
960 SWITCH_GLOBALS ;\
961 wr %g0, ASI_DMMU, %asi ;\
962 ldxa [MMU_TAG_ACCESS]%asi, %g2 ;\
963 ldxa [MMU_SFSR]%asi, %g3 ;\
964 ba,pt %xcc, .mmu_exception_end ;\
965 mov T_DATA_EXCEPTION, %g1 ;\
966 .align 32
967
968 #define DMMU_EXC_AG_PRIV \
969 wr %g0, ASI_DMMU, %asi ;\
970 ldxa [MMU_SFAR]%asi, %g2 ;\
971 ba,pt %xcc, .mmu_priv_exception ;\
972 ldxa [MMU_SFSR]%asi, %g3 ;\
973 .align 32
974
975 #define DMMU_EXC_AG_NOT_ALIGNED \
976 wr %g0, ASI_DMMU, %asi ;\
977 ldxa [MMU_SFAR]%asi, %g2 ;\
978 ba,pt %xcc, .mmu_exception_not_aligned ;\
979 ldxa [MMU_SFSR]%asi, %g3 ;\
980 .align 32
981
982 /*
983 * SPARC V9 IMPL. DEP. #109(1) and (2) and #110(1) and (2)
984 */
985 #define DMMU_EXC_LDDF_NOT_ALIGNED \
986 btst 1, %sp ;\
987 bnz,pt %xcc, .lddf_exception_not_aligned ;\
988 wr %g0, ASI_DMMU, %asi ;\
989 ldxa [MMU_SFAR]%asi, %g2 ;\
990 ba,pt %xcc, .mmu_exception_not_aligned ;\
991 ldxa [MMU_SFSR]%asi, %g3 ;\
992 .align 32
993
994 #define DMMU_EXC_STDF_NOT_ALIGNED \
995 btst 1, %sp ;\
996 bnz,pt %xcc, .stdf_exception_not_aligned ;\
997 wr %g0, ASI_DMMU, %asi ;\
998 ldxa [MMU_SFAR]%asi, %g2 ;\
999 ba,pt %xcc, .mmu_exception_not_aligned ;\
1000 ldxa [MMU_SFSR]%asi, %g3 ;\
1001 .align 32
1002
1003 /*
1004 * Flush the TLB using either the primary, secondary, or nucleus flush
1005 * operation based on whether the ctx from the tag access register matches
1006 * the primary or secondary context (flush the nucleus if neither matches).
1007 *
1008 * Requires a membar #Sync before next ld/st.
1009 * exits with:
1010 * g2 = tag access register
1011 * g3 = ctx number
1012 */
1013 #if TAGACC_CTX_MASK != CTXREG_CTX_MASK
1014 #error "TAGACC_CTX_MASK != CTXREG_CTX_MASK"
1015 #endif
1016 #define DTLB_DEMAP_ENTRY \
1017 mov MMU_TAG_ACCESS, %g1 ;\
1018 mov MMU_PCONTEXT, %g5 ;\
1019 ldxa [%g1]ASI_DMMU, %g2 ;\
1020 sethi %hi(TAGACC_CTX_MASK), %g4 ;\
1021 or %g4, %lo(TAGACC_CTX_MASK), %g4 ;\
1022 and %g2, %g4, %g3 /* g3 = ctx */ ;\
1023 ldxa [%g5]ASI_DMMU, %g6 /* g6 = primary ctx */ ;\
1024 and %g6, %g4, %g6 /* &= CTXREG_CTX_MASK */ ;\
1025 cmp %g3, %g6 ;\
1026 be,pt %xcc, 1f ;\
1027 andn %g2, %g4, %g1 /* ctx = primary */ ;\
1028 mov MMU_SCONTEXT, %g5 ;\
1029 ldxa [%g5]ASI_DMMU, %g6 /* g6 = secondary ctx */ ;\
1030 and %g6, %g4, %g6 /* &= CTXREG_CTX_MASK */ ;\
1031 cmp %g3, %g6 ;\
1032 be,a,pt %xcc, 1f ;\
1033 or %g1, DEMAP_SECOND, %g1 ;\
1034 or %g1, DEMAP_NUCLEUS, %g1 ;\
1035 1: stxa %g0, [%g1]ASI_DTLB_DEMAP /* MMU_DEMAP_PAGE */ ;\
1036 membar #Sync
1037
1038 #if defined(cscope)
1039 /*
1040 * Define labels to direct cscope quickly to labels that
1041 * are generated by macro expansion of DTLB_MISS().
1042 */
1043 .global tt0_dtlbmiss
1044 tt0_dtlbmiss:
1045 .global tt1_dtlbmiss
1046 tt1_dtlbmiss:
1047 nop
1048 #endif
1049
1050 /*
1051 * Needs to be exactly 32 instructions
1052 *
1053 * UTLB NOTE: If we don't hit on the 8k pointer then we branch
1054 * to a special 4M tsb handler. It would be nice if that handler
1055 * could live in this file but currently it seems better to allow
1056 * it to fall thru to sfmmu_tsb_miss.
1057 */
1058 #ifdef UTSB_PHYS
1059 #define DTLB_MISS(table_name) ;\
1060 .global table_name/**/_dtlbmiss ;\
1061 table_name/**/_dtlbmiss: ;\
1062 mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\
1063 ldxa [%g0]ASI_DMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\
1064 ldxa [%g6]ASI_DMMU, %g2 /* g2 = tag access */ ;\
1065 sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\
1066 srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\
1067 cmp %g3, INVALID_CONTEXT ;\
1068 ble,pn %xcc, sfmmu_kdtlb_miss ;\
1069 srax %g2, PREDISM_BASESHIFT, %g6 /* g6 > 0 ISM predicted */ ;\
1070 brgz,pn %g6, sfmmu_udtlb_slowpath_ismpred ;\
1071 srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\
1072 ldda [%g1]ASI_QUAD_LDD_PHYS, %g4 /* g4 = tag, %g5 data */;\
1073 cmp %g4, %g7 ;\
1074 bne,pn %xcc, sfmmu_udtlb_slowpath_noismpred ;\
1075 nop ;\
1076 TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\
1077 stxa %g5, [%g0]ASI_DTLB_IN /* trapstat expects TTE */ ;\
1078 retry /* in %g5 */ ;\
1079 unimp 0 ;\
1080 unimp 0 ;\
1081 unimp 0 ;\
1082 unimp 0 ;\
1083 unimp 0 ;\
1084 unimp 0 ;\
1085 unimp 0 ;\
1086 unimp 0 ;\
1087 unimp 0 ;\
1088 unimp 0 ;\
1089 unimp 0 ;\
1090 unimp 0 ;\
1091 unimp 0 ;\
1092 unimp 0 ;\
1093 .align 128
1094
1095 #else /* UTSB_PHYS */
1096 #define DTLB_MISS(table_name) ;\
1097 .global table_name/**/_dtlbmiss ;\
1098 table_name/**/_dtlbmiss: ;\
1099 mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\
1100 ldxa [%g0]ASI_DMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\
1101 ldxa [%g6]ASI_DMMU, %g2 /* g2 = tag access */ ;\
1102 sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\
1103 srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\
1104 cmp %g3, INVALID_CONTEXT ;\
1105 ble,pn %xcc, sfmmu_kdtlb_miss ;\
1106 srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\
1107 brlz,pn %g1, sfmmu_udtlb_slowpath ;\
1108 nop ;\
1109 ldda [%g1]ASI_NQUAD_LD, %g4 /* g4 = tag, %g5 data */ ;\
1110 cmp %g4, %g7 ;\
1111 bne,pn %xcc, sfmmu_tsb_miss_tt /* no 4M TSB, miss */ ;\
1112 mov -1, %g3 /* set 4M tsbe ptr to -1 */ ;\
1113 TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\
1114 stxa %g5, [%g0]ASI_DTLB_IN /* trapstat expects TTE */ ;\
1115 retry /* in %g5 */ ;\
1116 unimp 0 ;\
1117 unimp 0 ;\
1118 unimp 0 ;\
1119 unimp 0 ;\
1120 unimp 0 ;\
1121 unimp 0 ;\
1122 unimp 0 ;\
1123 unimp 0 ;\
1124 unimp 0 ;\
1125 unimp 0 ;\
1126 unimp 0 ;\
1127 unimp 0 ;\
1128 unimp 0 ;\
1129 unimp 0 ;\
1130 .align 128
1131 #endif /* UTSB_PHYS */
1132
1133 #if defined(cscope)
1134 /*
1135 * Define labels to direct cscope quickly to labels that
1136 * are generated by macro expansion of ITLB_MISS().
1137 */
1138 .global tt0_itlbmiss
1139 tt0_itlbmiss:
1140 .global tt1_itlbmiss
1141 tt1_itlbmiss:
1142 nop
1143 #endif
1144
1145 /*
1146 * Instruction miss handler.
1147 * ldda instructions will have their ASI patched
1148 * by sfmmu_patch_ktsb at runtime.
1149 * MUST be EXACTLY 32 instructions or we'll break.
1150 */
1151 #ifdef UTSB_PHYS
1152 #define ITLB_MISS(table_name) \
1153 .global table_name/**/_itlbmiss ;\
1154 table_name/**/_itlbmiss: ;\
1155 mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\
1156 ldxa [%g0]ASI_IMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\
1157 ldxa [%g6]ASI_IMMU, %g2 /* g2 = tag access */ ;\
1158 sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\
1159 srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\
1160 cmp %g3, INVALID_CONTEXT ;\
1161 ble,pn %xcc, sfmmu_kitlb_miss ;\
1162 srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\
1163 ldda [%g1]ASI_QUAD_LDD_PHYS, %g4 /* g4 = tag, g5 = data */ ;\
1164 cmp %g4, %g7 ;\
1165 bne,pn %xcc, sfmmu_uitlb_slowpath ;\
1166 andcc %g5, TTE_EXECPRM_INT, %g0 /* check execute bit */ ;\
1167 bz,pn %icc, exec_fault ;\
1168 nop ;\
1169 TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\
1170 stxa %g5, [%g0]ASI_ITLB_IN /* trapstat expects %g5 */ ;\
1171 retry ;\
1172 unimp 0 ;\
1173 unimp 0 ;\
1174 unimp 0 ;\
1175 unimp 0 ;\
1176 unimp 0 ;\
1177 unimp 0 ;\
1178 unimp 0 ;\
1179 unimp 0 ;\
1180 unimp 0 ;\
1181 unimp 0 ;\
1182 unimp 0 ;\
1183 unimp 0 ;\
1184 unimp 0 ;\
1185 unimp 0 ;\
1186 .align 128
1187
1188 #else /* UTSB_PHYS */
1189 #define ITLB_MISS(table_name) \
1190 .global table_name/**/_itlbmiss ;\
1191 table_name/**/_itlbmiss: ;\
1192 mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\
1193 ldxa [%g0]ASI_IMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\
1194 ldxa [%g6]ASI_IMMU, %g2 /* g2 = tag access */ ;\
1195 sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\
1196 srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\
1197 cmp %g3, INVALID_CONTEXT ;\
1198 ble,pn %xcc, sfmmu_kitlb_miss ;\
1199 srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\
1200 brlz,pn %g1, sfmmu_uitlb_slowpath /* if >1 TSB branch */ ;\
1201 nop ;\
1202 ldda [%g1]ASI_NQUAD_LD, %g4 /* g4 = tag, g5 = data */ ;\
1203 cmp %g4, %g7 ;\
1204 bne,pn %xcc, sfmmu_tsb_miss_tt /* br if 8k ptr miss */ ;\
1205 mov -1, %g3 /* set 4M TSB ptr to -1 */ ;\
1206 andcc %g5, TTE_EXECPRM_INT, %g0 /* check execute bit */ ;\
1207 bz,pn %icc, exec_fault ;\
1208 nop ;\
1209 TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\
1210 stxa %g5, [%g0]ASI_ITLB_IN /* trapstat expects %g5 */ ;\
1211 retry ;\
1212 unimp 0 ;\
1213 unimp 0 ;\
1214 unimp 0 ;\
1215 unimp 0 ;\
1216 unimp 0 ;\
1217 unimp 0 ;\
1218 unimp 0 ;\
1219 unimp 0 ;\
1220 unimp 0 ;\
1221 unimp 0 ;\
1222 unimp 0 ;\
1223 .align 128
1224 #endif /* UTSB_PHYS */
1225
1226
1227 /*
1228 * This macro is the first level handler for fast protection faults.
1229 * It first demaps the tlb entry which generated the fault and then
1230 * attempts to set the modify bit on the hash. It needs to be
1231 * exactly 32 instructions.
1232 */
1233 #define DTLB_PROT \
1234 DTLB_DEMAP_ENTRY /* 20 instructions */ ;\
1235 /* ;\
1236 * At this point: ;\
1237 * g1 = ???? ;\
1238 * g2 = tag access register ;\
1239 * g3 = ctx number ;\
1240 * g4 = ???? ;\
1241 */ ;\
1242 TT_TRACE(trace_dataprot) /* 2 instr ifdef TRAPTRACE */ ;\
1243 /* clobbers g1 and g6 */ ;\
1244 ldxa [%g0]ASI_DMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\
1245 brnz,pt %g3, sfmmu_uprot_trap /* user trap */ ;\
1246 nop ;\
1247 ba,a,pt %xcc, sfmmu_kprot_trap /* kernel trap */ ;\
1248 unimp 0 ;\
1249 unimp 0 ;\
1250 unimp 0 ;\
1251 unimp 0 ;\
1252 unimp 0 ;\
1253 unimp 0 ;\
1254 .align 128
1255
1256 #define DMMU_EXCEPTION_TL1 ;\
1257 SWITCH_GLOBALS ;\
1258 ba,a,pt %xcc, mmu_trap_tl1 ;\
1259 nop ;\
1260 .align 32
1261
1262 #define MISALIGN_ADDR_TL1 ;\
1263 ba,a,pt %xcc, mmu_trap_tl1 ;\
1264 nop ;\
1265 .align 32
1266
1267 /*
1268 * Trace a tsb hit
1269 * g1 = tsbe pointer (in/clobbered)
1270 * g2 = tag access register (in)
1271 * g3 - g4 = scratch (clobbered)
1272 * g5 = tsbe data (in)
1273 * g6 = scratch (clobbered)
1274 * g7 = pc we jumped here from (in)
1275 * ttextra = value to OR in to trap type (%tt) (in)
1276 */
1277 #ifdef TRAPTRACE
1278 #define TRACE_TSBHIT(ttextra) \
1279 membar #Sync ;\
1280 sethi %hi(FLUSH_ADDR), %g6 ;\
1281 flush %g6 ;\
1282 TRACE_PTR(%g3, %g6) ;\
1283 GET_TRACE_TICK(%g6, %g4) ;\
1284 stxa %g6, [%g3 + TRAP_ENT_TICK]%asi ;\
1285 stxa %g2, [%g3 + TRAP_ENT_SP]%asi /* tag access */ ;\
1286 stxa %g5, [%g3 + TRAP_ENT_F1]%asi /* tsb data */ ;\
1287 rdpr %tnpc, %g6 ;\
1288 stxa %g6, [%g3 + TRAP_ENT_F2]%asi ;\
1289 stxa %g1, [%g3 + TRAP_ENT_F3]%asi /* tsb pointer */ ;\
1290 stxa %g0, [%g3 + TRAP_ENT_F4]%asi ;\
1291 rdpr %tpc, %g6 ;\
1292 stxa %g6, [%g3 + TRAP_ENT_TPC]%asi ;\
1293 rdpr %tl, %g6 ;\
1294 stha %g6, [%g3 + TRAP_ENT_TL]%asi ;\
1295 rdpr %tt, %g6 ;\
1296 or %g6, (ttextra), %g6 ;\
1297 stha %g6, [%g3 + TRAP_ENT_TT]%asi ;\
1298 ldxa [%g0]ASI_IMMU, %g1 /* tag target */ ;\
1299 ldxa [%g0]ASI_DMMU, %g4 ;\
1300 cmp %g6, FAST_IMMU_MISS_TT ;\
1301 movne %icc, %g4, %g1 ;\
1302 stxa %g1, [%g3 + TRAP_ENT_TSTATE]%asi /* tsb tag */ ;\
1303 stxa %g0, [%g3 + TRAP_ENT_TR]%asi ;\
1304 TRACE_NEXT(%g3, %g4, %g6)
1305 #else
1306 #define TRACE_TSBHIT(ttextra)
1307 #endif
1308
1309 /*
1310 * =======================================================================
1311 * SPARC V9 TRAP TABLE
1312 *
1313 * The trap table is divided into two halves: the first half is used when
1314 * taking traps when TL=0; the second half is used when taking traps from
1315 * TL>0. Note that handlers in the second half of the table might not be able
1316 * to make the same assumptions as handlers in the first half of the table.
1317 *
1318 * Worst case trap nesting so far:
1319 *
1320 * at TL=0 client issues software trap requesting service
1321 * at TL=1 nucleus wants a register window
1322 * at TL=2 register window clean/spill/fill takes a TLB miss
1323 * at TL=3 processing TLB miss
1324 * at TL=4 handle asynchronous error
1325 *
1326 * Note that a trap from TL=4 to TL=5 places Spitfire in "RED mode".
1327 *
1328 * =======================================================================
1329 */
1330 .section ".text"
1331 .align 4
1332 .global trap_table, scb, trap_table0, trap_table1, etrap_table
1333 .type trap_table, #object
1334 .type scb, #object
1335 trap_table:
1336 scb:
1337 trap_table0:
1338 /* hardware traps */
1339 NOT; /* 000 reserved */
1340 RED; /* 001 power on reset */
1341 RED; /* 002 watchdog reset */
1342 RED; /* 003 externally initiated reset */
1343 RED; /* 004 software initiated reset */
1344 RED; /* 005 red mode exception */
1345 NOT; NOT; /* 006 - 007 reserved */
1346 IMMU_EXCEPTION; /* 008 instruction access exception */
1347 NOT; /* 009 instruction access MMU miss */
1348 ASYNC_TRAP(T_INSTR_ERROR, trace_gen, tt0_iae);
1349 /* 00A instruction access error */
1350 NOT; NOT4; /* 00B - 00F reserved */
1351 ILLTRAP_INSTR; /* 010 illegal instruction */
1352 TRAP(T_PRIV_INSTR); /* 011 privileged opcode */
1353 NOT; /* 012 unimplemented LDD */
1354 NOT; /* 013 unimplemented STD */
1355 NOT4; NOT4; NOT4; /* 014 - 01F reserved */
1356 FP_DISABLED_TRAP; /* 020 fp disabled */
1357 FP_IEEE_TRAP; /* 021 fp exception ieee 754 */
1358 FP_TRAP; /* 022 fp exception other */
1359 TAG_OVERFLOW; /* 023 tag overflow */
1360 CLEAN_WINDOW; /* 024 - 027 clean window */
1361 DIV_BY_ZERO; /* 028 division by zero */
1362 NOT; /* 029 internal processor error */
1363 NOT; NOT; NOT4; /* 02A - 02F reserved */
1364 DMMU_EXCEPTION; /* 030 data access exception */
1365 NOT; /* 031 data access MMU miss */
1366 ASYNC_TRAP(T_DATA_ERROR, trace_gen, tt0_dae);
1367 /* 032 data access error */
1368 NOT; /* 033 data access protection */
1369 DMMU_EXC_AG_NOT_ALIGNED; /* 034 mem address not aligned */
1370 DMMU_EXC_LDDF_NOT_ALIGNED; /* 035 LDDF mem address not aligned */
1371 DMMU_EXC_STDF_NOT_ALIGNED; /* 036 STDF mem address not aligned */
1372 DMMU_EXC_AG_PRIV; /* 037 privileged action */
1373 NOT; /* 038 LDQF mem address not aligned */
1374 NOT; /* 039 STQF mem address not aligned */
1375 NOT; NOT; NOT4; /* 03A - 03F reserved */
1376 LABELED_BAD(tt0_asdat); /* 040 async data error */
1377 LEVEL_INTERRUPT(1); /* 041 interrupt level 1 */
1378 LEVEL_INTERRUPT(2); /* 042 interrupt level 2 */
1379 LEVEL_INTERRUPT(3); /* 043 interrupt level 3 */
1380 LEVEL_INTERRUPT(4); /* 044 interrupt level 4 */
1381 LEVEL_INTERRUPT(5); /* 045 interrupt level 5 */
1382 LEVEL_INTERRUPT(6); /* 046 interrupt level 6 */
1383 LEVEL_INTERRUPT(7); /* 047 interrupt level 7 */
1384 LEVEL_INTERRUPT(8); /* 048 interrupt level 8 */
1385 LEVEL_INTERRUPT(9); /* 049 interrupt level 9 */
1386 LEVEL_INTERRUPT(10); /* 04A interrupt level 10 */
1387 LEVEL_INTERRUPT(11); /* 04B interrupt level 11 */
1388 LEVEL_INTERRUPT(12); /* 04C interrupt level 12 */
1389 LEVEL_INTERRUPT(13); /* 04D interrupt level 13 */
1390 LEVEL14_INTERRUPT; /* 04E interrupt level 14 */
1391 LEVEL15_INTERRUPT; /* 04F interrupt level 15 */
1392 NOT4; NOT4; NOT4; NOT4; /* 050 - 05F reserved */
1393 VECTOR_INTERRUPT; /* 060 interrupt vector */
1394 GOTO(kmdb_trap); /* 061 PA watchpoint */
1395 GOTO(kmdb_trap); /* 062 VA watchpoint */
1396 GOTO_TT(ce_err, trace_gen); /* 063 corrected ECC error */
1397 ITLB_MISS(tt0); /* 064 instruction access MMU miss */
1398 DTLB_MISS(tt0); /* 068 data access MMU miss */
1399 DTLB_PROT; /* 06C data access protection */
1400 LABELED_BAD(tt0_fecc); /* 070 fast ecache ECC error */
1401 LABELED_BAD(tt0_dperr); /* 071 Cheetah+ dcache parity error */
1402 LABELED_BAD(tt0_iperr); /* 072 Cheetah+ icache parity error */
1403 NOT; /* 073 reserved */
1404 NOT4; NOT4; NOT4; /* 074 - 07F reserved */
1405 NOT4; /* 080 spill 0 normal */
1406 SPILL_32bit_asi(ASI_AIUP,sn0); /* 084 spill 1 normal */
1407 SPILL_64bit_asi(ASI_AIUP,sn0); /* 088 spill 2 normal */
1408 SPILL_32clean(ASI_AIUP,sn0); /* 08C spill 3 normal */
1409 SPILL_64clean(ASI_AIUP,sn0); /* 090 spill 4 normal */
1410 SPILL_32bit(not); /* 094 spill 5 normal */
1411 SPILL_64bit(not); /* 098 spill 6 normal */
1412 SPILL_mixed; /* 09C spill 7 normal */
1413 NOT4; /* 0A0 spill 0 other */
1414 SPILL_32bit_asi(ASI_AIUS,so0); /* 0A4 spill 1 other */
1415 SPILL_64bit_asi(ASI_AIUS,so0); /* 0A8 spill 2 other */
1416 SPILL_32bit_asi(ASI_AIUS,so0); /* 0AC spill 3 other */
1417 SPILL_64bit_asi(ASI_AIUS,so0); /* 0B0 spill 4 other */
1418 NOT4; /* 0B4 spill 5 other */
1419 NOT4; /* 0B8 spill 6 other */
1420 NOT4; /* 0BC spill 7 other */
1421 NOT4; /* 0C0 fill 0 normal */
1422 FILL_32bit_asi(ASI_AIUP,fn0); /* 0C4 fill 1 normal */
1423 FILL_64bit_asi(ASI_AIUP,fn0); /* 0C8 fill 2 normal */
1424 FILL_32bit_asi(ASI_AIUP,fn0); /* 0CC fill 3 normal */
1425 FILL_64bit_asi(ASI_AIUP,fn0); /* 0D0 fill 4 normal */
1426 FILL_32bit(not); /* 0D4 fill 5 normal */
1427 FILL_64bit(not); /* 0D8 fill 6 normal */
1428 FILL_mixed; /* 0DC fill 7 normal */
1429 NOT4; /* 0E0 fill 0 other */
1430 NOT4; /* 0E4 fill 1 other */
1431 NOT4; /* 0E8 fill 2 other */
1432 NOT4; /* 0EC fill 3 other */
1433 NOT4; /* 0F0 fill 4 other */
1434 NOT4; /* 0F4 fill 5 other */
1435 NOT4; /* 0F8 fill 6 other */
1436 NOT4; /* 0FC fill 7 other */
1437 /* user traps */
1438 GOTO(syscall_trap_4x); /* 100 old system call */
1439 TRAP(T_BREAKPOINT); /* 101 user breakpoint */
1440 TRAP(T_DIV0); /* 102 user divide by zero */
1441 FLUSHW(tt0_flushw); /* 103 flush windows */
1442 GOTO(.clean_windows); /* 104 clean windows */
1443 BAD; /* 105 range check ?? */
1444 GOTO(.fix_alignment); /* 106 do unaligned references */
1445 BAD; /* 107 unused */
1446 SYSCALL_TRAP32; /* 108 ILP32 system call on LP64 */
1447 GOTO(set_trap0_addr); /* 109 set trap0 address */
1448 BAD; BAD; BAD4; /* 10A - 10F unused */
1449 TRP4; TRP4; TRP4; TRP4; /* 110 - 11F V9 user trap handlers */
1450 GOTO(.getcc); /* 120 get condition codes */
1451 GOTO(.setcc); /* 121 set condition codes */
1452 GOTO(.getpsr); /* 122 get psr */
1453 GOTO(.setpsr); /* 123 set psr (some fields) */
1454 GOTO(get_timestamp); /* 124 get timestamp */
1455 GOTO(get_virtime); /* 125 get lwp virtual time */
1456 PRIV(self_xcall); /* 126 self xcall */
1457 GOTO(get_hrestime); /* 127 get hrestime */
1458 BAD; /* 128 ST_SETV9STACK */
1459 GOTO(.getlgrp); /* 129 get lgrpid */
1460 BAD; BAD; BAD4; /* 12A - 12F unused */
1461 BAD4; BAD4; /* 130 - 137 unused */
1462 DTRACE_PID; /* 138 dtrace pid tracing provider */
1463 BAD; /* 139 unused */
1464 DTRACE_RETURN; /* 13A dtrace pid return probe */
1465 BAD; BAD4; /* 13B - 13F unused */
1466 SYSCALL_TRAP; /* 140 LP64 system call */
1467 SYSCALL(nosys); /* 141 unused system call trap */
1468 #ifdef DEBUG_USER_TRAPTRACECTL
1469 GOTO(.traptrace_freeze); /* 142 freeze traptrace */
1470 GOTO(.traptrace_unfreeze); /* 143 unfreeze traptrace */
1471 #else
1472 SYSCALL(nosys); /* 142 unused system call trap */
1473 SYSCALL(nosys); /* 143 unused system call trap */
1474 #endif
1475 BAD4; BAD4; BAD4; /* 144 - 14F unused */
1476 BAD4; BAD4; BAD4; BAD4; /* 150 - 15F unused */
1477 BAD4; BAD4; BAD4; BAD4; /* 160 - 16F unused */
1478 BAD; /* 170 - unused */
1479 BAD; /* 171 - unused */
1480 BAD; BAD; /* 172 - 173 unused */
1481 BAD4; BAD4; /* 174 - 17B unused */
1482 #ifdef PTL1_PANIC_DEBUG
1483 mov PTL1_BAD_DEBUG, %g1; GOTO(ptl1_panic);
1484 /* 17C test ptl1_panic */
1485 #else
1486 BAD; /* 17C unused */
1487 #endif /* PTL1_PANIC_DEBUG */
1488 PRIV(kmdb_trap); /* 17D kmdb enter (L1-A) */
1489 PRIV(kmdb_trap); /* 17E kmdb breakpoint */
1490 PRIV(kctx_obp_bpt); /* 17F obp breakpoint */
1491 /* reserved */
1492 NOT4; NOT4; NOT4; NOT4; /* 180 - 18F reserved */
1493 NOT4; NOT4; NOT4; NOT4; /* 190 - 19F reserved */
1494 NOT4; NOT4; NOT4; NOT4; /* 1A0 - 1AF reserved */
1495 NOT4; NOT4; NOT4; NOT4; /* 1B0 - 1BF reserved */
1496 NOT4; NOT4; NOT4; NOT4; /* 1C0 - 1CF reserved */
1497 NOT4; NOT4; NOT4; NOT4; /* 1D0 - 1DF reserved */
1498 NOT4; NOT4; NOT4; NOT4; /* 1E0 - 1EF reserved */
1499 NOT4; NOT4; NOT4; NOT4; /* 1F0 - 1FF reserved */
1500 trap_table1:
1501 NOT4; NOT4; NOT; NOT; /* 000 - 009 unused */
1502 ASYNC_TRAP(T_INSTR_ERROR + T_TL1, trace_gen, tt1_iae);
1503 /* 00A instruction access error */
1504 NOT; NOT4; /* 00B - 00F unused */
1505 NOT4; NOT4; NOT4; NOT4; /* 010 - 01F unused */
1506 NOT4; /* 020 - 023 unused */
1507 CLEAN_WINDOW; /* 024 - 027 clean window */
1508 NOT4; NOT4; /* 028 - 02F unused */
1509 DMMU_EXCEPTION_TL1; /* 030 data access exception */
1510 NOT; /* 031 unused */
1511 ASYNC_TRAP(T_DATA_ERROR + T_TL1, trace_gen, tt1_dae);
1512 /* 032 data access error */
1513 NOT; /* 033 unused */
1514 MISALIGN_ADDR_TL1; /* 034 mem address not aligned */
1515 NOT; NOT; NOT; NOT4; NOT4 /* 035 - 03F unused */
1516 LABELED_BAD(tt1_asdat); /* 040 async data error */
1517 NOT; NOT; NOT; /* 041 - 043 unused */
1518 NOT4; NOT4; NOT4; /* 044 - 04F unused */
1519 NOT4; NOT4; NOT4; NOT4; /* 050 - 05F unused */
1520 NOT; /* 060 unused */
1521 GOTO(kmdb_trap_tl1); /* 061 PA watchpoint */
1522 GOTO(kmdb_trap_tl1); /* 062 VA watchpoint */
1523 GOTO_TT(ce_err_tl1, trace_gen); /* 063 corrected ECC error */
1524 ITLB_MISS(tt1); /* 064 instruction access MMU miss */
1525 DTLB_MISS(tt1); /* 068 data access MMU miss */
1526 DTLB_PROT; /* 06C data access protection */
1527 LABELED_BAD(tt1_fecc); /* 070 fast ecache ECC error */
1528 LABELED_BAD(tt1_dperr); /* 071 Cheetah+ dcache parity error */
1529 LABELED_BAD(tt1_iperr); /* 072 Cheetah+ icache parity error */
1530 NOT; /* 073 reserved */
1531 NOT4; NOT4; NOT4; /* 074 - 07F reserved */
1532 NOT4; /* 080 spill 0 normal */
1533 SPILL_32bit_tt1(ASI_AIUP,sn1); /* 084 spill 1 normal */
1534 SPILL_64bit_tt1(ASI_AIUP,sn1); /* 088 spill 2 normal */
1535 SPILL_32bit_tt1(ASI_AIUP,sn1); /* 08C spill 3 normal */
1536 SPILL_64bit_tt1(ASI_AIUP,sn1); /* 090 spill 4 normal */
1537 SPILL_32bit(not); /* 094 spill 5 normal */
1538 SPILL_64bit(not); /* 098 spill 6 normal */
1539 SPILL_mixed; /* 09C spill 7 normal */
1540 NOT4; /* 0A0 spill 0 other */
1541 SPILL_32bit_tt1(ASI_AIUS,so1); /* 0A4 spill 1 other */
1542 SPILL_64bit_tt1(ASI_AIUS,so1); /* 0A8 spill 2 other */
1543 SPILL_32bit_tt1(ASI_AIUS,so1); /* 0AC spill 3 other */
1544 SPILL_64bit_tt1(ASI_AIUS,so1); /* 0B0 spill 4 other */
1545 NOT4; /* 0B4 spill 5 other */
1546 NOT4; /* 0B8 spill 6 other */
1547 NOT4; /* 0BC spill 7 other */
1548 NOT4; /* 0C0 fill 0 normal */
1549 FILL_32bit_tt1(ASI_AIUP,fn1); /* 0C4 fill 1 normal */
1550 FILL_64bit_tt1(ASI_AIUP,fn1); /* 0C8 fill 2 normal */
1551 FILL_32bit_tt1(ASI_AIUP,fn1); /* 0CC fill 3 normal */
1552 FILL_64bit_tt1(ASI_AIUP,fn1); /* 0D0 fill 4 normal */
1553 FILL_32bit(not); /* 0D4 fill 5 normal */
1554 FILL_64bit(not); /* 0D8 fill 6 normal */
1555 FILL_mixed; /* 0DC fill 7 normal */
1556 NOT4; NOT4; NOT4; NOT4; /* 0E0 - 0EF unused */
1557 NOT4; NOT4; NOT4; NOT4; /* 0F0 - 0FF unused */
1558 LABELED_BAD(tt1_swtrap0); /* 100 fast ecache ECC error (cont) */
1559 LABELED_BAD(tt1_swtrap1); /* 101 Ch+ D$ parity error (cont) */
1560 LABELED_BAD(tt1_swtrap2); /* 102 Ch+ I$ parity error (cont) */
1561 NOT; /* 103 reserved */
1562 /*
1563 * We only reserve the above four special case soft traps for code running
1564 * at TL>0, so we can truncate the trap table here.
1565 */
1566 etrap_table:
1567 .size trap_table, (.-trap_table)
1568 .size scb, (.-scb)
1569
1570 /*
1571 * We get to exec_fault in the case of an instruction miss and tte
1572 * has no execute bit set. We go to tl0 to handle it.
1573 *
1574 * g1 = tsbe pointer (in/clobbered)
1575 * g2 = tag access register (in)
1576 * g3 - g4 = scratch (clobbered)
1577 * g5 = tsbe data (in)
1578 * g6 = scratch (clobbered)
1579 */
1580 ALTENTRY(exec_fault)
1581 TRACE_TSBHIT(0x200)
1582 SWITCH_GLOBALS
1583 mov MMU_TAG_ACCESS, %g4
1584 ldxa [%g4]ASI_IMMU, %g2 ! arg1 = addr
1585 mov T_INSTR_MMU_MISS, %g3 ! arg2 = traptype
1586 set trap, %g1
1587 ba,pt %xcc, sys_trap
1588 mov -1, %g4
1589
1590 .mmu_exception_not_aligned:
1591 rdpr %tstate, %g1
1592 btst TSTATE_PRIV, %g1
1593 bnz,pn %icc, 2f
1594 nop
1595 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1596 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1597 ldn [%g1 + T_PROCP], %g1 ! load proc pointer
1598 ldn [%g1 + P_UTRAPS], %g5 ! are there utraps?
1599 brz,pt %g5, 2f
1600 nop
1601 ldn [%g5 + P_UTRAP15], %g5 ! unaligned utrap?
1602 brz,pn %g5, 2f
1603 nop
1604 btst 1, %sp
1605 bz,pt %xcc, 1f ! 32 bit user program
1606 nop
1607 ba,pt %xcc, .setup_v9utrap ! 64 bit user program
1608 nop
1609 1:
1610 ba,pt %xcc, .setup_utrap
1611 or %g2, %g0, %g7
1612 2:
1613 ba,pt %xcc, .mmu_exception_end
1614 mov T_ALIGNMENT, %g1
1615
1616 .mmu_priv_exception:
1617 rdpr %tstate, %g1
1618 btst TSTATE_PRIV, %g1
1619 bnz,pn %icc, 1f
1620 nop
1621 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1622 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1623 ldn [%g1 + T_PROCP], %g1 ! load proc pointer
1624 ldn [%g1 + P_UTRAPS], %g5 ! are there utraps?
1625 brz,pt %g5, 1f
1626 nop
1627 ldn [%g5 + P_UTRAP16], %g5
1628 brnz,pt %g5, .setup_v9utrap
1629 nop
1630 1:
1631 mov T_PRIV_INSTR, %g1
1632
1633 .mmu_exception_end:
1634 CPU_INDEX(%g4, %g5)
1635 set cpu_core, %g5
1636 sllx %g4, CPU_CORE_SHIFT, %g4
1637 add %g4, %g5, %g4
1638 lduh [%g4 + CPUC_DTRACE_FLAGS], %g5
1639 andcc %g5, CPU_DTRACE_NOFAULT, %g0
1640 bz %xcc, .mmu_exception_tlb_chk
1641 or %g5, CPU_DTRACE_BADADDR, %g5
1642 stuh %g5, [%g4 + CPUC_DTRACE_FLAGS]
1643 done
1644
1645 .mmu_exception_tlb_chk:
1646 GET_CPU_IMPL(%g5) ! check SFSR.FT to see if this
1647 cmp %g5, PANTHER_IMPL ! is a TLB parity error. But
1648 bne 2f ! we only do this check while
1649 mov 1, %g4 ! running on Panther CPUs
1650 sllx %g4, PN_SFSR_PARITY_SHIFT, %g4 ! since US-I/II use the same
1651 andcc %g3, %g4, %g0 ! bit for something else which
1652 bz 2f ! will be handled later.
1653 nop
1654 .mmu_exception_is_tlb_parity:
1655 .weak itlb_parity_trap
1656 .weak dtlb_parity_trap
1657 set itlb_parity_trap, %g4
1658 cmp %g1, T_INSTR_EXCEPTION ! branch to the itlb or
1659 be 3f ! dtlb parity handler
1660 nop ! if this trap is due
1661 set dtlb_parity_trap, %g4
1662 cmp %g1, T_DATA_EXCEPTION ! to a IMMU exception
1663 be 3f ! or DMMU exception.
1664 nop
1665 2:
1666 sllx %g3, 32, %g3
1667 or %g3, %g1, %g3
1668 set trap, %g1
1669 ba,pt %xcc, sys_trap
1670 sub %g0, 1, %g4
1671 3:
1672 jmp %g4 ! off to the appropriate
1673 nop ! TLB parity handler
1674
1675 .fp_disabled:
1676 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1677 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1678 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
1679 brz,a,pn %g1, 2f
1680 nop
1681 #endif
1682 rdpr %tstate, %g4
1683 btst TSTATE_PRIV, %g4
1684 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
1685 bnz,pn %icc, 2f
1686 nop
1687 #else
1688 bnz,a,pn %icc, ptl1_panic
1689 mov PTL1_BAD_FPTRAP, %g1
1690 #endif
1691 ldn [%g1 + T_PROCP], %g1 ! load proc pointer
1692 ldn [%g1 + P_UTRAPS], %g5 ! are there utraps?
1693 brz,a,pt %g5, 2f
1694 nop
1695 ldn [%g5 + P_UTRAP7], %g5 ! fp_disabled utrap?
1696 brz,a,pn %g5, 2f
1697 nop
1698 btst 1, %sp
1699 bz,a,pt %xcc, 1f ! 32 bit user program
1700 nop
1701 ba,a,pt %xcc, .setup_v9utrap ! 64 bit user program
1702 nop
1703 1:
1704 ba,pt %xcc, .setup_utrap
1705 or %g0, %g0, %g7
1706 2:
1707 set fp_disabled, %g1
1708 ba,pt %xcc, sys_trap
1709 sub %g0, 1, %g4
1710
1711 .fp_ieee_exception:
1712 rdpr %tstate, %g1
1713 btst TSTATE_PRIV, %g1
1714 bnz,a,pn %icc, ptl1_panic
1715 mov PTL1_BAD_FPTRAP, %g1
1716 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1717 stx %fsr, [%g1 + CPU_TMP1]
1718 ldx [%g1 + CPU_TMP1], %g2
1719 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1720 ldn [%g1 + T_PROCP], %g1 ! load proc pointer
1721 ldn [%g1 + P_UTRAPS], %g5 ! are there utraps?
1722 brz,a,pt %g5, 1f
1723 nop
1724 ldn [%g5 + P_UTRAP8], %g5
1725 brnz,a,pt %g5, .setup_v9utrap
1726 nop
1727 1:
1728 set _fp_ieee_exception, %g1
1729 ba,pt %xcc, sys_trap
1730 sub %g0, 1, %g4
1731
1732 /*
1733 * Register Inputs:
1734 * %g5 user trap handler
1735 * %g7 misaligned addr - for alignment traps only
1736 */
1737 .setup_utrap:
1738 set trap, %g1 ! setup in case we go
1739 mov T_FLUSH_PCB, %g3 ! through sys_trap on
1740 sub %g0, 1, %g4 ! the save instruction below
1741
1742 /*
1743 * If the DTrace pid provider is single stepping a copied-out
1744 * instruction, t->t_dtrace_step will be set. In that case we need
1745 * to abort the single-stepping (since execution of the instruction
1746 * was interrupted) and use the value of t->t_dtrace_npc as the %npc.
1747 */
1748 save %sp, -SA(MINFRAME32), %sp ! window for trap handler
1749 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1750 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1751 ldub [%g1 + T_DTRACE_STEP], %g2 ! load t->t_dtrace_step
1752 rdpr %tnpc, %l2 ! arg1 == tnpc
1753 brz,pt %g2, 1f
1754 rdpr %tpc, %l1 ! arg0 == tpc
1755
1756 ldub [%g1 + T_DTRACE_AST], %g2 ! load t->t_dtrace_ast
1757 ldn [%g1 + T_DTRACE_NPC], %l2 ! arg1 = t->t_dtrace_npc (step)
1758 brz,pt %g2, 1f
1759 st %g0, [%g1 + T_DTRACE_FT] ! zero all pid provider flags
1760 stub %g2, [%g1 + T_ASTFLAG] ! aston(t) if t->t_dtrace_ast
1761 1:
1762 mov %g7, %l3 ! arg2 == misaligned address
1763
1764 rdpr %tstate, %g1 ! cwp for trap handler
1765 rdpr %cwp, %g4
1766 bclr TSTATE_CWP_MASK, %g1
1767 wrpr %g1, %g4, %tstate
1768 wrpr %g0, %g5, %tnpc ! trap handler address
1769 FAST_TRAP_DONE
1770 /* NOTREACHED */
1771
1772 .check_v9utrap:
1773 rdpr %tstate, %g1
1774 btst TSTATE_PRIV, %g1
1775 bnz,a,pn %icc, 3f
1776 nop
1777 CPU_ADDR(%g4, %g1) ! load CPU struct addr
1778 ldn [%g4 + CPU_THREAD], %g5 ! load thread pointer
1779 ldn [%g5 + T_PROCP], %g5 ! load proc pointer
1780 ldn [%g5 + P_UTRAPS], %g5 ! are there utraps?
1781
1782 cmp %g3, T_SOFTWARE_TRAP
1783 bne,a,pt %icc, 1f
1784 nop
1785
1786 brz,pt %g5, 3f ! if p_utraps == NULL goto trap()
1787 rdpr %tt, %g3 ! delay - get actual hw trap type
1788
1789 sub %g3, 254, %g1 ! UT_TRAP_INSTRUCTION_16 = p_utraps[18]
1790 ba,pt %icc, 2f
1791 smul %g1, CPTRSIZE, %g2
1792 1:
1793 brz,a,pt %g5, 3f ! if p_utraps == NULL goto trap()
1794 nop
1795
1796 cmp %g3, T_UNIMP_INSTR
1797 bne,a,pt %icc, 2f
1798 nop
1799
1800 mov 1, %g1
1801 st %g1, [%g4 + CPU_TL1_HDLR] ! set CPU_TL1_HDLR
1802 rdpr %tpc, %g1 ! ld trapping instruction using
1803 lduwa [%g1]ASI_AIUP, %g1 ! "AS IF USER" ASI which could fault
1804 st %g0, [%g4 + CPU_TL1_HDLR] ! clr CPU_TL1_HDLR
1805
1806 sethi %hi(0xc1c00000), %g4 ! setup mask for illtrap instruction
1807 andcc %g1, %g4, %g4 ! and instruction with mask
1808 bnz,a,pt %icc, 3f ! if %g4 == zero, %g1 is an ILLTRAP
1809 nop ! fall thru to setup
1810 2:
1811 ldn [%g5 + %g2], %g5
1812 brnz,a,pt %g5, .setup_v9utrap
1813 nop
1814 3:
1815 set trap, %g1
1816 ba,pt %xcc, sys_trap
1817 sub %g0, 1, %g4
1818 /* NOTREACHED */
1819
1820 /*
1821 * Register Inputs:
1822 * %g5 user trap handler
1823 */
1824 .setup_v9utrap:
1825 set trap, %g1 ! setup in case we go
1826 mov T_FLUSH_PCB, %g3 ! through sys_trap on
1827 sub %g0, 1, %g4 ! the save instruction below
1828
1829 /*
1830 * If the DTrace pid provider is single stepping a copied-out
1831 * instruction, t->t_dtrace_step will be set. In that case we need
1832 * to abort the single-stepping (since execution of the instruction
1833 * was interrupted) and use the value of t->t_dtrace_npc as the %npc.
1834 */
1835 save %sp, -SA(MINFRAME64), %sp ! window for trap handler
1836 CPU_ADDR(%g1, %g4) ! load CPU struct addr
1837 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
1838 ldub [%g1 + T_DTRACE_STEP], %g2 ! load t->t_dtrace_step
1839 rdpr %tnpc, %l7 ! arg1 == tnpc
1840 brz,pt %g2, 1f
1841 rdpr %tpc, %l6 ! arg0 == tpc
1842
1843 ldub [%g1 + T_DTRACE_AST], %g2 ! load t->t_dtrace_ast
1844 ldn [%g1 + T_DTRACE_NPC], %l7 ! arg1 == t->t_dtrace_npc (step)
1845 brz,pt %g2, 1f
1846 st %g0, [%g1 + T_DTRACE_FT] ! zero all pid provider flags
1847 stub %g2, [%g1 + T_ASTFLAG] ! aston(t) if t->t_dtrace_ast
1848 1:
1849 rdpr %tstate, %g2 ! cwp for trap handler
1850 rdpr %cwp, %g4
1851 bclr TSTATE_CWP_MASK, %g2
1852 wrpr %g2, %g4, %tstate
1853
1854 ldn [%g1 + T_PROCP], %g4 ! load proc pointer
1855 ldn [%g4 + P_AS], %g4 ! load as pointer
1856 ldn [%g4 + A_USERLIMIT], %g4 ! load as userlimit
1857 cmp %l7, %g4 ! check for single-step set
1858 bne,pt %xcc, 4f
1859 nop
1860 ldn [%g1 + T_LWP], %g1 ! load klwp pointer
1861 ld [%g1 + PCB_STEP], %g4 ! load single-step flag
1862 cmp %g4, STEP_ACTIVE ! step flags set in pcb?
1863 bne,pt %icc, 4f
1864 nop
1865 stn %g5, [%g1 + PCB_TRACEPC] ! save trap handler addr in pcb
1866 mov %l7, %g4 ! on entry to precise user trap
1867 add %l6, 4, %l7 ! handler, %l6 == pc, %l7 == npc
1868 ! at time of trap
1869 wrpr %g0, %g4, %tnpc ! generate FLTBOUNDS,
1870 ! %g4 == userlimit
1871 FAST_TRAP_DONE
1872 /* NOTREACHED */
1873 4:
1874 wrpr %g0, %g5, %tnpc ! trap handler address
1875 FAST_TRAP_DONE_CHK_INTR
1876 /* NOTREACHED */
1877
1878 .fp_exception:
1879 CPU_ADDR(%g1, %g4)
1880 stx %fsr, [%g1 + CPU_TMP1]
1881 ldx [%g1 + CPU_TMP1], %g2
1882
1883 /*
1884 * Cheetah takes unfinished_FPop trap for certain range of operands
1885 * to the "fitos" instruction. Instead of going through the slow
1886 * software emulation path, we try to simulate the "fitos" instruction
1887 * via "fitod" and "fdtos" provided the following conditions are met:
1888 *
1889 * fpu_exists is set (if DEBUG)
1890 * not in privileged mode
1891 * ftt is unfinished_FPop
1892 * NXM IEEE trap is not enabled
1893 * instruction at %tpc is "fitos"
1894 *
1895 * Usage:
1896 * %g1 per cpu address
1897 * %g2 %fsr
1898 * %g6 user instruction
1899 *
1900 * Note that we can take a memory access related trap while trying
1901 * to fetch the user instruction. Therefore, we set CPU_TL1_HDLR
1902 * flag to catch those traps and let the SFMMU code deal with page
1903 * fault and data access exception.
1904 */
1905 #if defined(DEBUG) || defined(NEED_FPU_EXISTS)
1906 sethi %hi(fpu_exists), %g7
1907 ld [%g7 + %lo(fpu_exists)], %g7
1908 brz,pn %g7, .fp_exception_cont
1909 nop
1910 #endif
1911 rdpr %tstate, %g7 ! branch if in privileged mode
1912 btst TSTATE_PRIV, %g7
1913 bnz,pn %xcc, .fp_exception_cont
1914 srl %g2, FSR_FTT_SHIFT, %g7 ! extract ftt from %fsr
1915 and %g7, (FSR_FTT>>FSR_FTT_SHIFT), %g7
1916 cmp %g7, FTT_UNFIN
1917 set FSR_TEM_NX, %g5
1918 bne,pn %xcc, .fp_exception_cont ! branch if NOT unfinished_FPop
1919 andcc %g2, %g5, %g0
1920 bne,pn %xcc, .fp_exception_cont ! branch if FSR_TEM_NX enabled
1921 rdpr %tpc, %g5 ! get faulting PC
1922
1923 or %g0, 1, %g7
1924 st %g7, [%g1 + CPU_TL1_HDLR] ! set tl1_hdlr flag
1925 lda [%g5]ASI_USER, %g6 ! get user's instruction
1926 st %g0, [%g1 + CPU_TL1_HDLR] ! clear tl1_hdlr flag
1927
1928 set FITOS_INSTR_MASK, %g7
1929 and %g6, %g7, %g7
1930 set FITOS_INSTR, %g5
1931 cmp %g7, %g5
1932 bne,pn %xcc, .fp_exception_cont ! branch if not FITOS_INSTR
1933 nop
1934
1935 /*
1936 * This is unfinished FPops trap for "fitos" instruction. We
1937 * need to simulate "fitos" via "fitod" and "fdtos" instruction
1938 * sequence.
1939 *
1940 * We need a temporary FP register to do the conversion. Since
1941 * both source and destination operands for the "fitos" instruction
1942 * have to be within %f0-%f31, we use an FP register from the upper
1943 * half to guarantee that it won't collide with the source or the
1944 * dest operand. However, we do have to save and restore its value.
1945 *
1946 * We use %d62 as a temporary FP register for the conversion and
1947 * branch to appropriate instruction within the conversion tables
1948 * based upon the rs2 and rd values.
1949 */
1950
1951 std %d62, [%g1 + CPU_TMP1] ! save original value
1952
1953 srl %g6, FITOS_RS2_SHIFT, %g7
1954 and %g7, FITOS_REG_MASK, %g7
1955 set _fitos_fitod_table, %g4
1956 sllx %g7, 2, %g7
1957 jmp %g4 + %g7
1958 ba,pt %xcc, _fitos_fitod_done
1959 .empty
1960
1961 _fitos_fitod_table:
1962 fitod %f0, %d62
1963 fitod %f1, %d62
1964 fitod %f2, %d62
1965 fitod %f3, %d62
1966 fitod %f4, %d62
1967 fitod %f5, %d62
1968 fitod %f6, %d62
1969 fitod %f7, %d62
1970 fitod %f8, %d62
1971 fitod %f9, %d62
1972 fitod %f10, %d62
1973 fitod %f11, %d62
1974 fitod %f12, %d62
1975 fitod %f13, %d62
1976 fitod %f14, %d62
1977 fitod %f15, %d62
1978 fitod %f16, %d62
1979 fitod %f17, %d62
1980 fitod %f18, %d62
1981 fitod %f19, %d62
1982 fitod %f20, %d62
1983 fitod %f21, %d62
1984 fitod %f22, %d62
1985 fitod %f23, %d62
1986 fitod %f24, %d62
1987 fitod %f25, %d62
1988 fitod %f26, %d62
1989 fitod %f27, %d62
1990 fitod %f28, %d62
1991 fitod %f29, %d62
1992 fitod %f30, %d62
1993 fitod %f31, %d62
1994 _fitos_fitod_done:
1995
1996 /*
1997 * Now convert data back into single precision
1998 */
1999 srl %g6, FITOS_RD_SHIFT, %g7
2000 and %g7, FITOS_REG_MASK, %g7
2001 set _fitos_fdtos_table, %g4
2002 sllx %g7, 2, %g7
2003 jmp %g4 + %g7
2004 ba,pt %xcc, _fitos_fdtos_done
2005 .empty
2006
2007 _fitos_fdtos_table:
2008 fdtos %d62, %f0
2009 fdtos %d62, %f1
2010 fdtos %d62, %f2
2011 fdtos %d62, %f3
2012 fdtos %d62, %f4
2013 fdtos %d62, %f5
2014 fdtos %d62, %f6
2015 fdtos %d62, %f7
2016 fdtos %d62, %f8
2017 fdtos %d62, %f9
2018 fdtos %d62, %f10
2019 fdtos %d62, %f11
2020 fdtos %d62, %f12
2021 fdtos %d62, %f13
2022 fdtos %d62, %f14
2023 fdtos %d62, %f15
2024 fdtos %d62, %f16
2025 fdtos %d62, %f17
2026 fdtos %d62, %f18
2027 fdtos %d62, %f19
2028 fdtos %d62, %f20
2029 fdtos %d62, %f21
2030 fdtos %d62, %f22
2031 fdtos %d62, %f23
2032 fdtos %d62, %f24
2033 fdtos %d62, %f25
2034 fdtos %d62, %f26
2035 fdtos %d62, %f27
2036 fdtos %d62, %f28
2037 fdtos %d62, %f29
2038 fdtos %d62, %f30
2039 fdtos %d62, %f31
2040 _fitos_fdtos_done:
2041
2042 ldd [%g1 + CPU_TMP1], %d62 ! restore %d62
2043
2044 #if DEBUG
2045 /*
2046 * Update FPop_unfinished trap kstat
2047 */
2048 set fpustat+FPUSTAT_UNFIN_KSTAT, %g7
2049 ldx [%g7], %g5
2050 1:
2051 add %g5, 1, %g6
2052
2053 casxa [%g7] ASI_N, %g5, %g6
2054 cmp %g5, %g6
2055 bne,a,pn %xcc, 1b
2056 or %g0, %g6, %g5
2057
2058 /*
2059 * Update fpu_sim_fitos kstat
2060 */
2061 set fpuinfo+FPUINFO_FITOS_KSTAT, %g7
2062 ldx [%g7], %g5
2063 1:
2064 add %g5, 1, %g6
2065
2066 casxa [%g7] ASI_N, %g5, %g6
2067 cmp %g5, %g6
2068 bne,a,pn %xcc, 1b
2069 or %g0, %g6, %g5
2070 #endif /* DEBUG */
2071
2072 FAST_TRAP_DONE
2073
2074 .fp_exception_cont:
2075 /*
2076 * Let _fp_exception deal with simulating FPop instruction.
2077 * Note that we need to pass %fsr in %g2 (already read above).
2078 */
2079
2080 set _fp_exception, %g1
2081 ba,pt %xcc, sys_trap
2082 sub %g0, 1, %g4
2083
2084 .global opl_cleanw_patch
2085 opl_cleanw_patch:
2086 .clean_windows:
2087 set trap, %g1
2088 mov T_FLUSH_PCB, %g3
2089 sub %g0, 1, %g4
2090 save
2091 flushw
2092 restore
2093 wrpr %g0, %g0, %cleanwin ! no clean windows
2094
2095 CPU_ADDR(%g4, %g5)
2096 ldn [%g4 + CPU_MPCB], %g4
2097 brz,a,pn %g4, 1f
2098 nop
2099 ld [%g4 + MPCB_WSTATE], %g5
2100 add %g5, WSTATE_CLEAN_OFFSET, %g5
2101 wrpr %g0, %g5, %wstate
2102 1: FAST_TRAP_DONE
2103
2104 /*
2105 * .spill_clean: clean the previous window, restore the wstate, and
2106 * "done".
2107 *
2108 * Entry: %g7 contains new wstate
2109 */
2110 .spill_clean:
2111 sethi %hi(nwin_minus_one), %g5
2112 ld [%g5 + %lo(nwin_minus_one)], %g5 ! %g5 = nwin - 1
2113 rdpr %cwp, %g6 ! %g6 = %cwp
2114 deccc %g6 ! %g6--
2115 movneg %xcc, %g5, %g6 ! if (%g6<0) %g6 = nwin-1
2116 wrpr %g6, %cwp
2117 TT_TRACE_L(trace_win)
2118 clr %l0
2119 clr %l1
2120 clr %l2
2121 clr %l3
2122 clr %l4
2123 clr %l5
2124 clr %l6
2125 clr %l7
2126 wrpr %g0, %g7, %wstate
2127 saved
2128 retry ! restores correct %cwp
2129
2130 .fix_alignment:
2131 CPU_ADDR(%g1, %g2) ! load CPU struct addr to %g1 using %g2
2132 ldn [%g1 + CPU_THREAD], %g1 ! load thread pointer
2133 ldn [%g1 + T_PROCP], %g1
2134 mov 1, %g2
2135 stb %g2, [%g1 + P_FIXALIGNMENT]
2136 FAST_TRAP_DONE
2137
2138 #define STDF_REG(REG, ADDR, TMP) \
2139 sll REG, 3, REG ;\
2140 mark1: set start1, TMP ;\
2141 jmp REG + TMP ;\
2142 nop ;\
2143 start1: ba,pt %xcc, done1 ;\
2144 std %f0, [ADDR + CPU_TMP1] ;\
2145 ba,pt %xcc, done1 ;\
2146 std %f32, [ADDR + CPU_TMP1] ;\
2147 ba,pt %xcc, done1 ;\
2148 std %f2, [ADDR + CPU_TMP1] ;\
2149 ba,pt %xcc, done1 ;\
2150 std %f34, [ADDR + CPU_TMP1] ;\
2151 ba,pt %xcc, done1 ;\
2152 std %f4, [ADDR + CPU_TMP1] ;\
2153 ba,pt %xcc, done1 ;\
2154 std %f36, [ADDR + CPU_TMP1] ;\
2155 ba,pt %xcc, done1 ;\
2156 std %f6, [ADDR + CPU_TMP1] ;\
2157 ba,pt %xcc, done1 ;\
2158 std %f38, [ADDR + CPU_TMP1] ;\
2159 ba,pt %xcc, done1 ;\
2160 std %f8, [ADDR + CPU_TMP1] ;\
2161 ba,pt %xcc, done1 ;\
2162 std %f40, [ADDR + CPU_TMP1] ;\
2163 ba,pt %xcc, done1 ;\
2164 std %f10, [ADDR + CPU_TMP1] ;\
2165 ba,pt %xcc, done1 ;\
2166 std %f42, [ADDR + CPU_TMP1] ;\
2167 ba,pt %xcc, done1 ;\
2168 std %f12, [ADDR + CPU_TMP1] ;\
2169 ba,pt %xcc, done1 ;\
2170 std %f44, [ADDR + CPU_TMP1] ;\
2171 ba,pt %xcc, done1 ;\
2172 std %f14, [ADDR + CPU_TMP1] ;\
2173 ba,pt %xcc, done1 ;\
2174 std %f46, [ADDR + CPU_TMP1] ;\
2175 ba,pt %xcc, done1 ;\
2176 std %f16, [ADDR + CPU_TMP1] ;\
2177 ba,pt %xcc, done1 ;\
2178 std %f48, [ADDR + CPU_TMP1] ;\
2179 ba,pt %xcc, done1 ;\
2180 std %f18, [ADDR + CPU_TMP1] ;\
2181 ba,pt %xcc, done1 ;\
2182 std %f50, [ADDR + CPU_TMP1] ;\
2183 ba,pt %xcc, done1 ;\
2184 std %f20, [ADDR + CPU_TMP1] ;\
2185 ba,pt %xcc, done1 ;\
2186 std %f52, [ADDR + CPU_TMP1] ;\
2187 ba,pt %xcc, done1 ;\
2188 std %f22, [ADDR + CPU_TMP1] ;\
2189 ba,pt %xcc, done1 ;\
2190 std %f54, [ADDR + CPU_TMP1] ;\
2191 ba,pt %xcc, done1 ;\
2192 std %f24, [ADDR + CPU_TMP1] ;\
2193 ba,pt %xcc, done1 ;\
2194 std %f56, [ADDR + CPU_TMP1] ;\
2195 ba,pt %xcc, done1 ;\
2196 std %f26, [ADDR + CPU_TMP1] ;\
2197 ba,pt %xcc, done1 ;\
2198 std %f58, [ADDR + CPU_TMP1] ;\
2199 ba,pt %xcc, done1 ;\
2200 std %f28, [ADDR + CPU_TMP1] ;\
2201 ba,pt %xcc, done1 ;\
2202 std %f60, [ADDR + CPU_TMP1] ;\
2203 ba,pt %xcc, done1 ;\
2204 std %f30, [ADDR + CPU_TMP1] ;\
2205 ba,pt %xcc, done1 ;\
2206 std %f62, [ADDR + CPU_TMP1] ;\
2207 done1:
2208
2209 #define LDDF_REG(REG, ADDR, TMP) \
2210 sll REG, 3, REG ;\
2211 mark2: set start2, TMP ;\
2212 jmp REG + TMP ;\
2213 nop ;\
2214 start2: ba,pt %xcc, done2 ;\
2215 ldd [ADDR + CPU_TMP1], %f0 ;\
2216 ba,pt %xcc, done2 ;\
2217 ldd [ADDR + CPU_TMP1], %f32 ;\
2218 ba,pt %xcc, done2 ;\
2219 ldd [ADDR + CPU_TMP1], %f2 ;\
2220 ba,pt %xcc, done2 ;\
2221 ldd [ADDR + CPU_TMP1], %f34 ;\
2222 ba,pt %xcc, done2 ;\
2223 ldd [ADDR + CPU_TMP1], %f4 ;\
2224 ba,pt %xcc, done2 ;\
2225 ldd [ADDR + CPU_TMP1], %f36 ;\
2226 ba,pt %xcc, done2 ;\
2227 ldd [ADDR + CPU_TMP1], %f6 ;\
2228 ba,pt %xcc, done2 ;\
2229 ldd [ADDR + CPU_TMP1], %f38 ;\
2230 ba,pt %xcc, done2 ;\
2231 ldd [ADDR + CPU_TMP1], %f8 ;\
2232 ba,pt %xcc, done2 ;\
2233 ldd [ADDR + CPU_TMP1], %f40 ;\
2234 ba,pt %xcc, done2 ;\
2235 ldd [ADDR + CPU_TMP1], %f10 ;\
2236 ba,pt %xcc, done2 ;\
2237 ldd [ADDR + CPU_TMP1], %f42 ;\
2238 ba,pt %xcc, done2 ;\
2239 ldd [ADDR + CPU_TMP1], %f12 ;\
2240 ba,pt %xcc, done2 ;\
2241 ldd [ADDR + CPU_TMP1], %f44 ;\
2242 ba,pt %xcc, done2 ;\
2243 ldd [ADDR + CPU_TMP1], %f14 ;\
2244 ba,pt %xcc, done2 ;\
2245 ldd [ADDR + CPU_TMP1], %f46 ;\
2246 ba,pt %xcc, done2 ;\
2247 ldd [ADDR + CPU_TMP1], %f16 ;\
2248 ba,pt %xcc, done2 ;\
2249 ldd [ADDR + CPU_TMP1], %f48 ;\
2250 ba,pt %xcc, done2 ;\
2251 ldd [ADDR + CPU_TMP1], %f18 ;\
2252 ba,pt %xcc, done2 ;\
2253 ldd [ADDR + CPU_TMP1], %f50 ;\
2254 ba,pt %xcc, done2 ;\
2255 ldd [ADDR + CPU_TMP1], %f20 ;\
2256 ba,pt %xcc, done2 ;\
2257 ldd [ADDR + CPU_TMP1], %f52 ;\
2258 ba,pt %xcc, done2 ;\
2259 ldd [ADDR + CPU_TMP1], %f22 ;\
2260 ba,pt %xcc, done2 ;\
2261 ldd [ADDR + CPU_TMP1], %f54 ;\
2262 ba,pt %xcc, done2 ;\
2263 ldd [ADDR + CPU_TMP1], %f24 ;\
2264 ba,pt %xcc, done2 ;\
2265 ldd [ADDR + CPU_TMP1], %f56 ;\
2266 ba,pt %xcc, done2 ;\
2267 ldd [ADDR + CPU_TMP1], %f26 ;\
2268 ba,pt %xcc, done2 ;\
2269 ldd [ADDR + CPU_TMP1], %f58 ;\
2270 ba,pt %xcc, done2 ;\
2271 ldd [ADDR + CPU_TMP1], %f28 ;\
2272 ba,pt %xcc, done2 ;\
2273 ldd [ADDR + CPU_TMP1], %f60 ;\
2274 ba,pt %xcc, done2 ;\
2275 ldd [ADDR + CPU_TMP1], %f30 ;\
2276 ba,pt %xcc, done2 ;\
2277 ldd [ADDR + CPU_TMP1], %f62 ;\
2278 done2:
2279
2280 .lddf_exception_not_aligned:
2281 /*
2282 * Cheetah overwrites SFAR on a DTLB miss, hence read it now.
2283 */
2284 ldxa [MMU_SFAR]%asi, %g5 ! misaligned vaddr in %g5
2285
2286 #if defined(DEBUG) || defined(NEED_FPU_EXISTS)
2287 sethi %hi(fpu_exists), %g2 ! check fpu_exists
2288 ld [%g2 + %lo(fpu_exists)], %g2
2289 brz,a,pn %g2, 4f
2290 nop
2291 #endif
2292 CPU_ADDR(%g1, %g4)
2293 or %g0, 1, %g4
2294 st %g4, [%g1 + CPU_TL1_HDLR] ! set tl1_hdlr flag
2295
2296 rdpr %tpc, %g2
2297 lda [%g2]ASI_AIUP, %g6 ! get the user's lddf instruction
2298 srl %g6, 23, %g1 ! using ldda or not?
2299 and %g1, 1, %g1
2300 brz,a,pt %g1, 2f ! check for ldda instruction
2301 nop
2302 srl %g6, 13, %g1 ! check immflag
2303 and %g1, 1, %g1
2304 rdpr %tstate, %g2 ! %tstate in %g2
2305 brnz,a,pn %g1, 1f
2306 srl %g2, 31, %g1 ! get asi from %tstate
2307 srl %g6, 5, %g1 ! get asi from instruction
2308 and %g1, 0xFF, %g1 ! imm_asi field
2309 1:
2310 cmp %g1, ASI_P ! primary address space
2311 be,a,pt %icc, 2f
2312 nop
2313 cmp %g1, ASI_PNF ! primary no fault address space
2314 be,a,pt %icc, 2f
2315 nop
2316 cmp %g1, ASI_S ! secondary address space
2317 be,a,pt %icc, 2f
2318 nop
2319 cmp %g1, ASI_SNF ! secondary no fault address space
2320 bne,a,pn %icc, 3f
2321 nop
2322 2:
2323 lduwa [%g5]ASI_USER, %g7 ! get first half of misaligned data
2324 add %g5, 4, %g5 ! increment misaligned data address
2325 lduwa [%g5]ASI_USER, %g5 ! get second half of misaligned data
2326
2327 sllx %g7, 32, %g7
2328 or %g5, %g7, %g5 ! combine data
2329 CPU_ADDR(%g7, %g1) ! save data on a per-cpu basis
2330 stx %g5, [%g7 + CPU_TMP1] ! save in cpu_tmp1
2331
2332 srl %g6, 25, %g3 ! %g6 has the instruction
2333 and %g3, 0x1F, %g3 ! %g3 has rd
2334 LDDF_REG(%g3, %g7, %g4)
2335
2336 CPU_ADDR(%g1, %g4)
2337 st %g0, [%g1 + CPU_TL1_HDLR] ! clear tl1_hdlr flag
2338 FAST_TRAP_DONE
2339 3:
2340 CPU_ADDR(%g1, %g4)
2341 st %g0, [%g1 + CPU_TL1_HDLR] ! clear tl1_hdlr flag
2342 4:
2343 set T_USER, %g3 ! trap type in %g3
2344 or %g3, T_LDDF_ALIGN, %g3
2345 mov %g5, %g2 ! misaligned vaddr in %g2
2346 set fpu_trap, %g1 ! goto C for the little and
2347 ba,pt %xcc, sys_trap ! no fault little asi's
2348 sub %g0, 1, %g4
2349
2350 .stdf_exception_not_aligned:
2351 /*
2352 * Cheetah overwrites SFAR on a DTLB miss, hence read it now.
2353 */
2354 ldxa [MMU_SFAR]%asi, %g5 ! misaligned vaddr in %g5
2355
2356 #if defined(DEBUG) || defined(NEED_FPU_EXISTS)
2357 sethi %hi(fpu_exists), %g7 ! check fpu_exists
2358 ld [%g7 + %lo(fpu_exists)], %g3
2359 brz,a,pn %g3, 4f
2360 nop
2361 #endif
2362 CPU_ADDR(%g1, %g4)
2363 or %g0, 1, %g4
2364 st %g4, [%g1 + CPU_TL1_HDLR] ! set tl1_hdlr flag
2365
2366 rdpr %tpc, %g2
2367 lda [%g2]ASI_AIUP, %g6 ! get the user's stdf instruction
2368
2369 srl %g6, 23, %g1 ! using stda or not?
2370 and %g1, 1, %g1
2371 brz,a,pt %g1, 2f ! check for stda instruction
2372 nop
2373 srl %g6, 13, %g1 ! check immflag
2374 and %g1, 1, %g1
2375 rdpr %tstate, %g2 ! %tstate in %g2
2376 brnz,a,pn %g1, 1f
2377 srl %g2, 31, %g1 ! get asi from %tstate
2378 srl %g6, 5, %g1 ! get asi from instruction
2379 and %g1, 0xFF, %g1 ! imm_asi field
2380 1:
2381 cmp %g1, ASI_P ! primary address space
2382 be,a,pt %icc, 2f
2383 nop
2384 cmp %g1, ASI_S ! secondary address space
2385 bne,a,pn %icc, 3f
2386 nop
2387 2:
2388 srl %g6, 25, %g6
2389 and %g6, 0x1F, %g6 ! %g6 has rd
2390 CPU_ADDR(%g7, %g1)
2391 STDF_REG(%g6, %g7, %g4) ! STDF_REG(REG, ADDR, TMP)
2392
2393 ldx [%g7 + CPU_TMP1], %g6
2394 srlx %g6, 32, %g7
2395 stuwa %g7, [%g5]ASI_USER ! first half
2396 add %g5, 4, %g5 ! increment misaligned data address
2397 stuwa %g6, [%g5]ASI_USER ! second half
2398
2399 CPU_ADDR(%g1, %g4)
2400 st %g0, [%g1 + CPU_TL1_HDLR] ! clear tl1_hdlr flag
2401 FAST_TRAP_DONE
2402 3:
2403 CPU_ADDR(%g1, %g4)
2404 st %g0, [%g1 + CPU_TL1_HDLR] ! clear tl1_hdlr flag
2405 4:
2406 set T_USER, %g3 ! trap type in %g3
2407 or %g3, T_STDF_ALIGN, %g3
2408 mov %g5, %g2 ! misaligned vaddr in %g2
2409 set fpu_trap, %g1 ! goto C for the little and
2410 ba,pt %xcc, sys_trap ! nofault little asi's
2411 sub %g0, 1, %g4
2412
2413 #ifdef DEBUG_USER_TRAPTRACECTL
2414
2415 .traptrace_freeze:
2416 mov %l0, %g1 ; mov %l1, %g2 ; mov %l2, %g3 ; mov %l4, %g4
2417 TT_TRACE_L(trace_win)
2418 mov %g4, %l4 ; mov %g3, %l2 ; mov %g2, %l1 ; mov %g1, %l0
2419 set trap_freeze, %g1
2420 mov 1, %g2
2421 st %g2, [%g1]
2422 FAST_TRAP_DONE
2423
2424 .traptrace_unfreeze:
2425 set trap_freeze, %g1
2426 st %g0, [%g1]
2427 mov %l0, %g1 ; mov %l1, %g2 ; mov %l2, %g3 ; mov %l4, %g4
2428 TT_TRACE_L(trace_win)
2429 mov %g4, %l4 ; mov %g3, %l2 ; mov %g2, %l1 ; mov %g1, %l0
2430 FAST_TRAP_DONE
2431
2432 #endif /* DEBUG_USER_TRAPTRACECTL */
2433
2434 .getcc:
2435 CPU_ADDR(%g1, %g2)
2436 stx %o0, [%g1 + CPU_TMP1] ! save %o0
2437 stx %o1, [%g1 + CPU_TMP2] ! save %o1
2438 rdpr %tstate, %g3 ! get tstate
2439 srlx %g3, PSR_TSTATE_CC_SHIFT, %o0 ! shift ccr to V8 psr
2440 set PSR_ICC, %g2
2441 and %o0, %g2, %o0 ! mask out the rest
2442 srl %o0, PSR_ICC_SHIFT, %o0 ! right justify
2443 rdpr %pstate, %o1
2444 wrpr %o1, PSTATE_AG, %pstate ! get into normal globals
2445 mov %o0, %g1 ! move ccr to normal %g1
2446 wrpr %g0, %o1, %pstate ! back into alternate globals
2447 ldx [%g1 + CPU_TMP1], %o0 ! restore %o0
2448 ldx [%g1 + CPU_TMP2], %o1 ! restore %o1
2449 FAST_TRAP_DONE
2450
2451 .setcc:
2452 CPU_ADDR(%g1, %g2)
2453 stx %o0, [%g1 + CPU_TMP1] ! save %o0
2454 stx %o1, [%g1 + CPU_TMP2] ! save %o1
2455 rdpr %pstate, %o0
2456 wrpr %o0, PSTATE_AG, %pstate ! get into normal globals
2457 mov %g1, %o1
2458 wrpr %g0, %o0, %pstate ! back to alternates
2459 sll %o1, PSR_ICC_SHIFT, %g2
2460 set PSR_ICC, %g3
2461 and %g2, %g3, %g2 ! mask out rest
2462 sllx %g2, PSR_TSTATE_CC_SHIFT, %g2
2463 rdpr %tstate, %g3 ! get tstate
2464 srl %g3, 0, %g3 ! clear upper word
2465 or %g3, %g2, %g3 ! or in new bits
2466 wrpr %g3, %tstate
2467 ldx [%g1 + CPU_TMP1], %o0 ! restore %o0
2468 ldx [%g1 + CPU_TMP2], %o1 ! restore %o1
2469 FAST_TRAP_DONE
2470
2471 /*
2472 * getpsr(void)
2473 * Note that the xcc part of the ccr is not provided.
2474 * The V8 code shows why the V9 trap is not faster:
2475 * #define GETPSR_TRAP() \
2476 * mov %psr, %i0; jmp %l2; rett %l2+4; nop;
2477 */
2478
2479 .type .getpsr, #function
2480 .getpsr:
2481 rdpr %tstate, %g1 ! get tstate
2482 srlx %g1, PSR_TSTATE_CC_SHIFT, %o0 ! shift ccr to V8 psr
2483 set PSR_ICC, %g2
2484 and %o0, %g2, %o0 ! mask out the rest
2485
2486 rd %fprs, %g1 ! get fprs
2487 and %g1, FPRS_FEF, %g2 ! mask out dirty upper/lower
2488 sllx %g2, PSR_FPRS_FEF_SHIFT, %g2 ! shift fef to V8 psr.ef
2489 or %o0, %g2, %o0 ! or result into psr.ef
2490
2491 set V9_PSR_IMPLVER, %g2 ! SI assigned impl/ver: 0xef
2492 or %o0, %g2, %o0 ! or psr.impl/ver
2493 FAST_TRAP_DONE
2494 SET_SIZE(.getpsr)
2495
2496 /*
2497 * setpsr(newpsr)
2498 * Note that there is no support for ccr.xcc in the V9 code.
2499 */
2500
2501 .type .setpsr, #function
2502 .setpsr:
2503 rdpr %tstate, %g1 ! get tstate
2504 ! setx TSTATE_V8_UBITS, %g2
2505 or %g0, CCR_ICC, %g3
2506 sllx %g3, TSTATE_CCR_SHIFT, %g2
2507
2508 andn %g1, %g2, %g1 ! zero current user bits
2509 set PSR_ICC, %g2
2510 and %g2, %o0, %g2 ! clear all but psr.icc bits
2511 sllx %g2, PSR_TSTATE_CC_SHIFT, %g3 ! shift to tstate.ccr.icc
2512 wrpr %g1, %g3, %tstate ! write tstate
2513
2514 set PSR_EF, %g2
2515 and %g2, %o0, %g2 ! clear all but fp enable bit
2516 srlx %g2, PSR_FPRS_FEF_SHIFT, %g4 ! shift ef to V9 fprs.fef
2517 wr %g0, %g4, %fprs ! write fprs
2518
2519 CPU_ADDR(%g1, %g2) ! load CPU struct addr to %g1
2520 ldn [%g1 + CPU_THREAD], %g2 ! load thread pointer
2521 ldn [%g2 + T_LWP], %g3 ! load klwp pointer
2522 ldn [%g3 + LWP_FPU], %g2 ! get lwp_fpu pointer
2523 stuw %g4, [%g2 + FPU_FPRS] ! write fef value to fpu_fprs
2524 srlx %g4, 2, %g4 ! shift fef value to bit 0
2525 stub %g4, [%g2 + FPU_EN] ! write fef value to fpu_en
2526 FAST_TRAP_DONE
2527 SET_SIZE(.setpsr)
2528
2529 /*
2530 * getlgrp
2531 * get home lgrpid on which the calling thread is currently executing.
2532 */
2533 .type .getlgrp, #function
2534 .getlgrp:
2535 CPU_ADDR(%g1, %g2) ! load CPU struct addr to %g1 using %g2
2536 ld [%g1 + CPU_ID], %o0 ! load cpu_id
2537 ldn [%g1 + CPU_THREAD], %g2 ! load thread pointer
2538 ldn [%g2 + T_LPL], %g2 ! load lpl pointer
2539 ld [%g2 + LPL_LGRPID], %g1 ! load lpl_lgrpid
2540 sra %g1, 0, %o1
2541 FAST_TRAP_DONE
2542 SET_SIZE(.getlgrp)
2543
2544 /*
2545 * Entry for old 4.x trap (trap 0).
2546 */
2547 ENTRY_NP(syscall_trap_4x)
2548 CPU_ADDR(%g1, %g2) ! load CPU struct addr to %g1 using %g2
2549 ldn [%g1 + CPU_THREAD], %g2 ! load thread pointer
2550 ldn [%g2 + T_LWP], %g2 ! load klwp pointer
2551 ld [%g2 + PCB_TRAP0], %g2 ! lwp->lwp_pcb.pcb_trap0addr
2552 brz,pn %g2, 1f ! has it been set?
2553 st %l0, [%g1 + CPU_TMP1] ! delay - save some locals
2554 st %l1, [%g1 + CPU_TMP2]
2555 rdpr %tnpc, %l1 ! save old tnpc
2556 wrpr %g0, %g2, %tnpc ! setup tnpc
2557
2558 rdpr %pstate, %l0
2559 wrpr %l0, PSTATE_AG, %pstate ! switch to normal globals
2560 mov %l1, %g6 ! pass tnpc to user code in %g6
2561 wrpr %l0, %g0, %pstate ! switch back to alternate globals
2562
2563 ! Note that %g1 still contains CPU struct addr
2564 ld [%g1 + CPU_TMP2], %l1 ! restore locals
2565 ld [%g1 + CPU_TMP1], %l0
2566 FAST_TRAP_DONE_CHK_INTR
2567 1:
2568 mov %g1, %l0
2569 st %l1, [%g1 + CPU_TMP2]
2570 rdpr %pstate, %l1
2571 wrpr %l1, PSTATE_AG, %pstate
2572 !
2573 ! check for old syscall mmap which is the only different one which
2574 ! must be the same. Others are handled in the compatibility library.
2575 !
2576 cmp %g1, OSYS_mmap ! compare to old 4.x mmap
2577 movz %icc, SYS_mmap, %g1
2578 wrpr %g0, %l1, %pstate
2579 ld [%l0 + CPU_TMP2], %l1 ! restore locals
2580 ld [%l0 + CPU_TMP1], %l0
2581 SYSCALL(syscall_trap32)
2582 SET_SIZE(syscall_trap_4x)
2583
2584 /*
2585 * Handler for software trap 9.
2586 * Set trap0 emulation address for old 4.x system call trap.
2587 * XXX - this should be a system call.
2588 */
2589 ENTRY_NP(set_trap0_addr)
2590 CPU_ADDR(%g1, %g2) ! load CPU struct addr to %g1 using %g2
2591 ldn [%g1 + CPU_THREAD], %g2 ! load thread pointer
2592 ldn [%g2 + T_LWP], %g2 ! load klwp pointer
2593 st %l0, [%g1 + CPU_TMP1] ! save some locals
2594 st %l1, [%g1 + CPU_TMP2]
2595 rdpr %pstate, %l0
2596 wrpr %l0, PSTATE_AG, %pstate
2597 mov %g1, %l1
2598 wrpr %g0, %l0, %pstate
2599 andn %l1, 3, %l1 ! force alignment
2600 st %l1, [%g2 + PCB_TRAP0] ! lwp->lwp_pcb.pcb_trap0addr
2601 ld [%g1 + CPU_TMP1], %l0 ! restore locals
2602 ld [%g1 + CPU_TMP2], %l1
2603 FAST_TRAP_DONE
2604 SET_SIZE(set_trap0_addr)
2605
2606 /*
2607 * mmu_trap_tl1
2608 * trap handler for unexpected mmu traps.
2609 * simply checks if the trap was a user lddf/stdf alignment trap, in which
2610 * case we go to fpu_trap or a user trap from the window handler, in which
2611 * case we go save the state on the pcb. Otherwise, we go to ptl1_panic.
2612 */
2613 .type mmu_trap_tl1, #function
2614 mmu_trap_tl1:
2615 #ifdef TRAPTRACE
2616 TRACE_PTR(%g5, %g6)
2617 GET_TRACE_TICK(%g6, %g7)
2618 stxa %g6, [%g5 + TRAP_ENT_TICK]%asi
2619 rdpr %tl, %g6
2620 stha %g6, [%g5 + TRAP_ENT_TL]%asi
2621 rdpr %tt, %g6
2622 stha %g6, [%g5 + TRAP_ENT_TT]%asi
2623 rdpr %tstate, %g6
2624 stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi
2625 stna %sp, [%g5 + TRAP_ENT_SP]%asi
2626 stna %g0, [%g5 + TRAP_ENT_TR]%asi
2627 rdpr %tpc, %g6
2628 stna %g6, [%g5 + TRAP_ENT_TPC]%asi
2629 set MMU_SFAR, %g6
2630 ldxa [%g6]ASI_DMMU, %g6
2631 stxa %g6, [%g5 + TRAP_ENT_F1]%asi
2632 CPU_PADDR(%g7, %g6);
2633 add %g7, CPU_TL1_HDLR, %g7
2634 lda [%g7]ASI_MEM, %g6
2635 stxa %g6, [%g5 + TRAP_ENT_F2]%asi
2636 set 0xdeadbeef, %g6
2637 stna %g6, [%g5 + TRAP_ENT_F3]%asi
2638 stna %g6, [%g5 + TRAP_ENT_F4]%asi
2639 TRACE_NEXT(%g5, %g6, %g7)
2640 #endif /* TRAPTRACE */
2641
2642 GET_CPU_IMPL(%g5)
2643 cmp %g5, PANTHER_IMPL
2644 bne mmu_trap_tl1_4
2645 nop
2646 rdpr %tt, %g5
2647 cmp %g5, T_DATA_EXCEPTION
2648 bne mmu_trap_tl1_4
2649 nop
2650 wr %g0, ASI_DMMU, %asi
2651 ldxa [MMU_SFSR]%asi, %g5
2652 mov 1, %g6
2653 sllx %g6, PN_SFSR_PARITY_SHIFT, %g6
2654 andcc %g5, %g6, %g0
2655 bz mmu_trap_tl1_4
2656
2657 /*
2658 * We are running on a Panther and have hit a DTLB parity error.
2659 */
2660 ldxa [MMU_TAG_ACCESS]%asi, %g2
2661 mov %g5, %g3
2662 ba,pt %xcc, .mmu_exception_is_tlb_parity
2663 mov T_DATA_EXCEPTION, %g1
2664
2665 mmu_trap_tl1_4:
2666 CPU_PADDR(%g7, %g6);
2667 add %g7, CPU_TL1_HDLR, %g7 ! %g7 = &cpu_m.tl1_hdlr (PA)
2668 /*
2669 * AM is cleared on trap, so addresses are 64 bit
2670 */
2671 lda [%g7]ASI_MEM, %g6
2672 brz,a,pt %g6, 1f
2673 nop
2674 /*
2675 * We are going to update cpu_m.tl1_hdlr using physical address.
2676 * Flush the D$ line, so that stale data won't be accessed later.
2677 */
2678 CPU_ADDR(%g6, %g5)
2679 add %g6, CPU_TL1_HDLR, %g6 ! %g6 = &cpu_m.tl1_hdlr (VA)
2680 GET_CPU_IMPL(%g5)
2681 cmp %g5, CHEETAH_IMPL
2682 bl,pt %icc, 3f
2683 cmp %g5, SPITFIRE_IMPL
2684 stxa %g0, [%g7]ASI_DC_INVAL
2685 membar #Sync
2686 ba,pt %xcc, 2f
2687 nop
2688 3:
2689 bl,pt %icc, 2f
2690 sethi %hi(dcache_line_mask), %g5
2691 ld [%g5 + %lo(dcache_line_mask)], %g5
2692 and %g6, %g5, %g5
2693 stxa %g0, [%g5]ASI_DC_TAG
2694 membar #Sync
2695 2:
2696 sta %g0, [%g7]ASI_MEM
2697 SWITCH_GLOBALS ! back to mmu globals
2698 ba,a,pt %xcc, sfmmu_mmu_trap ! handle page faults
2699 1:
2700 rdpr %tt, %g5
2701 rdpr %tl, %g7
2702 sub %g7, 1, %g6
2703 wrpr %g6, %tl
2704 rdpr %tt, %g6
2705 wrpr %g7, %tl
2706 and %g6, WTRAP_TTMASK, %g6
2707 cmp %g6, WTRAP_TYPE
2708 bne,a,pn %xcc, ptl1_panic
2709 mov PTL1_BAD_MMUTRAP, %g1
2710 rdpr %tpc, %g7
2711 /* tpc should be in the trap table */
2712 set trap_table, %g6
2713 cmp %g7, %g6
2714 blt,a,pn %xcc, ptl1_panic
2715 mov PTL1_BAD_MMUTRAP, %g1
2716 set etrap_table, %g6
2717 cmp %g7, %g6
2718 bge,a,pn %xcc, ptl1_panic
2719 mov PTL1_BAD_MMUTRAP, %g1
2720 cmp %g5, T_ALIGNMENT
2721 move %icc, MMU_SFAR, %g6
2722 movne %icc, MMU_TAG_ACCESS, %g6
2723 ldxa [%g6]ASI_DMMU, %g6
2724 andn %g7, WTRAP_ALIGN, %g7 /* 128 byte aligned */
2725 add %g7, WTRAP_FAULTOFF, %g7
2726 wrpr %g0, %g7, %tnpc
2727 done
2728 SET_SIZE(mmu_trap_tl1)
2729
2730 /*
2731 * Several traps use kmdb_trap and kmdb_trap_tl1 as their handlers. These
2732 * traps are valid only when kmdb is loaded. When the debugger is active,
2733 * the code below is rewritten to transfer control to the appropriate
2734 * debugger entry points.
2735 */
2736 .global kmdb_trap
2737 .align 8
2738 kmdb_trap:
2739 ba,a trap_table0
2740 jmp %g1 + 0
2741 nop
2742
2743 .global kmdb_trap_tl1
2744 .align 8
2745 kmdb_trap_tl1:
2746 ba,a trap_table0
2747 jmp %g1 + 0
2748 nop
2749
2750 /*
2751 * This entry is copied from OBP's trap table during boot.
2752 */
2753 .global obp_bpt
2754 .align 8
2755 obp_bpt:
2756 NOT
2757
2758 /*
2759 * if kernel, set PCONTEXT to 0 for debuggers
2760 * if user, clear nucleus page sizes
2761 */
2762 .global kctx_obp_bpt
2763 kctx_obp_bpt:
2764 set obp_bpt, %g2
2765 1:
2766 #ifndef _OPL
2767 mov MMU_PCONTEXT, %g1
2768 ldxa [%g1]ASI_DMMU, %g1
2769 srlx %g1, CTXREG_NEXT_SHIFT, %g3
2770 brz,pt %g3, 3f ! nucleus pgsz is 0, no problem
2771 sllx %g3, CTXREG_NEXT_SHIFT, %g3
2772 set CTXREG_CTX_MASK, %g4 ! check Pcontext
2773 btst %g4, %g1
2774 bz,a,pt %xcc, 2f
2775 clr %g3 ! kernel: PCONTEXT=0
2776 xor %g3, %g1, %g3 ! user: clr N_pgsz0/1 bits
2777 2:
2778 set DEMAP_ALL_TYPE, %g1
2779 stxa %g0, [%g1]ASI_DTLB_DEMAP
2780 stxa %g0, [%g1]ASI_ITLB_DEMAP
2781 mov MMU_PCONTEXT, %g1
2782 stxa %g3, [%g1]ASI_DMMU
2783 membar #Sync
2784 sethi %hi(FLUSH_ADDR), %g1
2785 flush %g1 ! flush required by immu
2786 #endif /* _OPL */
2787 3:
2788 jmp %g2
2789 nop
2790
2791
2792 #ifdef TRAPTRACE
2793 /*
2794 * TRAPTRACE support.
2795 * labels here are branched to with "rd %pc, %g7" in the delay slot.
2796 * Return is done by "jmp %g7 + 4".
2797 */
2798
2799 trace_gen:
2800 TRACE_PTR(%g3, %g6)
2801 GET_TRACE_TICK(%g6, %g4)
2802 stxa %g6, [%g3 + TRAP_ENT_TICK]%asi
2803 rdpr %tl, %g6
2804 stha %g6, [%g3 + TRAP_ENT_TL]%asi
2805 rdpr %tt, %g6
2806 stha %g6, [%g3 + TRAP_ENT_TT]%asi
2807 rdpr %tstate, %g6
2808 stxa %g6, [%g3 + TRAP_ENT_TSTATE]%asi
2809 stna %sp, [%g3 + TRAP_ENT_SP]%asi
2810 rdpr %tpc, %g6
2811 stna %g6, [%g3 + TRAP_ENT_TPC]%asi
2812 TRACE_NEXT(%g3, %g4, %g5)
2813 jmp %g7 + 4
2814 nop
2815
2816 trace_win:
2817 TRACE_WIN_INFO(0, %l0, %l1, %l2)
2818 ! Keep the locals as clean as possible, caller cleans %l4
2819 clr %l2
2820 clr %l1
2821 jmp %l4 + 4
2822 clr %l0
2823
2824 /*
2825 * Trace a tsb hit
2826 * g1 = tsbe pointer (in/clobbered)
2827 * g2 = tag access register (in)
2828 * g3 - g4 = scratch (clobbered)
2829 * g5 = tsbe data (in)
2830 * g6 = scratch (clobbered)
2831 * g7 = pc we jumped here from (in)
2832 */
2833
2834 ! Do not disturb %g5, it will be used after the trace
2835 ALTENTRY(trace_tsbhit)
2836 TRACE_TSBHIT(0)
2837 jmp %g7 + 4
2838 nop
2839
2840 /*
2841 * Trace a TSB miss
2842 *
2843 * g1 = tsb8k pointer (in)
2844 * g2 = tag access register (in)
2845 * g3 = tsb4m pointer (in)
2846 * g4 = tsbe tag (in/clobbered)
2847 * g5 - g6 = scratch (clobbered)
2848 * g7 = pc we jumped here from (in)
2849 */
2850 .global trace_tsbmiss
2851 trace_tsbmiss:
2852 membar #Sync
2853 sethi %hi(FLUSH_ADDR), %g6
2854 flush %g6
2855 TRACE_PTR(%g5, %g6)
2856 stxa %g2, [%g5 + TRAP_ENT_SP]%asi ! tag access
2857 stxa %g4, [%g5 + TRAP_ENT_F1]%asi ! tsb tag
2858 GET_TRACE_TICK(%g6, %g4)
2859 stxa %g6, [%g5 + TRAP_ENT_TICK]%asi
2860 rdpr %tnpc, %g6
2861 stxa %g6, [%g5 + TRAP_ENT_F2]%asi
2862 stna %g1, [%g5 + TRAP_ENT_F3]%asi ! tsb8k pointer
2863 srlx %g1, 32, %g6
2864 stna %g6, [%g5 + TRAP_ENT_F4]%asi ! huh?
2865 rdpr %tpc, %g6
2866 stna %g6, [%g5 + TRAP_ENT_TPC]%asi
2867 rdpr %tl, %g6
2868 stha %g6, [%g5 + TRAP_ENT_TL]%asi
2869 rdpr %tt, %g6
2870 or %g6, TT_MMU_MISS, %g4
2871 stha %g4, [%g5 + TRAP_ENT_TT]%asi
2872 cmp %g6, FAST_IMMU_MISS_TT
2873 be,a %icc, 1f
2874 ldxa [%g0]ASI_IMMU, %g6
2875 ldxa [%g0]ASI_DMMU, %g6
2876 1: stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! tag target
2877 stxa %g3, [%g5 + TRAP_ENT_TR]%asi ! tsb4m pointer
2878 TRACE_NEXT(%g5, %g4, %g6)
2879 jmp %g7 + 4
2880 nop
2881
2882 /*
2883 * g2 = tag access register (in)
2884 * g3 = ctx number (in)
2885 */
2886 trace_dataprot:
2887 membar #Sync
2888 sethi %hi(FLUSH_ADDR), %g6
2889 flush %g6
2890 TRACE_PTR(%g1, %g6)
2891 GET_TRACE_TICK(%g6, %g5)
2892 stxa %g6, [%g1 + TRAP_ENT_TICK]%asi
2893 rdpr %tpc, %g6
2894 stna %g6, [%g1 + TRAP_ENT_TPC]%asi
2895 rdpr %tstate, %g6
2896 stxa %g6, [%g1 + TRAP_ENT_TSTATE]%asi
2897 stxa %g2, [%g1 + TRAP_ENT_SP]%asi ! tag access reg
2898 stxa %g0, [%g1 + TRAP_ENT_TR]%asi
2899 stxa %g0, [%g1 + TRAP_ENT_F1]%asi
2900 stxa %g0, [%g1 + TRAP_ENT_F2]%asi
2901 stxa %g0, [%g1 + TRAP_ENT_F3]%asi
2902 stxa %g0, [%g1 + TRAP_ENT_F4]%asi
2903 rdpr %tl, %g6
2904 stha %g6, [%g1 + TRAP_ENT_TL]%asi
2905 rdpr %tt, %g6
2906 stha %g6, [%g1 + TRAP_ENT_TT]%asi
2907 TRACE_NEXT(%g1, %g4, %g5)
2908 jmp %g7 + 4
2909 nop
2910
2911 #endif /* TRAPTRACE */
2912
2913 .align 32
2914 .global pil15_epilogue
2915 pil15_epilogue:
2916 ba pil_interrupt_common
2917 nop
2918 .align 32
2919
2920 /*
2921 * fast_trap_done, fast_trap_done_chk_intr:
2922 *
2923 * Due to the design of UltraSPARC pipeline, pending interrupts are not
2924 * taken immediately after a RETRY or DONE instruction which causes IE to
2925 * go from 0 to 1. Instead, the instruction at %tpc or %tnpc is allowed
2926 * to execute first before taking any interrupts. If that instruction
2927 * results in other traps, and if the corresponding trap handler runs
2928 * entirely at TL=1 with interrupts disabled, then pending interrupts
2929 * won't be taken until after yet another instruction following the %tpc
2930 * or %tnpc.
2931 *
2932 * A malicious user program can use this feature to block out interrupts
2933 * for extended durations, which can result in send_mondo_timeout kernel
2934 * panic.
2935 *
2936 * This problem is addressed by servicing any pending interrupts via
2937 * sys_trap before returning back to the user mode from a fast trap
2938 * handler. The "done" instruction within a fast trap handler, which
2939 * runs entirely at TL=1 with interrupts disabled, is replaced with the
2940 * FAST_TRAP_DONE macro, which branches control to this fast_trap_done
2941 * entry point.
2942 *
2943 * We check for any pending interrupts here and force a sys_trap to
2944 * service those interrupts, if any. To minimize overhead, pending
2945 * interrupts are checked if the %tpc happens to be at 16K boundary,
2946 * which allows a malicious program to execute at most 4K consecutive
2947 * instructions before we service any pending interrupts. If a worst
2948 * case fast trap handler takes about 2 usec, then interrupts will be
2949 * blocked for at most 8 msec, less than a clock tick.
2950 *
2951 * For the cases where we don't know if the %tpc will cross a 16K
2952 * boundary, we can't use the above optimization and always process
2953 * any pending interrupts via fast_frap_done_chk_intr entry point.
2954 *
2955 * Entry Conditions:
2956 * %pstate am:0 priv:1 ie:0
2957 * globals are AG (not normal globals)
2958 */
2959
2960 .global fast_trap_done, fast_trap_done_chk_intr
2961 fast_trap_done:
2962 rdpr %tpc, %g5
2963 sethi %hi(0xffffc000), %g6 ! 1's complement of 0x3fff
2964 andncc %g5, %g6, %g0 ! check lower 14 bits of %tpc
2965 bz,a,pn %icc, 1f ! branch if zero (lower 32 bits only)
2966 ldxa [%g0]ASI_INTR_RECEIVE_STATUS, %g5
2967 done
2968
2969 ALTENTRY(fast_trap_done_check_interrupts)
2970 fast_trap_done_chk_intr:
2971 ldxa [%g0]ASI_INTR_RECEIVE_STATUS, %g5
2972
2973 1: rd SOFTINT, %g6
2974 and %g5, IRSR_BUSY, %g5
2975 orcc %g5, %g6, %g0
2976 bnz,pn %xcc, 2f ! branch if any pending intr
2977 nop
2978 done
2979
2980 2:
2981 /*
2982 * We get here if there are any pending interrupts.
2983 * Adjust %tpc/%tnpc as we'll be resuming via "retry"
2984 * instruction.
2985 */
2986 rdpr %tnpc, %g5
2987 wrpr %g0, %g5, %tpc
2988 add %g5, 4, %g5
2989 wrpr %g0, %g5, %tnpc
2990
2991 /*
2992 * Force a dummy sys_trap call so that interrupts can be serviced.
2993 */
2994 set fast_trap_dummy_call, %g1
2995 ba,pt %xcc, sys_trap
2996 mov -1, %g4
2997
2998 fast_trap_dummy_call:
2999 retl
3000 nop
3001
3002 /*
3003 * Currently the brand syscall interposition code is not enabled by
3004 * default. Instead, when a branded zone is first booted the brand
3005 * infrastructure will patch the trap table so that the syscall
3006 * entry points are redirected to syscall_wrapper32 and syscall_wrapper
3007 * for ILP32 and LP64 syscalls respectively. this is done in
3008 * brand_plat_interposition_enable(). Note that the syscall wrappers
3009 * below do not collect any trap trace data since the syscall hot patch
3010 * points are reached after trap trace data has already been collected.
3011 */
3012 #define BRAND_CALLBACK(callback_id) \
3013 CPU_ADDR(%g2, %g1) /* load CPU struct addr to %g2 */ ;\
3014 ldn [%g2 + CPU_THREAD], %g3 /* load thread pointer */ ;\
3015 ldn [%g3 + T_PROCP], %g3 /* get proc pointer */ ;\
3016 ldn [%g3 + P_BRAND], %g3 /* get brand pointer */ ;\
3017 brz %g3, 1f /* No brand? No callback. */ ;\
3018 nop ;\
3019 ldn [%g3 + B_MACHOPS], %g3 /* get machops list */ ;\
3020 ldn [%g3 + (callback_id << 3)], %g3 ;\
3021 brz %g3, 1f ;\
3022 /* \
3023 * This isn't pretty. We want a low-latency way for the callback \
3024 * routine to decline to do anything. We just pass in an address \
3025 * the routine can directly jmp back to, pretending that nothing \
3026 * has happened. \
3027 * \
3028 * %g1: return address (where the brand handler jumps back to) \
3029 * %g2: address of CPU structure \
3030 * %g3: address of brand handler (where we will jump to) \
3031 */ \
3032 mov %pc, %g1 ;\
3033 add %g1, 16, %g1 ;\
3034 jmp %g3 ;\
3035 nop ;\
3036 1:
3037
3038 ENTRY_NP(syscall_wrapper32)
3039 BRAND_CALLBACK(BRAND_CB_SYSCALL32)
3040 SYSCALL_NOTT(syscall_trap32)
3041 SET_SIZE(syscall_wrapper32)
3042
3043 ENTRY_NP(syscall_wrapper)
3044 BRAND_CALLBACK(BRAND_CB_SYSCALL)
3045 SYSCALL_NOTT(syscall_trap)
3046 SET_SIZE(syscall_wrapper)
3047
--- EOF ---