xref: /netbsd/sys/arch/powerpc/powerpc/locore_subr.S (revision c4a72b64)
1/*	$NetBSD: locore_subr.S,v 1.5 2002/07/28 07:05:06 chs Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * NOTICE: This is not a standalone file.  to use it, #include it in
36 * your port's locore.S, like so:
37 *
38 *	#include <powerpc/powerpc/locore_subr.S>
39 */
40
41	.data
42GLOBAL(powersave)
43	.long	-1
44
45	.text
46/*
47 * No processes are runnable, so loop waiting for one.
48 * Separate label here for accounting purposes.
49 * When we get here, interrupts are off (MSR[EE]=0) and sched_lock is held.
50 */
51ASENTRY(Idle)
52	lis	8,_C_LABEL(sched_whichqs)@ha
53	lwz	9,_C_LABEL(sched_whichqs)@l(8)
54
55	or.	9,9,9
56	bne+	.Lsw1			/* at least one queue non-empty */
57
58#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
59	bl	_C_LABEL(sched_unlock_idle)
60#endif
61
62	mfmsr	3
63	ori	3,3,PSL_EE@l		/* reenable ints again */
64	mtmsr	3
65	isync
66
67/* Check if we can use power saving mode */
68	lis	8,_C_LABEL(powersave)@ha
69	lwz	9,_C_LABEL(powersave)@l(8)
70
71	add.	9,9,9
72	ble	1f
73
74	sync
75	oris	3,3,PSL_POW@h		/* enter power saving mode */
76	mtmsr	3
77	isync
781:
79	andi.	3,3,~PSL_EE@l		/* disable interrupts while
80					   manipulating runque */
81	mtmsr	3
82#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
83	bl	_C_LABEL(sched_lock_idle)
84#endif
85	b	_ASM_LABEL(Idle)
86
87/*
88 * switchexit gets called from cpu_exit to complete the exit procedure.
89 */
90ENTRY(switchexit)
91/* First switch to the idle pcb/kernel stack */
92#if defined(MULTIPROCESSOR)
93	GET_CPUINFO(7)
94	lwz	6,CI_IDLE_PCB(7)
95	stw	6,CI_CURPCB(7)
96#else
97	lis	6,idle_u@ha
98	lwz	6,idle_u@l(6)
99	lis	7,_C_LABEL(curpcb)@ha
100	stw	6,_C_LABEL(curpcb)@l(7)
101#endif
102	addi	1,6,USPACE-16		/* 16 bytes are reserved at stack top */
103	/*
104	 * Schedule the vmspace and stack to be freed (the proc arg is
105	 * already in r3).
106	 */
107	bl	_C_LABEL(exit2)
108
109#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
110	bl	_C_LABEL(sched_lock_idle)
111#endif
112
113/* Fall through to cpu_switch to actually select another proc */
114	li	3,0			/* indicate exited process */
115
116/*
117 * void cpu_switch(struct proc *p)
118 * Find a runnable process and switch to it.
119 */
120ENTRY_NOPROFILE(cpu_switch)
121	mflr	0			/* save lr */
122	stw	0,4(1)
123	stwu	1,-16(1)
124	stw	31,12(1)
125	stw	30,8(1)
126
127	mr	30,3
128#if defined(MULTIPROCESSOR)
129	/* Switch to the idle PCB unless we're already running on it. */
130	GET_CPUINFO(7)
131	cmpwi	30,0			/* old process was exiting? */
132	beq	1f
133
134	mfsr	10,USER_SR		/* save USER_SR for copyin/copyout */
135	mfcr	11			/* save cr */
136	mr	12,2			/* save r2 */
137	stwu	1,-SFRAMELEN(1)		/* still running on old stack */
138	stmw	10,8(1)
139	lwz	3,P_ADDR(30)
140	stw	1,PCB_SP(3)		/* save SP */
141
142	lwz	6,CI_IDLE_PCB(7)
143	addi	1,6,USPACE-16		/* 16 bytes are reserved at stack top */
144
1451:
146	xor	31,31,31
147	stw	31,CI_CURPROC(7)	/* Zero to not accumulate cpu time */
148	lwz	31,CI_CURPCB(7)
149
150	lwz	3,CI_CPL(7)
151	stw	3,PCB_SPL(31)		/* save spl */
152#else
153	lis	3,_C_LABEL(curproc)@ha
154	xor	31,31,31
155	stw	31,_C_LABEL(curproc)@l(3) /* Zero to not accumulate cpu time */
156	lis	3,_C_LABEL(curpcb)@ha
157	lwz	31,_C_LABEL(curpcb)@l(3)
158#endif
159
160#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
161/* Release the sched_lock before processing interrupts. */
162	bl	_C_LABEL(sched_unlock_idle)
163#endif
164
165	xor	3,3,3			/* spl0() */
166	bl	_C_LABEL(lcsplx)
167#if !defined(MULTIPROCESSOR)
168	stw	3,PCB_SPL(31)		/* save spl */
169#endif
170
171/* Lock the scheduler. */
172	mfmsr	3
173	andi.	3,3,~PSL_EE@l		/* disable interrupts while
174					   manipulating runque */
175	mtmsr	3
176	isync
177#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
178	bl	_C_LABEL(sched_lock_idle)
179#endif
180
181/* Find a new process */
182	lis	8,_C_LABEL(sched_whichqs)@ha
183	lwz	9,_C_LABEL(sched_whichqs)@l(8)
184
185	or.	9,9,9
186	beq-	_ASM_LABEL(Idle)	/* all queues empty */
187.Lsw1:
188	cntlzw	10,9
189	lis	4,_C_LABEL(sched_qs)@ha
190	addi	4,4,_C_LABEL(sched_qs)@l
191	slwi	3,10,3
192	add	3,3,4			/* select queue */
193
194	lwz	31,P_FORW(3)		/* unlink first proc from queue */
195	lwz	4,P_FORW(31)
196	stw	4,P_FORW(3)
197	stw	3,P_BACK(4)
198
199	cmpl	0,3,4			/* queue empty? */
200	bne	1f
201
202	lis	3,0x80000000@h
203	srw	3,3,10
204	andc	9,9,3
205	stw	9,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */
206
2071:
208	/* just did this resched thing */
209	xor	3,3,3
210#if defined(MULTIPROCESSOR)
211	GET_CPUINFO(4)
212	stw	3,CI_WANT_RESCHED(4)
213#else
214	lis	4,_C_LABEL(want_resched)@ha
215	stw	3,_C_LABEL(want_resched)@l(4)
216#endif
217
218	stw	3,P_BACK(31)		/* probably superfluous */
219
220#if defined(MULTIPROCESSOR)
221	GET_CPUINFO(4)
222	stw	4,P_CPU(31)		/* p->p_cpu = curcpu() */
223#endif
224
225	/* Process now running on a processor. */
226	li	3,SONPROC		/* p->p_stat = SONPROC */
227	stb	3,P_STAT(31)
228
229	/* record new process */
230#if defined(MULTIPROCESSOR)
231	stw	31,CI_CURPROC(4)
232#else
233	lis	4,_C_LABEL(curproc)@ha
234	stw	31,_C_LABEL(curproc)@l(4)
235#endif
236	lwz	4,P_ADDR(31)
237
238#if !defined(MULTIPROCESSOR)		/* XXX */
239	cmpl	0,31,30			/* is it the same process? */
240	beq	switch_return
241
242	or.	30,30,30		/* old process was exiting? */
243	beq	switch_exited
244
245	mfsr	10,USER_SR		/* save USER_SR for copyin/copyout */
246	mfcr	11			/* save cr */
247	mr	12,2			/* save r2 */
248	stwu	1,-SFRAMELEN(1)		/* still running on old stack */
249	stmw	10,8(1)
250	lwz	3,P_ADDR(30)
251	stw	1,PCB_SP(3)		/* save SP */
252
253switch_exited:
254#endif
255
256	/* indicate new pcb */
257#if defined(MULTIPROCESSOR)
258	GET_CPUINFO(6)
259	stw	4,CI_CURPCB(6)
260#else
261	lis	5,_C_LABEL(curpcb)@ha
262	stw	4,_C_LABEL(curpcb)@l(5)
263#endif
264
265	/* save real pmap pointer for spill fill */
266	lwz	5,PCB_PMR(4)
267#if defined(MULTIPROCESSOR)
268	stwu	5,CI_CURPM(6)
269#else
270	lis	6,_C_LABEL(curpm)@ha
271	stwu	5,_C_LABEL(curpm)@l(6)
272#endif
273	stwcx.	5,0,6			/* clear possible reservation */
274	isync
275
276	lwz	1,PCB_SP(4)		/* get new procs SP */
277	lmw	10,8(1)			/* get other regs */
278	lwz	1,0(1)			/* get saved SP */
279	mr	2,12			/* get saved r2 */
280	mtcr	11			/* get saved cr */
281	isync
282	mtsr	USER_SR,10		/* get saved USER_SR */
283	isync
284
285switch_return:
286#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
287	/* Unlock the sched_lock, but leave interrupts off, for now. */
288	bl	_C_LABEL(sched_unlock_idle)
289#endif
290
291	mfmsr	3
292	ori	3,3,PSL_EE@l		/* interrupts are okay again */
293	mtmsr	3
294
295	mr	30,7			/* save proc pointer */
296	lwz	3,PCB_SPL(4)
297	bl	_C_LABEL(lcsplx)
298
299	mr	3,30			/* get curproc for special fork
300					   returns */
301
302	lwz	31,12(1)
303	lwz	30,8(1)
304	addi	1,1,16
305	lwz	0,4(1)
306	mtlr	0
307	blr
308
309/*
310 * Child comes here at the end of a fork.
311 * Return to userspace via the trap return path.
312 */
313	.globl	_C_LABEL(fork_trampoline)
314_C_LABEL(fork_trampoline):
315#if defined(MULTIPROCESSOR)
316	bl	_C_LABEL(proc_trampoline_mp)
317#endif
318	xor	3,3,3
319	bl	_C_LABEL(lcsplx)
320	mtlr	31
321	mr	3,30
322	blrl				/* jump indirect to r31 */
323	b	trapexit
324
325/*
326 * int setfault()
327 *
328 * Similar to setjmp to setup for handling faults on accesses to user memory.
329 * Any routine using this may only call bcopy, either the form below,
330 * or the (currently used) C code optimized, so it doesn't use any non-volatile
331 * registers.
332 */
333	.globl	_C_LABEL(setfault)
334_C_LABEL(setfault):
335	mflr	0
336	mfcr	12
337#if defined(MULTIPROCESSOR)
338	GET_CPUINFO(4)
339	lwz	4,CI_CURPCB(4)
340#else
341	lis	4,_C_LABEL(curpcb)@ha
342	lwz	4,_C_LABEL(curpcb)@l(4)
343#endif
344	stw	3,PCB_FAULT(4)
345	stw	0,0(3)
346	stw	1,4(3)
347	stw	2,8(3)
348	stmw	12,12(3)
349	xor	3,3,3
350	blr
351