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