1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/asm_linkage.h> 29 #include <sys/machthread.h> 30 #include <sys/privregs.h> 31 #include <sys/machasi.h> 32 #include <sys/trap.h> 33 #include <sys/mmu.h> 34 #include <sys/machparam.h> 35 #include <sys/machtrap.h> 36 #include <sys/traptrace.h> 37 38 #if !defined(lint) 39 #include "assym.h" 40 41 /* 42 * Spill fault handlers 43 * sn0 - spill normal tl 0 44 * sn1 - spill normal tl >0 45 * so0 - spill other tl 0 46 * so1 - spill other tl >0 47 */ 48 49 ENTRY_NP(fault_32bit_sn0) 50 ! 51 FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_SN0) 52 ! 53 ! Spill normal tl0 fault. 54 ! This happens when a user tries to spill to an unmapped or 55 ! misaligned stack. We handle an unmapped stack by simulating 56 ! a pagefault at the trap pc and a misaligned stack by generating 57 ! a user alignment trap. 58 ! 59 ! spill the window into wbuf slot 0 60 ! (we know wbuf is empty since we came from user mode) 61 ! 62 ! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or 63 ! sfar (g5 == T_ALIGNMENT) 64 ! 65 CPU_ADDR(%g4, %g1) 66 ldn [%g4 + CPU_MPCB], %g1 67 stn %sp, [%g1 + MPCB_SPBUF] 68 ldn [%g1 + MPCB_WBUF], %g2 69 SAVE_V8WINDOW(%g2) 70 mov 1, %g2 71 st %g2, [%g1 + MPCB_WBCNT] 72 saved 73 ! 74 ! setup user_trap args 75 ! 76 set sfmmu_tsbmiss_exception, %g1 77 mov %g6, %g2 ! arg2 = tagaccess 78 mov T_WIN_OVERFLOW, %g3 ! arg3 = traptype 79 cmp %g5, T_ALIGNMENT 80 bne %icc, 1f 81 nop 82 set trap, %g1 83 mov T_ALIGNMENT, %g3 84 1: 85 sub %g0, 1, %g4 86 ! 87 ! spill traps increment %cwp by 2, 88 ! but user_trap wants the trap %cwp 89 ! 90 rdpr %tstate, %g5 91 and %g5, TSTATE_CWP, %g5 92 ba,pt %xcc, user_trap 93 wrpr %g0, %g5, %cwp 94 SET_SIZE(fault_32bit_sn0) 95 96 ! 97 ! Spill normal tl1 fault. 98 ! This happens when sys_trap's save spills to an unmapped stack. 99 ! We handle it by spilling the window to the wbuf and trying 100 ! sys_trap again. 101 ! 102 ! spill the window into wbuf slot 0 103 ! (we know wbuf is empty since we came from user mode) 104 ! 105 ENTRY_NP(fault_32bit_sn1) 106 FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SN1) 107 CPU_ADDR(%g5, %g6) 108 ldn [%g5 + CPU_MPCB], %g6 109 stn %sp, [%g6 + MPCB_SPBUF] 110 ldn [%g6 + MPCB_WBUF], %g5 111 SAVE_V8WINDOW(%g5) 112 mov 1, %g5 113 st %g5, [%g6 + MPCB_WBCNT] 114 saved 115 set sys_trap, %g5 116 wrpr %g5, %tnpc 117 done 118 SET_SIZE(fault_32bit_sn1) 119 120 ENTRY_NP(fault_32bit_so0) 121 ! 122 FAULT_WINTRACE(%g5, %g6, %g1, TT_F32_SO0) 123 ! 124 ! Spill other tl0 fault. 125 ! This happens when the kernel spills a user window and that 126 ! user's stack has been unmapped. 127 ! We handle it by spilling the window into the user's wbuf. 128 ! 129 ! find lwp & increment wbcnt 130 ! 131 CPU_ADDR(%g5, %g6) 132 ldn [%g5 + CPU_MPCB], %g1 133 ld [%g1 + MPCB_WBCNT], %g2 134 add %g2, 1, %g3 135 st %g3, [%g1 + MPCB_WBCNT] 136 ! 137 ! use previous wbcnt to spill new spbuf & wbuf 138 ! 139 sll %g2, CPTRSHIFT, %g4 ! spbuf size is sizeof (caddr_t) 140 add %g1, MPCB_SPBUF, %g3 141 stn %sp, [%g3 + %g4] 142 sll %g2, RWIN32SHIFT, %g4 143 ldn [%g1 + MPCB_WBUF], %g3 144 add %g3, %g4, %g3 145 SAVE_V8WINDOW(%g3) 146 saved 147 retry 148 SET_SIZE(fault_32bit_so0) 149 150 ! 151 ! Spill other tl1 fault. 152 ! This happens when priv_trap spills a user window and that 153 ! user's stack has been unmapped. 154 ! We handle it by spilling the window to the wbuf and retrying 155 ! the save. 156 ! 157 ENTRY_NP(fault_32bit_so1) 158 FAULT_WINTRACE(%g5, %g6, %g7, TT_F32_SO1) 159 CPU_ADDR(%g5, %g6) 160 ! 161 ! find lwp & increment wbcnt 162 ! 163 ldn [%g5 + CPU_MPCB], %g6 164 ld [%g6 + MPCB_WBCNT], %g5 165 add %g5, 1, %g7 166 st %g7, [%g6 + MPCB_WBCNT] 167 ! 168 ! use previous wbcnt to spill new spbuf & wbuf 169 ! 170 sll %g5, CPTRSHIFT, %g7 ! spbuf size is sizeof (caddr_t) 171 add %g6, %g7, %g7 172 stn %sp, [%g7 + MPCB_SPBUF] 173 sll %g5, RWIN32SHIFT, %g7 174 ldn [%g6 + MPCB_WBUF], %g5 175 add %g5, %g7, %g7 176 SAVE_V8WINDOW(%g7) 177 saved 178 set sys_trap, %g5 179 wrpr %g5, %tnpc 180 done 181 SET_SIZE(fault_32bit_so1) 182 183 ENTRY_NP(fault_64bit_sn0) 184 ! 185 FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_SN0) 186 ! 187 ! Spill normal tl0 fault. 188 ! This happens when a user tries to spill to an unmapped or 189 ! misaligned stack. We handle an unmapped stack by simulating 190 ! a pagefault at the trap pc and a misaligned stack by generating 191 ! a user alignment trap. 192 ! 193 ! spill the window into wbuf slot 0 194 ! (we know wbuf is empty since we came from user mode) 195 ! 196 ! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or 197 ! sfar (g5 == T_ALIGNMENT) 198 ! 199 CPU_ADDR(%g4, %g1) 200 ldn [%g4 + CPU_MPCB], %g1 201 stn %sp, [%g1 + MPCB_SPBUF] 202 ldn [%g1 + MPCB_WBUF], %g2 203 SAVE_V9WINDOW(%g2) 204 mov 1, %g2 205 st %g2, [%g1 + MPCB_WBCNT] 206 saved 207 ! 208 ! setup user_trap args 209 ! 210 set sfmmu_tsbmiss_exception, %g1 211 mov %g6, %g2 ! arg2 = tagaccess 212 mov %g5, %g3 ! arg3 = traptype 213 cmp %g5, T_ALIGNMENT 214 bne %icc, 1f 215 nop 216 set trap, %g1 217 mov T_ALIGNMENT, %g3 218 1: 219 sub %g0, 1, %g4 220 ! 221 ! spill traps increment %cwp by 2, 222 ! but user_trap wants the trap %cwp 223 ! 224 rdpr %tstate, %g5 225 and %g5, TSTATE_CWP, %g5 226 ba,pt %xcc, user_trap 227 wrpr %g0, %g5, %cwp 228 SET_SIZE(fault_64bit_sn0) 229 230 ! 231 ! Spill normal tl1 fault. 232 ! This happens when sys_trap's save spills to an unmapped stack. 233 ! We handle it by spilling the window to the wbuf and trying 234 ! sys_trap again. 235 ! 236 ! spill the window into wbuf slot 0 237 ! (we know wbuf is empty since we came from user mode) 238 ! 239 ENTRY_NP(fault_64bit_sn1) 240 FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SN1) 241 CPU_ADDR(%g5, %g6) 242 ldn [%g5 + CPU_MPCB], %g6 243 stn %sp, [%g6 + MPCB_SPBUF] 244 ldn [%g6 + MPCB_WBUF], %g5 245 SAVE_V9WINDOW(%g5) 246 mov 1, %g5 247 st %g5, [%g6 + MPCB_WBCNT] 248 saved 249 set sys_trap, %g5 250 wrpr %g5, %tnpc 251 done 252 SET_SIZE(fault_64bit_sn1) 253 254 ENTRY_NP(fault_64bit_so0) 255 ! 256 FAULT_WINTRACE(%g5, %g6, %g1, TT_F64_SO0) 257 ! 258 ! Spill other tl0 fault. 259 ! This happens when the kernel spills a user window and that 260 ! user's stack has been unmapped. 261 ! We handle it by spilling the window into the user's wbuf. 262 ! 263 ! find lwp & increment wbcnt 264 ! 265 CPU_ADDR(%g5, %g6) 266 ldn [%g5 + CPU_MPCB], %g1 267 ld [%g1 + MPCB_WBCNT], %g2 268 add %g2, 1, %g3 269 st %g3, [%g1 + MPCB_WBCNT] 270 ! 271 ! use previous wbcnt to spill new spbuf & wbuf 272 ! 273 sll %g2, CPTRSHIFT, %g4 ! spbuf size is sizeof (caddr_t) 274 add %g1, MPCB_SPBUF, %g3 275 stn %sp, [%g3 + %g4] 276 sll %g2, RWIN64SHIFT, %g4 277 ldn [%g1 + MPCB_WBUF], %g3 278 add %g3, %g4, %g3 279 SAVE_V9WINDOW(%g3) 280 saved 281 retry 282 SET_SIZE(fault_64bit_so0) 283 284 ! 285 ! Spill other tl1 fault. 286 ! This happens when priv_trap spills a user window and that 287 ! user's stack has been unmapped. 288 ! We handle it by spilling the window to the wbuf and retrying 289 ! the save. 290 ! 291 ENTRY_NP(fault_64bit_so1) 292 FAULT_WINTRACE(%g5, %g6, %g7, TT_F64_SO1) 293 CPU_ADDR(%g5, %g6) 294 ! 295 ! find lwp & increment wbcnt 296 ! 297 ldn [%g5 + CPU_MPCB], %g6 298 ld [%g6 + MPCB_WBCNT], %g5 299 add %g5, 1, %g7 300 st %g7, [%g6 + MPCB_WBCNT] 301 ! 302 ! use previous wbcnt to spill new spbuf & wbuf 303 ! 304 sll %g5, CPTRSHIFT, %g7 ! spbuf size is sizeof (caddr_t) 305 add %g6, %g7, %g7 306 stn %sp, [%g7 + MPCB_SPBUF] 307 sll %g5, RWIN64SHIFT, %g7 308 ldn [%g6 + MPCB_WBUF], %g5 309 add %g5, %g7, %g7 310 SAVE_V9WINDOW(%g7) 311 saved 312 set sys_trap, %g5 313 wrpr %g5, %tnpc 314 done 315 SET_SIZE(fault_64bit_so1) 316 317 /* 318 * Fill fault handlers 319 * fn0 - fill normal tl 0 320 * fn1 - fill normal tl 1 321 */ 322 323 ENTRY_NP(fault_32bit_fn0) 324 ! 325 FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN0) 326 ! 327 .fault_fn0_common: 328 ! 329 ! Fill normal tl0 fault. 330 ! This happens when a user tries to fill to an unmapped or 331 ! misaligned stack. We handle an unmapped stack by simulating 332 ! a pagefault at the trap pc and a misaligned stack by generating 333 ! a user alignment trap. 334 ! 335 ! setup user_trap args 336 ! 337 ! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or 338 ! sfar (g5 == T_ALIGNMENT) 339 ! 340 set sfmmu_tsbmiss_exception, %g1 341 mov %g6, %g2 ! arg2 = tagaccess 342 mov T_WIN_UNDERFLOW, %g3 343 cmp %g5, T_ALIGNMENT 344 bne %icc, 1f 345 nop 346 set trap, %g1 347 mov T_ALIGNMENT, %g3 348 1: 349 sub %g0, 1, %g4 350 ! 351 ! sys_trap wants %cwp to be the same as when the trap occured, 352 ! so set it from %tstate 353 ! 354 rdpr %tstate, %g5 355 and %g5, TSTATE_CWP, %g5 356 ba,pt %xcc, user_trap 357 wrpr %g0, %g5, %cwp 358 SET_SIZE(fault_32bit_fn0) 359 360 ENTRY_NP(fault_32bit_fn1) 361 ! 362 FAULT_WINTRACE(%g1, %g2, %g3, TT_F32_FN1) 363 ! 364 .fault_fn1_common: 365 ! 366 ! Fill normal tl1 fault. 367 ! This happens when user_rtt's restore fills from an unmapped or 368 ! misaligned stack. We handle an unmapped stack by simulating 369 ! a pagefault at user_rtt and a misaligned stack by generating 370 ! a RTT alignment trap. 371 ! 372 ! save fault addr & fix %cwp 373 ! 374 rdpr %tstate, %g1 375 and %g1, TSTATE_CWP, %g1 376 wrpr %g0, %g1, %cwp 377 ! 378 ! fake tl1 traps regs so that after pagefault runs, we 379 ! re-execute at user_rtt. 380 ! 381 wrpr %g0, 1, %tl 382 set TSTATE_KERN | TSTATE_IE, %g1 383 wrpr %g0, %g1, %tstate 384 set user_rtt, %g1 385 wrpr %g0, %g1, %tpc 386 add %g1, 4, %g1 387 wrpr %g0, %g1, %tnpc 388 ! 389 ! setup sys_trap args 390 ! 391 ! g5 = mmu trap type, g6 = tag access reg (g5 != T_ALIGNMENT) or 392 ! sfar (g5 == T_ALIGNMENT) 393 ! 394 set sfmmu_tsbmiss_exception, %g1 395 mov %g6, %g2 ! arg2 = tagaccess 396 set T_USER | T_SYS_RTT_PAGE, %g3 ! arg3 = traptype 397 cmp %g5, T_ALIGNMENT 398 bne %icc, 1f 399 nop 400 set trap, %g1 401 set T_USER | T_SYS_RTT_ALIGN, %g3 402 1: 403 sub %g0, 1, %g4 404 ! 405 ! setup to run kernel again by setting THREAD_REG, %wstate 406 ! and the mmu to their kernel values. 407 ! 408 rdpr %pstate, %l1 409 wrpr %l1, PSTATE_AG, %pstate 410 mov %l6, THREAD_REG ! %l6 is user_rtt's thread 411 wrpr %g0, %l1, %pstate 412 rdpr %wstate, %l1 413 sllx %l1, WSTATE_SHIFT, %l1 414 wrpr %l1, WSTATE_K64, %wstate 415 sethi %hi(kcontextreg), %g5 ! mov KCONTEXT, %g5 416 ldx [%g5 + %lo(kcontextreg)], %g5 417 mov MMU_PCONTEXT, %g6 418 ldxa [%g6]ASI_MMU_CTX, %g7 419 xor %g5, %g7, %g7 420 srlx %g7, CTXREG_NEXT_SHIFT, %g7 421 brz %g7, 1f ! if N_pgsz0/1 changed, need demap 422 nop 423 mov DEMAP_ALL_TYPE, %g7 424 stxa %g0, [%g7]ASI_DTLB_DEMAP 425 stxa %g0, [%g7]ASI_ITLB_DEMAP 426 1: 427 stxa %g5, [%g6]ASI_MMU_CTX 428 sethi %hi(FLUSH_ADDR), %g5 429 flush %g5 430 431 ba,pt %xcc, priv_trap 432 nop 433 SET_SIZE(fault_32bit_fn1) 434 435 ENTRY_NP(fault_64bit_fn0) 436 FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN0) 437 b .fault_fn0_common 438 nop 439 SET_SIZE(fault_64bit_fn0) 440 441 ENTRY_NP(fault_64bit_fn1) 442 FAULT_WINTRACE(%g1, %g2, %g3, TT_F64_FN1) 443 b .fault_fn1_common 444 nop 445 SET_SIZE(fault_64bit_fn1) 446 447 /* 448 * Kernel fault handlers 449 */ 450 ENTRY_NP(fault_32bit_not) 451 ENTRY_NP(fault_64bit_not) 452 ba,pt %xcc, ptl1_panic 453 mov PTL1_BAD_WTRAP, %g1 454 SET_SIZE(fault_32bit_not) 455 SET_SIZE(fault_64bit_not) 456 #endif /* !lint */