xref: /linux/arch/powerpc/kernel/misc_64.S (revision 858259cf7d1c443c836a2022b78cb281f0a9b95e)
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
411:	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
531:	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
1372:	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"
147PPC64_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
1791:	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
1952:	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
2250:	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
2590:	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
2820:	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
3110:	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
3211:	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-
34800:	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-
36100:	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-
37200:	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-
38500:	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-
39600:	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-
40900:	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-
42100:	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-
43500:	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-
44600:	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-
45900:	lwzu	r5,4(r4)
460	stw	r5,0(r3)
461	bdnz	00b
462	sync
463	blr
464
465/*
466 * identify_cpu and calls setup_cpu
467 * In:	r3 = base of the cpu_specs array
468 *	r4 = address of cur_cpu_spec
469 *	r5 = relocation offset
470 */
471_GLOBAL(identify_cpu)
472	mfpvr	r7
4731:
474	lwz	r8,CPU_SPEC_PVR_MASK(r3)
475	and	r8,r8,r7
476	lwz	r9,CPU_SPEC_PVR_VALUE(r3)
477	cmplw	0,r9,r8
478	beq	1f
479	addi	r3,r3,CPU_SPEC_ENTRY_SIZE
480	b	1b
4811:
482	sub	r0,r3,r5
483	std	r0,0(r4)
484	ld	r4,CPU_SPEC_SETUP(r3)
485	add	r4,r4,r5
486	ld	r4,0(r4)
487	add	r4,r4,r5
488	mtctr	r4
489	/* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
490	mr	r4,r3
491	mr	r3,r5
492	bctr
493
494/*
495 * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
496 * and writes nop's over sections of code that don't apply for this cpu.
497 * r3 = data offset (not changed)
498 */
499_GLOBAL(do_cpu_ftr_fixups)
500	/* Get CPU 0 features */
501	LOADADDR(r6,cur_cpu_spec)
502	sub	r6,r6,r3
503	ld	r4,0(r6)
504	sub	r4,r4,r3
505	ld	r4,CPU_SPEC_FEATURES(r4)
506	/* Get the fixup table */
507	LOADADDR(r6,__start___ftr_fixup)
508	sub	r6,r6,r3
509	LOADADDR(r7,__stop___ftr_fixup)
510	sub	r7,r7,r3
511	/* Do the fixup */
5121:	cmpld	r6,r7
513	bgelr
514	addi	r6,r6,32
515	ld	r8,-32(r6)	/* mask */
516	and	r8,r8,r4
517	ld	r9,-24(r6)	/* value */
518	cmpld	r8,r9
519	beq	1b
520	ld	r8,-16(r6)	/* section begin */
521	ld	r9,-8(r6)	/* section end */
522	subf.	r9,r8,r9
523	beq	1b
524	/* write nops over the section of code */
525	/* todo: if large section, add a branch at the start of it */
526	srwi	r9,r9,2
527	mtctr	r9
528	sub	r8,r8,r3
529	lis	r0,0x60000000@h	/* nop */
5303:	stw	r0,0(r8)
531	andi.	r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
532	beq	2f
533	dcbst	0,r8		/* suboptimal, but simpler */
534	sync
535	icbi	0,r8
5362:	addi	r8,r8,4
537	bdnz	3b
538	sync			/* additional sync needed on g4 */
539	isync
540	b	1b
541
542#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
543/*
544 * Do an IO access in real mode
545 */
546_GLOBAL(real_readb)
547	mfmsr	r7
548	ori	r0,r7,MSR_DR
549	xori	r0,r0,MSR_DR
550	sync
551	mtmsrd	r0
552	sync
553	isync
554	mfspr	r6,SPRN_HID4
555	rldicl	r5,r6,32,0
556	ori	r5,r5,0x100
557	rldicl	r5,r5,32,0
558	sync
559	mtspr	SPRN_HID4,r5
560	isync
561	slbia
562	isync
563	lbz	r3,0(r3)
564	sync
565	mtspr	SPRN_HID4,r6
566	isync
567	slbia
568	isync
569	mtmsrd	r7
570	sync
571	isync
572	blr
573
574	/*
575 * Do an IO access in real mode
576 */
577_GLOBAL(real_writeb)
578	mfmsr	r7
579	ori	r0,r7,MSR_DR
580	xori	r0,r0,MSR_DR
581	sync
582	mtmsrd	r0
583	sync
584	isync
585	mfspr	r6,SPRN_HID4
586	rldicl	r5,r6,32,0
587	ori	r5,r5,0x100
588	rldicl	r5,r5,32,0
589	sync
590	mtspr	SPRN_HID4,r5
591	isync
592	slbia
593	isync
594	stb	r3,0(r4)
595	sync
596	mtspr	SPRN_HID4,r6
597	isync
598	slbia
599	isync
600	mtmsrd	r7
601	sync
602	isync
603	blr
604#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
605
606/*
607 * Create a kernel thread
608 *   kernel_thread(fn, arg, flags)
609 */
610_GLOBAL(kernel_thread)
611	std	r29,-24(r1)
612	std	r30,-16(r1)
613	stdu	r1,-STACK_FRAME_OVERHEAD(r1)
614	mr	r29,r3
615	mr	r30,r4
616	ori	r3,r5,CLONE_VM	/* flags */
617	oris	r3,r3,(CLONE_UNTRACED>>16)
618	li	r4,0		/* new sp (unused) */
619	li	r0,__NR_clone
620	sc
621	cmpdi	0,r3,0		/* parent or child? */
622	bne	1f		/* return if parent */
623	li	r0,0
624	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
625	ld	r2,8(r29)
626	ld	r29,0(r29)
627	mtlr	r29              /* fn addr in lr */
628	mr	r3,r30	        /* load arg and call fn */
629	blrl
630	li	r0,__NR_exit	/* exit after child exits */
631        li	r3,0
632	sc
6331:	addi	r1,r1,STACK_FRAME_OVERHEAD
634	ld	r29,-24(r1)
635	ld	r30,-16(r1)
636	blr
637
638/*
639 * disable_kernel_fp()
640 * Disable the FPU.
641 */
642_GLOBAL(disable_kernel_fp)
643	mfmsr	r3
644	rldicl	r0,r3,(63-MSR_FP_LG),1
645	rldicl	r3,r0,(MSR_FP_LG+1),0
646	mtmsrd	r3			/* disable use of fpu now */
647	isync
648	blr
649
650#ifdef CONFIG_ALTIVEC
651
652#if 0 /* this has no callers for now */
653/*
654 * disable_kernel_altivec()
655 * Disable the VMX.
656 */
657_GLOBAL(disable_kernel_altivec)
658	mfmsr	r3
659	rldicl	r0,r3,(63-MSR_VEC_LG),1
660	rldicl	r3,r0,(MSR_VEC_LG+1),0
661	mtmsrd	r3			/* disable use of VMX now */
662	isync
663	blr
664#endif /* 0 */
665
666/*
667 * giveup_altivec(tsk)
668 * Disable VMX for the task given as the argument,
669 * and save the vector registers in its thread_struct.
670 * Enables the VMX for use in the kernel on return.
671 */
672_GLOBAL(giveup_altivec)
673	mfmsr	r5
674	oris	r5,r5,MSR_VEC@h
675	mtmsrd	r5			/* enable use of VMX now */
676	isync
677	cmpdi	0,r3,0
678	beqlr-				/* if no previous owner, done */
679	addi	r3,r3,THREAD		/* want THREAD of task */
680	ld	r5,PT_REGS(r3)
681	cmpdi	0,r5,0
682	SAVE_32VRS(0,r4,r3)
683	mfvscr	vr0
684	li	r4,THREAD_VSCR
685	stvx	vr0,r4,r3
686	beq	1f
687	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
688	lis	r3,MSR_VEC@h
689	andc	r4,r4,r3		/* disable FP for previous task */
690	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
6911:
692#ifndef CONFIG_SMP
693	li	r5,0
694	ld	r4,last_task_used_altivec@got(r2)
695	std	r5,0(r4)
696#endif /* CONFIG_SMP */
697	blr
698
699#endif /* CONFIG_ALTIVEC */
700
701_GLOBAL(__setup_cpu_power3)
702	blr
703
704_GLOBAL(execve)
705	li	r0,__NR_execve
706	sc
707	bnslr
708	neg	r3,r3
709	blr
710
711/* kexec_wait(phys_cpu)
712 *
713 * wait for the flag to change, indicating this kernel is going away but
714 * the slave code for the next one is at addresses 0 to 100.
715 *
716 * This is used by all slaves.
717 *
718 * Physical (hardware) cpu id should be in r3.
719 */
720_GLOBAL(kexec_wait)
721	bl	1f
7221:	mflr	r5
723	addi	r5,r5,kexec_flag-1b
724
72599:	HMT_LOW
726#ifdef CONFIG_KEXEC		/* use no memory without kexec */
727	lwz	r4,0(r5)
728	cmpwi	0,r4,0
729	bnea	0x60
730#endif
731	b	99b
732
733/* this can be in text because we won't change it until we are
734 * running in real anyways
735 */
736kexec_flag:
737	.long	0
738
739
740#ifdef CONFIG_KEXEC
741
742/* kexec_smp_wait(void)
743 *
744 * call with interrupts off
745 * note: this is a terminal routine, it does not save lr
746 *
747 * get phys id from paca
748 * set paca id to -1 to say we got here
749 * switch to real mode
750 * join other cpus in kexec_wait(phys_id)
751 */
752_GLOBAL(kexec_smp_wait)
753	lhz	r3,PACAHWCPUID(r13)
754	li	r4,-1
755	sth	r4,PACAHWCPUID(r13)	/* let others know we left */
756	bl	real_mode
757	b	.kexec_wait
758
759/*
760 * switch to real mode (turn mmu off)
761 * we use the early kernel trick that the hardware ignores bits
762 * 0 and 1 (big endian) of the effective address in real mode
763 *
764 * don't overwrite r3 here, it is live for kexec_wait above.
765 */
766real_mode:	/* assume normal blr return */
7671:	li	r9,MSR_RI
768	li	r10,MSR_DR|MSR_IR
769	mflr	r11		/* return address to SRR0 */
770	mfmsr	r12
771	andc	r9,r12,r9
772	andc	r10,r12,r10
773
774	mtmsrd	r9,1
775	mtspr	SPRN_SRR1,r10
776	mtspr	SPRN_SRR0,r11
777	rfid
778
779
780/*
781 * kexec_sequence(newstack, start, image, control, clear_all())
782 *
783 * does the grungy work with stack switching and real mode switches
784 * also does simple calls to other code
785 */
786
787_GLOBAL(kexec_sequence)
788	mflr	r0
789	std	r0,16(r1)
790
791	/* switch stacks to newstack -- &kexec_stack.stack */
792	stdu	r1,THREAD_SIZE-112(r3)
793	mr	r1,r3
794
795	li	r0,0
796	std	r0,16(r1)
797
798	/* save regs for local vars on new stack.
799	 * yes, we won't go back, but ...
800	 */
801	std	r31,-8(r1)
802	std	r30,-16(r1)
803	std	r29,-24(r1)
804	std	r28,-32(r1)
805	std	r27,-40(r1)
806	std	r26,-48(r1)
807	std	r25,-56(r1)
808
809	stdu	r1,-112-64(r1)
810
811	/* save args into preserved regs */
812	mr	r31,r3			/* newstack (both) */
813	mr	r30,r4			/* start (real) */
814	mr	r29,r5			/* image (virt) */
815	mr	r28,r6			/* control, unused */
816	mr	r27,r7			/* clear_all() fn desc */
817	mr	r26,r8			/* spare */
818	lhz	r25,PACAHWCPUID(r13)	/* get our phys cpu from paca */
819
820	/* disable interrupts, we are overwriting kernel data next */
821	mfmsr	r3
822	rlwinm	r3,r3,0,17,15
823	mtmsrd	r3,1
824
825	/* copy dest pages, flush whole dest image */
826	mr	r3,r29
827	bl	.kexec_copy_flush	/* (image) */
828
829	/* turn off mmu */
830	bl	real_mode
831
832	/* clear out hardware hash page table and tlb */
833	ld	r5,0(r27)		/* deref function descriptor */
834	mtctr	r5
835	bctrl				/* ppc_md.hash_clear_all(void); */
836
837/*
838 *   kexec image calling is:
839 *      the first 0x100 bytes of the entry point are copied to 0
840 *
841 *      all slaves branch to slave = 0x60 (absolute)
842 *              slave(phys_cpu_id);
843 *
844 *      master goes to start = entry point
845 *              start(phys_cpu_id, start, 0);
846 *
847 *
848 *   a wrapper is needed to call existing kernels, here is an approximate
849 *   description of one method:
850 *
851 * v2: (2.6.10)
852 *   start will be near the boot_block (maybe 0x100 bytes before it?)
853 *   it will have a 0x60, which will b to boot_block, where it will wait
854 *   and 0 will store phys into struct boot-block and load r3 from there,
855 *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
856 *
857 * v1: (2.6.9)
858 *    boot block will have all cpus scanning device tree to see if they
859 *    are the boot cpu ?????
860 *    other device tree differences (prop sizes, va vs pa, etc)...
861 */
862
863	/* copy  0x100 bytes starting at start to 0 */
864	li	r3,0
865	mr	r4,r30
866	li	r5,0x100
867	li	r6,0
868	bl	.copy_and_flush	/* (dest, src, copy limit, start offset) */
8691:	/* assume normal blr return */
870
871	/* release other cpus to the new kernel secondary start at 0x60 */
872	mflr	r5
873	li	r6,1
874	stw	r6,kexec_flag-1b(5)
875	mr	r3,r25	# my phys cpu
876	mr	r4,r30	# start, aka phys mem offset
877	mtlr	4
878	li	r5,0
879	blr	/* image->start(physid, image->start, 0); */
880#endif /* CONFIG_KEXEC */
881