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