xref: /netbsd/sys/arch/powerpc/powerpc/locore_subr.S (revision bf9ec67e)
1/*	$NetBSD: locore_subr.S,v 1.2 2001/02/28 20:44:41 tsubai 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	0
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	or.	9,9,9
72	beq	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
83#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
84	bl	_C_LABEL(sched_lock_idle)
85#endif
86	b	_ASM_LABEL(Idle)
87
88/*
89 * switchexit gets called from cpu_exit to complete the exit procedure.
90 */
91ENTRY(switchexit)
92/* First switch to the idle pcb/kernel stack */
93#if defined(MULTIPROCESSOR)
94	GET_CPUINFO(7)
95	lwz	6,CI_IDLE_PCB(7)
96	stw	6,CI_CURPCB(7)
97#else
98	lis	6,idle_u@ha
99	lwz	6,idle_u@l(6)
100	lis	7,_C_LABEL(curpcb)@ha
101	stw	6,_C_LABEL(curpcb)@l(7)
102#endif
103	addi	1,6,USPACE-16		/* 16 bytes are reserved at stack top */
104	/*
105	 * Schedule the vmspace and stack to be freed (the proc arg is
106	 * already in r3).
107	 */
108	bl	_C_LABEL(exit2)
109
110#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
111	bl	_C_LABEL(sched_lock_idle)
112#endif
113
114/* Fall through to cpu_switch to actually select another proc */
115	li	3,0			/* indicate exited process */
116
117/*
118 * void cpu_switch(struct proc *p)
119 * Find a runnable process and switch to it.
120 */
121/* XXX noprofile?  --thorpej@netbsd.org */
122ENTRY(cpu_switch)
123	mflr	0			/* save lr */
124	stw	0,4(1)
125	stwu	1,-16(1)
126	stw	31,12(1)
127	stw	30,8(1)
128
129	mr	30,3
130#if defined(MULTIPROCESSOR)
131	/* Switch to the idle PCB unless we're already running on it. */
132	GET_CPUINFO(7)
133	cmpwi	30,0			/* old process was exiting? */
134	beq	1f
135
136	mfsr	10,USER_SR		/* save USER_SR for copyin/copyout */
137	mfcr	11			/* save cr */
138	mr	12,2			/* save r2 */
139	stwu	1,-SFRAMELEN(1)		/* still running on old stack */
140	stmw	10,8(1)
141	lwz	3,P_ADDR(30)
142	stw	1,PCB_SP(3)		/* save SP */
143
144	lwz	6,CI_IDLE_PCB(7)
145	addi	1,6,USPACE-16		/* 16 bytes are reserved at stack top */
146
1471:
148	xor	31,31,31
149	stw	31,CI_CURPROC(7)	/* Zero to not accumulate cpu time */
150	lwz	31,CI_CURPCB(7)
151
152	lwz	3,CI_CPL(7)
153	stw	3,PCB_SPL(31)		/* save spl */
154#else
155	lis	3,_C_LABEL(curproc)@ha
156	xor	31,31,31
157	stw	31,_C_LABEL(curproc)@l(3) /* Zero to not accumulate cpu time */
158	lis	3,_C_LABEL(curpcb)@ha
159	lwz	31,_C_LABEL(curpcb)@l(3)
160#endif
161
162#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
163/* Release the sched_lock before processing interrupts. */
164	bl	_C_LABEL(sched_unlock_idle)
165#endif
166
167	xor	3,3,3
168	bl	_C_LABEL(lcsplx)
169#if !defined(MULTIPROCESSOR)
170	stw	3,PCB_SPL(31)		/* save spl */
171#endif
172
173/* Lock the scheduler. */
174	mfmsr	3
175	andi.	3,3,~PSL_EE@l		/* disable interrupts while
176					   manipulating runque */
177	mtmsr	3
178	isync
179#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
180	bl	_C_LABEL(sched_lock_idle)
181#endif
182
183/* Find a new process */
184	lis	8,_C_LABEL(sched_whichqs)@ha
185	lwz	9,_C_LABEL(sched_whichqs)@l(8)
186
187	or.	9,9,9
188	beq-	_ASM_LABEL(Idle)	/* all queues empty */
189.Lsw1:
190	cntlzw	10,9
191	lis	4,_C_LABEL(sched_qs)@ha
192	addi	4,4,_C_LABEL(sched_qs)@l
193	slwi	3,10,3
194	add	3,3,4			/* select queue */
195
196	lwz	31,P_FORW(3)		/* unlink first proc from queue */
197	lwz	4,P_FORW(31)
198	stw	4,P_FORW(3)
199	stw	3,P_BACK(4)
200
201	cmpl	0,3,4			/* queue empty? */
202	bne	1f
203
204	lis	3,0x80000000@h
205	srw	3,3,10
206	andc	9,9,3
207	stw	9,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */
208
2091:
210	/* just did this resched thing */
211	xor	3,3,3
212#if defined(MULTIPROCESSOR)
213	GET_CPUINFO(4)
214	stw	3,CI_WANT_RESCHED(4)
215#else
216	lis	4,_C_LABEL(want_resched)@ha
217	stw	3,_C_LABEL(want_resched)@l(4)
218#endif
219
220	stw	3,P_BACK(31)		/* probably superfluous */
221
222#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
223	/* Unlock the sched_lock, but leave interrupts off, for now. */
224	bl	_C_LABEL(sched_unlock_idle)
225#endif
226
227#if defined(MULTIPROCESSOR)
228	GET_CPUINFO(4)
229	stw	4,P_CPU(31)		/* p->p_cpu = curcpu() */
230#endif
231
232	/* Process now running on a processor. */
233	li	3,SONPROC		/* p->p_stat = SONPROC */
234	stb	3,P_STAT(31)
235
236	/* record new process */
237#if defined(MULTIPROCESSOR)
238	stw	31,CI_CURPROC(4)
239#else
240	lis	4,_C_LABEL(curproc)@ha
241	stw	31,_C_LABEL(curproc)@l(4)
242#endif
243	lwz	4,P_ADDR(31)
244
245	mfmsr	3
246	ori	3,3,PSL_EE@l		/* Now we can interrupt again */
247	mtmsr	3
248
249#if !defined(MULTIPROCESSOR)		/* XXX */
250	cmpl	0,31,30			/* is it the same process? */
251	beq	switch_return
252
253	or.	30,30,30		/* old process was exiting? */
254	beq	switch_exited
255
256	mfsr	10,USER_SR		/* save USER_SR for copyin/copyout */
257	mfcr	11			/* save cr */
258	mr	12,2			/* save r2 */
259	stwu	1,-SFRAMELEN(1)		/* still running on old stack */
260	stmw	10,8(1)
261	lwz	3,P_ADDR(30)
262	stw	1,PCB_SP(3)		/* save SP */
263#endif
264
265switch_exited:
266	mfmsr	3
267	andi.	3,3,~PSL_EE@l		/* disable interrupts while
268					   actually switching */
269	mtmsr	3
270
271	/* indicate new pcb */
272#if defined(MULTIPROCESSOR)
273	GET_CPUINFO(6)
274	stw	4,CI_CURPCB(6)
275#else
276	lis	5,_C_LABEL(curpcb)@ha
277	stw	4,_C_LABEL(curpcb)@l(5)
278#endif
279
280	/* save real pmap pointer for spill fill */
281	lwz	5,PCB_PMR(4)
282#if defined(MULTIPROCESSOR)
283	stwu	5,CI_CURPM(6)
284#else
285	lis	6,_C_LABEL(curpm)@ha
286	stwu	5,_C_LABEL(curpm)@l(6)
287#endif
288	stwcx.	5,0,6			/* clear possible reservation */
289
290	addic.	5,5,64
291	li	6,0
292	mfsr	8,KERNEL_SR		/* save kernel SR */
2931:
294	addis	6,6,-0x10000000@ha	/* set new procs segment registers */
295	or.	6,6,6			/* This is done from the real
296					   address pmap */
297	lwzu	7,-4(5)			/* so we don't have to worry */
298	mtsrin	7,6			/* about accessibility */
299	bne	1b
300	mtsr	KERNEL_SR,8		/* restore kernel SR */
301	isync
302
303	lwz	1,PCB_SP(4)		/* get new procs SP */
304
305	ori	3,3,PSL_EE@l		/* interrupts are okay again */
306	mtmsr	3
307
308	lmw	10,8(1)			/* get other regs */
309	lwz	1,0(1)			/* get saved SP */
310	mr	2,12			/* get saved r2 */
311	mtcr	11			/* get saved cr */
312	isync
313	mtsr	USER_SR,10		/* get saved USER_SR */
314	isync
315
316switch_return:
317	mr	30,7			/* save proc pointer */
318	lwz	3,PCB_SPL(4)
319	bl	_C_LABEL(lcsplx)
320
321	mr	3,30			/* get curproc for special fork
322					   returns */
323
324	lwz	31,12(1)
325	lwz	30,8(1)
326	addi	1,1,16
327	lwz	0,4(1)
328	mtlr	0
329	blr
330
331/*
332 * Child comes here at the end of a fork.
333 * Return to userspace via the trap return path.
334 */
335	.globl	_C_LABEL(fork_trampoline)
336_C_LABEL(fork_trampoline):
337#if defined(MULTIPROCESSOR)
338	bl	_C_LABEL(proc_trampoline_mp)
339#endif
340	xor	3,3,3
341	bl	_C_LABEL(lcsplx)
342	mtlr	31
343	mr	3,30
344	blrl				/* jump indirect to r31 */
345	b	trapexit
346
347/*
348 * int setfault()
349 *
350 * Similar to setjmp to setup for handling faults on accesses to user memory.
351 * Any routine using this may only call bcopy, either the form below,
352 * or the (currently used) C code optimized, so it doesn't use any non-volatile
353 * registers.
354 */
355	.globl	_C_LABEL(setfault)
356_C_LABEL(setfault):
357	mflr	0
358	mfcr	12
359#if defined(MULTIPROCESSOR)
360	GET_CPUINFO(4)
361	lwz	4,CI_CURPCB(4)
362#else
363	lis	4,_C_LABEL(curpcb)@ha
364	lwz	4,_C_LABEL(curpcb)@l(4)
365#endif
366	stw	3,PCB_FAULT(4)
367	stw	0,0(3)
368	stw	1,4(3)
369	stw	2,8(3)
370	stmw	12,12(3)
371	xor	3,3,3
372	blr
373