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 (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24  
  25 /*
  26  * Process switching routines.
  27  */
  28 
  29 #include "assym.h"
  30 
  31 #include <sys/param.h>
  32 #include <sys/asm_linkage.h>
  33 #include <sys/mmu.h>
  34 #include <sys/pcb.h>
  35 #include <sys/machthread.h>
  36 #include <sys/machclock.h>
  37 #include <sys/privregs.h>
  38 #include <sys/vtrace.h>
  39 #include <vm/hat_sfmmu.h>
  40 
  41 /*
  42  * resume(kthread_id_t)
  43  *
  44  * a thread can only run on one processor at a time. there
  45  * exists a window on MPs where the current thread on one
  46  * processor is capable of being dispatched by another processor.
  47  * some overlap between outgoing and incoming threads can happen
  48  * when they are the same thread. in this case where the threads
  49  * are the same, resume() on one processor will spin on the incoming 
  50  * thread until resume() on the other processor has finished with
  51  * the outgoing thread.
  52  *
  53  * The MMU context changes when the resuming thread resides in a different
  54  * process.  Kernel threads are known by resume to reside in process 0.
  55  * The MMU context, therefore, only changes when resuming a thread in
  56  * a process different from curproc.
  57  *
  58  * resume_from_intr() is called when the thread being resumed was not 
  59  * passivated by resume (e.g. was interrupted).  This means that the
  60  * resume lock is already held and that a restore context is not needed.
  61  * Also, the MMU context is not changed on the resume in this case.
  62  *
  63  * resume_from_zombie() is the same as resume except the calling thread
  64  * is a zombie and must be put on the deathrow list after the CPU is
  65  * off the stack.
  66  */
  67 
  68         ENTRY(resume)
  69         save    %sp, -SA(MINFRAME), %sp         ! save ins and locals
  70 
  71         call    __dtrace_probe___sched_off__cpu ! DTrace probe
  72         mov     %i0, %o0                        ! arg for DTrace probe
  73 
  74         membar  #Sync                           ! flush writebuffers
  75         flushw                                  ! flushes all but this window
  76 
  77         stn     %i7, [THREAD_REG + T_PC]        ! save return address
  78         stn     %fp, [THREAD_REG + T_SP]        ! save sp
  79 
  80         !
  81         ! Save GSR (Graphics Status Register).
  82         !
  83         ! Read fprs, call fp_save if FPRS_FEF set.
  84         ! This handles floating-point state saving.
  85         ! The fprs could be turned on by hw bcopy software,
  86         ! *or* by fp_disabled. Handle it either way.
  87         !
  88         ldn     [THREAD_REG + T_LWP], %o4       ! get lwp pointer
  89         rd      %fprs, %g4                      ! read fprs
  90         brnz,pt %o4, 0f                         ! if user thread skip
  91           ldn   [THREAD_REG + T_CPU], %i1       ! get CPU pointer
  92 
  93         !
  94         ! kernel thread
  95         !       
  96         ! we save fprs at the beginning the stack so we know
  97         ! where to check at resume time
  98         ldn     [THREAD_REG + T_STACK], %i2
  99         ldn     [THREAD_REG + T_CTX], %g3       ! get ctx pointer
 100         andcc   %g4, FPRS_FEF, %g0              ! is FPRS_FEF set
 101         bz,pt   %icc, 1f                        ! nope, skip
 102           st    %g4, [%i2 + SA(MINFRAME) + FPU_FPRS]    ! save fprs
 103           
 104         ! save kernel fp state in stack
 105         add     %i2, SA(MINFRAME), %o0          ! o0 = kfpu_t ptr
 106         rd      %gsr, %g5
 107         call    fp_save
 108         stx     %g5, [%o0 + FPU_GSR]            ! store GSR
 109         ba,a,pt %icc, 1f
 110           nop
 111 
 112 0:
 113         ! user thread
 114         ! o4 = lwp ptr
 115         ! g4 = fprs
 116         ! i1 = CPU ptr
 117         ldn     [%o4 + LWP_FPU], %o0            ! fp pointer
 118         stn     %fp, [THREAD_REG + T_SP]        ! save sp
 119         andcc   %g4, FPRS_FEF, %g0              ! is FPRS_FEF set
 120         st      %g4, [%o0 + FPU_FPRS]           ! store FPRS
 121 #if defined(DEBUG) || defined(NEED_FPU_EXISTS)
 122         sethi   %hi(fpu_exists), %g5
 123         ld      [%g5 + %lo(fpu_exists)], %g5
 124         brz,pn  %g5, 1f
 125           ldn   [THREAD_REG + T_CTX], %g3       ! get ctx pointer
 126 #endif
 127         bz,pt   %icc, 1f                        ! most apps don't use fp
 128           ldn   [THREAD_REG + T_CTX], %g3       ! get ctx pointer
 129         ldn     [%o4 + LWP_FPU], %o0            ! fp pointer
 130         rd      %gsr, %g5
 131         call    fp_save                         ! doesn't touch globals
 132         stx     %g5, [%o0 + FPU_GSR]            ! store GSR
 133 1:
 134         !
 135         ! Perform context switch callback if set.
 136         ! This handles coprocessor state saving.
 137         ! i1 = cpu ptr
 138         ! g3 = ctx pointer
 139         !
 140         wr      %g0, %g0, %fprs                 ! disable fpu and clear fprs
 141         brz,pt  %g3, 2f                         ! skip call when zero
 142         ldn     [%i0 + T_PROCP], %i3            ! delay slot - get proc pointer
 143         call    savectx
 144         mov     THREAD_REG, %o0                 ! delay - arg = thread pointer
 145 2:
 146         ldn     [THREAD_REG + T_PROCP], %i2     ! load old curproc - for mmu
 147 
 148         !
 149         ! Temporarily switch to idle thread's stack
 150         !
 151         ldn     [%i1 + CPU_IDLE_THREAD], %o0    ! idle thread pointer
 152         ldn     [%o0 + T_SP], %o1               ! get onto idle thread stack
 153         sub     %o1, SA(MINFRAME), %sp          ! save room for ins and locals
 154         clr     %fp
 155 
 156         !
 157         ! Set the idle thread as the current thread
 158         !
 159         mov     THREAD_REG, %l3                 ! save %g7 (current thread)
 160         mov     %o0, THREAD_REG                 ! set %g7 to idle
 161         stn     %o0, [%i1 + CPU_THREAD]         ! set CPU's thread to idle
 162 
 163         !
 164         ! Clear and unlock previous thread's t_lock
 165         ! to allow it to be dispatched by another processor.
 166         !
 167         clrb    [%l3 + T_LOCK]                  ! clear tp->t_lock
 168 
 169         !
 170         ! IMPORTANT: Registers at this point must be:
 171         !       %i0 = new thread
 172         !       %i1 = cpu pointer
 173         !       %i2 = old proc pointer
 174         !       %i3 = new proc pointer
 175         !       
 176         ! Here we are in the idle thread, have dropped the old thread.
 177         ! 
 178         ALTENTRY(_resume_from_idle)
 179 
 180         ! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3)
 181         SET_KCONTEXTREG(%o0, %g1, %g2, %g3, %o3, l1, l2, l3)
 182 
 183         cmp     %i2, %i3                ! resuming the same process?
 184         be,pt   %xcc, 5f                ! yes.
 185           nop
 186 
 187         ldx     [%i3 + P_AS], %o0       ! load p->p_as
 188         ldx     [%o0 + A_HAT], %i5      ! %i5 = new proc hat
 189 
 190         !
 191         ! update cpusran field
 192         !
 193         ld      [%i1 + CPU_ID], %o4
 194         add     %i5, SFMMU_CPUSRAN, %o5
 195         CPU_INDEXTOSET(%o5, %o4, %g1)
 196         ldx     [%o5], %o2              ! %o2 = cpusran field
 197         mov     1, %g2
 198         sllx    %g2, %o4, %o4           ! %o4 = bit for this cpu
 199         andcc   %o4, %o2, %g0
 200         bnz,pn  %xcc, 0f                ! bit already set, go to 0
 201           nop
 202 3:
 203         or      %o2, %o4, %o1           ! or in this cpu's bit mask
 204         casx    [%o5], %o2, %o1
 205         cmp     %o2, %o1
 206         bne,a,pn %xcc, 3b
 207           ldx   [%o5], %o2              ! o2 = cpusran field
 208         membar  #LoadLoad|#StoreLoad
 209 
 210 0:
 211         ! 
 212         ! disable interrupts
 213         !
 214         ! if resume from user to kernel thread
 215         !       call sfmmu_setctx_sec
 216         ! if resume from kernel (or a different user) thread to user thread
 217         !       call sfmmu_alloc_ctx
 218         ! sfmmu_load_mmustate
 219         !
 220         ! enable interrupts
 221         !
 222         ! %i5 = new proc hat
 223         !
 224 
 225         sethi   %hi(ksfmmup), %o2
 226         ldx     [%o2 + %lo(ksfmmup)], %o2
 227 
 228         rdpr    %pstate, %i4
 229         cmp     %i5, %o2                ! new proc hat == ksfmmup ?
 230         bne,pt  %xcc, 3f                ! new proc is not kernel as, go to 3
 231           wrpr  %i4, PSTATE_IE, %pstate
 232 
 233         SET_KAS_CTXSEC_ARGS(%i5, %o0, %o1)
 234 
 235         ! new proc is kernel as
 236 
 237         call    sfmmu_setctx_sec                ! switch to kernel context
 238           or    %o0, %o1, %o0
 239         
 240         ba,a,pt %icc, 4f
 241 
 242         !
 243         ! Switch to user address space.
 244         !
 245 3:
 246         mov     %i5, %o0                        ! %o0 = sfmmup
 247         mov     %i1, %o2                        ! %o2 = CPU
 248         set     SFMMU_PRIVATE, %o3              ! %o3 = sfmmu private flag
 249         call    sfmmu_alloc_ctx
 250           mov   %g0, %o1                        ! %o1 = allocate flag = 0
 251 
 252         brz,a,pt %o0, 4f                        ! %o0 == 0, no private alloc'ed
 253           nop
 254 
 255         ldn     [%i5 + SFMMU_SCDP], %o0         ! using shared contexts?
 256         brz,a,pt %o0, 4f
 257           nop
 258 
 259         ldn   [%o0 + SCD_SFMMUP], %o0           ! %o0 = scdp->scd_sfmmup
 260         mov     %i1, %o2                        ! %o2 = CPU
 261         set     SFMMU_SHARED, %o3               ! %o3 = sfmmu shared flag
 262         call    sfmmu_alloc_ctx
 263           mov   1, %o1                          ! %o1 = allocate flag = 1
 264         
 265 4:
 266         call    sfmmu_load_mmustate             ! program MMU registers
 267           mov   %i5, %o0
 268 
 269         wrpr    %g0, %i4, %pstate               ! enable interrupts
 270         
 271 5:
 272         !
 273         ! spin until dispatched thread's mutex has
 274         ! been unlocked. this mutex is unlocked when
 275         ! it becomes safe for the thread to run.
 276         ! 
 277         ldstub  [%i0 + T_LOCK], %o0     ! lock curthread's t_lock
 278 6:
 279         brnz,pn %o0, 7f                 ! lock failed
 280           ldx   [%i0 + T_PC], %i7       ! delay - restore resuming thread's pc
 281 
 282         !
 283         ! Fix CPU structure to indicate new running thread.
 284         ! Set pointer in new thread to the CPU structure.
 285         ! XXX - Move migration statistic out of here
 286         !
 287         ldx     [%i0 + T_CPU], %g2      ! last CPU to run the new thread
 288         cmp     %g2, %i1                ! test for migration
 289         be,pt   %xcc, 4f                ! no migration
 290           ldn   [%i0 + T_LWP], %o1      ! delay - get associated lwp (if any)
 291         ldx     [%i1 + CPU_STATS_SYS_CPUMIGRATE], %g2
 292         inc     %g2
 293         stx     %g2, [%i1 + CPU_STATS_SYS_CPUMIGRATE]
 294         stx     %i1, [%i0 + T_CPU]      ! set new thread's CPU pointer
 295 4:
 296         stx     %i0, [%i1 + CPU_THREAD] ! set CPU's thread pointer
 297         membar  #StoreLoad              ! synchronize with mutex_exit()
 298         mov     %i0, THREAD_REG         ! update global thread register
 299         stx     %o1, [%i1 + CPU_LWP]    ! set CPU's lwp ptr
 300         brz,a,pn %o1, 1f                ! if no lwp, branch and clr mpcb
 301           stx   %g0, [%i1 + CPU_MPCB]
 302         !
 303         ! user thread
 304         ! o1 = lwp
 305         ! i0 = new thread
 306         !
 307         ldx     [%i0 + T_STACK], %o0
 308         stx     %o0, [%i1 + CPU_MPCB]   ! set CPU's mpcb pointer
 309 #ifdef CPU_MPCB_PA
 310         ldx     [%o0 + MPCB_PA], %o0
 311         stx     %o0, [%i1 + CPU_MPCB_PA]
 312 #endif
 313         ! Switch to new thread's stack
 314         ldx     [%i0 + T_SP], %o0       ! restore resuming thread's sp
 315         sub     %o0, SA(MINFRAME), %sp  ! in case of intr or trap before restore
 316         mov     %o0, %fp
 317         !
 318         ! Restore resuming thread's GSR reg and floating-point regs
 319         ! Note that the ld to the gsr register ensures that the loading of
 320         ! the floating point saved state has completed without necessity
 321         ! of a membar #Sync.
 322         !
 323 #if defined(DEBUG) || defined(NEED_FPU_EXISTS)
 324         sethi   %hi(fpu_exists), %g3
 325         ld      [%g3 + %lo(fpu_exists)], %g3
 326         brz,pn  %g3, 2f
 327           ldx   [%i0 + T_CTX], %i5      ! should resumed thread restorectx?
 328 #endif
 329         ldx     [%o1 + LWP_FPU], %o0            ! fp pointer
 330         ld      [%o0 + FPU_FPRS], %g5           ! get fpu_fprs
 331         andcc   %g5, FPRS_FEF, %g0              ! is FPRS_FEF set?
 332         bz,a,pt %icc, 9f                        ! no, skip fp_restore
 333           wr    %g0, FPRS_FEF, %fprs            ! enable fprs so fp_zero works
 334 
 335         ldx     [THREAD_REG + T_CPU], %o4       ! cpu pointer
 336         call    fp_restore
 337           wr    %g5, %g0, %fprs                 ! enable fpu and restore fprs
 338 
 339         ldx     [%o0 + FPU_GSR], %g5            ! load saved GSR data
 340         wr      %g5, %g0, %gsr                  ! restore %gsr data
 341         ba,pt   %icc,2f
 342           ldx   [%i0 + T_CTX], %i5      ! should resumed thread restorectx?
 343 
 344 9:
 345         !
 346         ! Zero resuming thread's fp registers, for *all* non-fp program
 347         ! Remove all possibility of using the fp regs as a "covert channel".
 348         !
 349         call    fp_zero
 350           wr    %g0, %g0, %gsr
 351         ldx     [%i0 + T_CTX], %i5      ! should resumed thread restorectx?
 352         ba,pt   %icc, 2f
 353           wr    %g0, %g0, %fprs                 ! disable fprs
 354 
 355 1:
 356 #ifdef CPU_MPCB_PA
 357         mov     -1, %o1
 358         stx     %o1, [%i1 + CPU_MPCB_PA]
 359 #endif
 360         !
 361         ! kernel thread
 362         ! i0 = new thread
 363         !
 364         ! Switch to new thread's stack
 365         !
 366         ldx     [%i0 + T_SP], %o0       ! restore resuming thread's sp
 367         sub     %o0, SA(MINFRAME), %sp  ! in case of intr or trap before restore
 368         mov     %o0, %fp
 369         !
 370         ! Restore resuming thread's GSR reg and floating-point regs
 371         ! Note that the ld to the gsr register ensures that the loading of
 372         ! the floating point saved state has completed without necessity
 373         ! of a membar #Sync.
 374         !
 375         ldx     [%i0 + T_STACK], %o0
 376         ld      [%o0 + SA(MINFRAME) + FPU_FPRS], %g5    ! load fprs
 377         ldx     [%i0 + T_CTX], %i5              ! should thread restorectx?
 378         andcc   %g5, FPRS_FEF, %g0              ! did we save fp in stack?
 379         bz,a,pt %icc, 2f
 380           wr    %g0, %g0, %fprs                 ! clr fprs
 381 
 382         wr      %g5, %g0, %fprs                 ! enable fpu and restore fprs
 383         call    fp_restore
 384         add     %o0, SA(MINFRAME), %o0          ! o0 = kpu_t ptr
 385         ldx     [%o0 + FPU_GSR], %g5            ! load saved GSR data
 386         wr      %g5, %g0, %gsr                  ! restore %gsr data
 387 
 388 2:
 389         !
 390         ! Restore resuming thread's context
 391         ! i5 = ctx ptr
 392         !
 393         brz,a,pt %i5, 8f                ! skip restorectx() when zero
 394           ld    [%i1 + CPU_BASE_SPL], %o0
 395         call    restorectx              ! thread can not sleep on temp stack
 396           mov   THREAD_REG, %o0         ! delay slot - arg = thread pointer
 397         !
 398         ! Set priority as low as possible, blocking all interrupt threads
 399         ! that may be active.
 400         !
 401         ld      [%i1 + CPU_BASE_SPL], %o0
 402 8:
 403         wrpr    %o0, 0, %pil
 404         wrpr    %g0, WSTATE_KERN, %wstate
 405         !
 406         ! If we are resuming an interrupt thread, store a starting timestamp
 407         ! in the thread structure.
 408         !
 409         lduh    [THREAD_REG + T_FLAGS], %o0
 410         andcc   %o0, T_INTR_THREAD, %g0
 411         bnz,pn  %xcc, 0f
 412           nop
 413 5:              
 414         call    __dtrace_probe___sched_on__cpu  ! DTrace probe
 415         nop
 416 
 417         ret                             ! resume curthread
 418         restore
 419 0:
 420         add     THREAD_REG, T_INTR_START, %o2
 421 1:      
 422         ldx     [%o2], %o1
 423         RD_CLOCK_TICK(%o0,%o3,%g5,__LINE__)
 424         casx    [%o2], %o1, %o0
 425         cmp     %o0, %o1
 426         be,pt   %xcc, 5b
 427           nop
 428         ! If an interrupt occurred while we were attempting to store
 429         ! the timestamp, try again.
 430         ba,pt   %xcc, 1b
 431           nop
 432 
 433         !
 434         ! lock failed - spin with regular load to avoid cache-thrashing.
 435         !
 436 7:
 437         brnz,a,pt %o0, 7b               ! spin while locked
 438           ldub  [%i0 + T_LOCK], %o0
 439         ba      %xcc, 6b
 440           ldstub  [%i0 + T_LOCK], %o0   ! delay - lock curthread's mutex
 441         SET_SIZE(_resume_from_idle)
 442         SET_SIZE(resume)
 443 
 444         ENTRY(resume_from_zombie)
 445         save    %sp, -SA(MINFRAME), %sp         ! save ins and locals
 446 
 447         call    __dtrace_probe___sched_off__cpu ! DTrace probe
 448         mov     %i0, %o0                        ! arg for DTrace probe
 449 
 450         ldn     [THREAD_REG + T_CPU], %i1       ! cpu pointer
 451                                         
 452         flushw                                  ! flushes all but this window
 453         ldn     [THREAD_REG + T_PROCP], %i2     ! old procp for mmu ctx
 454 
 455         !
 456         ! Temporarily switch to the idle thread's stack so that
 457         ! the zombie thread's stack can be reclaimed by the reaper.
 458         !
 459         ldn     [%i1 + CPU_IDLE_THREAD], %o2    ! idle thread pointer
 460         ldn     [%o2 + T_SP], %o1               ! get onto idle thread stack
 461         sub     %o1, SA(MINFRAME), %sp          ! save room for ins and locals
 462         clr     %fp
 463         !
 464         ! Set the idle thread as the current thread.
 465         ! Put the zombie on death-row.
 466         !       
 467         mov     THREAD_REG, %o0                 ! save %g7 = curthread for arg
 468         mov     %o2, THREAD_REG                 ! set %g7 to idle
 469         stn     %g0, [%i1 + CPU_MPCB]           ! clear mpcb
 470 #ifdef CPU_MPCB_PA
 471         mov     -1, %o1
 472         stx     %o1, [%i1 + CPU_MPCB_PA]
 473 #endif
 474         call    reapq_add                       ! reapq_add(old_thread);
 475         stn     %o2, [%i1 + CPU_THREAD]         ! delay - CPU's thread = idle
 476 
 477         !
 478         ! resume_from_idle args:
 479         !       %i0 = new thread
 480         !       %i1 = cpu
 481         !       %i2 = old proc
 482         !       %i3 = new proc
 483         !       
 484         b       _resume_from_idle               ! finish job of resume
 485         ldn     [%i0 + T_PROCP], %i3            ! new process
 486         SET_SIZE(resume_from_zombie)
 487 
 488         ENTRY(resume_from_intr)
 489         save    %sp, -SA(MINFRAME), %sp         ! save ins and locals
 490 
 491         !
 492         ! We read in the fprs and call fp_save if FPRS_FEF is set
 493         ! to save the floating-point state if fprs has been
 494         ! modified by operations such as hw bcopy or fp_disabled.
 495         ! This is to resolve an issue where an interrupting thread
 496         ! doesn't retain their floating-point registers when
 497         ! switching out of the interrupt context.
 498         !
 499         rd      %fprs, %g4
 500         ldn     [THREAD_REG + T_STACK], %i2
 501         andcc   %g4, FPRS_FEF, %g0              ! is FPRS_FEF set
 502         bz,pt   %icc, 4f
 503           st    %g4, [%i2 + SA(MINFRAME) + FPU_FPRS]    ! save fprs
 504 
 505         ! save kernel fp state in stack
 506         add     %i2, SA(MINFRAME), %o0          ! %o0 = kfpu_t ptr
 507         rd      %gsr, %g5
 508         call fp_save
 509         stx     %g5, [%o0 + FPU_GSR]            ! store GSR
 510 
 511 4:
 512 
 513         flushw                                  ! flushes all but this window
 514         stn     %fp, [THREAD_REG + T_SP]        ! delay - save sp
 515         stn     %i7, [THREAD_REG + T_PC]        ! save return address
 516 
 517         ldn     [%i0 + T_PC], %i7               ! restore resuming thread's pc
 518         ldn     [THREAD_REG + T_CPU], %i1       ! cpu pointer
 519 
 520         !
 521         ! Fix CPU structure to indicate new running thread.
 522         ! The pinned thread we're resuming already has the CPU pointer set.
 523         !
 524         mov     THREAD_REG, %l3         ! save old thread
 525         stn     %i0, [%i1 + CPU_THREAD] ! set CPU's thread pointer
 526         membar  #StoreLoad              ! synchronize with mutex_exit()
 527         mov     %i0, THREAD_REG         ! update global thread register
 528 
 529         !
 530         ! Switch to new thread's stack
 531         !
 532         ldn     [THREAD_REG + T_SP], %o0        ! restore resuming thread's sp
 533         sub     %o0, SA(MINFRAME), %sp ! in case of intr or trap before restore
 534         mov     %o0, %fp
 535         clrb    [%l3 + T_LOCK]          ! clear intr thread's tp->t_lock
 536 
 537         !
 538         ! If we are resuming an interrupt thread, store a timestamp in the
 539         ! thread structure.
 540         !
 541         lduh    [THREAD_REG + T_FLAGS], %o0
 542         andcc   %o0, T_INTR_THREAD, %g0
 543         bnz,pn  %xcc, 0f
 544         !
 545         ! We're resuming a non-interrupt thread.
 546         ! Clear CPU_INTRCNT and check if cpu_kprunrun set?
 547         !
 548         ldub    [%i1 + CPU_KPRUNRUN], %o5       ! delay
 549         brnz,pn %o5, 3f                         ! call kpreempt(KPREEMPT_SYNC);
 550         stub    %g0, [%i1 + CPU_INTRCNT]
 551 1:
 552         ret                             ! resume curthread
 553         restore
 554 0:
 555         !
 556         ! We're an interrupt thread. Update t_intr_start and cpu_intrcnt
 557         !
 558         add     THREAD_REG, T_INTR_START, %o2
 559 2:
 560         ldx     [%o2], %o1
 561         RD_CLOCK_TICK(%o0,%o3,%l1,__LINE__)
 562         casx    [%o2], %o1, %o0
 563         cmp     %o0, %o1
 564         bne,pn  %xcc, 2b
 565         ldn     [THREAD_REG + T_INTR], %l1      ! delay
 566         ! Reset cpu_intrcnt if we aren't pinning anyone
 567         brz,a,pt %l1, 2f
 568         stub    %g0, [%i1 + CPU_INTRCNT]
 569 2:      
 570         ba,pt   %xcc, 1b
 571         nop
 572 3:
 573         !
 574         ! We're a non-interrupt thread and cpu_kprunrun is set. call kpreempt.
 575         !
 576         call    kpreempt
 577         mov     KPREEMPT_SYNC, %o0
 578         ba,pt   %xcc, 1b
 579         nop
 580         SET_SIZE(resume_from_intr)
 581 
 582 
 583 /*
 584  * thread_start()
 585  *
 586  * the current register window was crafted by thread_run() to contain
 587  * an address of a procedure (in register %i7), and its args in registers
 588  * %i0 through %i5. a stack trace of this thread will show the procedure
 589  * that thread_start() invoked at the bottom of the stack. an exit routine
 590  * is stored in %l0 and called when started thread returns from its called
 591  * procedure.
 592  */
 593 
 594         ENTRY(thread_start)
 595         mov     %i0, %o0
 596         jmpl    %i7, %o7        ! call thread_run()'s start() procedure.
 597         mov     %i1, %o1
 598 
 599         call    thread_exit     ! destroy thread if it returns.
 600         nop
 601         unimp 0
 602         SET_SIZE(thread_start)