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)