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