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