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