1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 *  PowerPC version
4 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
5 *
6 *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
7 *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
8 *  Adapted for Power Macintosh by Paul Mackerras.
9 *  Low-level exception handlers and MMU support
10 *  rewritten by Paul Mackerras.
11 *    Copyright (C) 1996 Paul Mackerras.
12 *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
13 *
14 *  This file contains the low-level support and setup for the
15 *  PowerPC platform, including trap and interrupt dispatch.
16 *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
17 */
18
19#include <linux/init.h>
20#include <linux/pgtable.h>
21#include <asm/reg.h>
22#include <asm/page.h>
23#include <asm/mmu.h>
24#include <asm/cputable.h>
25#include <asm/cache.h>
26#include <asm/thread_info.h>
27#include <asm/ppc_asm.h>
28#include <asm/asm-offsets.h>
29#include <asm/ptrace.h>
30#include <asm/bug.h>
31#include <asm/kvm_book3s_asm.h>
32#include <asm/export.h>
33#include <asm/feature-fixups.h>
34#include <asm/interrupt.h>
35
36#include "head_32.h"
37
38#define LOAD_BAT(n, reg, RA, RB)	\
39	/* see the comment for clear_bats() -- Cort */ \
40	li	RA,0;			\
41	mtspr	SPRN_IBAT##n##U,RA;	\
42	mtspr	SPRN_DBAT##n##U,RA;	\
43	lwz	RA,(n*16)+0(reg);	\
44	lwz	RB,(n*16)+4(reg);	\
45	mtspr	SPRN_IBAT##n##U,RA;	\
46	mtspr	SPRN_IBAT##n##L,RB;	\
47	lwz	RA,(n*16)+8(reg);	\
48	lwz	RB,(n*16)+12(reg);	\
49	mtspr	SPRN_DBAT##n##U,RA;	\
50	mtspr	SPRN_DBAT##n##L,RB
51
52	__HEAD
53_GLOBAL(_stext);
54
55/*
56 * _start is defined this way because the XCOFF loader in the OpenFirmware
57 * on the powermac expects the entry point to be a procedure descriptor.
58 */
59_GLOBAL(_start);
60	/*
61	 * These are here for legacy reasons, the kernel used to
62	 * need to look like a coff function entry for the pmac
63	 * but we're always started by some kind of bootloader now.
64	 *  -- Cort
65	 */
66	nop	/* used by __secondary_hold on prep (mtx) and chrp smp */
67	nop	/* used by __secondary_hold on prep (mtx) and chrp smp */
68	nop
69
70/* PMAC
71 * Enter here with the kernel text, data and bss loaded starting at
72 * 0, running with virtual == physical mapping.
73 * r5 points to the prom entry point (the client interface handler
74 * address).  Address translation is turned on, with the prom
75 * managing the hash table.  Interrupts are disabled.  The stack
76 * pointer (r1) points to just below the end of the half-meg region
77 * from 0x380000 - 0x400000, which is mapped in already.
78 *
79 * If we are booted from MacOS via BootX, we enter with the kernel
80 * image loaded somewhere, and the following values in registers:
81 *  r3: 'BooX' (0x426f6f58)
82 *  r4: virtual address of boot_infos_t
83 *  r5: 0
84 *
85 * PREP
86 * This is jumped to on prep systems right after the kernel is relocated
87 * to its proper place in memory by the boot loader.  The expected layout
88 * of the regs is:
89 *   r3: ptr to residual data
90 *   r4: initrd_start or if no initrd then 0
91 *   r5: initrd_end - unused if r4 is 0
92 *   r6: Start of command line string
93 *   r7: End of command line string
94 *
95 * This just gets a minimal mmu environment setup so we can call
96 * start_here() to do the real work.
97 * -- Cort
98 */
99
100	.globl	__start
101__start:
102/*
103 * We have to do any OF calls before we map ourselves to KERNELBASE,
104 * because OF may have I/O devices mapped into that area
105 * (particularly on CHRP).
106 */
107	cmpwi	0,r5,0
108	beq	1f
109
110#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
111	/* find out where we are now */
112	bcl	20,31,$+4
1130:	mflr	r8			/* r8 = runtime addr here */
114	addis	r8,r8,(_stext - 0b)@ha
115	addi	r8,r8,(_stext - 0b)@l	/* current runtime base addr */
116	bl	prom_init
117#endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */
118
119	/* We never return. We also hit that trap if trying to boot
120	 * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
121	trap
122
123/*
124 * Check for BootX signature when supporting PowerMac and branch to
125 * appropriate trampoline if it's present
126 */
127#ifdef CONFIG_PPC_PMAC
1281:	lis	r31,0x426f
129	ori	r31,r31,0x6f58
130	cmpw	0,r3,r31
131	bne	1f
132	bl	bootx_init
133	trap
134#endif /* CONFIG_PPC_PMAC */
135
1361:	mr	r31,r3			/* save device tree ptr */
137	li	r24,0			/* cpu # */
138
139/*
140 * early_init() does the early machine identification and does
141 * the necessary low-level setup and clears the BSS
142 *  -- Cort <cort@fsmlabs.com>
143 */
144	bl	early_init
145
146/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
147 * the physical address we are running at, returned by early_init()
148 */
149 	bl	mmu_off
150__after_mmu_off:
151	bl	clear_bats
152	bl	flush_tlbs
153
154	bl	initial_bats
155	bl	load_segment_registers
156	bl	reloc_offset
157	bl	early_hash_table
158#if defined(CONFIG_BOOTX_TEXT)
159	bl	setup_disp_bat
160#endif
161#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
162	bl	setup_cpm_bat
163#endif
164#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
165	bl	setup_usbgecko_bat
166#endif
167
168/*
169 * Call setup_cpu for CPU 0 and initialize 6xx Idle
170 */
171	bl	reloc_offset
172	li	r24,0			/* cpu# */
173	bl	call_setup_cpu		/* Call setup_cpu for this CPU */
174	bl	reloc_offset
175	bl	init_idle_6xx
176
177
178/*
179 * We need to run with _start at physical address 0.
180 * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
181 * the exception vectors at 0 (and therefore this copy
182 * overwrites OF's exception vectors with our own).
183 * The MMU is off at this point.
184 */
185	bl	reloc_offset
186	mr	r26,r3
187	addis	r4,r3,KERNELBASE@h	/* current address of _start */
188	lis	r5,PHYSICAL_START@h
189	cmplw	0,r4,r5			/* already running at PHYSICAL_START? */
190	bne	relocate_kernel
191/*
192 * we now have the 1st 16M of ram mapped with the bats.
193 * prep needs the mmu to be turned on here, but pmac already has it on.
194 * this shouldn't bother the pmac since it just gets turned on again
195 * as we jump to our code at KERNELBASE. -- Cort
196 * Actually no, pmac doesn't have it on any more. BootX enters with MMU
197 * off, and in other cases, we now turn it off before changing BATs above.
198 */
199turn_on_mmu:
200	mfmsr	r0
201	ori	r0,r0,MSR_DR|MSR_IR|MSR_RI
202	mtspr	SPRN_SRR1,r0
203	lis	r0,start_here@h
204	ori	r0,r0,start_here@l
205	mtspr	SPRN_SRR0,r0
206	rfi				/* enables MMU */
207
208/*
209 * We need __secondary_hold as a place to hold the other cpus on
210 * an SMP machine, even when we are running a UP kernel.
211 */
212	. = 0xc0			/* for prep bootloader */
213	li	r3,1			/* MTX only has 1 cpu */
214	.globl	__secondary_hold
215__secondary_hold:
216	/* tell the master we're here */
217	stw	r3,__secondary_hold_acknowledge@l(0)
218#ifdef CONFIG_SMP
219100:	lwz	r4,0(0)
220	/* wait until we're told to start */
221	cmpw	0,r4,r3
222	bne	100b
223	/* our cpu # was at addr 0 - go */
224	mr	r24,r3			/* cpu # */
225	b	__secondary_start
226#else
227	b	.
228#endif /* CONFIG_SMP */
229
230	.globl	__secondary_hold_spinloop
231__secondary_hold_spinloop:
232	.long	0
233	.globl	__secondary_hold_acknowledge
234__secondary_hold_acknowledge:
235	.long	-1
236
237/* System reset */
238/* core99 pmac starts the seconary here by changing the vector, and
239   putting it back to what it was (unknown_async_exception) when done.  */
240	EXCEPTION(INTERRUPT_SYSTEM_RESET, Reset, unknown_async_exception)
241
242/* Machine check */
243/*
244 * On CHRP, this is complicated by the fact that we could get a
245 * machine check inside RTAS, and we have no guarantee that certain
246 * critical registers will have the values we expect.  The set of
247 * registers that might have bad values includes all the GPRs
248 * and all the BATs.  We indicate that we are in RTAS by putting
249 * a non-zero value, the address of the exception frame to use,
250 * in thread.rtas_sp.  The machine check handler checks thread.rtas_sp
251 * and uses its value if it is non-zero.
252 * (Other exception handlers assume that r1 is a valid kernel stack
253 * pointer when we take an exception from supervisor mode.)
254 *	-- paulus.
255 */
256	START_EXCEPTION(INTERRUPT_MACHINE_CHECK, MachineCheck)
257	EXCEPTION_PROLOG_0
258#ifdef CONFIG_PPC_CHRP
259	mtspr	SPRN_SPRG_SCRATCH2,r1
260	mfspr	r1, SPRN_SPRG_THREAD
261	lwz	r1, RTAS_SP(r1)
262	cmpwi	cr1, r1, 0
263	bne	cr1, 7f
264	mfspr	r1, SPRN_SPRG_SCRATCH2
265#endif /* CONFIG_PPC_CHRP */
266	EXCEPTION_PROLOG_1
2677:	EXCEPTION_PROLOG_2 0x200 MachineCheck
268#ifdef CONFIG_PPC_CHRP
269	beq	cr1, 1f
270	twi	31, 0, 0
271#endif
2721:	prepare_transfer_to_handler
273	bl	machine_check_exception
274	b	interrupt_return
275
276/* Data access exception. */
277	START_EXCEPTION(INTERRUPT_DATA_STORAGE, DataAccess)
278#ifdef CONFIG_PPC_BOOK3S_604
279BEGIN_MMU_FTR_SECTION
280	mtspr	SPRN_SPRG_SCRATCH2,r10
281	mfspr	r10, SPRN_SPRG_THREAD
282	stw	r11, THR11(r10)
283	mfspr	r10, SPRN_DSISR
284	mfcr	r11
285	andis.	r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
286	mfspr	r10, SPRN_SPRG_THREAD
287	beq	hash_page_dsi
288.Lhash_page_dsi_cont:
289	mtcr	r11
290	lwz	r11, THR11(r10)
291	mfspr	r10, SPRN_SPRG_SCRATCH2
292MMU_FTR_SECTION_ELSE
293	b	1f
294ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
295#endif
2961:	EXCEPTION_PROLOG_0 handle_dar_dsisr=1
297	EXCEPTION_PROLOG_1
298	EXCEPTION_PROLOG_2 INTERRUPT_DATA_STORAGE DataAccess handle_dar_dsisr=1
299	prepare_transfer_to_handler
300	lwz	r5, _DSISR(r1)
301	andis.	r0, r5, DSISR_DABRMATCH@h
302	bne-	1f
303	bl	do_page_fault
304	b	interrupt_return
3051:	bl	do_break
306	REST_NVGPRS(r1)
307	b	interrupt_return
308
309
310/* Instruction access exception. */
311	START_EXCEPTION(INTERRUPT_INST_STORAGE, InstructionAccess)
312	mtspr	SPRN_SPRG_SCRATCH0,r10
313	mtspr	SPRN_SPRG_SCRATCH1,r11
314	mfspr	r10, SPRN_SPRG_THREAD
315	mfspr	r11, SPRN_SRR0
316	stw	r11, SRR0(r10)
317	mfspr	r11, SPRN_SRR1		/* check whether user or kernel */
318	stw	r11, SRR1(r10)
319	mfcr	r10
320#ifdef CONFIG_PPC_BOOK3S_604
321BEGIN_MMU_FTR_SECTION
322	andis.	r11, r11, SRR1_ISI_NOPT@h	/* no pte found? */
323	bne	hash_page_isi
324.Lhash_page_isi_cont:
325	mfspr	r11, SPRN_SRR1		/* check whether user or kernel */
326END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
327#endif
328	andi.	r11, r11, MSR_PR
329
330	EXCEPTION_PROLOG_1
331	EXCEPTION_PROLOG_2 INTERRUPT_INST_STORAGE InstructionAccess
332	andis.	r5,r9,DSISR_SRR1_MATCH_32S@h /* Filter relevant SRR1 bits */
333	stw	r5, _DSISR(r11)
334	stw	r12, _DAR(r11)
335	prepare_transfer_to_handler
336	bl	do_page_fault
337	b	interrupt_return
338
339/* External interrupt */
340	EXCEPTION(INTERRUPT_EXTERNAL, HardwareInterrupt, do_IRQ)
341
342/* Alignment exception */
343	START_EXCEPTION(INTERRUPT_ALIGNMENT, Alignment)
344	EXCEPTION_PROLOG INTERRUPT_ALIGNMENT Alignment handle_dar_dsisr=1
345	prepare_transfer_to_handler
346	bl	alignment_exception
347	REST_NVGPRS(r1)
348	b	interrupt_return
349
350/* Program check exception */
351	START_EXCEPTION(INTERRUPT_PROGRAM, ProgramCheck)
352	EXCEPTION_PROLOG INTERRUPT_PROGRAM ProgramCheck
353	prepare_transfer_to_handler
354	bl	program_check_exception
355	REST_NVGPRS(r1)
356	b	interrupt_return
357
358/* Floating-point unavailable */
359	START_EXCEPTION(0x800, FPUnavailable)
360#ifdef CONFIG_PPC_FPU
361BEGIN_FTR_SECTION
362/*
363 * Certain Freescale cores don't have a FPU and treat fp instructions
364 * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
365 */
366	b 	ProgramCheck
367END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
368	EXCEPTION_PROLOG INTERRUPT_FP_UNAVAIL FPUnavailable
369	beq	1f
370	bl	load_up_fpu		/* if from user, just load it up */
371	b	fast_exception_return
3721:	prepare_transfer_to_handler
373	bl	kernel_fp_unavailable_exception
374	b	interrupt_return
375#else
376	b 	ProgramCheck
377#endif
378
379/* Decrementer */
380	EXCEPTION(INTERRUPT_DECREMENTER, Decrementer, timer_interrupt)
381
382	EXCEPTION(0xa00, Trap_0a, unknown_exception)
383	EXCEPTION(0xb00, Trap_0b, unknown_exception)
384
385/* System call */
386	START_EXCEPTION(INTERRUPT_SYSCALL, SystemCall)
387	SYSCALL_ENTRY	INTERRUPT_SYSCALL
388
389	EXCEPTION(INTERRUPT_TRACE, SingleStep, single_step_exception)
390	EXCEPTION(0xe00, Trap_0e, unknown_exception)
391
392/*
393 * The Altivec unavailable trap is at 0x0f20.  Foo.
394 * We effectively remap it to 0x3000.
395 * We include an altivec unavailable exception vector even if
396 * not configured for Altivec, so that you can't panic a
397 * non-altivec kernel running on a machine with altivec just
398 * by executing an altivec instruction.
399 */
400	START_EXCEPTION(INTERRUPT_PERFMON, PerformanceMonitorTrap)
401	b	PerformanceMonitor
402
403	START_EXCEPTION(INTERRUPT_ALTIVEC_UNAVAIL, AltiVecUnavailableTrap)
404	b	AltiVecUnavailable
405
406	__HEAD
407/*
408 * Handle TLB miss for instruction on 603/603e.
409 * Note: we get an alternate set of r0 - r3 to use automatically.
410 */
411	. = INTERRUPT_INST_TLB_MISS_603
412InstructionTLBMiss:
413/*
414 * r0:	scratch
415 * r1:	linux style pte ( later becomes ppc hardware pte )
416 * r2:	ptr to linux-style pte
417 * r3:	scratch
418 */
419	/* Get PTE (linux-style) and check access */
420	mfspr	r3,SPRN_IMISS
421#ifdef CONFIG_MODULES
422	lis	r1, TASK_SIZE@h		/* check if kernel address */
423	cmplw	0,r1,r3
424#endif
425	mfspr	r2, SPRN_SDR1
426	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
427	rlwinm	r2, r2, 28, 0xfffff000
428#ifdef CONFIG_MODULES
429	bgt-	112f
430	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
431	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
432	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
433#endif
434112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
435	lwz	r2,0(r2)		/* get pmd entry */
436	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
437	beq-	InstructionAddressInvalid	/* return if no mapping */
438	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
439	lwz	r0,0(r2)		/* get linux-style pte */
440	andc.	r1,r1,r0		/* check access & ~permission */
441	bne-	InstructionAddressInvalid /* return if access not permitted */
442	/* Convert linux-style PTE to low word of PPC-style PTE */
443	rlwimi	r0,r0,32-2,31,31	/* _PAGE_USER -> PP lsb */
444	ori	r1, r1, 0xe06		/* clear out reserved bits */
445	andc	r1, r0, r1		/* PP = user? 1 : 0 */
446BEGIN_FTR_SECTION
447	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
448END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
449	mtspr	SPRN_RPA,r1
450	tlbli	r3
451	mfspr	r3,SPRN_SRR1		/* Need to restore CR0 */
452	mtcrf	0x80,r3
453	rfi
454InstructionAddressInvalid:
455	mfspr	r3,SPRN_SRR1
456	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
457
458	addis	r1,r1,0x2000
459	mtspr	SPRN_DSISR,r1	/* (shouldn't be needed) */
460	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
461	or	r2,r2,r1
462	mtspr	SPRN_SRR1,r2
463	mfspr	r1,SPRN_IMISS	/* Get failing address */
464	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
465	rlwimi	r2,r2,1,30,30	/* change 1 -> 3 */
466	xor	r1,r1,r2
467	mtspr	SPRN_DAR,r1	/* Set fault address */
468	mfmsr	r0		/* Restore "normal" registers */
469	xoris	r0,r0,MSR_TGPR>>16
470	mtcrf	0x80,r3		/* Restore CR0 */
471	mtmsr	r0
472	b	InstructionAccess
473
474/*
475 * Handle TLB miss for DATA Load operation on 603/603e
476 */
477	. = INTERRUPT_DATA_LOAD_TLB_MISS_603
478DataLoadTLBMiss:
479/*
480 * r0:	scratch
481 * r1:	linux style pte ( later becomes ppc hardware pte )
482 * r2:	ptr to linux-style pte
483 * r3:	scratch
484 */
485	/* Get PTE (linux-style) and check access */
486	mfspr	r3,SPRN_DMISS
487	lis	r1, TASK_SIZE@h		/* check if kernel address */
488	cmplw	0,r1,r3
489	mfspr	r2, SPRN_SDR1
490	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
491	rlwinm	r2, r2, 28, 0xfffff000
492	bgt-	112f
493	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
494	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED
495	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
496112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
497	lwz	r2,0(r2)		/* get pmd entry */
498	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
499	beq-	DataAddressInvalid	/* return if no mapping */
500	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
501	lwz	r0,0(r2)		/* get linux-style pte */
502	andc.	r1,r1,r0		/* check access & ~permission */
503	bne-	DataAddressInvalid	/* return if access not permitted */
504	/* Convert linux-style PTE to low word of PPC-style PTE */
505	rlwinm	r1,r0,32-9,30,30	/* _PAGE_RW -> PP msb */
506	rlwimi	r0,r0,32-1,30,30	/* _PAGE_USER -> PP msb */
507	rlwimi	r1,r0,32-3,24,24	/* _PAGE_RW -> _PAGE_DIRTY */
508	rlwimi	r0,r0,32-1,31,31	/* _PAGE_USER -> PP lsb */
509	xori	r1,r1,_PAGE_DIRTY	/* clear dirty when not rw */
510	ori	r1,r1,0xe04		/* clear out reserved bits */
511	andc	r1,r0,r1		/* PP = user? rw? 1: 3: 0 */
512BEGIN_FTR_SECTION
513	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
514END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
515	mtspr	SPRN_RPA,r1
516BEGIN_MMU_FTR_SECTION
517	li	r0,1
518	mfspr	r1,SPRN_SPRG_603_LRU
519	rlwinm	r2,r3,20,27,31		/* Get Address bits 15:19 */
520	slw	r0,r0,r2
521	xor	r1,r0,r1
522	srw	r0,r1,r2
523	mtspr   SPRN_SPRG_603_LRU,r1
524	mfspr	r2,SPRN_SRR1
525	rlwimi	r2,r0,31-14,14,14
526	mtspr   SPRN_SRR1,r2
527	mtcrf	0x80,r2
528	tlbld	r3
529	rfi
530MMU_FTR_SECTION_ELSE
531	mfspr	r2,SPRN_SRR1		/* Need to restore CR0 */
532	mtcrf	0x80,r2
533	tlbld	r3
534	rfi
535ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
536DataAddressInvalid:
537	mfspr	r3,SPRN_SRR1
538	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
539	addis	r1,r1,0x2000
540	mtspr	SPRN_DSISR,r1
541	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
542	mtspr	SPRN_SRR1,r2
543	mfspr	r1,SPRN_DMISS	/* Get failing address */
544	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
545	beq	20f		/* Jump if big endian */
546	xori	r1,r1,3
54720:	mtspr	SPRN_DAR,r1	/* Set fault address */
548	mfmsr	r0		/* Restore "normal" registers */
549	xoris	r0,r0,MSR_TGPR>>16
550	mtcrf	0x80,r3		/* Restore CR0 */
551	mtmsr	r0
552	b	DataAccess
553
554/*
555 * Handle TLB miss for DATA Store on 603/603e
556 */
557	. = INTERRUPT_DATA_STORE_TLB_MISS_603
558DataStoreTLBMiss:
559/*
560 * r0:	scratch
561 * r1:	linux style pte ( later becomes ppc hardware pte )
562 * r2:	ptr to linux-style pte
563 * r3:	scratch
564 */
565	/* Get PTE (linux-style) and check access */
566	mfspr	r3,SPRN_DMISS
567	lis	r1, TASK_SIZE@h		/* check if kernel address */
568	cmplw	0,r1,r3
569	mfspr	r2, SPRN_SDR1
570	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
571	rlwinm	r2, r2, 28, 0xfffff000
572	bgt-	112f
573	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
574	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
575	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
576112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
577	lwz	r2,0(r2)		/* get pmd entry */
578	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
579	beq-	DataAddressInvalid	/* return if no mapping */
580	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
581	lwz	r0,0(r2)		/* get linux-style pte */
582	andc.	r1,r1,r0		/* check access & ~permission */
583	bne-	DataAddressInvalid	/* return if access not permitted */
584	/* Convert linux-style PTE to low word of PPC-style PTE */
585	rlwimi	r0,r0,32-2,31,31	/* _PAGE_USER -> PP lsb */
586	li	r1,0xe06		/* clear out reserved bits & PP msb */
587	andc	r1,r0,r1		/* PP = user? 1: 0 */
588BEGIN_FTR_SECTION
589	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
590END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
591	mtspr	SPRN_RPA,r1
592	mfspr	r2,SPRN_SRR1		/* Need to restore CR0 */
593	mtcrf	0x80,r2
594BEGIN_MMU_FTR_SECTION
595	li	r0,1
596	mfspr	r1,SPRN_SPRG_603_LRU
597	rlwinm	r2,r3,20,27,31		/* Get Address bits 15:19 */
598	slw	r0,r0,r2
599	xor	r1,r0,r1
600	srw	r0,r1,r2
601	mtspr   SPRN_SPRG_603_LRU,r1
602	mfspr	r2,SPRN_SRR1
603	rlwimi	r2,r0,31-14,14,14
604	mtspr   SPRN_SRR1,r2
605	mtcrf	0x80,r2
606	tlbld	r3
607	rfi
608MMU_FTR_SECTION_ELSE
609	mfspr	r2,SPRN_SRR1		/* Need to restore CR0 */
610	mtcrf	0x80,r2
611	tlbld	r3
612	rfi
613ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
614
615#ifndef CONFIG_ALTIVEC
616#define altivec_assist_exception	unknown_exception
617#endif
618
619#ifndef CONFIG_TAU_INT
620#define TAUException	unknown_async_exception
621#endif
622
623	EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception)
624	EXCEPTION(0x1400, SMI, SMIException)
625	EXCEPTION(0x1500, Trap_15, unknown_exception)
626	EXCEPTION(0x1600, Trap_16, altivec_assist_exception)
627	EXCEPTION(0x1700, Trap_17, TAUException)
628	EXCEPTION(0x1800, Trap_18, unknown_exception)
629	EXCEPTION(0x1900, Trap_19, unknown_exception)
630	EXCEPTION(0x1a00, Trap_1a, unknown_exception)
631	EXCEPTION(0x1b00, Trap_1b, unknown_exception)
632	EXCEPTION(0x1c00, Trap_1c, unknown_exception)
633	EXCEPTION(0x1d00, Trap_1d, unknown_exception)
634	EXCEPTION(0x1e00, Trap_1e, unknown_exception)
635	EXCEPTION(0x1f00, Trap_1f, unknown_exception)
636	EXCEPTION(0x2000, RunMode, RunModeException)
637	EXCEPTION(0x2100, Trap_21, unknown_exception)
638	EXCEPTION(0x2200, Trap_22, unknown_exception)
639	EXCEPTION(0x2300, Trap_23, unknown_exception)
640	EXCEPTION(0x2400, Trap_24, unknown_exception)
641	EXCEPTION(0x2500, Trap_25, unknown_exception)
642	EXCEPTION(0x2600, Trap_26, unknown_exception)
643	EXCEPTION(0x2700, Trap_27, unknown_exception)
644	EXCEPTION(0x2800, Trap_28, unknown_exception)
645	EXCEPTION(0x2900, Trap_29, unknown_exception)
646	EXCEPTION(0x2a00, Trap_2a, unknown_exception)
647	EXCEPTION(0x2b00, Trap_2b, unknown_exception)
648	EXCEPTION(0x2c00, Trap_2c, unknown_exception)
649	EXCEPTION(0x2d00, Trap_2d, unknown_exception)
650	EXCEPTION(0x2e00, Trap_2e, unknown_exception)
651	EXCEPTION(0x2f00, Trap_2f, unknown_exception)
652
653	__HEAD
654	. = 0x3000
655
656#ifdef CONFIG_PPC_BOOK3S_604
657.macro save_regs_thread		thread
658	stw	r0, THR0(\thread)
659	stw	r3, THR3(\thread)
660	stw	r4, THR4(\thread)
661	stw	r5, THR5(\thread)
662	stw	r6, THR6(\thread)
663	stw	r8, THR8(\thread)
664	stw	r9, THR9(\thread)
665	mflr	r0
666	stw	r0, THLR(\thread)
667	mfctr	r0
668	stw	r0, THCTR(\thread)
669.endm
670
671.macro restore_regs_thread	thread
672	lwz	r0, THLR(\thread)
673	mtlr	r0
674	lwz	r0, THCTR(\thread)
675	mtctr	r0
676	lwz	r0, THR0(\thread)
677	lwz	r3, THR3(\thread)
678	lwz	r4, THR4(\thread)
679	lwz	r5, THR5(\thread)
680	lwz	r6, THR6(\thread)
681	lwz	r8, THR8(\thread)
682	lwz	r9, THR9(\thread)
683.endm
684
685hash_page_dsi:
686	save_regs_thread	r10
687	mfdsisr	r3
688	mfdar	r4
689	mfsrr0	r5
690	mfsrr1	r9
691	rlwinm	r3, r3, 32 - 15, _PAGE_RW	/* DSISR_STORE -> _PAGE_RW */
692	bl	hash_page
693	mfspr	r10, SPRN_SPRG_THREAD
694	restore_regs_thread r10
695	b	.Lhash_page_dsi_cont
696
697hash_page_isi:
698	mr	r11, r10
699	mfspr	r10, SPRN_SPRG_THREAD
700	save_regs_thread	r10
701	li	r3, 0
702	lwz	r4, SRR0(r10)
703	lwz	r9, SRR1(r10)
704	bl	hash_page
705	mfspr	r10, SPRN_SPRG_THREAD
706	restore_regs_thread r10
707	mr	r10, r11
708	b	.Lhash_page_isi_cont
709
710	.globl fast_hash_page_return
711fast_hash_page_return:
712	andis.	r10, r9, SRR1_ISI_NOPT@h	/* Set on ISI, cleared on DSI */
713	mfspr	r10, SPRN_SPRG_THREAD
714	restore_regs_thread r10
715	bne	1f
716
717	/* DSI */
718	mtcr	r11
719	lwz	r11, THR11(r10)
720	mfspr	r10, SPRN_SPRG_SCRATCH2
721	rfi
722
7231:	/* ISI */
724	mtcr	r11
725	mfspr	r11, SPRN_SPRG_SCRATCH1
726	mfspr	r10, SPRN_SPRG_SCRATCH0
727	rfi
728#endif /* CONFIG_PPC_BOOK3S_604 */
729
730#ifdef CONFIG_VMAP_STACK
731	vmap_stack_overflow_exception
732#endif
733
734	__HEAD
735AltiVecUnavailable:
736	EXCEPTION_PROLOG 0xf20 AltiVecUnavailable
737#ifdef CONFIG_ALTIVEC
738	beq	1f
739	bl	load_up_altivec		/* if from user, just load it up */
740	b	fast_exception_return
741#endif /* CONFIG_ALTIVEC */
7421:	prepare_transfer_to_handler
743	bl	altivec_unavailable_exception
744	b	interrupt_return
745
746	__HEAD
747PerformanceMonitor:
748	EXCEPTION_PROLOG 0xf00 PerformanceMonitor
749	prepare_transfer_to_handler
750	bl	performance_monitor_exception
751	b	interrupt_return
752
753
754	__HEAD
755/*
756 * This code is jumped to from the startup code to copy
757 * the kernel image to physical address PHYSICAL_START.
758 */
759relocate_kernel:
760	lis	r3,PHYSICAL_START@h	/* Destination base address */
761	li	r6,0			/* Destination offset */
762	li	r5,0x4000		/* # bytes of memory to copy */
763	bl	copy_and_flush		/* copy the first 0x4000 bytes */
764	addi	r0,r3,4f@l		/* jump to the address of 4f */
765	mtctr	r0			/* in copy and do the rest. */
766	bctr				/* jump to the copy */
7674:	lis	r5,_end-KERNELBASE@h
768	ori	r5,r5,_end-KERNELBASE@l
769	bl	copy_and_flush		/* copy the rest */
770	b	turn_on_mmu
771
772/*
773 * Copy routine used to copy the kernel to start at physical address 0
774 * and flush and invalidate the caches as needed.
775 * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
776 * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
777 */
778_GLOBAL(copy_and_flush)
779	addi	r5,r5,-4
780	addi	r6,r6,-4
7814:	li	r0,L1_CACHE_BYTES/4
782	mtctr	r0
7833:	addi	r6,r6,4			/* copy a cache line */
784	lwzx	r0,r6,r4
785	stwx	r0,r6,r3
786	bdnz	3b
787	dcbst	r6,r3			/* write it to memory */
788	sync
789	icbi	r6,r3			/* flush the icache line */
790	cmplw	0,r6,r5
791	blt	4b
792	sync				/* additional sync needed on g4 */
793	isync
794	addi	r5,r5,4
795	addi	r6,r6,4
796	blr
797
798#ifdef CONFIG_SMP
799	.globl __secondary_start_mpc86xx
800__secondary_start_mpc86xx:
801	mfspr	r3, SPRN_PIR
802	stw	r3, __secondary_hold_acknowledge@l(0)
803	mr	r24, r3			/* cpu # */
804	b	__secondary_start
805
806	.globl	__secondary_start_pmac_0
807__secondary_start_pmac_0:
808	/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
809	li	r24,0
810	b	1f
811	li	r24,1
812	b	1f
813	li	r24,2
814	b	1f
815	li	r24,3
8161:
817	/* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
818	   set to map the 0xf0000000 - 0xffffffff region */
819	mfmsr	r0
820	rlwinm	r0,r0,0,28,26		/* clear DR (0x10) */
821	mtmsr	r0
822	isync
823
824	.globl	__secondary_start
825__secondary_start:
826	/* Copy some CPU settings from CPU 0 */
827	bl	__restore_cpu_setup
828
829	lis	r3,-KERNELBASE@h
830	mr	r4,r24
831	bl	call_setup_cpu		/* Call setup_cpu for this CPU */
832	lis	r3,-KERNELBASE@h
833	bl	init_idle_6xx
834
835	/* get current's stack and current */
836	lis	r2,secondary_current@ha
837	tophys(r2,r2)
838	lwz	r2,secondary_current@l(r2)
839	tophys(r1,r2)
840	lwz	r1,TASK_STACK(r1)
841
842	/* stack */
843	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
844	li	r0,0
845	tophys(r3,r1)
846	stw	r0,0(r3)
847
848	/* load up the MMU */
849	bl	load_segment_registers
850	bl	load_up_mmu
851
852	/* ptr to phys current thread */
853	tophys(r4,r2)
854	addi	r4,r4,THREAD	/* phys address of our thread_struct */
855	mtspr	SPRN_SPRG_THREAD,r4
856BEGIN_MMU_FTR_SECTION
857	lis	r4, (swapper_pg_dir - PAGE_OFFSET)@h
858	ori	r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
859	rlwinm	r4, r4, 4, 0xffff01ff
860	mtspr	SPRN_SDR1, r4
861END_MMU_FTR_SECTION_IFCLR(MMU_FTR_HPTE_TABLE)
862
863	/* enable MMU and jump to start_secondary */
864	li	r4,MSR_KERNEL
865	lis	r3,start_secondary@h
866	ori	r3,r3,start_secondary@l
867	mtspr	SPRN_SRR0,r3
868	mtspr	SPRN_SRR1,r4
869	rfi
870#endif /* CONFIG_SMP */
871
872#ifdef CONFIG_KVM_BOOK3S_HANDLER
873#include "../kvm/book3s_rmhandlers.S"
874#endif
875
876/*
877 * Load stuff into the MMU.  Intended to be called with
878 * IR=0 and DR=0.
879 */
880early_hash_table:
881	sync			/* Force all PTE updates to finish */
882	isync
883	tlbia			/* Clear all TLB entries */
884	sync			/* wait for tlbia/tlbie to finish */
885	TLBSYNC			/* ... on all CPUs */
886	/* Load the SDR1 register (hash table base & size) */
887	lis	r6, early_hash - PAGE_OFFSET@h
888	ori	r6, r6, 3	/* 256kB table */
889	mtspr	SPRN_SDR1, r6
890	blr
891
892load_up_mmu:
893	sync			/* Force all PTE updates to finish */
894	isync
895	tlbia			/* Clear all TLB entries */
896	sync			/* wait for tlbia/tlbie to finish */
897	TLBSYNC			/* ... on all CPUs */
898BEGIN_MMU_FTR_SECTION
899	/* Load the SDR1 register (hash table base & size) */
900	lis	r6,_SDR1@ha
901	tophys(r6,r6)
902	lwz	r6,_SDR1@l(r6)
903	mtspr	SPRN_SDR1,r6
904END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
905
906/* Load the BAT registers with the values set up by MMU_init. */
907	lis	r3,BATS@ha
908	addi	r3,r3,BATS@l
909	tophys(r3,r3)
910	LOAD_BAT(0,r3,r4,r5)
911	LOAD_BAT(1,r3,r4,r5)
912	LOAD_BAT(2,r3,r4,r5)
913	LOAD_BAT(3,r3,r4,r5)
914BEGIN_MMU_FTR_SECTION
915	LOAD_BAT(4,r3,r4,r5)
916	LOAD_BAT(5,r3,r4,r5)
917	LOAD_BAT(6,r3,r4,r5)
918	LOAD_BAT(7,r3,r4,r5)
919END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
920	blr
921
922_GLOBAL(load_segment_registers)
923	li	r0, NUM_USER_SEGMENTS /* load up user segment register values */
924	mtctr	r0		/* for context 0 */
925#ifdef CONFIG_PPC_KUEP
926	lis	r3, SR_NX@h	/* Kp = 0, Ks = 0, VSID = 0 */
927#else
928	li	r3, 0		/* Kp = 0, Ks = 0, VSID = 0 */
929#endif
930	li	r4, 0
9313:	mtsrin	r3, r4
932	addi	r3, r3, 0x111	/* increment VSID */
933	addis	r4, r4, 0x1000	/* address of next segment */
934	bdnz	3b
935	li	r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
936	mtctr	r0			/* for context 0 */
937	rlwinm	r3, r3, 0, ~SR_NX	/* Nx = 0 */
938	rlwinm	r3, r3, 0, ~SR_KS	/* Ks = 0 */
939	oris	r3, r3, SR_KP@h		/* Kp = 1 */
9403:	mtsrin	r3, r4
941	addi	r3, r3, 0x111	/* increment VSID */
942	addis	r4, r4, 0x1000	/* address of next segment */
943	bdnz	3b
944	blr
945
946/*
947 * This is where the main kernel code starts.
948 */
949start_here:
950	/* ptr to current */
951	lis	r2,init_task@h
952	ori	r2,r2,init_task@l
953	/* Set up for using our exception vectors */
954	/* ptr to phys current thread */
955	tophys(r4,r2)
956	addi	r4,r4,THREAD	/* init task's THREAD */
957	mtspr	SPRN_SPRG_THREAD,r4
958BEGIN_MMU_FTR_SECTION
959	lis	r4, (swapper_pg_dir - PAGE_OFFSET)@h
960	ori	r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
961	rlwinm	r4, r4, 4, 0xffff01ff
962	mtspr	SPRN_SDR1, r4
963END_MMU_FTR_SECTION_IFCLR(MMU_FTR_HPTE_TABLE)
964
965	/* stack */
966	lis	r1,init_thread_union@ha
967	addi	r1,r1,init_thread_union@l
968	li	r0,0
969	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
970/*
971 * Do early platform-specific initialization,
972 * and set up the MMU.
973 */
974#ifdef CONFIG_KASAN
975	bl	kasan_early_init
976#endif
977	li	r3,0
978	mr	r4,r31
979	bl	machine_init
980	bl	__save_cpu_setup
981	bl	MMU_init
982	bl	MMU_init_hw_patch
983
984/*
985 * Go back to running unmapped so we can load up new values
986 * for SDR1 (hash table pointer) and the segment registers
987 * and change to using our exception vectors.
988 */
989	lis	r4,2f@h
990	ori	r4,r4,2f@l
991	tophys(r4,r4)
992	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
993
994	.align	4
995	mtspr	SPRN_SRR0,r4
996	mtspr	SPRN_SRR1,r3
997	rfi
998/* Load up the kernel context */
9992:	bl	load_up_mmu
1000
1001#ifdef CONFIG_BDI_SWITCH
1002	/* Add helper information for the Abatron bdiGDB debugger.
1003	 * We do this here because we know the mmu is disabled, and
1004	 * will be enabled for real in just a few instructions.
1005	 */
1006	lis	r5, abatron_pteptrs@h
1007	ori	r5, r5, abatron_pteptrs@l
1008	stw	r5, 0xf0(0)	/* This much match your Abatron config */
1009	lis	r6, swapper_pg_dir@h
1010	ori	r6, r6, swapper_pg_dir@l
1011	tophys(r5, r5)
1012	stw	r6, 0(r5)
1013#endif /* CONFIG_BDI_SWITCH */
1014
1015/* Now turn on the MMU for real! */
1016	li	r4,MSR_KERNEL
1017	lis	r3,start_kernel@h
1018	ori	r3,r3,start_kernel@l
1019	mtspr	SPRN_SRR0,r3
1020	mtspr	SPRN_SRR1,r4
1021	rfi
1022
1023/*
1024 * An undocumented "feature" of 604e requires that the v bit
1025 * be cleared before changing BAT values.
1026 *
1027 * Also, newer IBM firmware does not clear bat3 and 4 so
1028 * this makes sure it's done.
1029 *  -- Cort
1030 */
1031clear_bats:
1032	li	r10,0
1033
1034	mtspr	SPRN_DBAT0U,r10
1035	mtspr	SPRN_DBAT0L,r10
1036	mtspr	SPRN_DBAT1U,r10
1037	mtspr	SPRN_DBAT1L,r10
1038	mtspr	SPRN_DBAT2U,r10
1039	mtspr	SPRN_DBAT2L,r10
1040	mtspr	SPRN_DBAT3U,r10
1041	mtspr	SPRN_DBAT3L,r10
1042	mtspr	SPRN_IBAT0U,r10
1043	mtspr	SPRN_IBAT0L,r10
1044	mtspr	SPRN_IBAT1U,r10
1045	mtspr	SPRN_IBAT1L,r10
1046	mtspr	SPRN_IBAT2U,r10
1047	mtspr	SPRN_IBAT2L,r10
1048	mtspr	SPRN_IBAT3U,r10
1049	mtspr	SPRN_IBAT3L,r10
1050BEGIN_MMU_FTR_SECTION
1051	/* Here's a tweak: at this point, CPU setup have
1052	 * not been called yet, so HIGH_BAT_EN may not be
1053	 * set in HID0 for the 745x processors. However, it
1054	 * seems that doesn't affect our ability to actually
1055	 * write to these SPRs.
1056	 */
1057	mtspr	SPRN_DBAT4U,r10
1058	mtspr	SPRN_DBAT4L,r10
1059	mtspr	SPRN_DBAT5U,r10
1060	mtspr	SPRN_DBAT5L,r10
1061	mtspr	SPRN_DBAT6U,r10
1062	mtspr	SPRN_DBAT6L,r10
1063	mtspr	SPRN_DBAT7U,r10
1064	mtspr	SPRN_DBAT7L,r10
1065	mtspr	SPRN_IBAT4U,r10
1066	mtspr	SPRN_IBAT4L,r10
1067	mtspr	SPRN_IBAT5U,r10
1068	mtspr	SPRN_IBAT5L,r10
1069	mtspr	SPRN_IBAT6U,r10
1070	mtspr	SPRN_IBAT6L,r10
1071	mtspr	SPRN_IBAT7U,r10
1072	mtspr	SPRN_IBAT7L,r10
1073END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
1074	blr
1075
1076_GLOBAL(update_bats)
1077	lis	r4, 1f@h
1078	ori	r4, r4, 1f@l
1079	tophys(r4, r4)
1080	mfmsr	r6
1081	mflr	r7
1082	li	r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)
1083	rlwinm	r0, r6, 0, ~MSR_RI
1084	rlwinm	r0, r0, 0, ~MSR_EE
1085	mtmsr	r0
1086
1087	.align	4
1088	mtspr	SPRN_SRR0, r4
1089	mtspr	SPRN_SRR1, r3
1090	rfi
10911:	bl	clear_bats
1092	lis	r3, BATS@ha
1093	addi	r3, r3, BATS@l
1094	tophys(r3, r3)
1095	LOAD_BAT(0, r3, r4, r5)
1096	LOAD_BAT(1, r3, r4, r5)
1097	LOAD_BAT(2, r3, r4, r5)
1098	LOAD_BAT(3, r3, r4, r5)
1099BEGIN_MMU_FTR_SECTION
1100	LOAD_BAT(4, r3, r4, r5)
1101	LOAD_BAT(5, r3, r4, r5)
1102	LOAD_BAT(6, r3, r4, r5)
1103	LOAD_BAT(7, r3, r4, r5)
1104END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
1105	li	r3, MSR_KERNEL & ~(MSR_IR | MSR_DR | MSR_RI)
1106	mtmsr	r3
1107	mtspr	SPRN_SRR0, r7
1108	mtspr	SPRN_SRR1, r6
1109	rfi
1110
1111flush_tlbs:
1112	lis	r10, 0x40
11131:	addic.	r10, r10, -0x1000
1114	tlbie	r10
1115	bgt	1b
1116	sync
1117	blr
1118
1119mmu_off:
1120 	addi	r4, r3, __after_mmu_off - _start
1121	mfmsr	r3
1122	andi.	r0,r3,MSR_DR|MSR_IR		/* MMU enabled? */
1123	beqlr
1124	andc	r3,r3,r0
1125
1126	.align	4
1127	mtspr	SPRN_SRR0,r4
1128	mtspr	SPRN_SRR1,r3
1129	sync
1130	rfi
1131
1132/* We use one BAT to map up to 256M of RAM at _PAGE_OFFSET */
1133initial_bats:
1134	lis	r11,PAGE_OFFSET@h
1135	tophys(r8,r11)
1136#ifdef CONFIG_SMP
1137	ori	r8,r8,0x12		/* R/W access, M=1 */
1138#else
1139	ori	r8,r8,2			/* R/W access */
1140#endif /* CONFIG_SMP */
1141	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
1142
1143	mtspr	SPRN_DBAT0L,r8		/* N.B. 6xx have valid */
1144	mtspr	SPRN_DBAT0U,r11		/* bit in upper BAT register */
1145	mtspr	SPRN_IBAT0L,r8
1146	mtspr	SPRN_IBAT0U,r11
1147	isync
1148	blr
1149
1150#ifdef CONFIG_BOOTX_TEXT
1151setup_disp_bat:
1152	/*
1153	 * setup the display bat prepared for us in prom.c
1154	 */
1155	mflr	r8
1156	bl	reloc_offset
1157	mtlr	r8
1158	addis	r8,r3,disp_BAT@ha
1159	addi	r8,r8,disp_BAT@l
1160	cmpwi	cr0,r8,0
1161	beqlr
1162	lwz	r11,0(r8)
1163	lwz	r8,4(r8)
1164	mtspr	SPRN_DBAT3L,r8
1165	mtspr	SPRN_DBAT3U,r11
1166	blr
1167#endif /* CONFIG_BOOTX_TEXT */
1168
1169#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
1170setup_cpm_bat:
1171	lis	r8, 0xf000
1172	ori	r8, r8,	0x002a
1173	mtspr	SPRN_DBAT1L, r8
1174
1175	lis	r11, 0xf000
1176	ori	r11, r11, (BL_1M << 2) | 2
1177	mtspr	SPRN_DBAT1U, r11
1178
1179	blr
1180#endif
1181
1182#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
1183setup_usbgecko_bat:
1184	/* prepare a BAT for early io */
1185#if defined(CONFIG_GAMECUBE)
1186	lis	r8, 0x0c00
1187#elif defined(CONFIG_WII)
1188	lis	r8, 0x0d00
1189#else
1190#error Invalid platform for USB Gecko based early debugging.
1191#endif
1192	/*
1193	 * The virtual address used must match the virtual address
1194	 * associated to the fixmap entry FIX_EARLY_DEBUG_BASE.
1195	 */
1196	lis	r11, 0xfffe	/* top 128K */
1197	ori	r8, r8, 0x002a	/* uncached, guarded ,rw */
1198	ori	r11, r11, 0x2	/* 128K, Vs=1, Vp=0 */
1199	mtspr	SPRN_DBAT1L, r8
1200	mtspr	SPRN_DBAT1U, r11
1201	blr
1202#endif
1203
1204	.data
1205