]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/powerpc/kernel/misc_64.S
8fe295693c09e85851b9c9d37c1f221aa1a1fa5f
[karo-tx-linux.git] / arch / powerpc / kernel / misc_64.S
1 /*
2  *  arch/powerpc/kernel/misc64.S
3  *
4  * This file contains miscellaneous low-level functions.
5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6  *
7  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
8  * and Paul Mackerras.
9  * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
10  * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version
15  * 2 of the License, or (at your option) any later version.
16  *
17  */
18
19 #include <linux/config.h>
20 #include <linux/sys.h>
21 #include <asm/unistd.h>
22 #include <asm/errno.h>
23 #include <asm/processor.h>
24 #include <asm/page.h>
25 #include <asm/cache.h>
26 #include <asm/ppc_asm.h>
27 #include <asm/asm-offsets.h>
28 #include <asm/cputable.h>
29
30         .text
31
32 /*
33  * Returns (address we are running at) - (address we were linked at)
34  * for use before the text and data are mapped to KERNELBASE.
35  */
36
37 _GLOBAL(reloc_offset)
38         mflr    r0
39         bl      1f
40 1:      mflr    r3
41         LOADADDR(r4,1b)
42         subf    r3,r4,r3
43         mtlr    r0
44         blr
45
46 /*
47  * add_reloc_offset(x) returns x + reloc_offset().
48  */
49 _GLOBAL(add_reloc_offset)
50         mflr    r0
51         bl      1f
52 1:      mflr    r5
53         LOADADDR(r4,1b)
54         subf    r5,r4,r5
55         add     r3,r3,r5
56         mtlr    r0
57         blr
58
59 _GLOBAL(get_msr)
60         mfmsr   r3
61         blr
62
63 _GLOBAL(get_dar)
64         mfdar   r3
65         blr
66
67 _GLOBAL(get_srr0)
68         mfsrr0  r3
69         blr
70
71 _GLOBAL(get_srr1)
72         mfsrr1  r3
73         blr
74         
75 _GLOBAL(get_sp)
76         mr      r3,r1
77         blr
78
79 #ifdef CONFIG_IRQSTACKS
80 _GLOBAL(call_do_softirq)
81         mflr    r0
82         std     r0,16(r1)
83         stdu    r1,THREAD_SIZE-112(r3)
84         mr      r1,r3
85         bl      .__do_softirq
86         ld      r1,0(r1)
87         ld      r0,16(r1)
88         mtlr    r0
89         blr
90
91 _GLOBAL(call_handle_IRQ_event)
92         mflr    r0
93         std     r0,16(r1)
94         stdu    r1,THREAD_SIZE-112(r6)
95         mr      r1,r6
96         bl      .handle_IRQ_event
97         ld      r1,0(r1)
98         ld      r0,16(r1)
99         mtlr    r0
100         blr
101 #endif /* CONFIG_IRQSTACKS */
102
103         /*
104  * To be called by C code which needs to do some operations with MMU
105  * disabled. Note that interrupts have to be disabled by the caller
106  * prior to calling us. The code called _MUST_ be in the RMO of course
107  * and part of the linear mapping as we don't attempt to translate the
108  * stack pointer at all. The function is called with the stack switched
109  * to this CPU emergency stack
110  *
111  * prototype is void *call_with_mmu_off(void *func, void *data);
112  *
113  * the called function is expected to be of the form
114  *
115  * void *called(void *data); 
116  */
117 _GLOBAL(call_with_mmu_off)
118         mflr    r0                      /* get link, save it on stackframe */
119         std     r0,16(r1)
120         mr      r1,r5                   /* save old stack ptr */
121         ld      r1,PACAEMERGSP(r13)     /* get emerg. stack */
122         subi    r1,r1,STACK_FRAME_OVERHEAD
123         std     r0,16(r1)               /* save link on emerg. stack */
124         std     r5,0(r1)                /* save old stack ptr in backchain */
125         ld      r3,0(r3)                /* get to real function ptr (assume same TOC) */
126         bl      2f                      /* we need LR to return, continue at label 2 */
127
128         ld      r0,16(r1)               /* we return here from the call, get LR and */
129         ld      r1,0(r1)                /* .. old stack ptr */
130         mtspr   SPRN_SRR0,r0            /* and get back to virtual mode with these */
131         mfmsr   r4
132         ori     r4,r4,MSR_IR|MSR_DR
133         mtspr   SPRN_SRR1,r4
134         rfid
135
136 2:      mtspr   SPRN_SRR0,r3            /* coming from above, enter real mode */
137         mr      r3,r4                   /* get parameter */
138         mfmsr   r0
139         ori     r0,r0,MSR_IR|MSR_DR
140         xori    r0,r0,MSR_IR|MSR_DR
141         mtspr   SPRN_SRR1,r0
142         rfid
143
144
145         .section        ".toc","aw"
146 PPC64_CACHES:
147         .tc             ppc64_caches[TC],ppc64_caches
148         .section        ".text"
149
150 /*
151  * Write any modified data cache blocks out to memory
152  * and invalidate the corresponding instruction cache blocks.
153  *
154  * flush_icache_range(unsigned long start, unsigned long stop)
155  *
156  *   flush all bytes from start through stop-1 inclusive
157  */
158
159 _KPROBE(__flush_icache_range)
160
161 /*
162  * Flush the data cache to memory 
163  * 
164  * Different systems have different cache line sizes
165  * and in some cases i-cache and d-cache line sizes differ from
166  * each other.
167  */
168         ld      r10,PPC64_CACHES@toc(r2)
169         lwz     r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
170         addi    r5,r7,-1
171         andc    r6,r3,r5                /* round low to line bdy */
172         subf    r8,r6,r4                /* compute length */
173         add     r8,r8,r5                /* ensure we get enough */
174         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of cache line size */
175         srw.    r8,r8,r9                /* compute line count */
176         beqlr                           /* nothing to do? */
177         mtctr   r8
178 1:      dcbst   0,r6
179         add     r6,r6,r7
180         bdnz    1b
181         sync
182
183 /* Now invalidate the instruction cache */
184         
185         lwz     r7,ICACHEL1LINESIZE(r10)        /* Get Icache line size */
186         addi    r5,r7,-1
187         andc    r6,r3,r5                /* round low to line bdy */
188         subf    r8,r6,r4                /* compute length */
189         add     r8,r8,r5
190         lwz     r9,ICACHEL1LOGLINESIZE(r10)     /* Get log-2 of Icache line size */
191         srw.    r8,r8,r9                /* compute line count */
192         beqlr                           /* nothing to do? */
193         mtctr   r8
194 2:      icbi    0,r6
195         add     r6,r6,r7
196         bdnz    2b
197         isync
198         blr
199         .previous .text
200 /*
201  * Like above, but only do the D-cache.
202  *
203  * flush_dcache_range(unsigned long start, unsigned long stop)
204  *
205  *    flush all bytes from start to stop-1 inclusive
206  */
207 _GLOBAL(flush_dcache_range)
208
209 /*
210  * Flush the data cache to memory 
211  * 
212  * Different systems have different cache line sizes
213  */
214         ld      r10,PPC64_CACHES@toc(r2)
215         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
216         addi    r5,r7,-1
217         andc    r6,r3,r5                /* round low to line bdy */
218         subf    r8,r6,r4                /* compute length */
219         add     r8,r8,r5                /* ensure we get enough */
220         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of dcache line size */
221         srw.    r8,r8,r9                /* compute line count */
222         beqlr                           /* nothing to do? */
223         mtctr   r8
224 0:      dcbst   0,r6
225         add     r6,r6,r7
226         bdnz    0b
227         sync
228         blr
229
230 /*
231  * Like above, but works on non-mapped physical addresses.
232  * Use only for non-LPAR setups ! It also assumes real mode
233  * is cacheable. Used for flushing out the DART before using
234  * it as uncacheable memory 
235  *
236  * flush_dcache_phys_range(unsigned long start, unsigned long stop)
237  *
238  *    flush all bytes from start to stop-1 inclusive
239  */
240 _GLOBAL(flush_dcache_phys_range)
241         ld      r10,PPC64_CACHES@toc(r2)
242         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
243         addi    r5,r7,-1
244         andc    r6,r3,r5                /* round low to line bdy */
245         subf    r8,r6,r4                /* compute length */
246         add     r8,r8,r5                /* ensure we get enough */
247         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of dcache line size */
248         srw.    r8,r8,r9                /* compute line count */
249         beqlr                           /* nothing to do? */
250         mfmsr   r5                      /* Disable MMU Data Relocation */
251         ori     r0,r5,MSR_DR
252         xori    r0,r0,MSR_DR
253         sync
254         mtmsr   r0
255         sync
256         isync
257         mtctr   r8
258 0:      dcbst   0,r6
259         add     r6,r6,r7
260         bdnz    0b
261         sync
262         isync
263         mtmsr   r5                      /* Re-enable MMU Data Relocation */
264         sync
265         isync
266         blr
267
268 _GLOBAL(flush_inval_dcache_range)
269         ld      r10,PPC64_CACHES@toc(r2)
270         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
271         addi    r5,r7,-1
272         andc    r6,r3,r5                /* round low to line bdy */
273         subf    r8,r6,r4                /* compute length */
274         add     r8,r8,r5                /* ensure we get enough */
275         lwz     r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
276         srw.    r8,r8,r9                /* compute line count */
277         beqlr                           /* nothing to do? */
278         sync
279         isync
280         mtctr   r8
281 0:      dcbf    0,r6
282         add     r6,r6,r7
283         bdnz    0b
284         sync
285         isync
286         blr
287
288
289 /*
290  * Flush a particular page from the data cache to RAM.
291  * Note: this is necessary because the instruction cache does *not*
292  * snoop from the data cache.
293  *
294  *      void __flush_dcache_icache(void *page)
295  */
296 _GLOBAL(__flush_dcache_icache)
297 /*
298  * Flush the data cache to memory 
299  * 
300  * Different systems have different cache line sizes
301  */
302
303 /* Flush the dcache */
304         ld      r7,PPC64_CACHES@toc(r2)
305         clrrdi  r3,r3,PAGE_SHIFT                    /* Page align */
306         lwz     r4,DCACHEL1LINESPERPAGE(r7)     /* Get # dcache lines per page */
307         lwz     r5,DCACHEL1LINESIZE(r7)         /* Get dcache line size */
308         mr      r6,r3
309         mtctr   r4
310 0:      dcbst   0,r6
311         add     r6,r6,r5
312         bdnz    0b
313         sync
314
315 /* Now invalidate the icache */ 
316
317         lwz     r4,ICACHEL1LINESPERPAGE(r7)     /* Get # icache lines per page */
318         lwz     r5,ICACHEL1LINESIZE(r7)         /* Get icache line size */
319         mtctr   r4
320 1:      icbi    0,r3
321         add     r3,r3,r5
322         bdnz    1b
323         isync
324         blr
325         
326 /*
327  * I/O string operations
328  *
329  * insb(port, buf, len)
330  * outsb(port, buf, len)
331  * insw(port, buf, len)
332  * outsw(port, buf, len)
333  * insl(port, buf, len)
334  * outsl(port, buf, len)
335  * insw_ns(port, buf, len)
336  * outsw_ns(port, buf, len)
337  * insl_ns(port, buf, len)
338  * outsl_ns(port, buf, len)
339  *
340  * The *_ns versions don't do byte-swapping.
341  */
342 _GLOBAL(_insb)
343         cmpwi   0,r5,0
344         mtctr   r5
345         subi    r4,r4,1
346         blelr-
347 00:     lbz     r5,0(r3)
348         eieio
349         stbu    r5,1(r4)
350         bdnz    00b
351         twi     0,r5,0
352         isync
353         blr
354
355 _GLOBAL(_outsb)
356         cmpwi   0,r5,0
357         mtctr   r5
358         subi    r4,r4,1
359         blelr-
360 00:     lbzu    r5,1(r4)
361         stb     r5,0(r3)
362         bdnz    00b
363         sync
364         blr     
365
366 _GLOBAL(_insw)
367         cmpwi   0,r5,0
368         mtctr   r5
369         subi    r4,r4,2
370         blelr-
371 00:     lhbrx   r5,0,r3
372         eieio
373         sthu    r5,2(r4)
374         bdnz    00b
375         twi     0,r5,0
376         isync
377         blr
378
379 _GLOBAL(_outsw)
380         cmpwi   0,r5,0
381         mtctr   r5
382         subi    r4,r4,2
383         blelr-
384 00:     lhzu    r5,2(r4)
385         sthbrx  r5,0,r3 
386         bdnz    00b
387         sync
388         blr     
389
390 _GLOBAL(_insl)
391         cmpwi   0,r5,0
392         mtctr   r5
393         subi    r4,r4,4
394         blelr-
395 00:     lwbrx   r5,0,r3
396         eieio
397         stwu    r5,4(r4)
398         bdnz    00b
399         twi     0,r5,0
400         isync
401         blr
402
403 _GLOBAL(_outsl)
404         cmpwi   0,r5,0
405         mtctr   r5
406         subi    r4,r4,4
407         blelr-
408 00:     lwzu    r5,4(r4)
409         stwbrx  r5,0,r3
410         bdnz    00b
411         sync
412         blr     
413
414 /* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
415 _GLOBAL(_insw_ns)
416         cmpwi   0,r5,0
417         mtctr   r5
418         subi    r4,r4,2
419         blelr-
420 00:     lhz     r5,0(r3)
421         eieio
422         sthu    r5,2(r4)
423         bdnz    00b
424         twi     0,r5,0
425         isync
426         blr
427
428 /* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
429 _GLOBAL(_outsw_ns)
430         cmpwi   0,r5,0
431         mtctr   r5
432         subi    r4,r4,2
433         blelr-
434 00:     lhzu    r5,2(r4)
435         sth     r5,0(r3)
436         bdnz    00b
437         sync
438         blr     
439
440 _GLOBAL(_insl_ns)
441         cmpwi   0,r5,0
442         mtctr   r5
443         subi    r4,r4,4
444         blelr-
445 00:     lwz     r5,0(r3)
446         eieio
447         stwu    r5,4(r4)
448         bdnz    00b
449         twi     0,r5,0
450         isync
451         blr
452
453 _GLOBAL(_outsl_ns)
454         cmpwi   0,r5,0
455         mtctr   r5
456         subi    r4,r4,4
457         blelr-
458 00:     lwzu    r5,4(r4)
459         stw     r5,0(r3)
460         bdnz    00b
461         sync
462         blr     
463
464
465 _GLOBAL(cvt_fd)
466         lfd     0,0(r5)         /* load up fpscr value */
467         mtfsf   0xff,0
468         lfs     0,0(r3)
469         stfd    0,0(r4)
470         mffs    0               /* save new fpscr value */
471         stfd    0,0(r5)
472         blr
473
474 _GLOBAL(cvt_df)
475         lfd     0,0(r5)         /* load up fpscr value */
476         mtfsf   0xff,0
477         lfd     0,0(r3)
478         stfs    0,0(r4)
479         mffs    0               /* save new fpscr value */
480         stfd    0,0(r5)
481         blr
482
483 /*
484  * identify_cpu and calls setup_cpu
485  * In:  r3 = base of the cpu_specs array
486  *      r4 = address of cur_cpu_spec
487  *      r5 = relocation offset
488  */
489 _GLOBAL(identify_cpu)
490         mfpvr   r7
491 1:
492         lwz     r8,CPU_SPEC_PVR_MASK(r3)
493         and     r8,r8,r7
494         lwz     r9,CPU_SPEC_PVR_VALUE(r3)
495         cmplw   0,r9,r8
496         beq     1f
497         addi    r3,r3,CPU_SPEC_ENTRY_SIZE
498         b       1b
499 1:
500         sub     r0,r3,r5
501         std     r0,0(r4)
502         ld      r4,CPU_SPEC_SETUP(r3)
503         add     r4,r4,r5
504         ld      r4,0(r4)
505         add     r4,r4,r5
506         mtctr   r4
507         /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
508         mr      r4,r3
509         mr      r3,r5
510         bctr
511
512 /*
513  * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
514  * and writes nop's over sections of code that don't apply for this cpu.
515  * r3 = data offset (not changed)
516  */
517 _GLOBAL(do_cpu_ftr_fixups)
518         /* Get CPU 0 features */
519         LOADADDR(r6,cur_cpu_spec)
520         sub     r6,r6,r3
521         ld      r4,0(r6)
522         sub     r4,r4,r3
523         ld      r4,CPU_SPEC_FEATURES(r4)
524         /* Get the fixup table */
525         LOADADDR(r6,__start___ftr_fixup)
526         sub     r6,r6,r3
527         LOADADDR(r7,__stop___ftr_fixup)
528         sub     r7,r7,r3
529         /* Do the fixup */
530 1:      cmpld   r6,r7
531         bgelr
532         addi    r6,r6,32
533         ld      r8,-32(r6)      /* mask */
534         and     r8,r8,r4
535         ld      r9,-24(r6)      /* value */
536         cmpld   r8,r9
537         beq     1b
538         ld      r8,-16(r6)      /* section begin */
539         ld      r9,-8(r6)       /* section end */
540         subf.   r9,r8,r9
541         beq     1b
542         /* write nops over the section of code */
543         /* todo: if large section, add a branch at the start of it */
544         srwi    r9,r9,2
545         mtctr   r9
546         sub     r8,r8,r3
547         lis     r0,0x60000000@h /* nop */
548 3:      stw     r0,0(r8)
549         andi.   r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
550         beq     2f
551         dcbst   0,r8            /* suboptimal, but simpler */
552         sync
553         icbi    0,r8
554 2:      addi    r8,r8,4
555         bdnz    3b
556         sync                    /* additional sync needed on g4 */
557         isync
558         b       1b
559
560 #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
561 /*
562  * Do an IO access in real mode
563  */
564 _GLOBAL(real_readb)
565         mfmsr   r7
566         ori     r0,r7,MSR_DR
567         xori    r0,r0,MSR_DR
568         sync
569         mtmsrd  r0
570         sync
571         isync
572         mfspr   r6,SPRN_HID4
573         rldicl  r5,r6,32,0
574         ori     r5,r5,0x100
575         rldicl  r5,r5,32,0
576         sync
577         mtspr   SPRN_HID4,r5
578         isync
579         slbia
580         isync
581         lbz     r3,0(r3)
582         sync
583         mtspr   SPRN_HID4,r6
584         isync
585         slbia
586         isync
587         mtmsrd  r7
588         sync
589         isync
590         blr
591
592         /*
593  * Do an IO access in real mode
594  */
595 _GLOBAL(real_writeb)
596         mfmsr   r7
597         ori     r0,r7,MSR_DR
598         xori    r0,r0,MSR_DR
599         sync
600         mtmsrd  r0
601         sync
602         isync
603         mfspr   r6,SPRN_HID4
604         rldicl  r5,r6,32,0
605         ori     r5,r5,0x100
606         rldicl  r5,r5,32,0
607         sync
608         mtspr   SPRN_HID4,r5
609         isync
610         slbia
611         isync
612         stb     r3,0(r4)
613         sync
614         mtspr   SPRN_HID4,r6
615         isync
616         slbia
617         isync
618         mtmsrd  r7
619         sync
620         isync
621         blr
622 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
623
624 /*
625  * Create a kernel thread
626  *   kernel_thread(fn, arg, flags)
627  */
628 _GLOBAL(kernel_thread)
629         std     r29,-24(r1)
630         std     r30,-16(r1)
631         stdu    r1,-STACK_FRAME_OVERHEAD(r1)
632         mr      r29,r3
633         mr      r30,r4
634         ori     r3,r5,CLONE_VM  /* flags */
635         oris    r3,r3,(CLONE_UNTRACED>>16)
636         li      r4,0            /* new sp (unused) */
637         li      r0,__NR_clone
638         sc
639         cmpdi   0,r3,0          /* parent or child? */
640         bne     1f              /* return if parent */
641         li      r0,0
642         stdu    r0,-STACK_FRAME_OVERHEAD(r1)
643         ld      r2,8(r29)
644         ld      r29,0(r29)
645         mtlr    r29              /* fn addr in lr */
646         mr      r3,r30          /* load arg and call fn */
647         blrl
648         li      r0,__NR_exit    /* exit after child exits */
649         li      r3,0
650         sc
651 1:      addi    r1,r1,STACK_FRAME_OVERHEAD      
652         ld      r29,-24(r1)
653         ld      r30,-16(r1)
654         blr
655
656 /*
657  * disable_kernel_fp()
658  * Disable the FPU.
659  */
660 _GLOBAL(disable_kernel_fp)
661         mfmsr   r3
662         rldicl  r0,r3,(63-MSR_FP_LG),1
663         rldicl  r3,r0,(MSR_FP_LG+1),0
664         mtmsrd  r3                      /* disable use of fpu now */
665         isync
666         blr
667
668 #ifdef CONFIG_ALTIVEC
669
670 #if 0 /* this has no callers for now */
671 /*
672  * disable_kernel_altivec()
673  * Disable the VMX.
674  */
675 _GLOBAL(disable_kernel_altivec)
676         mfmsr   r3
677         rldicl  r0,r3,(63-MSR_VEC_LG),1
678         rldicl  r3,r0,(MSR_VEC_LG+1),0
679         mtmsrd  r3                      /* disable use of VMX now */
680         isync
681         blr
682 #endif /* 0 */
683
684 /*
685  * giveup_altivec(tsk)
686  * Disable VMX for the task given as the argument,
687  * and save the vector registers in its thread_struct.
688  * Enables the VMX for use in the kernel on return.
689  */
690 _GLOBAL(giveup_altivec)
691         mfmsr   r5
692         oris    r5,r5,MSR_VEC@h
693         mtmsrd  r5                      /* enable use of VMX now */
694         isync
695         cmpdi   0,r3,0
696         beqlr-                          /* if no previous owner, done */
697         addi    r3,r3,THREAD            /* want THREAD of task */
698         ld      r5,PT_REGS(r3)
699         cmpdi   0,r5,0
700         SAVE_32VRS(0,r4,r3)
701         mfvscr  vr0
702         li      r4,THREAD_VSCR
703         stvx    vr0,r4,r3
704         beq     1f
705         ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
706         lis     r3,MSR_VEC@h
707         andc    r4,r4,r3                /* disable FP for previous task */
708         std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
709 1:
710 #ifndef CONFIG_SMP
711         li      r5,0
712         ld      r4,last_task_used_altivec@got(r2)
713         std     r5,0(r4)
714 #endif /* CONFIG_SMP */
715         blr
716
717 #endif /* CONFIG_ALTIVEC */
718
719 _GLOBAL(__setup_cpu_power3)
720         blr
721
722 _GLOBAL(execve)
723         li      r0,__NR_execve
724         sc
725         bnslr
726         neg     r3,r3
727         blr
728
729 /* kexec_wait(phys_cpu)
730  *
731  * wait for the flag to change, indicating this kernel is going away but
732  * the slave code for the next one is at addresses 0 to 100.
733  *
734  * This is used by all slaves.
735  *
736  * Physical (hardware) cpu id should be in r3.
737  */
738 _GLOBAL(kexec_wait)
739         bl      1f
740 1:      mflr    r5
741         addi    r5,r5,kexec_flag-1b
742
743 99:     HMT_LOW
744 #ifdef CONFIG_KEXEC             /* use no memory without kexec */
745         lwz     r4,0(r5)
746         cmpwi   0,r4,0
747         bnea    0x60
748 #endif
749         b       99b
750
751 /* this can be in text because we won't change it until we are
752  * running in real anyways
753  */
754 kexec_flag:
755         .long   0
756
757
758 #ifdef CONFIG_KEXEC
759
760 /* kexec_smp_wait(void)
761  *
762  * call with interrupts off
763  * note: this is a terminal routine, it does not save lr
764  *
765  * get phys id from paca
766  * set paca id to -1 to say we got here
767  * switch to real mode
768  * join other cpus in kexec_wait(phys_id)
769  */
770 _GLOBAL(kexec_smp_wait)
771         lhz     r3,PACAHWCPUID(r13)
772         li      r4,-1
773         sth     r4,PACAHWCPUID(r13)     /* let others know we left */
774         bl      real_mode
775         b       .kexec_wait
776
777 /*
778  * switch to real mode (turn mmu off)
779  * we use the early kernel trick that the hardware ignores bits
780  * 0 and 1 (big endian) of the effective address in real mode
781  *
782  * don't overwrite r3 here, it is live for kexec_wait above.
783  */
784 real_mode:      /* assume normal blr return */
785 1:      li      r9,MSR_RI
786         li      r10,MSR_DR|MSR_IR
787         mflr    r11             /* return address to SRR0 */
788         mfmsr   r12
789         andc    r9,r12,r9
790         andc    r10,r12,r10
791
792         mtmsrd  r9,1
793         mtspr   SPRN_SRR1,r10
794         mtspr   SPRN_SRR0,r11
795         rfid
796
797
798 /*
799  * kexec_sequence(newstack, start, image, control, clear_all())
800  *
801  * does the grungy work with stack switching and real mode switches
802  * also does simple calls to other code
803  */
804
805 _GLOBAL(kexec_sequence)
806         mflr    r0
807         std     r0,16(r1)
808
809         /* switch stacks to newstack -- &kexec_stack.stack */
810         stdu    r1,THREAD_SIZE-112(r3)
811         mr      r1,r3
812
813         li      r0,0
814         std     r0,16(r1)
815
816         /* save regs for local vars on new stack.
817          * yes, we won't go back, but ...
818          */
819         std     r31,-8(r1)
820         std     r30,-16(r1)
821         std     r29,-24(r1)
822         std     r28,-32(r1)
823         std     r27,-40(r1)
824         std     r26,-48(r1)
825         std     r25,-56(r1)
826
827         stdu    r1,-112-64(r1)
828
829         /* save args into preserved regs */
830         mr      r31,r3                  /* newstack (both) */
831         mr      r30,r4                  /* start (real) */
832         mr      r29,r5                  /* image (virt) */
833         mr      r28,r6                  /* control, unused */
834         mr      r27,r7                  /* clear_all() fn desc */
835         mr      r26,r8                  /* spare */
836         lhz     r25,PACAHWCPUID(r13)    /* get our phys cpu from paca */
837
838         /* disable interrupts, we are overwriting kernel data next */
839         mfmsr   r3
840         rlwinm  r3,r3,0,17,15
841         mtmsrd  r3,1
842
843         /* copy dest pages, flush whole dest image */
844         mr      r3,r29
845         bl      .kexec_copy_flush       /* (image) */
846
847         /* turn off mmu */
848         bl      real_mode
849
850         /* clear out hardware hash page table and tlb */
851         ld      r5,0(r27)               /* deref function descriptor */
852         mtctr   r5
853         bctrl                           /* ppc_md.hash_clear_all(void); */
854
855 /*
856  *   kexec image calling is:
857  *      the first 0x100 bytes of the entry point are copied to 0
858  *
859  *      all slaves branch to slave = 0x60 (absolute)
860  *              slave(phys_cpu_id);
861  *
862  *      master goes to start = entry point
863  *              start(phys_cpu_id, start, 0);
864  *
865  *
866  *   a wrapper is needed to call existing kernels, here is an approximate
867  *   description of one method:
868  *
869  * v2: (2.6.10)
870  *   start will be near the boot_block (maybe 0x100 bytes before it?)
871  *   it will have a 0x60, which will b to boot_block, where it will wait
872  *   and 0 will store phys into struct boot-block and load r3 from there,
873  *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
874  *
875  * v1: (2.6.9)
876  *    boot block will have all cpus scanning device tree to see if they
877  *    are the boot cpu ?????
878  *    other device tree differences (prop sizes, va vs pa, etc)...
879  */
880
881         /* copy  0x100 bytes starting at start to 0 */
882         li      r3,0
883         mr      r4,r30
884         li      r5,0x100
885         li      r6,0
886         bl      .copy_and_flush /* (dest, src, copy limit, start offset) */
887 1:      /* assume normal blr return */
888
889         /* release other cpus to the new kernel secondary start at 0x60 */
890         mflr    r5
891         li      r6,1
892         stw     r6,kexec_flag-1b(5)
893         mr      r3,r25  # my phys cpu
894         mr      r4,r30  # start, aka phys mem offset
895         mtlr    4
896         li      r5,0
897         blr     /* image->start(physid, image->start, 0); */
898 #endif /* CONFIG_KEXEC */