/*1* PowerPC version2* Copyright (C) 1995-1996 Gary Thomas ([email protected])3*4* Rewritten by Cort Dougan ([email protected]) for PReP5* Copyright (C) 1996 Cort Dougan <[email protected]>6* Adapted for Power Macintosh by Paul Mackerras.7* Low-level exception handlers and MMU support8* rewritten by Paul Mackerras.9* Copyright (C) 1996 Paul Mackerras.10* MPC8xx modifications Copyright (C) 1997 Dan Malek ([email protected]).11*12* This file contains the low-level support and setup for the13* PowerPC platform, including trap and interrupt dispatch.14* (The PPC 8xx embedded CPUs use head_8xx.S instead.)15*16* This program is free software; you can redistribute it and/or17* modify it under the terms of the GNU General Public License18* as published by the Free Software Foundation; either version19* 2 of the License, or (at your option) any later version.20*21*/2223#include <linux/init.h>24#include <asm/reg.h>25#include <asm/page.h>26#include <asm/mmu.h>27#include <asm/pgtable.h>28#include <asm/cputable.h>29#include <asm/cache.h>30#include <asm/thread_info.h>31#include <asm/ppc_asm.h>32#include <asm/asm-offsets.h>33#include <asm/ptrace.h>34#include <asm/bug.h>35#include <asm/kvm_book3s_asm.h>3637/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */38#define LOAD_BAT(n, reg, RA, RB) \39/* see the comment for clear_bats() -- Cort */ \40li RA,0; \41mtspr SPRN_IBAT##n##U,RA; \42mtspr SPRN_DBAT##n##U,RA; \43lwz RA,(n*16)+0(reg); \44lwz RB,(n*16)+4(reg); \45mtspr SPRN_IBAT##n##U,RA; \46mtspr SPRN_IBAT##n##L,RB; \47beq 1f; \48lwz RA,(n*16)+8(reg); \49lwz RB,(n*16)+12(reg); \50mtspr SPRN_DBAT##n##U,RA; \51mtspr SPRN_DBAT##n##L,RB; \521:5354__HEAD55.stabs "arch/powerpc/kernel/",N_SO,0,0,0f56.stabs "head_32.S",N_SO,0,0,0f570:58_ENTRY(_stext);5960/*61* _start is defined this way because the XCOFF loader in the OpenFirmware62* on the powermac expects the entry point to be a procedure descriptor.63*/64_ENTRY(_start);65/*66* These are here for legacy reasons, the kernel used to67* need to look like a coff function entry for the pmac68* but we're always started by some kind of bootloader now.69* -- Cort70*/71nop /* used by __secondary_hold on prep (mtx) and chrp smp */72nop /* used by __secondary_hold on prep (mtx) and chrp smp */73nop7475/* PMAC76* Enter here with the kernel text, data and bss loaded starting at77* 0, running with virtual == physical mapping.78* r5 points to the prom entry point (the client interface handler79* address). Address translation is turned on, with the prom80* managing the hash table. Interrupts are disabled. The stack81* pointer (r1) points to just below the end of the half-meg region82* from 0x380000 - 0x400000, which is mapped in already.83*84* If we are booted from MacOS via BootX, we enter with the kernel85* image loaded somewhere, and the following values in registers:86* r3: 'BooX' (0x426f6f58)87* r4: virtual address of boot_infos_t88* r5: 089*90* PREP91* This is jumped to on prep systems right after the kernel is relocated92* to its proper place in memory by the boot loader. The expected layout93* of the regs is:94* r3: ptr to residual data95* r4: initrd_start or if no initrd then 096* r5: initrd_end - unused if r4 is 097* r6: Start of command line string98* r7: End of command line string99*100* This just gets a minimal mmu environment setup so we can call101* start_here() to do the real work.102* -- Cort103*/104105.globl __start106__start:107/*108* We have to do any OF calls before we map ourselves to KERNELBASE,109* because OF may have I/O devices mapped into that area110* (particularly on CHRP).111*/112cmpwi 0,r5,0113beq 1f114115#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE116/* find out where we are now */117bcl 20,31,$+41180: mflr r8 /* r8 = runtime addr here */119addis r8,r8,(_stext - 0b)@ha120addi r8,r8,(_stext - 0b)@l /* current runtime base addr */121bl prom_init122#endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */123124/* We never return. We also hit that trap if trying to boot125* from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */126trap127128/*129* Check for BootX signature when supporting PowerMac and branch to130* appropriate trampoline if it's present131*/132#ifdef CONFIG_PPC_PMAC1331: lis r31,0x426f134ori r31,r31,0x6f58135cmpw 0,r3,r31136bne 1f137bl bootx_init138trap139#endif /* CONFIG_PPC_PMAC */1401411: mr r31,r3 /* save parameters */142mr r30,r4143li r24,0 /* cpu # */144145/*146* early_init() does the early machine identification and does147* the necessary low-level setup and clears the BSS148* -- Cort <[email protected]>149*/150bl early_init151152/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains153* the physical address we are running at, returned by early_init()154*/155bl mmu_off156__after_mmu_off:157bl clear_bats158bl flush_tlbs159160bl initial_bats161#if defined(CONFIG_BOOTX_TEXT)162bl setup_disp_bat163#endif164#ifdef CONFIG_PPC_EARLY_DEBUG_CPM165bl setup_cpm_bat166#endif167#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO168bl setup_usbgecko_bat169#endif170171/*172* Call setup_cpu for CPU 0 and initialize 6xx Idle173*/174bl reloc_offset175li r24,0 /* cpu# */176bl call_setup_cpu /* Call setup_cpu for this CPU */177#ifdef CONFIG_6xx178bl reloc_offset179bl init_idle_6xx180#endif /* CONFIG_6xx */181182183/*184* We need to run with _start at physical address 0.185* On CHRP, we are loaded at 0x10000 since OF on CHRP uses186* the exception vectors at 0 (and therefore this copy187* overwrites OF's exception vectors with our own).188* The MMU is off at this point.189*/190bl reloc_offset191mr r26,r3192addis r4,r3,KERNELBASE@h /* current address of _start */193lis r5,PHYSICAL_START@h194cmplw 0,r4,r5 /* already running at PHYSICAL_START? */195bne relocate_kernel196/*197* we now have the 1st 16M of ram mapped with the bats.198* prep needs the mmu to be turned on here, but pmac already has it on.199* this shouldn't bother the pmac since it just gets turned on again200* as we jump to our code at KERNELBASE. -- Cort201* Actually no, pmac doesn't have it on any more. BootX enters with MMU202* off, and in other cases, we now turn it off before changing BATs above.203*/204turn_on_mmu:205mfmsr r0206ori r0,r0,MSR_DR|MSR_IR207mtspr SPRN_SRR1,r0208lis r0,start_here@h209ori r0,r0,start_here@l210mtspr SPRN_SRR0,r0211SYNC212RFI /* enables MMU */213214/*215* We need __secondary_hold as a place to hold the other cpus on216* an SMP machine, even when we are running a UP kernel.217*/218. = 0xc0 /* for prep bootloader */219li r3,1 /* MTX only has 1 cpu */220.globl __secondary_hold221__secondary_hold:222/* tell the master we're here */223stw r3,__secondary_hold_acknowledge@l(0)224#ifdef CONFIG_SMP225100: lwz r4,0(0)226/* wait until we're told to start */227cmpw 0,r4,r3228bne 100b229/* our cpu # was at addr 0 - go */230mr r24,r3 /* cpu # */231b __secondary_start232#else233b .234#endif /* CONFIG_SMP */235236.globl __secondary_hold_spinloop237__secondary_hold_spinloop:238.long 0239.globl __secondary_hold_acknowledge240__secondary_hold_acknowledge:241.long -1242243/*244* Exception entry code. This code runs with address translation245* turned off, i.e. using physical addresses.246* We assume sprg3 has the physical address of the current247* task's thread_struct.248*/249#define EXCEPTION_PROLOG \250mtspr SPRN_SPRG_SCRATCH0,r10; \251mtspr SPRN_SPRG_SCRATCH1,r11; \252mfcr r10; \253EXCEPTION_PROLOG_1; \254EXCEPTION_PROLOG_2255256#define EXCEPTION_PROLOG_1 \257mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \258andi. r11,r11,MSR_PR; \259tophys(r11,r1); /* use tophys(r1) if kernel */ \260beq 1f; \261mfspr r11,SPRN_SPRG_THREAD; \262lwz r11,THREAD_INFO-THREAD(r11); \263addi r11,r11,THREAD_SIZE; \264tophys(r11,r11); \2651: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */266267268#define EXCEPTION_PROLOG_2 \269CLR_TOP32(r11); \270stw r10,_CCR(r11); /* save registers */ \271stw r12,GPR12(r11); \272stw r9,GPR9(r11); \273mfspr r10,SPRN_SPRG_SCRATCH0; \274stw r10,GPR10(r11); \275mfspr r12,SPRN_SPRG_SCRATCH1; \276stw r12,GPR11(r11); \277mflr r10; \278stw r10,_LINK(r11); \279mfspr r12,SPRN_SRR0; \280mfspr r9,SPRN_SRR1; \281stw r1,GPR1(r11); \282stw r1,0(r11); \283tovirt(r1,r11); /* set new kernel sp */ \284li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \285MTMSRD(r10); /* (except for mach check in rtas) */ \286stw r0,GPR0(r11); \287lis r10,STACK_FRAME_REGS_MARKER@ha; /* exception frame marker */ \288addi r10,r10,STACK_FRAME_REGS_MARKER@l; \289stw r10,8(r11); \290SAVE_4GPRS(3, r11); \291SAVE_2GPRS(7, r11)292293/*294* Note: code which follows this uses cr0.eq (set if from kernel),295* r11, r12 (SRR0), and r9 (SRR1).296*297* Note2: once we have set r1 we are in a position to take exceptions298* again, and we could thus set MSR:RI at that point.299*/300301/*302* Exception vectors.303*/304#define EXCEPTION(n, label, hdlr, xfer) \305. = n; \306DO_KVM n; \307label: \308EXCEPTION_PROLOG; \309addi r3,r1,STACK_FRAME_OVERHEAD; \310xfer(n, hdlr)311312#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \313li r10,trap; \314stw r10,_TRAP(r11); \315li r10,MSR_KERNEL; \316copyee(r10, r9); \317bl tfer; \318i##n: \319.long hdlr; \320.long ret321322#define COPY_EE(d, s) rlwimi d,s,0,16,16323#define NOCOPY(d, s)324325#define EXC_XFER_STD(n, hdlr) \326EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \327ret_from_except_full)328329#define EXC_XFER_LITE(n, hdlr) \330EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \331ret_from_except)332333#define EXC_XFER_EE(n, hdlr) \334EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \335ret_from_except_full)336337#define EXC_XFER_EE_LITE(n, hdlr) \338EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \339ret_from_except)340341/* System reset */342/* core99 pmac starts the seconary here by changing the vector, and343putting it back to what it was (unknown_exception) when done. */344EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)345346/* Machine check */347/*348* On CHRP, this is complicated by the fact that we could get a349* machine check inside RTAS, and we have no guarantee that certain350* critical registers will have the values we expect. The set of351* registers that might have bad values includes all the GPRs352* and all the BATs. We indicate that we are in RTAS by putting353* a non-zero value, the address of the exception frame to use,354* in SPRG2. The machine check handler checks SPRG2 and uses its355* value if it is non-zero. If we ever needed to free up SPRG2,356* we could use a field in the thread_info or thread_struct instead.357* (Other exception handlers assume that r1 is a valid kernel stack358* pointer when we take an exception from supervisor mode.)359* -- paulus.360*/361. = 0x200362DO_KVM 0x200363mtspr SPRN_SPRG_SCRATCH0,r10364mtspr SPRN_SPRG_SCRATCH1,r11365mfcr r10366#ifdef CONFIG_PPC_CHRP367mfspr r11,SPRN_SPRG_RTAS368cmpwi 0,r11,0369bne 7f370#endif /* CONFIG_PPC_CHRP */371EXCEPTION_PROLOG_13727: EXCEPTION_PROLOG_2373addi r3,r1,STACK_FRAME_OVERHEAD374#ifdef CONFIG_PPC_CHRP375mfspr r4,SPRN_SPRG_RTAS376cmpwi cr1,r4,0377bne cr1,1f378#endif379EXC_XFER_STD(0x200, machine_check_exception)380#ifdef CONFIG_PPC_CHRP3811: b machine_check_in_rtas382#endif383384/* Data access exception. */385. = 0x300386DO_KVM 0x300387DataAccess:388EXCEPTION_PROLOG389mfspr r10,SPRN_DSISR390stw r10,_DSISR(r11)391andis. r0,r10,0xa470 /* weird error? */392bne 1f /* if not, try to put a PTE */393mfspr r4,SPRN_DAR /* into the hash table */394rlwinm r3,r10,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */395bl hash_page3961: lwz r5,_DSISR(r11) /* get DSISR value */397mfspr r4,SPRN_DAR398EXC_XFER_EE_LITE(0x300, handle_page_fault)399400401/* Instruction access exception. */402. = 0x400403DO_KVM 0x400404InstructionAccess:405EXCEPTION_PROLOG406andis. r0,r9,0x4000 /* no pte found? */407beq 1f /* if so, try to put a PTE */408li r3,0 /* into the hash table */409mr r4,r12 /* SRR0 is fault address */410bl hash_page4111: mr r4,r12412mr r5,r9413EXC_XFER_EE_LITE(0x400, handle_page_fault)414415/* External interrupt */416EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)417418/* Alignment exception */419. = 0x600420DO_KVM 0x600421Alignment:422EXCEPTION_PROLOG423mfspr r4,SPRN_DAR424stw r4,_DAR(r11)425mfspr r5,SPRN_DSISR426stw r5,_DSISR(r11)427addi r3,r1,STACK_FRAME_OVERHEAD428EXC_XFER_EE(0x600, alignment_exception)429430/* Program check exception */431EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)432433/* Floating-point unavailable */434. = 0x800435DO_KVM 0x800436FPUnavailable:437BEGIN_FTR_SECTION438/*439* Certain Freescale cores don't have a FPU and treat fp instructions440* as a FP Unavailable exception. Redirect to illegal/emulation handling.441*/442b ProgramCheck443END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)444EXCEPTION_PROLOG445beq 1f446bl load_up_fpu /* if from user, just load it up */447b fast_exception_return4481: addi r3,r1,STACK_FRAME_OVERHEAD449EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)450451/* Decrementer */452EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)453454EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE)455EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)456457/* System call */458. = 0xc00459DO_KVM 0xc00460SystemCall:461EXCEPTION_PROLOG462EXC_XFER_EE_LITE(0xc00, DoSyscall)463464/* Single step - not used on 601 */465EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)466EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE)467468/*469* The Altivec unavailable trap is at 0x0f20. Foo.470* We effectively remap it to 0x3000.471* We include an altivec unavailable exception vector even if472* not configured for Altivec, so that you can't panic a473* non-altivec kernel running on a machine with altivec just474* by executing an altivec instruction.475*/476. = 0xf00477DO_KVM 0xf00478b PerformanceMonitor479480. = 0xf20481DO_KVM 0xf20482b AltiVecUnavailable483484/*485* Handle TLB miss for instruction on 603/603e.486* Note: we get an alternate set of r0 - r3 to use automatically.487*/488. = 0x1000489InstructionTLBMiss:490/*491* r0: scratch492* r1: linux style pte ( later becomes ppc hardware pte )493* r2: ptr to linux-style pte494* r3: scratch495*/496/* Get PTE (linux-style) and check access */497mfspr r3,SPRN_IMISS498lis r1,PAGE_OFFSET@h /* check if kernel address */499cmplw 0,r1,r3500mfspr r2,SPRN_SPRG_THREAD501li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */502lwz r2,PGDIR(r2)503bge- 112f504mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */505rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */506lis r2,swapper_pg_dir@ha /* if kernel address, use */507addi r2,r2,swapper_pg_dir@l /* kernel page table */508112: tophys(r2,r2)509rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */510lwz r2,0(r2) /* get pmd entry */511rlwinm. r2,r2,0,0,19 /* extract address of pte page */512beq- InstructionAddressInvalid /* return if no mapping */513rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */514lwz r0,0(r2) /* get linux-style pte */515andc. r1,r1,r0 /* check access & ~permission */516bne- InstructionAddressInvalid /* return if access not permitted */517ori r0,r0,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */518/*519* NOTE! We are assuming this is not an SMP system, otherwise520* we would need to update the pte atomically with lwarx/stwcx.521*/522stw r0,0(r2) /* update PTE (accessed bit) */523/* Convert linux-style PTE to low word of PPC-style PTE */524rlwinm r1,r0,32-10,31,31 /* _PAGE_RW -> PP lsb */525rlwinm r2,r0,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */526and r1,r1,r2 /* writable if _RW and _DIRTY */527rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */528rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */529ori r1,r1,0xe04 /* clear out reserved bits */530andc r1,r0,r1 /* PP = user? (rw&dirty? 2: 3): 0 */531BEGIN_FTR_SECTION532rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */533END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)534mtspr SPRN_RPA,r1535tlbli r3536mfspr r3,SPRN_SRR1 /* Need to restore CR0 */537mtcrf 0x80,r3538rfi539InstructionAddressInvalid:540mfspr r3,SPRN_SRR1541rlwinm r1,r3,9,6,6 /* Get load/store bit */542543addis r1,r1,0x2000544mtspr SPRN_DSISR,r1 /* (shouldn't be needed) */545andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */546or r2,r2,r1547mtspr SPRN_SRR1,r2548mfspr r1,SPRN_IMISS /* Get failing address */549rlwinm. r2,r2,0,31,31 /* Check for little endian access */550rlwimi r2,r2,1,30,30 /* change 1 -> 3 */551xor r1,r1,r2552mtspr SPRN_DAR,r1 /* Set fault address */553mfmsr r0 /* Restore "normal" registers */554xoris r0,r0,MSR_TGPR>>16555mtcrf 0x80,r3 /* Restore CR0 */556mtmsr r0557b InstructionAccess558559/*560* Handle TLB miss for DATA Load operation on 603/603e561*/562. = 0x1100563DataLoadTLBMiss:564/*565* r0: scratch566* r1: linux style pte ( later becomes ppc hardware pte )567* r2: ptr to linux-style pte568* r3: scratch569*/570/* Get PTE (linux-style) and check access */571mfspr r3,SPRN_DMISS572lis r1,PAGE_OFFSET@h /* check if kernel address */573cmplw 0,r1,r3574mfspr r2,SPRN_SPRG_THREAD575li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */576lwz r2,PGDIR(r2)577bge- 112f578mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */579rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */580lis r2,swapper_pg_dir@ha /* if kernel address, use */581addi r2,r2,swapper_pg_dir@l /* kernel page table */582112: tophys(r2,r2)583rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */584lwz r2,0(r2) /* get pmd entry */585rlwinm. r2,r2,0,0,19 /* extract address of pte page */586beq- DataAddressInvalid /* return if no mapping */587rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */588lwz r0,0(r2) /* get linux-style pte */589andc. r1,r1,r0 /* check access & ~permission */590bne- DataAddressInvalid /* return if access not permitted */591ori r0,r0,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */592/*593* NOTE! We are assuming this is not an SMP system, otherwise594* we would need to update the pte atomically with lwarx/stwcx.595*/596stw r0,0(r2) /* update PTE (accessed bit) */597/* Convert linux-style PTE to low word of PPC-style PTE */598rlwinm r1,r0,32-10,31,31 /* _PAGE_RW -> PP lsb */599rlwinm r2,r0,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */600and r1,r1,r2 /* writable if _RW and _DIRTY */601rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */602rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */603ori r1,r1,0xe04 /* clear out reserved bits */604andc r1,r0,r1 /* PP = user? (rw&dirty? 2: 3): 0 */605BEGIN_FTR_SECTION606rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */607END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)608mtspr SPRN_RPA,r1609mfspr r2,SPRN_SRR1 /* Need to restore CR0 */610mtcrf 0x80,r2611BEGIN_MMU_FTR_SECTION612li r0,1613mfspr r1,SPRN_SPRG_603_LRU614rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */615slw r0,r0,r2616xor r1,r0,r1617srw r0,r1,r2618mtspr SPRN_SPRG_603_LRU,r1619mfspr r2,SPRN_SRR1620rlwimi r2,r0,31-14,14,14621mtspr SPRN_SRR1,r2622END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)623tlbld r3624rfi625DataAddressInvalid:626mfspr r3,SPRN_SRR1627rlwinm r1,r3,9,6,6 /* Get load/store bit */628addis r1,r1,0x2000629mtspr SPRN_DSISR,r1630andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */631mtspr SPRN_SRR1,r2632mfspr r1,SPRN_DMISS /* Get failing address */633rlwinm. r2,r2,0,31,31 /* Check for little endian access */634beq 20f /* Jump if big endian */635xori r1,r1,363620: mtspr SPRN_DAR,r1 /* Set fault address */637mfmsr r0 /* Restore "normal" registers */638xoris r0,r0,MSR_TGPR>>16639mtcrf 0x80,r3 /* Restore CR0 */640mtmsr r0641b DataAccess642643/*644* Handle TLB miss for DATA Store on 603/603e645*/646. = 0x1200647DataStoreTLBMiss:648/*649* r0: scratch650* r1: linux style pte ( later becomes ppc hardware pte )651* r2: ptr to linux-style pte652* r3: scratch653*/654/* Get PTE (linux-style) and check access */655mfspr r3,SPRN_DMISS656lis r1,PAGE_OFFSET@h /* check if kernel address */657cmplw 0,r1,r3658mfspr r2,SPRN_SPRG_THREAD659li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */660lwz r2,PGDIR(r2)661bge- 112f662mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */663rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */664lis r2,swapper_pg_dir@ha /* if kernel address, use */665addi r2,r2,swapper_pg_dir@l /* kernel page table */666112: tophys(r2,r2)667rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */668lwz r2,0(r2) /* get pmd entry */669rlwinm. r2,r2,0,0,19 /* extract address of pte page */670beq- DataAddressInvalid /* return if no mapping */671rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */672lwz r0,0(r2) /* get linux-style pte */673andc. r1,r1,r0 /* check access & ~permission */674bne- DataAddressInvalid /* return if access not permitted */675ori r0,r0,_PAGE_ACCESSED|_PAGE_DIRTY676/*677* NOTE! We are assuming this is not an SMP system, otherwise678* we would need to update the pte atomically with lwarx/stwcx.679*/680stw r0,0(r2) /* update PTE (accessed/dirty bits) */681/* Convert linux-style PTE to low word of PPC-style PTE */682rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */683li r1,0xe05 /* clear out reserved bits & PP lsb */684andc r1,r0,r1 /* PP = user? 2: 0 */685BEGIN_FTR_SECTION686rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */687END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)688mtspr SPRN_RPA,r1689mfspr r2,SPRN_SRR1 /* Need to restore CR0 */690mtcrf 0x80,r2691BEGIN_MMU_FTR_SECTION692li r0,1693mfspr r1,SPRN_SPRG_603_LRU694rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */695slw r0,r0,r2696xor r1,r0,r1697srw r0,r1,r2698mtspr SPRN_SPRG_603_LRU,r1699mfspr r2,SPRN_SRR1700rlwimi r2,r0,31-14,14,14701mtspr SPRN_SRR1,r2702END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)703tlbld r3704rfi705706#ifndef CONFIG_ALTIVEC707#define altivec_assist_exception unknown_exception708#endif709710EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE)711EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)712EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)713EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE)714EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)715EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE)716EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE)717EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE)718EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE)719EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE)720EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE)721EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE)722EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE)723EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE)724EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE)725EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE)726EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE)727EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE)728EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE)729EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE)730EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE)731EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE)732EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE)733EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE)734EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE)735EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE)736EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE)737EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE)738EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE)739740.globl mol_trampoline741.set mol_trampoline, i0x2f00742743. = 0x3000744745AltiVecUnavailable:746EXCEPTION_PROLOG747#ifdef CONFIG_ALTIVEC748beq 1f749bl load_up_altivec /* if from user, just load it up */750b fast_exception_return751#endif /* CONFIG_ALTIVEC */7521: addi r3,r1,STACK_FRAME_OVERHEAD753EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)754755PerformanceMonitor:756EXCEPTION_PROLOG757addi r3,r1,STACK_FRAME_OVERHEAD758EXC_XFER_STD(0xf00, performance_monitor_exception)759760761/*762* This code is jumped to from the startup code to copy763* the kernel image to physical address PHYSICAL_START.764*/765relocate_kernel:766addis r9,r26,klimit@ha /* fetch klimit */767lwz r25,klimit@l(r9)768addis r25,r25,-KERNELBASE@h769lis r3,PHYSICAL_START@h /* Destination base address */770li r6,0 /* Destination offset */771li r5,0x4000 /* # bytes of memory to copy */772bl copy_and_flush /* copy the first 0x4000 bytes */773addi r0,r3,4f@l /* jump to the address of 4f */774mtctr r0 /* in copy and do the rest. */775bctr /* jump to the copy */7764: mr r5,r25777bl copy_and_flush /* copy the rest */778b turn_on_mmu779780/*781* Copy routine used to copy the kernel to start at physical address 0782* and flush and invalidate the caches as needed.783* r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset784* on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.785*/786_ENTRY(copy_and_flush)787addi r5,r5,-4788addi r6,r6,-47894: li r0,L1_CACHE_BYTES/4790mtctr r07913: addi r6,r6,4 /* copy a cache line */792lwzx r0,r6,r4793stwx r0,r6,r3794bdnz 3b795dcbst r6,r3 /* write it to memory */796sync797icbi r6,r3 /* flush the icache line */798cmplw 0,r6,r5799blt 4b800sync /* additional sync needed on g4 */801isync802addi r5,r5,4803addi r6,r6,4804blr805806#ifdef CONFIG_SMP807.globl __secondary_start_mpc86xx808__secondary_start_mpc86xx:809mfspr r3, SPRN_PIR810stw r3, __secondary_hold_acknowledge@l(0)811mr r24, r3 /* cpu # */812b __secondary_start813814.globl __secondary_start_pmac_0815__secondary_start_pmac_0:816/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */817li r24,0818b 1f819li r24,1820b 1f821li r24,2822b 1f823li r24,38241:825/* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0826set to map the 0xf0000000 - 0xffffffff region */827mfmsr r0828rlwinm r0,r0,0,28,26 /* clear DR (0x10) */829SYNC830mtmsr r0831isync832833.globl __secondary_start834__secondary_start:835/* Copy some CPU settings from CPU 0 */836bl __restore_cpu_setup837838lis r3,-KERNELBASE@h839mr r4,r24840bl call_setup_cpu /* Call setup_cpu for this CPU */841#ifdef CONFIG_6xx842lis r3,-KERNELBASE@h843bl init_idle_6xx844#endif /* CONFIG_6xx */845846/* get current_thread_info and current */847lis r1,secondary_ti@ha848tophys(r1,r1)849lwz r1,secondary_ti@l(r1)850tophys(r2,r1)851lwz r2,TI_TASK(r2)852853/* stack */854addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD855li r0,0856tophys(r3,r1)857stw r0,0(r3)858859/* load up the MMU */860bl load_up_mmu861862/* ptr to phys current thread */863tophys(r4,r2)864addi r4,r4,THREAD /* phys address of our thread_struct */865CLR_TOP32(r4)866mtspr SPRN_SPRG_THREAD,r4867li r3,0868mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */869870/* enable MMU and jump to start_secondary */871li r4,MSR_KERNEL872FIX_SRR1(r4,r5)873lis r3,start_secondary@h874ori r3,r3,start_secondary@l875mtspr SPRN_SRR0,r3876mtspr SPRN_SRR1,r4877SYNC878RFI879#endif /* CONFIG_SMP */880881#ifdef CONFIG_KVM_BOOK3S_HANDLER882#include "../kvm/book3s_rmhandlers.S"883#endif884885/*886* Those generic dummy functions are kept for CPUs not887* included in CONFIG_6xx888*/889#if !defined(CONFIG_6xx)890_ENTRY(__save_cpu_setup)891blr892_ENTRY(__restore_cpu_setup)893blr894#endif /* !defined(CONFIG_6xx) */895896897/*898* Load stuff into the MMU. Intended to be called with899* IR=0 and DR=0.900*/901load_up_mmu:902sync /* Force all PTE updates to finish */903isync904tlbia /* Clear all TLB entries */905sync /* wait for tlbia/tlbie to finish */906TLBSYNC /* ... on all CPUs */907/* Load the SDR1 register (hash table base & size) */908lis r6,_SDR1@ha909tophys(r6,r6)910lwz r6,_SDR1@l(r6)911mtspr SPRN_SDR1,r6912li r0,16 /* load up segment register values */913mtctr r0 /* for context 0 */914lis r3,0x2000 /* Ku = 1, VSID = 0 */915li r4,09163: mtsrin r3,r4917addi r3,r3,0x111 /* increment VSID */918addis r4,r4,0x1000 /* address of next segment */919bdnz 3b920921/* Load the BAT registers with the values set up by MMU_init.922MMU_init takes care of whether we're on a 601 or not. */923mfpvr r3924srwi r3,r3,16925cmpwi r3,1926lis r3,BATS@ha927addi r3,r3,BATS@l928tophys(r3,r3)929LOAD_BAT(0,r3,r4,r5)930LOAD_BAT(1,r3,r4,r5)931LOAD_BAT(2,r3,r4,r5)932LOAD_BAT(3,r3,r4,r5)933BEGIN_MMU_FTR_SECTION934LOAD_BAT(4,r3,r4,r5)935LOAD_BAT(5,r3,r4,r5)936LOAD_BAT(6,r3,r4,r5)937LOAD_BAT(7,r3,r4,r5)938END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)939blr940941/*942* This is where the main kernel code starts.943*/944start_here:945/* ptr to current */946lis r2,init_task@h947ori r2,r2,init_task@l948/* Set up for using our exception vectors */949/* ptr to phys current thread */950tophys(r4,r2)951addi r4,r4,THREAD /* init task's THREAD */952CLR_TOP32(r4)953mtspr SPRN_SPRG_THREAD,r4954li r3,0955mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */956957/* stack */958lis r1,init_thread_union@ha959addi r1,r1,init_thread_union@l960li r0,0961stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)962/*963* Do early platform-specific initialization,964* and set up the MMU.965*/966mr r3,r31967mr r4,r30968bl machine_init969bl __save_cpu_setup970bl MMU_init971972/*973* Go back to running unmapped so we can load up new values974* for SDR1 (hash table pointer) and the segment registers975* and change to using our exception vectors.976*/977lis r4,2f@h978ori r4,r4,2f@l979tophys(r4,r4)980li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)981FIX_SRR1(r3,r5)982mtspr SPRN_SRR0,r4983mtspr SPRN_SRR1,r3984SYNC985RFI986/* Load up the kernel context */9872: bl load_up_mmu988989#ifdef CONFIG_BDI_SWITCH990/* Add helper information for the Abatron bdiGDB debugger.991* We do this here because we know the mmu is disabled, and992* will be enabled for real in just a few instructions.993*/994lis r5, abatron_pteptrs@h995ori r5, r5, abatron_pteptrs@l996stw r5, 0xf0(r0) /* This much match your Abatron config */997lis r6, swapper_pg_dir@h998ori r6, r6, swapper_pg_dir@l999tophys(r5, r5)1000stw r6, 0(r5)1001#endif /* CONFIG_BDI_SWITCH */10021003/* Now turn on the MMU for real! */1004li r4,MSR_KERNEL1005FIX_SRR1(r4,r5)1006lis r3,start_kernel@h1007ori r3,r3,start_kernel@l1008mtspr SPRN_SRR0,r31009mtspr SPRN_SRR1,r41010SYNC1011RFI10121013/*1014* void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);1015*1016* Set up the segment registers for a new context.1017*/1018_ENTRY(switch_mmu_context)1019lwz r3,MMCONTEXTID(r4)1020cmpwi cr0,r3,01021blt- 4f1022mulli r3,r3,897 /* multiply context by skew factor */1023rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */1024addis r3,r3,0x6000 /* Set Ks, Ku bits */1025li r0,NUM_USER_SEGMENTS1026mtctr r010271028#ifdef CONFIG_BDI_SWITCH1029/* Context switch the PTE pointer for the Abatron BDI2000.1030* The PGDIR is passed as second argument.1031*/1032lwz r4,MM_PGD(r4)1033lis r5, KERNELBASE@h1034lwz r5, 0xf0(r5)1035stw r4, 0x4(r5)1036#endif1037li r4,01038isync10393:1040mtsrin r3,r41041addi r3,r3,0x111 /* next VSID */1042rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */1043addis r4,r4,0x1000 /* address of next segment */1044bdnz 3b1045sync1046isync1047blr10484: trap1049EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,01050blr10511052/*1053* An undocumented "feature" of 604e requires that the v bit1054* be cleared before changing BAT values.1055*1056* Also, newer IBM firmware does not clear bat3 and 4 so1057* this makes sure it's done.1058* -- Cort1059*/1060clear_bats:1061li r10,01062mfspr r9,SPRN_PVR1063rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */1064cmpwi r9, 11065beq 1f10661067mtspr SPRN_DBAT0U,r101068mtspr SPRN_DBAT0L,r101069mtspr SPRN_DBAT1U,r101070mtspr SPRN_DBAT1L,r101071mtspr SPRN_DBAT2U,r101072mtspr SPRN_DBAT2L,r101073mtspr SPRN_DBAT3U,r101074mtspr SPRN_DBAT3L,r1010751:1076mtspr SPRN_IBAT0U,r101077mtspr SPRN_IBAT0L,r101078mtspr SPRN_IBAT1U,r101079mtspr SPRN_IBAT1L,r101080mtspr SPRN_IBAT2U,r101081mtspr SPRN_IBAT2L,r101082mtspr SPRN_IBAT3U,r101083mtspr SPRN_IBAT3L,r101084BEGIN_MMU_FTR_SECTION1085/* Here's a tweak: at this point, CPU setup have1086* not been called yet, so HIGH_BAT_EN may not be1087* set in HID0 for the 745x processors. However, it1088* seems that doesn't affect our ability to actually1089* write to these SPRs.1090*/1091mtspr SPRN_DBAT4U,r101092mtspr SPRN_DBAT4L,r101093mtspr SPRN_DBAT5U,r101094mtspr SPRN_DBAT5L,r101095mtspr SPRN_DBAT6U,r101096mtspr SPRN_DBAT6L,r101097mtspr SPRN_DBAT7U,r101098mtspr SPRN_DBAT7L,r101099mtspr SPRN_IBAT4U,r101100mtspr SPRN_IBAT4L,r101101mtspr SPRN_IBAT5U,r101102mtspr SPRN_IBAT5L,r101103mtspr SPRN_IBAT6U,r101104mtspr SPRN_IBAT6L,r101105mtspr SPRN_IBAT7U,r101106mtspr SPRN_IBAT7L,r101107END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)1108blr11091110flush_tlbs:1111lis r10, 0x4011121: addic. r10, r10, -0x10001113tlbie r101114bgt 1b1115sync1116blr11171118mmu_off:1119addi r4, r3, __after_mmu_off - _start1120mfmsr r31121andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */1122beqlr1123andc r3,r3,r01124mtspr SPRN_SRR0,r41125mtspr SPRN_SRR1,r31126sync1127RFI11281129/*1130* On 601, we use 3 BATs to map up to 24M of RAM at _PAGE_OFFSET1131* (we keep one for debugging) and on others, we use one 256M BAT.1132*/1133initial_bats:1134lis r11,PAGE_OFFSET@h1135mfspr r9,SPRN_PVR1136rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */1137cmpwi 0,r9,11138bne 4f1139ori r11,r11,4 /* set up BAT registers for 601 */1140li r8,0x7f /* valid, block length = 8MB */1141mtspr SPRN_IBAT0U,r11 /* N.B. 601 has valid bit in */1142mtspr SPRN_IBAT0L,r8 /* lower BAT register */1143addis r11,r11,0x800000@h1144addis r8,r8,0x800000@h1145mtspr SPRN_IBAT1U,r111146mtspr SPRN_IBAT1L,r81147addis r11,r11,0x800000@h1148addis r8,r8,0x800000@h1149mtspr SPRN_IBAT2U,r111150mtspr SPRN_IBAT2L,r81151isync1152blr115311544: tophys(r8,r11)1155#ifdef CONFIG_SMP1156ori r8,r8,0x12 /* R/W access, M=1 */1157#else1158ori r8,r8,2 /* R/W access */1159#endif /* CONFIG_SMP */1160ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */11611162mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */1163mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */1164mtspr SPRN_IBAT0L,r81165mtspr SPRN_IBAT0U,r111166isync1167blr116811691170#ifdef CONFIG_BOOTX_TEXT1171setup_disp_bat:1172/*1173* setup the display bat prepared for us in prom.c1174*/1175mflr r81176bl reloc_offset1177mtlr r81178addis r8,r3,disp_BAT@ha1179addi r8,r8,disp_BAT@l1180cmpwi cr0,r8,01181beqlr1182lwz r11,0(r8)1183lwz r8,4(r8)1184mfspr r9,SPRN_PVR1185rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */1186cmpwi 0,r9,11187beq 1f1188mtspr SPRN_DBAT3L,r81189mtspr SPRN_DBAT3U,r111190blr11911: mtspr SPRN_IBAT3L,r81192mtspr SPRN_IBAT3U,r111193blr1194#endif /* CONFIG_BOOTX_TEXT */11951196#ifdef CONFIG_PPC_EARLY_DEBUG_CPM1197setup_cpm_bat:1198lis r8, 0xf0001199ori r8, r8, 0x002a1200mtspr SPRN_DBAT1L, r812011202lis r11, 0xf0001203ori r11, r11, (BL_1M << 2) | 21204mtspr SPRN_DBAT1U, r1112051206blr1207#endif12081209#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO1210setup_usbgecko_bat:1211/* prepare a BAT for early io */1212#if defined(CONFIG_GAMECUBE)1213lis r8, 0x0c001214#elif defined(CONFIG_WII)1215lis r8, 0x0d001216#else1217#error Invalid platform for USB Gecko based early debugging.1218#endif1219/*1220* The virtual address used must match the virtual address1221* associated to the fixmap entry FIX_EARLY_DEBUG_BASE.1222*/1223lis r11, 0xfffe /* top 128K */1224ori r8, r8, 0x002a /* uncached, guarded ,rw */1225ori r11, r11, 0x2 /* 128K, Vs=1, Vp=0 */1226mtspr SPRN_DBAT1L, r81227mtspr SPRN_DBAT1U, r111228blr1229#endif12301231#ifdef CONFIG_82601232/* Jump into the system reset for the rom.1233* We first disable the MMU, and then jump to the ROM reset address.1234*1235* r3 is the board info structure, r4 is the location for starting.1236* I use this for building a small kernel that can load other kernels,1237* rather than trying to write or rely on a rom monitor that can tftp load.1238*/1239.globl m8260_gorom1240m8260_gorom:1241mfmsr r01242rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */1243sync1244mtmsr r01245sync1246mfspr r11, SPRN_HID01247lis r10, 01248ori r10,r10,HID0_ICE|HID0_DCE1249andc r11, r11, r101250mtspr SPRN_HID0, r111251isync1252li r5, MSR_ME|MSR_RI1253lis r6,2f@h1254addis r6,r6,-KERNELBASE@h1255ori r6,r6,2f@l1256mtspr SPRN_SRR0,r61257mtspr SPRN_SRR1,r51258isync1259sync1260rfi12612:1262mtlr r41263blr1264#endif126512661267/*1268* We put a few things here that have to be page-aligned.1269* This stuff goes at the beginning of the data segment,1270* which is page-aligned.1271*/1272.data1273.globl sdata1274sdata:1275.globl empty_zero_page1276empty_zero_page:1277.space 409612781279.globl swapper_pg_dir1280swapper_pg_dir:1281.space PGD_TABLE_SIZE12821283.globl intercept_table1284intercept_table:1285.long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x7001286.long i0x800, 0, 0, 0, 0, i0xd00, 0, 01287.long 0, 0, 0, i0x1300, 0, 0, 0, 01288.long 0, 0, 0, 0, 0, 0, 0, 01289.long 0, 0, 0, 0, 0, 0, 0, 01290.long 0, 0, 0, 0, 0, 0, 0, 012911292/* Room for two PTE pointers, usually the kernel and current user pointers1293* to their respective root page table.1294*/1295abatron_pteptrs:1296.space 8129712981299