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 */