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 #if defined(lint)
27 #include <sys/types.h>
28 #include <sys/thread.h>
29 #else /* lint */
30 #include "assym.h"
31 #endif /* lint */
32
33 #include <sys/asm_linkage.h>
34 #include <sys/machthread.h>
35 #include <sys/machcpuvar.h>
36 #include <sys/intreg.h>
37 #include <sys/cmn_err.h>
38 #include <sys/ftrace.h>
39 #include <sys/machasi.h>
40 #include <sys/scb.h>
41 #include <sys/error.h>
42 #include <sys/mmu.h>
43 #include <vm/hat_sfmmu.h>
44 #define INTR_REPORT_SIZE 64
45
46 #ifdef TRAPTRACE
47 #include <sys/traptrace.h>
48 #endif /* TRAPTRACE */
49
50 #if defined(lint)
51
52 void
53 cpu_mondo(void)
54 {}
55
56 #else /* lint */
57
58
59 /*
60 * (TT 0x7c, TL>0) CPU Mondo Queue Handler
61 * Globals are the Interrupt Globals.
62 */
63 ENTRY_NP(cpu_mondo)
64 !
65 ! Register Usage:-
66 ! %g5 PC for fasttrap TL>0 handler
67 ! %g1 arg 1
68 ! %g2 arg 2
69 ! %g3 queue base VA
70 ! %g4 queue size mask
71 ! %g6 head ptr
72 ! %g7 tail ptr
73 mov CPU_MONDO_Q_HD, %g3
74 ldxa [%g3]ASI_QUEUE, %g6 ! %g6 = head ptr
75 mov CPU_MONDO_Q_TL, %g4
76 ldxa [%g4]ASI_QUEUE, %g7 ! %g7 = tail ptr
77 cmp %g6, %g7
78 be,pn %xcc, 3f ! head == tail
79 nop
80
81 CPU_ADDR(%g1,%g2)
82 add %g1, CPU_MCPU, %g2
83 ldx [%g2 + MCPU_CPU_Q_BASE], %g3 ! %g3 = queue base PA
84 ldx [%g2 + MCPU_CPU_Q_SIZE], %g4 ! queue size
85 sub %g4, 1, %g4 ! %g4 = queue size mask
86
87 ! Load interrupt receive data registers 1 and 2 to fetch
88 ! the arguments for the fast trap handler.
89 !
90 ! XXX - Since the data words in the interrupt report are not defined yet
91 ! we assume that the consective words contain valid data and preserve
92 ! sun4u's xcall mondo arguments.
93 ! Register usage:
94 ! %g5 PC for fasttrap TL>0 handler
95 ! %g1 arg 1
96 ! %g2 arg 2
97
98 ldxa [%g3 + %g6]ASI_MEM, %g5 ! get PC from q base + head
99 add %g6, 0x8, %g6 ! inc head
100 ldxa [%g3 + %g6]ASI_MEM, %g1 ! read data word 1
101 add %g6, 0x8, %g6 ! inc head
102 ldxa [%g3 + %g6]ASI_MEM, %g2 ! read data word 2
103 add %g6, (INTR_REPORT_SIZE - 16) , %g6 ! inc head to next record
104 and %g6, %g4, %g6 ! and size mask for wrap around
105 mov CPU_MONDO_Q_HD, %g3
106 stxa %g6, [%g3]ASI_QUEUE ! store head pointer
107 membar #Sync
108
109 #ifdef TRAPTRACE
110 TRACE_PTR(%g4, %g6)
111 GET_TRACE_TICK(%g6, %g3)
112 stxa %g6, [%g4 + TRAP_ENT_TICK]%asi
113 TRACE_SAVE_TL_GL_REGS(%g4, %g6)
114 rdpr %tt, %g6
115 stha %g6, [%g4 + TRAP_ENT_TT]%asi
116 rdpr %tpc, %g6
117 stna %g6, [%g4 + TRAP_ENT_TPC]%asi
118 rdpr %tstate, %g6
119 stxa %g6, [%g4 + TRAP_ENT_TSTATE]%asi
120 stna %sp, [%g4 + TRAP_ENT_SP]%asi
121 stna %g5, [%g4 + TRAP_ENT_TR]%asi ! pc of the TL>0 handler
122 stna %g1, [%g4 + TRAP_ENT_F1]%asi ! arg1
123 stna %g2, [%g4 + TRAP_ENT_F3]%asi ! arg2
124 mov CPU_MONDO_Q_HD, %g6
125 ldxa [%g6]ASI_QUEUE, %g6 ! new head offset
126 stna %g6, [%g4 + TRAP_ENT_F2]%asi
127 stna %g7, [%g4 + TRAP_ENT_F4]%asi ! tail offset
128 TRACE_NEXT(%g4, %g6, %g3)
129 #endif /* TRAPTRACE */
130
131 /*
132 * For now catch invalid PC being passed via cpu_mondo queue
133 */
134 set KERNELBASE, %g4
135 cmp %g5, %g4
136 bl,pn %xcc, 2f ! branch if bad %pc
137 nop
138
139
140 /*
141 * If this platform supports shared contexts and we are jumping
142 * to OBP code, then we need to invalidate both contexts to prevent OBP
143 * from corrupting the shared context registers.
144 *
145 * If shared contexts are not supported then the next two instructions
146 * will be patched with:
147 *
148 * jmp %g5
149 * nop
150 *
151 */
152 .global sfmmu_shctx_cpu_mondo_patch
153 sfmmu_shctx_cpu_mondo_patch:
154 set OFW_START_ADDR, %g4 ! Check if this a call into OBP?
155 cmp %g5, %g4
156 bl,pt %xcc, 1f
157 nop
158 set OFW_END_ADDR, %g4
159 cmp %g5, %g4
160 bg,pn %xcc, 1f
161 nop
162 mov MMU_PCONTEXT, %g3
163 ldxa [%g3]ASI_MMU_CTX, %g4
164 cmp %g4, INVALID_CONTEXT ! Check if we are in kernel mode
165 ble,pn %xcc, 1f ! or the primary context is invalid
166 nop
167 set INVALID_CONTEXT, %g4 ! Invalidate contexts - compatability
168 stxa %g4, [%g3]ASI_MMU_CTX ! mode ensures shared contexts are also
169 mov MMU_SCONTEXT, %g3 ! invalidated.
170 stxa %g4, [%g3]ASI_MMU_CTX
171 membar #Sync
172 mov %o0, %g3 ! save output regs
173 mov %o1, %g4
174 mov %o5, %g6
175 clr %o0 ! Invalidate tsbs, set ntsb = 0
176 clr %o1 ! and HV_TSB_INFO_PA = 0
177 mov MMU_TSB_CTXNON0, %o5
178 ta FAST_TRAP ! set TSB info for user process
179 brnz,a,pn %o0, ptl1_panic
180 mov PTL1_BAD_HCALL, %g1
181 mov %g3, %o0 ! restore output regs
182 mov %g4, %o1
183 mov %g6, %o5
184 1:
185 jmp %g5 ! jump to traphandler
186 nop
187 2:
188 ! invalid trap handler, discard it for now
189 set cpu_mondo_inval, %g4
190 ldx [%g4], %g5
191 inc %g5
192 stx %g5, [%g4]
193 3:
194 retry
195 /* Never Reached */
196 SET_SIZE(cpu_mondo)
197
198 #endif /* lint */
199
200 #if defined(lint)
201
202 void
203 dev_mondo(void)
204 {}
205
206 #else /* lint */
207
208
209 /*
210 * (TT 0x7d, TL>0) Dev Mondo Queue Handler
211 * Globals are the Interrupt Globals.
212 * We only process one interrupt at a time causing us to keep
213 * taking this trap till the queue is empty.
214 * We really should drain the whole queue for better performance
215 * but this will do for now.
216 */
217 ENTRY_NP(dev_mondo)
218 !
219 ! Register Usage:-
220 ! %g5 PC for fasttrap TL>0 handler
221 ! %g1 arg 1
222 ! %g2 arg 2
223 ! %g3 queue base PA
224 ! %g4 queue size mask
225 ! %g6 head ptr
226 ! %g7 tail ptr
227 mov DEV_MONDO_Q_HD, %g3
228 ldxa [%g3]ASI_QUEUE, %g6 ! %g6 = head ptr
229 mov DEV_MONDO_Q_TL, %g4
230 ldxa [%g4]ASI_QUEUE, %g7 ! %g7 = tail ptr
231 cmp %g6, %g7
232 be,pn %xcc, 0f ! head == tail
233 nop
234
235 CPU_ADDR(%g1,%g2)
236 add %g1, CPU_MCPU, %g2
237 ldx [%g2 + MCPU_DEV_Q_BASE], %g3 ! %g3 = queue base PA
238
239 ! Register usage:
240 ! %g5 - inum
241 ! %g1 - cpu struct pointer used below in TRAPTRACE
242 !
243 ldxa [%g3 + %g6]ASI_MEM, %g5 ! get inum from q base + head
244
245 !
246 ! We verify that inum is valid ( < MAXVNUM). If it is greater
247 ! than MAXVNUM, we let setvecint_tl1 take care of it.
248 !
249 set MAXIVNUM, %g4
250 cmp %g5, %g4
251 bgeu,a,pn %xcc, 1f
252 ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot
253
254 !
255 ! Copy 64-byte payload to the *iv_payload if it is not NULL
256 !
257 set intr_vec_table, %g1 ! %g1 = intr_vec_table
258 sll %g5, CPTRSHIFT, %g7 ! %g7 = offset to inum entry
259 ! in the intr_vec_table
260 add %g1, %g7, %g7 ! %g7 = &intr_vec_table[inum]
261 ldn [%g7], %g1 ! %g1 = ptr to intr_vec_t (iv)
262
263 !
264 ! Verify the pointer to first intr_vec_t for a given inum and
265 ! it should not be NULL. If this pointer is NULL, then it is a
266 ! spurious interrupt. In this case, just call setvecint_tl1 and
267 ! it will handle this spurious interrupt.
268 !
269 brz,a,pn %g1, 1f ! if %g1 is NULL
270 ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot
271
272 ldx [%g1 + IV_PAYLOAD_BUF], %g1 ! %g1 = iv->iv_payload_buf
273 brz,a,pt %g1, 1f ! if it is NULL
274 ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot
275
276 !
277 ! Now move 64 byte payload from mondo queue to buf
278 !
279 mov %g6, %g7 ! %g7 = head ptr
280 ldxa [%g3 + %g7]ASI_MEM, %g4
281 stx %g4, [%g1 + 0] ! byte 0 - 7
282 add %g7, 8, %g7
283 ldxa [%g3 + %g7]ASI_MEM, %g4
284 stx %g4, [%g1 + 8] ! byte 8 - 15
285 add %g7, 8, %g7
286 ldxa [%g3 + %g7]ASI_MEM, %g4
287 stx %g4, [%g1 + 16] ! byte 16 - 23
288 add %g7, 8, %g7
289 ldxa [%g3 + %g7]ASI_MEM, %g4
290 stx %g4, [%g1 + 24] ! byte 24 - 31
291 add %g7, 8, %g7
292 ldxa [%g3 + %g7]ASI_MEM, %g4
293 stx %g4, [%g1 + 32] ! byte 32 - 39
294 add %g7, 8, %g7
295 ldxa [%g3 + %g7]ASI_MEM, %g4
296 stx %g4, [%g1 + 40] ! byte 40 - 47
297 add %g7, 8, %g7
298 ldxa [%g3 + %g7]ASI_MEM, %g4
299 stx %g4, [%g1 + 48] ! byte 48 - 55
300 add %g7, 8, %g7
301 ldxa [%g3 + %g7]ASI_MEM, %g4
302 stx %g4, [%g1 + 56] ! byte 56 - 63
303 ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size
304
305 1: sub %g4, 1, %g4 ! %g4 = queue size mask
306 add %g6, INTR_REPORT_SIZE , %g6 ! inc head to next record
307 and %g6, %g4, %g6 ! and mask for wrap around
308 mov DEV_MONDO_Q_HD, %g3
309 stxa %g6, [%g3]ASI_QUEUE ! increment head offset
310 membar #Sync
311
312 #ifdef TRAPTRACE
313 TRACE_PTR(%g4, %g6)
314 GET_TRACE_TICK(%g6, %g3)
315 stxa %g6, [%g4 + TRAP_ENT_TICK]%asi
316 TRACE_SAVE_TL_GL_REGS(%g4, %g6)
317 rdpr %tt, %g6
318 stha %g6, [%g4 + TRAP_ENT_TT]%asi
319 rdpr %tpc, %g6
320 stna %g6, [%g4 + TRAP_ENT_TPC]%asi
321 rdpr %tstate, %g6
322 stxa %g6, [%g4 + TRAP_ENT_TSTATE]%asi
323 ! move head to sp
324 ldx [%g2 + MCPU_DEV_Q_BASE], %g6
325 stna %g6, [%g4 + TRAP_ENT_SP]%asi ! Device Queue Base PA
326 stna %g5, [%g4 + TRAP_ENT_TR]%asi ! Inum
327 mov DEV_MONDO_Q_HD, %g6
328 ldxa [%g6]ASI_QUEUE, %g6 ! New head offset
329 stna %g6, [%g4 + TRAP_ENT_F1]%asi
330 ldx [%g2 + MCPU_DEV_Q_SIZE], %g6
331 stna %g6, [%g4 + TRAP_ENT_F2]%asi ! Q Size
332 stna %g7, [%g4 + TRAP_ENT_F3]%asi ! tail offset
333 stna %g0, [%g4 + TRAP_ENT_F4]%asi
334 TRACE_NEXT(%g4, %g6, %g3)
335 #endif /* TRAPTRACE */
336
337 !
338 ! setvecint_tl1 will do all the work, and finish with a retry
339 !
340 ba,pt %xcc, setvecint_tl1
341 mov %g5, %g1 ! setvecint_tl1 expects inum in %g1
342
343 0: retry
344
345 /* Never Reached */
346 SET_SIZE(dev_mondo)
347 #endif /* lint */
348
349 #if defined(lint)
350 uint64_t cpu_mondo_inval;
351 #else /* lint */
352 .seg ".data"
353 .global cpu_mondo_inval
354 .align 8
355 cpu_mondo_inval:
356 .skip 8
357
358 .seg ".text"
359 #endif /* lint */
360
361
362 #if defined(lint)
363
364 void
365 resumable_error(void)
366 {}
367
368 #else /* lint */
369
370 /*
371 * (TT 0x7e, TL>0) Resumeable Error Queue Handler
372 * We keep a shadow copy of the queue in kernel buf.
373 * Read the resumable queue head and tail offset
374 * If there are entries on the queue, move them to
375 * the kernel buf, which is next to the resumable
376 * queue in the memory. Call C routine to process.
377 */
378 ENTRY_NP(resumable_error)
379 mov CPU_RQ_HD, %g4
380 ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset
381 mov CPU_RQ_TL, %g4
382 ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset
383 mov %g2, %g6 ! save head in %g2
384
385 cmp %g6, %g3
386 be,pn %xcc, 0f ! head == tail
387 nop
388
389 CPU_ADDR(%g1, %g4) ! %g1 = cpu struct addr
390
391 2: set CPU_RQ_BASE_OFF, %g4
392 ldx [%g1 + %g4], %g4 ! %g4 = queue base PA
393 add %g6, %g4, %g4 ! %g4 = PA of ER in Q
394 set CPU_RQ_SIZE, %g7
395 add %g4, %g7, %g7 ! %g7=PA of ER in kernel buf
396
397 ldxa [%g7]ASI_MEM, %g5 ! %g5=first 8 byte of ER buf
398 cmp 0, %g5
399 bne,pn %xcc, 1f ! first 8 byte is not 0
400 nop
401
402 /* Now we can move 64 bytes from queue to buf */
403 set 0, %g5
404 ldxa [%g4 + %g5]ASI_MEM, %g1
405 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 0 - 7
406 add %g5, 8, %g5
407 ldxa [%g4 + %g5]ASI_MEM, %g1
408 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 8 - 15
409 add %g5, 8, %g5
410 ldxa [%g4 + %g5]ASI_MEM, %g1
411 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 16 - 23
412 add %g5, 8, %g5
413 ldxa [%g4 + %g5]ASI_MEM, %g1
414 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 24 - 31
415 add %g5, 8, %g5
416 ldxa [%g4 + %g5]ASI_MEM, %g1
417 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 32 - 39
418 add %g5, 8, %g5
419 ldxa [%g4 + %g5]ASI_MEM, %g1
420 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 40 - 47
421 add %g5, 8, %g5
422 ldxa [%g4 + %g5]ASI_MEM, %g1
423 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 48 - 55
424 add %g5, 8, %g5
425 ldxa [%g4 + %g5]ASI_MEM, %g1
426 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 56 - 63
427
428 set CPU_RQ_SIZE, %g5 ! %g5 = queue size
429 sub %g5, 1, %g5 ! %g5 = queu size mask
430
431 add %g6, Q_ENTRY_SIZE, %g6 ! increment q head to next
432 and %g6, %g5, %g6 ! size mask for warp around
433 cmp %g6, %g3 ! head == tail ??
434
435 bne,pn %xcc, 2b ! still have more to process
436 nop
437
438 /*
439 * head equals to tail now, we can update the queue head
440 * and call sys_trap
441 */
442 mov CPU_RQ_HD, %g4
443 stxa %g6, [%g4]ASI_QUEUE ! update head offset
444 membar #Sync
445
446 /*
447 * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is
448 * head offset(arg2) and %g3 is tail
449 * offset(arg3).
450 */
451 set process_resumable_error, %g1
452 rdpr %pil, %g4
453 cmp %g4, PIL_14
454 ba sys_trap
455 movl %icc, PIL_14, %g4
456
457 /*
458 * We are here because the C routine is not able to process
459 * errors in time. So the first 8 bytes of ER in buf has not
460 * been cleared. We update head to tail and call sys_trap to
461 * print out an error message
462 */
463
464 1: mov CPU_RQ_HD, %g4
465 stxa %g3, [%g4]ASI_QUEUE ! set head equal to tail
466 membar #Sync
467
468 /*
469 * Set %g2 to %g6, which is current head offset. %g2
470 * is arg2 of the C routine. %g3 is the tail offset,
471 * which is arg3 of the C routine.
472 * Call rq_overflow at PIL 14 unless we're already at PIL 15.
473 */
474 mov %g6, %g2
475 set rq_overflow, %g1
476 rdpr %pil, %g4
477 cmp %g4, PIL_14
478 ba sys_trap
479 movl %icc, PIL_14, %g4
480
481 0: retry
482
483 /*NOTREACHED*/
484 SET_SIZE(resumable_error)
485 #endif /* lint */
486
487 #if defined(lint)
488
489 void
490 nonresumable_error(void)
491 {}
492
493 #else /* lint */
494
495 /*
496 * (TT 0x7f, TL>0) Non-resumeable Error Queue Handler
497 * We keep a shadow copy of the queue in kernel buf.
498 * Read non-resumable queue head and tail offset
499 * If there are entries on the queue, move them to
500 * the kernel buf, which is next to the non-resumable
501 * queue in the memory. Call C routine to process.
502 */
503 ENTRY_NP(nonresumable_error)
504 mov CPU_NRQ_HD, %g4
505 ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset
506 mov CPU_NRQ_TL, %g4
507 ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset
508
509 cmp %g2, %g3
510 be,pn %xcc, 0f ! head == tail
511 nop
512
513 /* force %gl to 1 as sys_trap requires */
514 wrpr %g0, 1, %gl
515 mov CPU_NRQ_HD, %g4
516 ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset
517 mov CPU_NRQ_TL, %g4
518 ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset
519 mov %g2, %g6 ! save head in %g2
520
521 CPU_PADDR(%g1, %g4) ! %g1 = cpu struct paddr
522
523 2: set CPU_NRQ_BASE_OFF, %g4
524 ldxa [%g1 + %g4]ASI_MEM, %g4 ! %g4 = queue base PA
525 add %g6, %g4, %g4 ! %g4 = PA of ER in Q
526 set CPU_NRQ_SIZE, %g7
527 add %g4, %g7, %g7 ! %g7 = PA of ER in kernel buf
528
529 ldxa [%g7]ASI_MEM, %g5 ! %g5 = first 8 byte of ER buf
530 cmp 0, %g5
531 bne,pn %xcc, 1f ! first 8 byte is not 0
532 nop
533
534 /* Now we can move 64 bytes from queue to buf */
535 set 0, %g5
536 ldxa [%g4 + %g5]ASI_MEM, %g1
537 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 0 - 7
538 add %g5, 8, %g5
539 ldxa [%g4 + %g5]ASI_MEM, %g1
540 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 8 - 15
541 add %g5, 8, %g5
542 ldxa [%g4 + %g5]ASI_MEM, %g1
543 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 16 - 23
544 add %g5, 8, %g5
545 ldxa [%g4 + %g5]ASI_MEM, %g1
546 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 24 - 31
547 add %g5, 8, %g5
548 ldxa [%g4 + %g5]ASI_MEM, %g1
549 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 32 - 39
550 add %g5, 8, %g5
551 ldxa [%g4 + %g5]ASI_MEM, %g1
552 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 40 - 47
553 add %g5, 8, %g5
554 ldxa [%g4 + %g5]ASI_MEM, %g1
555 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 48 - 55
556 add %g5, 8, %g5
557 ldxa [%g4 + %g5]ASI_MEM, %g1
558 stxa %g1, [%g7 + %g5]ASI_MEM ! byte 56 - 63
559
560 set CPU_NRQ_SIZE, %g5 ! %g5 = queue size
561 sub %g5, 1, %g5 ! %g5 = queu size mask
562
563 add %g6, Q_ENTRY_SIZE, %g6 ! increment q head to next
564 and %g6, %g5, %g6 ! size mask for warp around
565 cmp %g6, %g3 ! head == tail ??
566
567 bne,pn %xcc, 2b ! still have more to process
568 nop
569
570 /*
571 * head equals to tail now, we can update the queue head
572 * and call sys_trap
573 */
574 mov CPU_NRQ_HD, %g4
575 stxa %g6, [%g4]ASI_QUEUE ! update head offset
576 membar #Sync
577
578 /*
579 * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail
580 * offset(arg3).
581 * %g3 looks like following:
582 * +--------------------+--------------------+
583 * | tail offset | head offset |
584 * +--------------------+--------------------+
585 * 63 32 31 0
586 *
587 * Run at PIL 14 unless we're already at PIL 15.
588 */
589 sllx %g3, 32, %g3 ! %g3.h = tail offset
590 or %g3, %g2, %g3 ! %g3.l = head offset
591 rdpr %tl, %g2 ! %g2 = current tl
592
593 /*
594 * Now check if the first error that sent us here was caused
595 * in user's SPILL/FILL trap. If it was, we call sys_trap to
596 * kill the user process. Several considerations:
597 * - If multiple nonresumable errors happen, we only check the
598 * first one. Nonresumable errors cause system either panic
599 * or kill the user process. So the system has already
600 * panic'ed or killed user process after processing the first
601 * error. Therefore, no need to check if other error packet
602 * for this type of error.
603 * - Errors happen in user's SPILL/FILL trap will bring us at
604 * TL = 2.
605 * - We need to lower TL to 1 to get the trap type and tstate.
606 * We don't go back to TL = 2 so no need to save states.
607 */
608 cmp %g2, 2
609 bne,pt %xcc, 3f ! if tl != 2
610 nop
611 /* Check to see if the trap pc is in a window spill/fill handling */
612 rdpr %tpc, %g4
613 /* tpc should be in the trap table */
614 set trap_table, %g5
615 cmp %g4, %g5
616 blu,pt %xcc, 3f
617 nop
618 set etrap_table, %g5
619 cmp %g4, %g5
620 bgeu,pt %xcc, 3f
621 nop
622 /* Set tl to 1 in order to read tt[1] and tstate[1] */
623 wrpr %g0, 1, %tl
624 rdpr %tt, %g4 ! %g4 = tt[1]
625 /* Check if tt[1] is a window trap */
626 and %g4, WTRAP_TTMASK, %g4
627 cmp %g4, WTRAP_TYPE
628 bne,pt %xcc, 3f
629 nop
630 rdpr %tstate, %g5 ! %g5 = tstate[1]
631 btst TSTATE_PRIV, %g5
632 bnz %xcc, 3f ! Is it from user code?
633 nop
634 /*
635 * Now we know the error happened in user's SPILL/FILL trap.
636 * Turn on the user spill/fill flag in %g2
637 */
638 mov 1, %g4
639 sllx %g4, ERRH_U_SPILL_FILL_SHIFT, %g4
640 or %g2, %g4, %g2 ! turn on flag in %g2
641
642 3: sub %g2, 1, %g2 ! %g2.l = previous tl
643
644 set process_nonresumable_error, %g1
645 rdpr %pil, %g4
646 cmp %g4, PIL_14
647 ba sys_trap
648 movl %icc, PIL_14, %g4
649
650 /*
651 * We are here because the C routine is not able to process
652 * errors in time. So the first 8 bytes of ER in buf has not
653 * been cleared. We call sys_trap to panic.
654 * Run at PIL 14 unless we're already at PIL 15.
655 */
656 1: set nrq_overflow, %g1
657 rdpr %pil, %g4
658 cmp %g4, PIL_14
659 ba sys_trap
660 movl %icc, PIL_14, %g4
661
662 0: retry
663
664 /*NOTREACHED*/
665 SET_SIZE(nonresumable_error)
666 #endif /* lint */