4xx_locore.S revision 1.1.2.3 1 /* $NetBSD: 4xx_locore.S,v 1.1.2.3 2002/12/19 15:52:19 thorpej Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
40 * Copyright (C) 1995, 1996 TooLs GmbH.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by TooLs GmbH.
54 * 4. The name of TooLs GmbH may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
62 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
63 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
64 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
65 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
66 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * This is not a standalone file. To use it, #inlcude it at
71 * the end of your port's locore.S
72 */
73
74 /*
75 * Taken straight from Walnut's locore.S, with the following attribution:
76 * $OpenBSD: locore.S,v 1.4 1997/01/26 09:06:38 rahnds Exp $
77 */
78
79 /*
80 * No processes are runnable, so loop waiting for one.
81 * Separate label here for accounting purposes.
82 * When we get here, interrupts are off (MSR[EE]=0) and sched_lock is held.
83 */
84 ASENTRY(Idle)
85 lis 8,_C_LABEL(sched_whichqs)@ha
86 lwz 9,_C_LABEL(sched_whichqs)@l(8)
87
88 or. 9,9,9
89 bne- .Lsw1 /* at least one queue non-empty */
90
91 wrteei 1 /* reenable ints again */
92
93 /* May do some power saving here? */
94 /* Check if we can use power saving mode */
95 lis 8,_C_LABEL(powersave)@ha
96 lwz 9,_C_LABEL(powersave)@l(8)
97
98 or. 9,9,9
99 beq 1f
100
101 /* TODO: Enter power saving mode here */
102 1:
103
104 wrteei 0 /* disable interrupts while manipulating runque */
105
106 b _ASM_LABEL(Idle)
107
108 /*
109 * switch_exit(struct lwp *l)
110 * switch_exit gets called from cpu_exit to complete the exit procedure.
111 */
112 ENTRY(switch_lwp_exit)
113 /* First switch to the idle pcb/kernel stack */
114 lis 6,idle_u@ha
115 lwz 6,idle_u@l(6)
116 lis 7,_C_LABEL(curpcb)@ha
117 stw 6,_C_LABEL(curpcb)@l(7)
118 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */
119 /*
120 * Schedule the vmspace and stack to be freed (the proc arg is
121 * already in r3).
122 */
123 bl _C_LABEL(lwp_exit2)
124
125 b finish_switch_exit
126
127 /*
128 * switch_exit(struct lwp *l)
129 * switch_exit gets called from cpu_exit to complete the exit procedure.
130 */
131 ENTRY(switch_exit)
132 /* First switch to the idle pcb/kernel stack */
133 lis 6,idle_u@ha
134 lwz 6,idle_u@l(6)
135 lis 7,_C_LABEL(curpcb)@ha
136 stw 6,_C_LABEL(curpcb)@l(7)
137 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */
138 /*
139 * Schedule the vmspace and stack to be freed (the proc arg is
140 * already in r3).
141 */
142 bl _C_LABEL(exit2)
143
144 finish_switch_exit:
145 /* Fall through to cpu_switch to actually select another proc */
146 li 3,0 /* indicate exited process */
147
148 /*
149 * void cpu_switch(struct lwp *l)
150 * Find a runnable process and switch to it.
151 */
152 /* XXX noprofile? --thorpej (at) netbsd.org */
153 ENTRY(cpu_switch)
154 mflr 0 /* save lr */
155 stw 0,4(1)
156 stwu 1,-16(1)
157 stw 31,12(1)
158 stw 30,8(1)
159
160 mr 30,3
161 lis 3,_C_LABEL(curlwp)@ha
162 xor 31,31,31
163 stw 31,_C_LABEL(curlwp)@l(3) /* Zero to not accumulate cpu time */
164 lis 3,_C_LABEL(curpcb)@ha
165 lwz 31,_C_LABEL(curpcb)@l(3)
166
167 xor 3,3,3
168 bl _C_LABEL(lcsplx)
169 stw 3,PCB_SPL(31) /* save spl */
170
171 wrteei 0 /* disable interrupts while manipulating runque */
172
173 /* Find a new process */
174 lis 8,_C_LABEL(sched_whichqs)@ha
175 lwz 9,_C_LABEL(sched_whichqs)@l(8)
176
177 or. 9,9,9
178 beq- _ASM_LABEL(Idle) /* all queues empty */
179 .Lsw1:
180 cntlzw 10,9
181 lis 4,_C_LABEL(sched_qs)@ha
182 addi 4,4,_C_LABEL(sched_qs)@l
183 slwi 3,10,3
184 add 3,3,4 /* select queue */
185
186 lwz 31,L_FORW(3) /* unlink first proc from queue */
187 lwz 4,L_FORW(31)
188 stw 4,L_FORW(3)
189 stw 3,L_BACK(4)
190
191 cmpl 0,3,4 /* queue empty? */
192 bne 1f
193
194 lis 3,0x80000000@h
195 srw 3,3,10
196 andc 9,9,3
197 stw 9,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */
198
199 1:
200 /* just did this resched thing */
201 xor 3,3,3
202 lis 4,_C_LABEL(want_resched)@ha
203 stw 3,_C_LABEL(want_resched)@l(4)
204
205 stw 3,L_BACK(31) /* probably superfluous */
206
207 /* Process now running on a processor. */
208 li 3,LSONPROC /* l->l_stat = LSONPROC */
209 stw 3,L_STAT(31)
210
211 /* record new process */
212 lis 4,_C_LABEL(curlwp)@ha
213 stw 31,_C_LABEL(curlwp)@l(4)
214
215 wrteei 1 /* Now we can interrupt again */
216
217 li 3,0 /* if it's the same lwp, return 0 */
218 cmpl 0,31,30 /* is it the same process? */
219 beq switch_return
220
221 or. 30,30,30 /* old process was exiting? */
222 beq switch_exited
223
224 #ifndef PPC_IBM4XX
225 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */
226 #else
227 li 10,0 /* no SR for 4xx CPUs */
228 #endif
229 mfcr 11 /* save cr */
230 mr 12,2 /* save r2 */
231 stwu 1,-SFRAMELEN(1) /* still running on old stack */
232 stmw 10,8(1)
233 lwz 3,L_ADDR(30)
234 stw 1,PCB_SP(3) /* save SP */
235
236 switch_exited:
237 wrteei 0 /* disable interrupts while actually switching */
238
239 /* indicate new pcb */
240 lwz 4,L_ADDR(31)
241 lis 5,_C_LABEL(curpcb)@ha
242 stw 4,_C_LABEL(curpcb)@l(5)
243
244 /* save real pmap pointer for spill fill */
245 lwz 5,PCB_PMR(4)
246 lis 6,_C_LABEL(curpm)@ha
247 stwu 5,_C_LABEL(curpm)@l(6)
248 stwcx. 5,0,6 /* clear possible reservation */
249
250 /* Switch to the new virtual space */
251 /* Do not have to do anything here. TLB PID gets updated on return from trap. */
252
253 lwz 1,PCB_SP(4) /* get new procs SP */
254
255 wrteei 1 /* interrupts are okay again */
256
257 lmw 10,8(1) /* get other regs */
258 lwz 1,0(1) /* get saved SP */
259 mr 2,12 /* get saved r2 */
260 mtcr 11 /* get saved cr */
261 isync
262 li 3,1 /* switched lwps */
263
264 switch_return:
265 mr 30,3 /* save return value */
266
267 lwz 3,PCB_SPL(4)
268 bl _C_LABEL(lcsplx)
269
270 0:
271 lis 3,_C_LABEL(curpm)@ha
272 addi 3,3,_C_LABEL(curpm)@l /* Do we need a context? */
273 lwz 4,PM_CTX(3)
274 cmpwi 4,0
275 # mtspr SPR_SPR0,4 /* Always keep the current ctx here */
276 mr 3,30
277 bne 1f
278 bl _C_LABEL(ctx_alloc)
279 b 0b /* Reload */
280 1:
281 lwz 31,12(1)
282 lwz 30,8(1)
283 addi 1,1,16
284 lwz 0,4(1)
285 mtlr 0
286 blr
287
288 /*
289 * void cpu_preempt(struct lwp *current, struct lwp *new))
290 * Find a runnable process and switch to it.
291 */
292 ENTRY(cpu_preempt)
293 mflr 0 /* save lr */
294 stw 0,4(1)
295 stwu 1,-20(1)
296 stw 31,16(1)
297 stw 30,12(1)
298 stw 29,8(1)
299
300 mr 30,3
301 mr 29,4
302 lis 3,_C_LABEL(curlwp)@ha
303 xor 31,31,31
304 stw 31,_C_LABEL(curlwp)@l(3) /* Zero to not accumulate cpu time */
305 lis 3,_C_LABEL(curpcb)@ha
306 lwz 31,_C_LABEL(curpcb)@l(3)
307
308 xor 3,3,3
309 bl _C_LABEL(lcsplx)
310 stw 3,PCB_SPL(31) /* save spl */
311
312 wrteei 0 /* disable interrupts while manipulating runque */
313
314 /* Find a new process */
315 xor 3,3,3
316
317 mr 31,29 /* r31 = newlwp */
318 lwz 4,L_BACK(31) /* r4 = newlwp->l_back */
319 stw 3,L_BACK(31) /* newlwp->l_back = NULL */
320 lwz 3,L_FORW(31) /* r3 = newlwp->l_forw */
321 stw 4,L_BACK(3) /* r3->l_back = r4 */
322 stw 3,L_FORW(4) /* r4->l_forw = r3 */
323
324 cmpl 0,4,3 /* queue empty? */
325 bne 1f
326
327 /* so now r31 is newlwp and r3/r4 are scratch again */
328
329 lis 8,_C_LABEL(sched_whichqs)@ha
330 lwz 4,_C_LABEL(sched_whichqs)@l(8)
331
332 lbz 3,L_PRIORITY(31)
333 li 9,2
334 srw 3,3,9 /* r3 = newlwp->l_priority / 4 */
335 li 9,1
336 slw 3,9,3 /* r3 = 1 << r3 */
337 andc 4,4,3 /* sched_whichqs &= ~r3 */
338 stw 4,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */
339
340 1:
341 /* just did this resched thing */
342 xor 3,3,3
343 lis 4,_C_LABEL(want_resched)@ha
344 stw 3,_C_LABEL(want_resched)@l(4)
345
346 stw 3,L_BACK(31) /* probably superfluous */
347
348 /* Process now running on a processor. */
349 li 3,LSONPROC /* l->l_stat = LSONPROC */
350 stw 3,L_STAT(31)
351
352 /* record new process */
353 lis 4,_C_LABEL(curlwp)@ha
354 stw 31,_C_LABEL(curlwp)@l(4)
355
356 wrteei 1 /* Now we can interrupt again */
357
358 cmpl 0,31,30 /* is it the same process? */
359 beq preempt_return
360
361 or. 30,30,30 /* old process was exiting? */
362 beq preempt_exited
363
364 #ifndef PPC_IBM4XX
365 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */
366 #else
367 li 10,0 /* no SR for 4xx CPUs */
368 #endif
369 mfcr 11 /* save cr */
370 mr 12,2 /* save r2 */
371 stwu 1,-SFRAMELEN(1) /* still running on old stack */
372 stmw 10,8(1)
373 lwz 3,L_ADDR(30)
374 stw 1,PCB_SP(3) /* save SP */
375
376 preempt_exited:
377 wrteei 0 /* disable interrupts while actually switching */
378
379 /* indicate new pcb */
380 lwz 4,L_ADDR(31)
381 lis 5,_C_LABEL(curpcb)@ha
382 stw 4,_C_LABEL(curpcb)@l(5)
383
384 /* save real pmap pointer for spill fill */
385 lwz 5,PCB_PMR(4)
386 lis 6,_C_LABEL(curpm)@ha
387 stwu 5,_C_LABEL(curpm)@l(6)
388 stwcx. 5,0,6 /* clear possible reservation */
389
390 /* Switch to the new virtual space */
391 /* Do not have to do anything here. TLB PID gets updated on return from trap. */
392
393 lwz 1,PCB_SP(4) /* get new procs SP */
394
395 wrteei 1 /* interrupts are okay again */
396
397 lmw 10,8(1) /* get other regs */
398 lwz 1,0(1) /* get saved SP */
399 mr 2,12 /* get saved r2 */
400 mtcr 11 /* get saved cr */
401 isync
402
403 preempt_return:
404 lwz 3,PCB_SPL(4)
405 bl _C_LABEL(lcsplx)
406
407 0:
408 lis 3,_C_LABEL(curpm)@ha
409 addi 3,3,_C_LABEL(curpm)@l /* Do we need a context? */
410 lwz 4,PM_CTX(3)
411 cmpwi 4,0
412 # mtspr SPR_SPR0,4 /* Always keep the current ctx here */
413 mr 3,30
414 bne 1f
415 bl _C_LABEL(ctx_alloc)
416 b 0b /* Reload */
417 1:
418 lwz 31,16(1)
419 lwz 30,12(1)
420 lwz 29,8(1)
421 addi 1,1,20
422 lwz 0,4(1)
423 mtlr 0
424 blr
425
426
427 /*
428 * Child comes here at the end of a fork.
429 * Return to userspace via the trap return path.
430 */
431 .globl _C_LABEL(fork_trampoline)
432 _C_LABEL(fork_trampoline):
433 xor 3,3,3
434 bl _C_LABEL(lcsplx)
435 mtlr 31
436 mr 3,30
437 blrl /* jump indirect to r31 */
438 b trapexit
439
440 /*
441 * Pull in common trap vector code.
442 */
443 #include <powerpc/ibm4xx/trap_subr.S>
444 #include <powerpc/ibm4xx/4xx_trap_subr.S>
445
446 /*
447 * int setfault()
448 *
449 * Similar to setjmp to setup for handling faults on accesses to user memory.
450 * Any routine using this may only call bcopy, either the form below,
451 * or the (currently used) C code optimized, so it doesn't use any non-volatile
452 * registers.
453 */
454 .globl _C_LABEL(setfault)
455 _C_LABEL(setfault):
456 mflr 0
457 mfcr 12
458 lis 4,_C_LABEL(curpcb)@ha
459 lwz 4,_C_LABEL(curpcb)@l(4)
460 stw 3,PCB_FAULT(4)
461 stw 0,0(3)
462 stw 1,4(3)
463 stw 2,8(3)
464 stmw 12,12(3)
465 xor 3,3,3
466 blr
467
468 .globl _C_LABEL(ppc4xx_reset)
469 _C_LABEL(ppc4xx_reset):
470 mfspr 3,SPR_DBCR0
471 oris 3,r13,DBCR0_RST_SYSTEM@h
472 mtspr SPR_DBCR0,3
473 ba 0
474
475 #if 0
476 /*
477 * XXXX the following doesn't quite work right yet.
478 */
479 /*
480 * void bcopy(const void *src, void *dst, size_t len);
481 *
482 * swap r3 and r4 and fall through to memcopy.
483 */
484 .globl _C_LABEL(bcopy)
485 _C_LABEL(bcopy):
486 mr r0,r3
487 mr r3,r4
488 mr r4,r0
489 /* FALLTHROUGH */
490
491 /*
492 * void * memcpy(void *dst (r3), const void *src (r4), size_t len (r5));
493 *
494 * Copy memory (obviously)
495 *
496 * We will try to do data cache block aligned stores so we
497 * can use block allocate and not have to read from the
498 * destination.
499 *
500 * Register use:
501 *
502 * r1 stack (of course)
503 * r3 dst
504 * r4 src
505 * r5 len
506 * r6 tmp
507 * r7 holds 32
508 * r8 holds dst
509 * r24-r31 block move regs
510 *
511 */
512
513 ENTRY(memcpy)
514 stwu r1,-(10*4)(r1) /* Allocate some RAM to save 8 regs to. */
515 cmpwi r5, 32 /* Less than 32 bytes ? */
516 stmw r24,8(r1) /* Save ALL regs (could be optimized) */
517
518 mr r8,r3 /* save dst */
519 li r7,32
520
521 dcbt 0,r4 /* Start bringing in cache line. */
522 blt 1f /* Finish up */
523
524 neg r6,r3 /* Find how far unaligned we are... */
525 andi. r6,r6,31 /* Cache-align dest. */
526 mtxer r6
527 sub r5,r5,r6 /* subtract count */
528 lswx r24,0,r4 /* Load some. */
529 add r4,r4,r6
530 dcbt 0,r4 /* Fetch next line */
531 stswx r24,0,r3 /* Store some */
532 add r3,r3,r6
533 addic. r6,r5,-32 /* Pre-decrement next line */
534 ble 1f /* Less than 32-bytes? finishup */
535
536 /* Dest should not be cache line aligned. */
537 /* XXX need gas 2.11 to grok dcba insn */
538 #ifdef GAS_2_11
539 dcba 0,r3 /* Allocate a line */
540 #else
541 .long 0x7c001dec /* dcba 0,r3 */
542 #endif
543 0:
544 dcbt r7,r4 /* Bring in the next line, too */
545
546 lswi r24,r4,32
547 addi r4,r4,32 /* Inc src */
548 mr r5,r6
549
550 addic. r6,r5,-32
551 stswi r24,r3,32
552 addi r3,r3,32 /* Inc dst */
553 #ifdef GAS_2_11
554 dcba 0,r3 /* Allocate another line */
555 #else
556 .long 0x7c071dec /* dcba r7,r3 */
557 #endif
558 bgt 0b
559 1:
560 mtxer r5 /* Store byte count */
561 lswx r24,0,r4 /* Load up to 32 bytes */
562 stswx r24,0,r3 /* Store up to 32 bytes */
563
564 mr r3,r8 /* Return dst */
565
566 lmw r24,8(r1)
567 addi r1,r1,(10*4)
568 blr
569 #endif
570