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