Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  *  PowerPC version
0004  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
0005  *
0006  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
0007  *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
0008  *  Adapted for Power Macintosh by Paul Mackerras.
0009  *  Low-level exception handlers and MMU support
0010  *  rewritten by Paul Mackerras.
0011  *    Copyright (C) 1996 Paul Mackerras.
0012  *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
0013  *
0014  *  This file contains the low-level support and setup for the
0015  *  PowerPC platform, including trap and interrupt dispatch.
0016  *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
0017  */
0018 
0019 #include <linux/init.h>
0020 #include <linux/pgtable.h>
0021 #include <asm/reg.h>
0022 #include <asm/page.h>
0023 #include <asm/mmu.h>
0024 #include <asm/cputable.h>
0025 #include <asm/cache.h>
0026 #include <asm/thread_info.h>
0027 #include <asm/ppc_asm.h>
0028 #include <asm/asm-offsets.h>
0029 #include <asm/ptrace.h>
0030 #include <asm/bug.h>
0031 #include <asm/kvm_book3s_asm.h>
0032 #include <asm/export.h>
0033 #include <asm/feature-fixups.h>
0034 #include <asm/interrupt.h>
0035 
0036 #include "head_32.h"
0037 
0038 #define LOAD_BAT(n, reg, RA, RB)    \
0039     /* see the comment for clear_bats() -- Cort */ \
0040     li  RA,0;           \
0041     mtspr   SPRN_IBAT##n##U,RA; \
0042     mtspr   SPRN_DBAT##n##U,RA; \
0043     lwz RA,(n*16)+0(reg);   \
0044     lwz RB,(n*16)+4(reg);   \
0045     mtspr   SPRN_IBAT##n##U,RA; \
0046     mtspr   SPRN_IBAT##n##L,RB; \
0047     lwz RA,(n*16)+8(reg);   \
0048     lwz RB,(n*16)+12(reg);  \
0049     mtspr   SPRN_DBAT##n##U,RA; \
0050     mtspr   SPRN_DBAT##n##L,RB
0051 
0052     __HEAD
0053 _GLOBAL(_stext);
0054 
0055 /*
0056  * _start is defined this way because the XCOFF loader in the OpenFirmware
0057  * on the powermac expects the entry point to be a procedure descriptor.
0058  */
0059 _GLOBAL(_start);
0060     /*
0061      * These are here for legacy reasons, the kernel used to
0062      * need to look like a coff function entry for the pmac
0063      * but we're always started by some kind of bootloader now.
0064      *  -- Cort
0065      */
0066     nop /* used by __secondary_hold on prep (mtx) and chrp smp */
0067     nop /* used by __secondary_hold on prep (mtx) and chrp smp */
0068     nop
0069 
0070 /* PMAC
0071  * Enter here with the kernel text, data and bss loaded starting at
0072  * 0, running with virtual == physical mapping.
0073  * r5 points to the prom entry point (the client interface handler
0074  * address).  Address translation is turned on, with the prom
0075  * managing the hash table.  Interrupts are disabled.  The stack
0076  * pointer (r1) points to just below the end of the half-meg region
0077  * from 0x380000 - 0x400000, which is mapped in already.
0078  *
0079  * If we are booted from MacOS via BootX, we enter with the kernel
0080  * image loaded somewhere, and the following values in registers:
0081  *  r3: 'BooX' (0x426f6f58)
0082  *  r4: virtual address of boot_infos_t
0083  *  r5: 0
0084  *
0085  * PREP
0086  * This is jumped to on prep systems right after the kernel is relocated
0087  * to its proper place in memory by the boot loader.  The expected layout
0088  * of the regs is:
0089  *   r3: ptr to residual data
0090  *   r4: initrd_start or if no initrd then 0
0091  *   r5: initrd_end - unused if r4 is 0
0092  *   r6: Start of command line string
0093  *   r7: End of command line string
0094  *
0095  * This just gets a minimal mmu environment setup so we can call
0096  * start_here() to do the real work.
0097  * -- Cort
0098  */
0099 
0100     .globl  __start
0101 __start:
0102 /*
0103  * We have to do any OF calls before we map ourselves to KERNELBASE,
0104  * because OF may have I/O devices mapped into that area
0105  * (particularly on CHRP).
0106  */
0107     cmpwi   0,r5,0
0108     beq 1f
0109 
0110 #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
0111     /* find out where we are now */
0112     bcl 20,31,$+4
0113 0:  mflr    r8          /* r8 = runtime addr here */
0114     addis   r8,r8,(_stext - 0b)@ha
0115     addi    r8,r8,(_stext - 0b)@l   /* current runtime base addr */
0116     bl  prom_init
0117 #endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */
0118 
0119     /* We never return. We also hit that trap if trying to boot
0120      * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
0121     trap
0122 
0123 /*
0124  * Check for BootX signature when supporting PowerMac and branch to
0125  * appropriate trampoline if it's present
0126  */
0127 #ifdef CONFIG_PPC_PMAC
0128 1:  lis r31,0x426f
0129     ori r31,r31,0x6f58
0130     cmpw    0,r3,r31
0131     bne 1f
0132     bl  bootx_init
0133     trap
0134 #endif /* CONFIG_PPC_PMAC */
0135 
0136 1:  mr  r31,r3          /* save device tree ptr */
0137     li  r24,0           /* cpu # */
0138 
0139 /*
0140  * early_init() does the early machine identification and does
0141  * the necessary low-level setup and clears the BSS
0142  *  -- Cort <cort@fsmlabs.com>
0143  */
0144     bl  early_init
0145 
0146 /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
0147  * the physical address we are running at, returned by early_init()
0148  */
0149     bl  mmu_off
0150 __after_mmu_off:
0151     bl  clear_bats
0152     bl  flush_tlbs
0153 
0154     bl  initial_bats
0155     bl  load_segment_registers
0156     bl  reloc_offset
0157     bl  early_hash_table
0158 #if defined(CONFIG_BOOTX_TEXT)
0159     bl  setup_disp_bat
0160 #endif
0161 #ifdef CONFIG_PPC_EARLY_DEBUG_CPM
0162     bl  setup_cpm_bat
0163 #endif
0164 #ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
0165     bl  setup_usbgecko_bat
0166 #endif
0167 
0168 /*
0169  * Call setup_cpu for CPU 0 and initialize 6xx Idle
0170  */
0171     bl  reloc_offset
0172     li  r24,0           /* cpu# */
0173     bl  call_setup_cpu      /* Call setup_cpu for this CPU */
0174     bl  reloc_offset
0175     bl  init_idle_6xx
0176 
0177 
0178 /*
0179  * We need to run with _start at physical address 0.
0180  * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
0181  * the exception vectors at 0 (and therefore this copy
0182  * overwrites OF's exception vectors with our own).
0183  * The MMU is off at this point.
0184  */
0185     bl  reloc_offset
0186     mr  r26,r3
0187     addis   r4,r3,KERNELBASE@h  /* current address of _start */
0188     lis r5,PHYSICAL_START@h
0189     cmplw   0,r4,r5         /* already running at PHYSICAL_START? */
0190     bne relocate_kernel
0191 /*
0192  * we now have the 1st 16M of ram mapped with the bats.
0193  * prep needs the mmu to be turned on here, but pmac already has it on.
0194  * this shouldn't bother the pmac since it just gets turned on again
0195  * as we jump to our code at KERNELBASE. -- Cort
0196  * Actually no, pmac doesn't have it on any more. BootX enters with MMU
0197  * off, and in other cases, we now turn it off before changing BATs above.
0198  */
0199 turn_on_mmu:
0200     mfmsr   r0
0201     ori r0,r0,MSR_DR|MSR_IR|MSR_RI
0202     mtspr   SPRN_SRR1,r0
0203     lis r0,start_here@h
0204     ori r0,r0,start_here@l
0205     mtspr   SPRN_SRR0,r0
0206     rfi             /* enables MMU */
0207 
0208 /*
0209  * We need __secondary_hold as a place to hold the other cpus on
0210  * an SMP machine, even when we are running a UP kernel.
0211  */
0212     . = 0xc0            /* for prep bootloader */
0213     li  r3,1            /* MTX only has 1 cpu */
0214     .globl  __secondary_hold
0215 __secondary_hold:
0216     /* tell the master we're here */
0217     stw r3,__secondary_hold_acknowledge@l(0)
0218 #ifdef CONFIG_SMP
0219 100:    lwz r4,0(0)
0220     /* wait until we're told to start */
0221     cmpw    0,r4,r3
0222     bne 100b
0223     /* our cpu # was at addr 0 - go */
0224     mr  r24,r3          /* cpu # */
0225     b   __secondary_start
0226 #else
0227     b   .
0228 #endif /* CONFIG_SMP */
0229 
0230     .globl  __secondary_hold_spinloop
0231 __secondary_hold_spinloop:
0232     .long   0
0233     .globl  __secondary_hold_acknowledge
0234 __secondary_hold_acknowledge:
0235     .long   -1
0236 
0237 /* System reset */
0238 /* core99 pmac starts the seconary here by changing the vector, and
0239    putting it back to what it was (unknown_async_exception) when done.  */
0240     EXCEPTION(INTERRUPT_SYSTEM_RESET, Reset, unknown_async_exception)
0241 
0242 /* Machine check */
0243 /*
0244  * On CHRP, this is complicated by the fact that we could get a
0245  * machine check inside RTAS, and we have no guarantee that certain
0246  * critical registers will have the values we expect.  The set of
0247  * registers that might have bad values includes all the GPRs
0248  * and all the BATs.  We indicate that we are in RTAS by putting
0249  * a non-zero value, the address of the exception frame to use,
0250  * in thread.rtas_sp.  The machine check handler checks thread.rtas_sp
0251  * and uses its value if it is non-zero.
0252  * (Other exception handlers assume that r1 is a valid kernel stack
0253  * pointer when we take an exception from supervisor mode.)
0254  *  -- paulus.
0255  */
0256     START_EXCEPTION(INTERRUPT_MACHINE_CHECK, MachineCheck)
0257     EXCEPTION_PROLOG_0
0258 #ifdef CONFIG_PPC_CHRP
0259     mtspr   SPRN_SPRG_SCRATCH2,r1
0260     mfspr   r1, SPRN_SPRG_THREAD
0261     lwz r1, RTAS_SP(r1)
0262     cmpwi   cr1, r1, 0
0263     bne cr1, 7f
0264     mfspr   r1, SPRN_SPRG_SCRATCH2
0265 #endif /* CONFIG_PPC_CHRP */
0266     EXCEPTION_PROLOG_1
0267 7:  EXCEPTION_PROLOG_2 0x200 MachineCheck
0268 #ifdef CONFIG_PPC_CHRP
0269     beq cr1, 1f
0270     twi 31, 0, 0
0271 #endif
0272 1:  prepare_transfer_to_handler
0273     bl  machine_check_exception
0274     b   interrupt_return
0275 
0276 /* Data access exception. */
0277     START_EXCEPTION(INTERRUPT_DATA_STORAGE, DataAccess)
0278 #ifdef CONFIG_PPC_BOOK3S_604
0279 BEGIN_MMU_FTR_SECTION
0280     mtspr   SPRN_SPRG_SCRATCH2,r10
0281     mfspr   r10, SPRN_SPRG_THREAD
0282     stw r11, THR11(r10)
0283     mfspr   r10, SPRN_DSISR
0284     mfcr    r11
0285     andis.  r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
0286     mfspr   r10, SPRN_SPRG_THREAD
0287     beq hash_page_dsi
0288 .Lhash_page_dsi_cont:
0289     mtcr    r11
0290     lwz r11, THR11(r10)
0291     mfspr   r10, SPRN_SPRG_SCRATCH2
0292 MMU_FTR_SECTION_ELSE
0293     b   1f
0294 ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
0295 #endif
0296 1:  EXCEPTION_PROLOG_0 handle_dar_dsisr=1
0297     EXCEPTION_PROLOG_1
0298     EXCEPTION_PROLOG_2 INTERRUPT_DATA_STORAGE DataAccess handle_dar_dsisr=1
0299     prepare_transfer_to_handler
0300     lwz r5, _DSISR(r1)
0301     andis.  r0, r5, DSISR_DABRMATCH@h
0302     bne-    1f
0303     bl  do_page_fault
0304     b   interrupt_return
0305 1:  bl  do_break
0306     REST_NVGPRS(r1)
0307     b   interrupt_return
0308 
0309 
0310 /* Instruction access exception. */
0311     START_EXCEPTION(INTERRUPT_INST_STORAGE, InstructionAccess)
0312     mtspr   SPRN_SPRG_SCRATCH0,r10
0313     mtspr   SPRN_SPRG_SCRATCH1,r11
0314     mfspr   r10, SPRN_SPRG_THREAD
0315     mfspr   r11, SPRN_SRR0
0316     stw r11, SRR0(r10)
0317     mfspr   r11, SPRN_SRR1      /* check whether user or kernel */
0318     stw r11, SRR1(r10)
0319     mfcr    r10
0320 #ifdef CONFIG_PPC_BOOK3S_604
0321 BEGIN_MMU_FTR_SECTION
0322     andis.  r11, r11, SRR1_ISI_NOPT@h   /* no pte found? */
0323     bne hash_page_isi
0324 .Lhash_page_isi_cont:
0325     mfspr   r11, SPRN_SRR1      /* check whether user or kernel */
0326 END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
0327 #endif
0328     andi.   r11, r11, MSR_PR
0329 
0330     EXCEPTION_PROLOG_1
0331     EXCEPTION_PROLOG_2 INTERRUPT_INST_STORAGE InstructionAccess
0332     andis.  r5,r9,DSISR_SRR1_MATCH_32S@h /* Filter relevant SRR1 bits */
0333     stw r5, _DSISR(r11)
0334     stw r12, _DAR(r11)
0335     prepare_transfer_to_handler
0336     bl  do_page_fault
0337     b   interrupt_return
0338 
0339 /* External interrupt */
0340     EXCEPTION(INTERRUPT_EXTERNAL, HardwareInterrupt, do_IRQ)
0341 
0342 /* Alignment exception */
0343     START_EXCEPTION(INTERRUPT_ALIGNMENT, Alignment)
0344     EXCEPTION_PROLOG INTERRUPT_ALIGNMENT Alignment handle_dar_dsisr=1
0345     prepare_transfer_to_handler
0346     bl  alignment_exception
0347     REST_NVGPRS(r1)
0348     b   interrupt_return
0349 
0350 /* Program check exception */
0351     START_EXCEPTION(INTERRUPT_PROGRAM, ProgramCheck)
0352     EXCEPTION_PROLOG INTERRUPT_PROGRAM ProgramCheck
0353     prepare_transfer_to_handler
0354     bl  program_check_exception
0355     REST_NVGPRS(r1)
0356     b   interrupt_return
0357 
0358 /* Floating-point unavailable */
0359     START_EXCEPTION(0x800, FPUnavailable)
0360 #ifdef CONFIG_PPC_FPU
0361 BEGIN_FTR_SECTION
0362 /*
0363  * Certain Freescale cores don't have a FPU and treat fp instructions
0364  * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
0365  */
0366     b   ProgramCheck
0367 END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
0368     EXCEPTION_PROLOG INTERRUPT_FP_UNAVAIL FPUnavailable
0369     beq 1f
0370     bl  load_up_fpu     /* if from user, just load it up */
0371     b   fast_exception_return
0372 1:  prepare_transfer_to_handler
0373     bl  kernel_fp_unavailable_exception
0374     b   interrupt_return
0375 #else
0376     b   ProgramCheck
0377 #endif
0378 
0379 /* Decrementer */
0380     EXCEPTION(INTERRUPT_DECREMENTER, Decrementer, timer_interrupt)
0381 
0382     EXCEPTION(0xa00, Trap_0a, unknown_exception)
0383     EXCEPTION(0xb00, Trap_0b, unknown_exception)
0384 
0385 /* System call */
0386     START_EXCEPTION(INTERRUPT_SYSCALL, SystemCall)
0387     SYSCALL_ENTRY   INTERRUPT_SYSCALL
0388 
0389     EXCEPTION(INTERRUPT_TRACE, SingleStep, single_step_exception)
0390     EXCEPTION(0xe00, Trap_0e, unknown_exception)
0391 
0392 /*
0393  * The Altivec unavailable trap is at 0x0f20.  Foo.
0394  * We effectively remap it to 0x3000.
0395  * We include an altivec unavailable exception vector even if
0396  * not configured for Altivec, so that you can't panic a
0397  * non-altivec kernel running on a machine with altivec just
0398  * by executing an altivec instruction.
0399  */
0400     START_EXCEPTION(INTERRUPT_PERFMON, PerformanceMonitorTrap)
0401     b   PerformanceMonitor
0402 
0403     START_EXCEPTION(INTERRUPT_ALTIVEC_UNAVAIL, AltiVecUnavailableTrap)
0404     b   AltiVecUnavailable
0405 
0406     __HEAD
0407 /*
0408  * Handle TLB miss for instruction on 603/603e.
0409  * Note: we get an alternate set of r0 - r3 to use automatically.
0410  */
0411     . = INTERRUPT_INST_TLB_MISS_603
0412 InstructionTLBMiss:
0413 /*
0414  * r0:  scratch
0415  * r1:  linux style pte ( later becomes ppc hardware pte )
0416  * r2:  ptr to linux-style pte
0417  * r3:  scratch
0418  */
0419     /* Get PTE (linux-style) and check access */
0420     mfspr   r3,SPRN_IMISS
0421 #ifdef CONFIG_MODULES
0422     lis r1, TASK_SIZE@h     /* check if kernel address */
0423     cmplw   0,r1,r3
0424 #endif
0425     mfspr   r2, SPRN_SDR1
0426     li  r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
0427     rlwinm  r2, r2, 28, 0xfffff000
0428 #ifdef CONFIG_MODULES
0429     bgt-    112f
0430     lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
0431     li  r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
0432     addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l    /* kernel page table */
0433 #endif
0434 112:    rlwimi  r2,r3,12,20,29      /* insert top 10 bits of address */
0435     lwz r2,0(r2)        /* get pmd entry */
0436     rlwinm. r2,r2,0,0,19        /* extract address of pte page */
0437     beq-    InstructionAddressInvalid   /* return if no mapping */
0438     rlwimi  r2,r3,22,20,29      /* insert next 10 bits of address */
0439     lwz r0,0(r2)        /* get linux-style pte */
0440     andc.   r1,r1,r0        /* check access & ~permission */
0441     bne-    InstructionAddressInvalid /* return if access not permitted */
0442     /* Convert linux-style PTE to low word of PPC-style PTE */
0443     rlwimi  r0,r0,32-2,31,31    /* _PAGE_USER -> PP lsb */
0444     ori r1, r1, 0xe06       /* clear out reserved bits */
0445     andc    r1, r0, r1      /* PP = user? 1 : 0 */
0446 BEGIN_FTR_SECTION
0447     rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
0448 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
0449     mtspr   SPRN_RPA,r1
0450     tlbli   r3
0451     mfspr   r3,SPRN_SRR1        /* Need to restore CR0 */
0452     mtcrf   0x80,r3
0453     rfi
0454 InstructionAddressInvalid:
0455     mfspr   r3,SPRN_SRR1
0456     rlwinm  r1,r3,9,6,6 /* Get load/store bit */
0457 
0458     addis   r1,r1,0x2000
0459     mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
0460     andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
0461     or  r2,r2,r1
0462     mtspr   SPRN_SRR1,r2
0463     mfspr   r1,SPRN_IMISS   /* Get failing address */
0464     rlwinm. r2,r2,0,31,31   /* Check for little endian access */
0465     rlwimi  r2,r2,1,30,30   /* change 1 -> 3 */
0466     xor r1,r1,r2
0467     mtspr   SPRN_DAR,r1 /* Set fault address */
0468     mfmsr   r0      /* Restore "normal" registers */
0469     xoris   r0,r0,MSR_TGPR>>16
0470     mtcrf   0x80,r3     /* Restore CR0 */
0471     mtmsr   r0
0472     b   InstructionAccess
0473 
0474 /*
0475  * Handle TLB miss for DATA Load operation on 603/603e
0476  */
0477     . = INTERRUPT_DATA_LOAD_TLB_MISS_603
0478 DataLoadTLBMiss:
0479 /*
0480  * r0:  scratch
0481  * r1:  linux style pte ( later becomes ppc hardware pte )
0482  * r2:  ptr to linux-style pte
0483  * r3:  scratch
0484  */
0485     /* Get PTE (linux-style) and check access */
0486     mfspr   r3,SPRN_DMISS
0487     lis r1, TASK_SIZE@h     /* check if kernel address */
0488     cmplw   0,r1,r3
0489     mfspr   r2, SPRN_SDR1
0490     li  r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
0491     rlwinm  r2, r2, 28, 0xfffff000
0492     bgt-    112f
0493     lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
0494     li  r1, _PAGE_PRESENT | _PAGE_ACCESSED
0495     addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l    /* kernel page table */
0496 112:    rlwimi  r2,r3,12,20,29      /* insert top 10 bits of address */
0497     lwz r2,0(r2)        /* get pmd entry */
0498     rlwinm. r2,r2,0,0,19        /* extract address of pte page */
0499     beq-    DataAddressInvalid  /* return if no mapping */
0500     rlwimi  r2,r3,22,20,29      /* insert next 10 bits of address */
0501     lwz r0,0(r2)        /* get linux-style pte */
0502     andc.   r1,r1,r0        /* check access & ~permission */
0503     bne-    DataAddressInvalid  /* return if access not permitted */
0504     /* Convert linux-style PTE to low word of PPC-style PTE */
0505     rlwinm  r1,r0,32-9,30,30    /* _PAGE_RW -> PP msb */
0506     rlwimi  r0,r0,32-1,30,30    /* _PAGE_USER -> PP msb */
0507     rlwimi  r1,r0,32-3,24,24    /* _PAGE_RW -> _PAGE_DIRTY */
0508     rlwimi  r0,r0,32-1,31,31    /* _PAGE_USER -> PP lsb */
0509     xori    r1,r1,_PAGE_DIRTY   /* clear dirty when not rw */
0510     ori r1,r1,0xe04     /* clear out reserved bits */
0511     andc    r1,r0,r1        /* PP = user? rw? 1: 3: 0 */
0512 BEGIN_FTR_SECTION
0513     rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
0514 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
0515     mtspr   SPRN_RPA,r1
0516 BEGIN_MMU_FTR_SECTION
0517     li  r0,1
0518     mfspr   r1,SPRN_SPRG_603_LRU
0519     rlwinm  r2,r3,20,27,31      /* Get Address bits 15:19 */
0520     slw r0,r0,r2
0521     xor r1,r0,r1
0522     srw r0,r1,r2
0523     mtspr   SPRN_SPRG_603_LRU,r1
0524     mfspr   r2,SPRN_SRR1
0525     rlwimi  r2,r0,31-14,14,14
0526     mtspr   SPRN_SRR1,r2
0527     mtcrf   0x80,r2
0528     tlbld   r3
0529     rfi
0530 MMU_FTR_SECTION_ELSE
0531     mfspr   r2,SPRN_SRR1        /* Need to restore CR0 */
0532     mtcrf   0x80,r2
0533     tlbld   r3
0534     rfi
0535 ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
0536 DataAddressInvalid:
0537     mfspr   r3,SPRN_SRR1
0538     rlwinm  r1,r3,9,6,6 /* Get load/store bit */
0539     addis   r1,r1,0x2000
0540     mtspr   SPRN_DSISR,r1
0541     andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
0542     mtspr   SPRN_SRR1,r2
0543     mfspr   r1,SPRN_DMISS   /* Get failing address */
0544     rlwinm. r2,r2,0,31,31   /* Check for little endian access */
0545     beq 20f     /* Jump if big endian */
0546     xori    r1,r1,3
0547 20: mtspr   SPRN_DAR,r1 /* Set fault address */
0548     mfmsr   r0      /* Restore "normal" registers */
0549     xoris   r0,r0,MSR_TGPR>>16
0550     mtcrf   0x80,r3     /* Restore CR0 */
0551     mtmsr   r0
0552     b   DataAccess
0553 
0554 /*
0555  * Handle TLB miss for DATA Store on 603/603e
0556  */
0557     . = INTERRUPT_DATA_STORE_TLB_MISS_603
0558 DataStoreTLBMiss:
0559 /*
0560  * r0:  scratch
0561  * r1:  linux style pte ( later becomes ppc hardware pte )
0562  * r2:  ptr to linux-style pte
0563  * r3:  scratch
0564  */
0565     /* Get PTE (linux-style) and check access */
0566     mfspr   r3,SPRN_DMISS
0567     lis r1, TASK_SIZE@h     /* check if kernel address */
0568     cmplw   0,r1,r3
0569     mfspr   r2, SPRN_SDR1
0570     li  r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
0571     rlwinm  r2, r2, 28, 0xfffff000
0572     bgt-    112f
0573     lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
0574     li  r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
0575     addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l    /* kernel page table */
0576 112:    rlwimi  r2,r3,12,20,29      /* insert top 10 bits of address */
0577     lwz r2,0(r2)        /* get pmd entry */
0578     rlwinm. r2,r2,0,0,19        /* extract address of pte page */
0579     beq-    DataAddressInvalid  /* return if no mapping */
0580     rlwimi  r2,r3,22,20,29      /* insert next 10 bits of address */
0581     lwz r0,0(r2)        /* get linux-style pte */
0582     andc.   r1,r1,r0        /* check access & ~permission */
0583     bne-    DataAddressInvalid  /* return if access not permitted */
0584     /* Convert linux-style PTE to low word of PPC-style PTE */
0585     rlwimi  r0,r0,32-2,31,31    /* _PAGE_USER -> PP lsb */
0586     li  r1,0xe06        /* clear out reserved bits & PP msb */
0587     andc    r1,r0,r1        /* PP = user? 1: 0 */
0588 BEGIN_FTR_SECTION
0589     rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
0590 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
0591     mtspr   SPRN_RPA,r1
0592     mfspr   r2,SPRN_SRR1        /* Need to restore CR0 */
0593     mtcrf   0x80,r2
0594 BEGIN_MMU_FTR_SECTION
0595     li  r0,1
0596     mfspr   r1,SPRN_SPRG_603_LRU
0597     rlwinm  r2,r3,20,27,31      /* Get Address bits 15:19 */
0598     slw r0,r0,r2
0599     xor r1,r0,r1
0600     srw r0,r1,r2
0601     mtspr   SPRN_SPRG_603_LRU,r1
0602     mfspr   r2,SPRN_SRR1
0603     rlwimi  r2,r0,31-14,14,14
0604     mtspr   SPRN_SRR1,r2
0605     mtcrf   0x80,r2
0606     tlbld   r3
0607     rfi
0608 MMU_FTR_SECTION_ELSE
0609     mfspr   r2,SPRN_SRR1        /* Need to restore CR0 */
0610     mtcrf   0x80,r2
0611     tlbld   r3
0612     rfi
0613 ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
0614 
0615 #ifndef CONFIG_ALTIVEC
0616 #define altivec_assist_exception    unknown_exception
0617 #endif
0618 
0619 #ifndef CONFIG_TAU_INT
0620 #define TAUException    unknown_async_exception
0621 #endif
0622 
0623     EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception)
0624     EXCEPTION(0x1400, SMI, SMIException)
0625     EXCEPTION(0x1500, Trap_15, unknown_exception)
0626     EXCEPTION(0x1600, Trap_16, altivec_assist_exception)
0627     EXCEPTION(0x1700, Trap_17, TAUException)
0628     EXCEPTION(0x1800, Trap_18, unknown_exception)
0629     EXCEPTION(0x1900, Trap_19, unknown_exception)
0630     EXCEPTION(0x1a00, Trap_1a, unknown_exception)
0631     EXCEPTION(0x1b00, Trap_1b, unknown_exception)
0632     EXCEPTION(0x1c00, Trap_1c, unknown_exception)
0633     EXCEPTION(0x1d00, Trap_1d, unknown_exception)
0634     EXCEPTION(0x1e00, Trap_1e, unknown_exception)
0635     EXCEPTION(0x1f00, Trap_1f, unknown_exception)
0636     EXCEPTION(0x2000, RunMode, RunModeException)
0637     EXCEPTION(0x2100, Trap_21, unknown_exception)
0638     EXCEPTION(0x2200, Trap_22, unknown_exception)
0639     EXCEPTION(0x2300, Trap_23, unknown_exception)
0640     EXCEPTION(0x2400, Trap_24, unknown_exception)
0641     EXCEPTION(0x2500, Trap_25, unknown_exception)
0642     EXCEPTION(0x2600, Trap_26, unknown_exception)
0643     EXCEPTION(0x2700, Trap_27, unknown_exception)
0644     EXCEPTION(0x2800, Trap_28, unknown_exception)
0645     EXCEPTION(0x2900, Trap_29, unknown_exception)
0646     EXCEPTION(0x2a00, Trap_2a, unknown_exception)
0647     EXCEPTION(0x2b00, Trap_2b, unknown_exception)
0648     EXCEPTION(0x2c00, Trap_2c, unknown_exception)
0649     EXCEPTION(0x2d00, Trap_2d, unknown_exception)
0650     EXCEPTION(0x2e00, Trap_2e, unknown_exception)
0651     EXCEPTION(0x2f00, Trap_2f, unknown_exception)
0652 
0653     __HEAD
0654     . = 0x3000
0655 
0656 #ifdef CONFIG_PPC_BOOK3S_604
0657 .macro save_regs_thread     thread
0658     stw r0, THR0(\thread)
0659     stw r3, THR3(\thread)
0660     stw r4, THR4(\thread)
0661     stw r5, THR5(\thread)
0662     stw r6, THR6(\thread)
0663     stw r8, THR8(\thread)
0664     stw r9, THR9(\thread)
0665     mflr    r0
0666     stw r0, THLR(\thread)
0667     mfctr   r0
0668     stw r0, THCTR(\thread)
0669 .endm
0670 
0671 .macro restore_regs_thread  thread
0672     lwz r0, THLR(\thread)
0673     mtlr    r0
0674     lwz r0, THCTR(\thread)
0675     mtctr   r0
0676     lwz r0, THR0(\thread)
0677     lwz r3, THR3(\thread)
0678     lwz r4, THR4(\thread)
0679     lwz r5, THR5(\thread)
0680     lwz r6, THR6(\thread)
0681     lwz r8, THR8(\thread)
0682     lwz r9, THR9(\thread)
0683 .endm
0684 
0685 hash_page_dsi:
0686     save_regs_thread    r10
0687     mfdsisr r3
0688     mfdar   r4
0689     mfsrr0  r5
0690     mfsrr1  r9
0691     rlwinm  r3, r3, 32 - 15, _PAGE_RW   /* DSISR_STORE -> _PAGE_RW */
0692     bl  hash_page
0693     mfspr   r10, SPRN_SPRG_THREAD
0694     restore_regs_thread r10
0695     b   .Lhash_page_dsi_cont
0696 
0697 hash_page_isi:
0698     mr  r11, r10
0699     mfspr   r10, SPRN_SPRG_THREAD
0700     save_regs_thread    r10
0701     li  r3, 0
0702     lwz r4, SRR0(r10)
0703     lwz r9, SRR1(r10)
0704     bl  hash_page
0705     mfspr   r10, SPRN_SPRG_THREAD
0706     restore_regs_thread r10
0707     mr  r10, r11
0708     b   .Lhash_page_isi_cont
0709 
0710     .globl fast_hash_page_return
0711 fast_hash_page_return:
0712     andis.  r10, r9, SRR1_ISI_NOPT@h    /* Set on ISI, cleared on DSI */
0713     mfspr   r10, SPRN_SPRG_THREAD
0714     restore_regs_thread r10
0715     bne 1f
0716 
0717     /* DSI */
0718     mtcr    r11
0719     lwz r11, THR11(r10)
0720     mfspr   r10, SPRN_SPRG_SCRATCH2
0721     rfi
0722 
0723 1:  /* ISI */
0724     mtcr    r11
0725     mfspr   r11, SPRN_SPRG_SCRATCH1
0726     mfspr   r10, SPRN_SPRG_SCRATCH0
0727     rfi
0728 #endif /* CONFIG_PPC_BOOK3S_604 */
0729 
0730 #ifdef CONFIG_VMAP_STACK
0731     vmap_stack_overflow_exception
0732 #endif
0733 
0734     __HEAD
0735 AltiVecUnavailable:
0736     EXCEPTION_PROLOG 0xf20 AltiVecUnavailable
0737 #ifdef CONFIG_ALTIVEC
0738     beq 1f
0739     bl  load_up_altivec     /* if from user, just load it up */
0740     b   fast_exception_return
0741 #endif /* CONFIG_ALTIVEC */
0742 1:  prepare_transfer_to_handler
0743     bl  altivec_unavailable_exception
0744     b   interrupt_return
0745 
0746     __HEAD
0747 PerformanceMonitor:
0748     EXCEPTION_PROLOG 0xf00 PerformanceMonitor
0749     prepare_transfer_to_handler
0750     bl  performance_monitor_exception
0751     b   interrupt_return
0752 
0753 
0754     __HEAD
0755 /*
0756  * This code is jumped to from the startup code to copy
0757  * the kernel image to physical address PHYSICAL_START.
0758  */
0759 relocate_kernel:
0760     lis r3,PHYSICAL_START@h /* Destination base address */
0761     li  r6,0            /* Destination offset */
0762     li  r5,0x4000       /* # bytes of memory to copy */
0763     bl  copy_and_flush      /* copy the first 0x4000 bytes */
0764     addi    r0,r3,4f@l      /* jump to the address of 4f */
0765     mtctr   r0          /* in copy and do the rest. */
0766     bctr                /* jump to the copy */
0767 4:  lis r5,_end-KERNELBASE@h
0768     ori r5,r5,_end-KERNELBASE@l
0769     bl  copy_and_flush      /* copy the rest */
0770     b   turn_on_mmu
0771 
0772 /*
0773  * Copy routine used to copy the kernel to start at physical address 0
0774  * and flush and invalidate the caches as needed.
0775  * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
0776  * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
0777  */
0778 _GLOBAL(copy_and_flush)
0779     addi    r5,r5,-4
0780     addi    r6,r6,-4
0781 4:  li  r0,L1_CACHE_BYTES/4
0782     mtctr   r0
0783 3:  addi    r6,r6,4         /* copy a cache line */
0784     lwzx    r0,r6,r4
0785     stwx    r0,r6,r3
0786     bdnz    3b
0787     dcbst   r6,r3           /* write it to memory */
0788     sync
0789     icbi    r6,r3           /* flush the icache line */
0790     cmplw   0,r6,r5
0791     blt 4b
0792     sync                /* additional sync needed on g4 */
0793     isync
0794     addi    r5,r5,4
0795     addi    r6,r6,4
0796     blr
0797 
0798 #ifdef CONFIG_SMP
0799     .globl __secondary_start_mpc86xx
0800 __secondary_start_mpc86xx:
0801     mfspr   r3, SPRN_PIR
0802     stw r3, __secondary_hold_acknowledge@l(0)
0803     mr  r24, r3         /* cpu # */
0804     b   __secondary_start
0805 
0806     .globl  __secondary_start_pmac_0
0807 __secondary_start_pmac_0:
0808     /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
0809     li  r24,0
0810     b   1f
0811     li  r24,1
0812     b   1f
0813     li  r24,2
0814     b   1f
0815     li  r24,3
0816 1:
0817     /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
0818        set to map the 0xf0000000 - 0xffffffff region */
0819     mfmsr   r0
0820     rlwinm  r0,r0,0,28,26       /* clear DR (0x10) */
0821     mtmsr   r0
0822     isync
0823 
0824     .globl  __secondary_start
0825 __secondary_start:
0826     /* Copy some CPU settings from CPU 0 */
0827     bl  __restore_cpu_setup
0828 
0829     lis r3,-KERNELBASE@h
0830     mr  r4,r24
0831     bl  call_setup_cpu      /* Call setup_cpu for this CPU */
0832     lis r3,-KERNELBASE@h
0833     bl  init_idle_6xx
0834 
0835     /* get current's stack and current */
0836     lis r2,secondary_current@ha
0837     tophys(r2,r2)
0838     lwz r2,secondary_current@l(r2)
0839     tophys(r1,r2)
0840     lwz r1,TASK_STACK(r1)
0841 
0842     /* stack */
0843     addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
0844     li  r0,0
0845     tophys(r3,r1)
0846     stw r0,0(r3)
0847 
0848     /* load up the MMU */
0849     bl  load_segment_registers
0850     bl  load_up_mmu
0851 
0852     /* ptr to phys current thread */
0853     tophys(r4,r2)
0854     addi    r4,r4,THREAD    /* phys address of our thread_struct */
0855     mtspr   SPRN_SPRG_THREAD,r4
0856 BEGIN_MMU_FTR_SECTION
0857     lis r4, (swapper_pg_dir - PAGE_OFFSET)@h
0858     ori r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
0859     rlwinm  r4, r4, 4, 0xffff01ff
0860     mtspr   SPRN_SDR1, r4
0861 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_HPTE_TABLE)
0862 
0863     /* enable MMU and jump to start_secondary */
0864     li  r4,MSR_KERNEL
0865     lis r3,start_secondary@h
0866     ori r3,r3,start_secondary@l
0867     mtspr   SPRN_SRR0,r3
0868     mtspr   SPRN_SRR1,r4
0869     rfi
0870 #endif /* CONFIG_SMP */
0871 
0872 #ifdef CONFIG_KVM_BOOK3S_HANDLER
0873 #include "../kvm/book3s_rmhandlers.S"
0874 #endif
0875 
0876 /*
0877  * Load stuff into the MMU.  Intended to be called with
0878  * IR=0 and DR=0.
0879  */
0880 early_hash_table:
0881     sync            /* Force all PTE updates to finish */
0882     isync
0883     tlbia           /* Clear all TLB entries */
0884     sync            /* wait for tlbia/tlbie to finish */
0885     TLBSYNC         /* ... on all CPUs */
0886     /* Load the SDR1 register (hash table base & size) */
0887     lis r6, early_hash - PAGE_OFFSET@h
0888     ori r6, r6, 3   /* 256kB table */
0889     mtspr   SPRN_SDR1, r6
0890     blr
0891 
0892 load_up_mmu:
0893     sync            /* Force all PTE updates to finish */
0894     isync
0895     tlbia           /* Clear all TLB entries */
0896     sync            /* wait for tlbia/tlbie to finish */
0897     TLBSYNC         /* ... on all CPUs */
0898 BEGIN_MMU_FTR_SECTION
0899     /* Load the SDR1 register (hash table base & size) */
0900     lis r6,_SDR1@ha
0901     tophys(r6,r6)
0902     lwz r6,_SDR1@l(r6)
0903     mtspr   SPRN_SDR1,r6
0904 END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
0905 
0906 /* Load the BAT registers with the values set up by MMU_init. */
0907     lis r3,BATS@ha
0908     addi    r3,r3,BATS@l
0909     tophys(r3,r3)
0910     LOAD_BAT(0,r3,r4,r5)
0911     LOAD_BAT(1,r3,r4,r5)
0912     LOAD_BAT(2,r3,r4,r5)
0913     LOAD_BAT(3,r3,r4,r5)
0914 BEGIN_MMU_FTR_SECTION
0915     LOAD_BAT(4,r3,r4,r5)
0916     LOAD_BAT(5,r3,r4,r5)
0917     LOAD_BAT(6,r3,r4,r5)
0918     LOAD_BAT(7,r3,r4,r5)
0919 END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
0920     blr
0921 
0922 _GLOBAL(load_segment_registers)
0923     li  r0, NUM_USER_SEGMENTS /* load up user segment register values */
0924     mtctr   r0      /* for context 0 */
0925 #ifdef CONFIG_PPC_KUEP
0926     lis r3, SR_NX@h /* Kp = 0, Ks = 0, VSID = 0 */
0927 #else
0928     li  r3, 0       /* Kp = 0, Ks = 0, VSID = 0 */
0929 #endif
0930     li  r4, 0
0931 3:  mtsrin  r3, r4
0932     addi    r3, r3, 0x111   /* increment VSID */
0933     addis   r4, r4, 0x1000  /* address of next segment */
0934     bdnz    3b
0935     li  r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
0936     mtctr   r0          /* for context 0 */
0937     rlwinm  r3, r3, 0, ~SR_NX   /* Nx = 0 */
0938     rlwinm  r3, r3, 0, ~SR_KS   /* Ks = 0 */
0939     oris    r3, r3, SR_KP@h     /* Kp = 1 */
0940 3:  mtsrin  r3, r4
0941     addi    r3, r3, 0x111   /* increment VSID */
0942     addis   r4, r4, 0x1000  /* address of next segment */
0943     bdnz    3b
0944     blr
0945 
0946 /*
0947  * This is where the main kernel code starts.
0948  */
0949 start_here:
0950     /* ptr to current */
0951     lis r2,init_task@h
0952     ori r2,r2,init_task@l
0953     /* Set up for using our exception vectors */
0954     /* ptr to phys current thread */
0955     tophys(r4,r2)
0956     addi    r4,r4,THREAD    /* init task's THREAD */
0957     mtspr   SPRN_SPRG_THREAD,r4
0958 BEGIN_MMU_FTR_SECTION
0959     lis r4, (swapper_pg_dir - PAGE_OFFSET)@h
0960     ori r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
0961     rlwinm  r4, r4, 4, 0xffff01ff
0962     mtspr   SPRN_SDR1, r4
0963 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_HPTE_TABLE)
0964 
0965     /* stack */
0966     lis r1,init_thread_union@ha
0967     addi    r1,r1,init_thread_union@l
0968     li  r0,0
0969     stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
0970 /*
0971  * Do early platform-specific initialization,
0972  * and set up the MMU.
0973  */
0974 #ifdef CONFIG_KASAN
0975     bl  kasan_early_init
0976 #endif
0977     li  r3,0
0978     mr  r4,r31
0979     bl  machine_init
0980     bl  __save_cpu_setup
0981     bl  MMU_init
0982     bl  MMU_init_hw_patch
0983 
0984 /*
0985  * Go back to running unmapped so we can load up new values
0986  * for SDR1 (hash table pointer) and the segment registers
0987  * and change to using our exception vectors.
0988  */
0989     lis r4,2f@h
0990     ori r4,r4,2f@l
0991     tophys(r4,r4)
0992     li  r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
0993 
0994     .align  4
0995     mtspr   SPRN_SRR0,r4
0996     mtspr   SPRN_SRR1,r3
0997     rfi
0998 /* Load up the kernel context */
0999 2:  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  */
1031 clear_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
1050 BEGIN_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
1073 END_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
1091 1:  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)
1099 BEGIN_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)
1104 END_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 
1111 flush_tlbs:
1112     lis r10, 0x40
1113 1:  addic.  r10, r10, -0x1000
1114     tlbie   r10
1115     bgt 1b
1116     sync
1117     blr
1118 
1119 mmu_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 */
1133 initial_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
1151 setup_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
1170 setup_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
1183 setup_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