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