head.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:57k
- /*
- * arch/ppc64/kernel/head.S
- *
- * PowerPC version
- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- * Adapted for Power Macintosh by Paul Mackerras.
- * Low-level exception handlers and MMU support
- * rewritten by Paul Mackerras.
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- * This file contains the low-level support and setup for the
- * PowerPC-64 platform, including trap and interrupt dispatch.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
- #define SECONDARY_PROCESSORS
- #include "ppc_asm.h"
- #include "ppc_defs.h"
- #include <asm/processor.h>
- #include <asm/page.h>
- #include <linux/config.h>
- #include <asm/mmu.h>
- #include <asm/perfmon.h>
- #ifdef CONFIG_PPC_ISERIES
- #define DO_SOFT_DISABLE
- #endif
- /*
- * hcall interface to pSeries LPAR
- */
- #define HSC .long 0x44000022
- #define H_SET_ASR 0x30
- /*
- * We layout physical memory as follows:
- * 0x0000 - 0x00ff : Secondary processor spin code
- * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x3fff : Interrupt support
- * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : Initial segment table
- * 0x6000 : iSeries and common interrupt prologs
- */
- /*
- * SPRG Usage
- *
- * Register Definition
- *
- * SPRG0 reserved for hypervisor
- * SPRG1 temp - used to save gpr
- * SPRG2 temp - used to save gpr
- * SPRG3 virt addr of paca
- */
- /*
- * Entering into this code we make the following assumptions:
- * For pSeries:
- * 1. The MMU is off & open firmware is running in real mode.
- * 2. The kernel is entered at __start
- *
- * For iSeries:
- * 1. The MMU is on (as it always is for iSeries)
- * 2. The kernel is entered at SystemReset_Iseries
- */
- .text
- .globl _stext
- _stext:
- _STATIC(__start)
- b .__start_initialization_pSeries
- /* At offset 0x20, there is a pointer to iSeries LPAR data.
- * This is required by the hypervisor */
- . = 0x20
- .llong hvReleaseData-KERNELBASE
- /* At offset 0x28 and 0x30 are offsets to the msChunks
- * array (used by the iSeries LPAR debugger to do translation
- * between physical addresses and absolute addresses) and
- * to the pidhash table (also used by the debugger) */
- .llong msChunks-KERNELBASE
- .llong pidhash-KERNELBASE
- /* Offset 0x38 - Pointer to start of embedded System.map */
- .globl embedded_sysmap_start
- embedded_sysmap_start:
- .llong 0
- /* Offset 0x40 - Pointer to end of embedded System.map */
- .globl embedded_sysmap_end
- embedded_sysmap_end:
- .llong 0
- /* Secondary processors spin on this value until it goes to 1. */
- .globl __secondary_hold_spinloop
- __secondary_hold_spinloop:
- .llong 0x0
- /* Secondary processors write this value with their cpu # */
- /* after they enter the spin loop immediatly below. */
- .globl __secondary_hold_acknowledge
- __secondary_hold_acknowledge:
- .llong 0x0
- . = 0x60
- /*
- * The following code is used on pSeries to hold secondary processors
- * in a spin loop after they have been freed from OpenFirmware, but
- * before the bulk of the kernel has been relocated. This code
- * is relocated to physical address 0x60 before prom_init is run.
- * All of it must fit below the first exception vector at 0x100.
- */
- _GLOBAL(__secondary_hold)
- /* Grab our linux cpu number */
- mr r24,r3
- /* Tell the master cpu we're here */
- /* Relocation is off & we are located at an address less */
- /* than 0x100, so only need to grab low order offset. */
- std r24,__secondary_hold_acknowledge@l(0)
- /* All secondary cpu's wait here until told to start. */
- 100: ld r4,__secondary_hold_spinloop@l(0)
- cmpdi 0,r4,1
- bne 100b
- #ifdef CONFIG_HMT
- b .hmt_init
- #else
- #ifdef CONFIG_SMP
- mr r3,r24
- b .pseries_secondary_smp_init
- #else
- BUG_OPCODE
- #endif
- #endif
- /*
- * The following macros define the code that appears as
- * the prologue to each of the exception handlers. They
- * are split into two parts to allow a single kernel binary
- * to be used for pSeries, and iSeries.
- */
- /*
- * We make as much of the exception code common between native
- * exception handlers (including pSeries LPAR) and iSeries LPAR
- * implementations as possible.
- */
- /*
- * This is the start of the interrupt handlers for pSeries
- * This code runs with relocation off.
- */
- #define EX_SRR0 0
- #define EX_SRR1 8
- #define EX_R20 16
- #define EX_R21 24
- #define EX_R22 32
- #define EX_R23 40
- #define EX_DAR 48
- #define EX_DSISR 56
- #define EX_CCR 60
- #define EX_TRAP 60
- #define EXCEPTION_PROLOG_PSERIES(n,label)
- mtspr SPRG2,r20; /* use SPRG2 as scratch reg */
- mtspr SPRG1,r21; /* save r21 */
- mfspr r20,SPRG3; /* get paca virt addr */
- ld r21,PACAEXCSP(r20); /* get exception stack ptr */
- addi r21,r21,EXC_FRAME_SIZE; /* make exception frame */
- std r22,EX_R22(r21); /* Save r22 in exc. frame */
- li r22,n; /* Save the ex # in exc. frame*/
- stw r22,EX_TRAP(r21); /* */
- std r23,EX_R23(r21); /* Save r23 in exc. frame */
- mfspr r22,SRR0; /* EA of interrupted instr */
- std r22,EX_SRR0(r21); /* Save SRR0 in exc. frame */
- mfspr r23,SRR1; /* machine state at interrupt */
- std r23,EX_SRR1(r21); /* Save SRR1 in exc. frame */
- clrrdi r22,r20,60; /* Get 0xc part of the vaddr */
- ori r22,r22,(label)@l; /* add in the vaddr offset */
- /* assumes *_common < 16b */
- mfmsr r23;
- rotldi r23,r23,4;
- ori r23,r23,0x30B; /* Set IR, DR, SF, ISF, HV */
- rotldi r23,r23,60; /* for generic handlers */
- mtspr SRR0,r22;
- mtspr SRR1,r23;
- mfcr r23; /* save CR in r23 */
- rfid
- /*
- * This is the start of the interrupt handlers for iSeries
- * This code runs with relocation on.
- */
- #define EXCEPTION_PROLOG_ISERIES(n)
- mtspr SPRG2,r20; /* use SPRG2 as scratch reg */
- mtspr SPRG1,r21; /* save r21 */
- mfspr r20,SPRG3; /* get paca */
- ld r21,PACAEXCSP(r20); /* get exception stack ptr */
- addi r21,r21,EXC_FRAME_SIZE; /* make exception frame */
- std r22,EX_R22(r21); /* save r22 on exception frame */
- li r22,n; /* Save the ex # in exc. frame */
- stw r22,EX_TRAP(r21); /* */
- std r23,EX_R23(r21); /* Save r23 in exc. frame */
- ld r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */
- std r22,EX_SRR0(r21); /* save SRR0 in exc. frame */
- ld r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */
- std r23,EX_SRR1(r21); /* save SRR1 in exc. frame */
- mfcr r23; /* save CR in r23 */
- /*
- * The common exception prolog is used for all except a few exceptions
- * such as a segment miss on a kernel address. We have to be prepared
- * to take another exception from the point where we first touch the
- * kernel stack onwards.
- *
- * On entry r20 points to the paca and r21 points to the exception
- * frame on entry, r23 contains the saved CR, and relocation is on.
- */
- #define EXCEPTION_PROLOG_COMMON
- mfspr r22,SPRG2; /* Save r20 in exc. frame */
- std r22,EX_R20(r21);
- mfspr r22,SPRG1; /* Save r21 in exc. frame */
- std r22,EX_R21(r21);
- mfspr r22,DAR; /* Save DAR in exc. frame */
- std r22,EX_DAR(r21);
- std r21,PACAEXCSP(r20); /* update exception stack ptr */
- /* iff no protection flt */
- mfspr r22,DSISR; /* Save DSISR in exc. frame */
- stw r22,EX_DSISR(r21);
- ld r22,EX_SRR1(r21); /* Get SRR1 from exc. frame */
- andi. r22,r22,MSR_PR; /* Set CR for later branch */
- mr r22,r1; /* Save r1 */
- subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */
- beq- 1f;
- ld r1,PACAKSAVE(r20); /* kernel stack to use */
- 1: std r22,GPR1(r1); /* save r1 in stackframe */
- std r22,0(r1); /* make stack chain pointer */
- std r23,_CCR(r1); /* save CR in stackframe */
- ld r22,EX_R20(r21); /* move r20 to stackframe */
- std r22,GPR20(r1);
- ld r23,EX_R21(r21); /* move r21 to stackframe */
- std r23,GPR21(r1);
- ld r22,EX_R22(r21); /* move r22 to stackframe */
- std r22,GPR22(r1);
- ld r23,EX_R23(r21); /* move r23 to stackframe */
- std r23,GPR23(r1);
- mflr r22; /* save LR in stackframe */
- std r22,_LINK(r1);
- mfctr r23; /* save CTR in stackframe */
- std r23,_CTR(r1);
- mfspr r22,XER; /* save XER in stackframe */
- std r22,_XER(r1);
- ld r23,EX_DAR(r21); /* move DAR to stackframe */
- std r23,_DAR(r1);
- lwz r22,EX_DSISR(r21); /* move DSISR to stackframe */
- std r22,_DSISR(r1);
- lbz r22,PACAPROCENABLED(r20);
- std r22,SOFTE(r1);
- ld r22,EX_SRR0(r21); /* get SRR0 from exc. frame */
- ld r23,EX_SRR1(r21); /* get SRR1 from exc. frame */
- addi r21,r21,-EXC_FRAME_SIZE;/* pop off exception frame */
- std r21,PACAEXCSP(r20);
- SAVE_GPR(0, r1); /* save r0 in stackframe */
- SAVE_8GPRS(2, r1); /* save r2 - r13 in stackframe */
- SAVE_4GPRS(10, r1);
- ld r2,PACATOC(r20);
- ld r13,PACACURRENT(r20)
- /*
- * Note: code which follows this uses cr0.eq (set if from kernel),
- * r1, r22 (SRR0), and r23 (SRR1).
- */
- /*
- * Exception vectors.
- */
- #define STD_EXCEPTION_PSERIES(n, label )
- . = n;
- .globl label##_Pseries;
- label##_Pseries:
- EXCEPTION_PROLOG_PSERIES( n, label##_common )
- #define STD_EXCEPTION_ISERIES( n, label )
- .globl label##_Iseries;
- label##_Iseries:
- EXCEPTION_PROLOG_ISERIES( n );
- b label##_common
- #define MASKABLE_EXCEPTION_ISERIES( n, label )
- .globl label##_Iseries;
- label##_Iseries:
- EXCEPTION_PROLOG_ISERIES( n );
- lbz r22,PACAPROFMODE(r20);
- cmpi 0,r22,PMC_STATE_DECR_PROFILE;
- beq- label##_Iseries_profile;
- label##_Iseries_prof_ret:
- lbz r22,PACAPROCENABLED(r20);
- cmpi 0,r22,0;
- beq- label##_Iseries_masked;
- b label##_common;
- label##_Iseries_profile:
- std r24,48(r21);
- std r25,56(r21);
- mflr r24;
- bl do_profile;
- mtlr r24;
- ld r24,48(r21);
- ld r25,56(r21);
- b label##_Iseries_prof_ret
- #define STD_EXCEPTION_COMMON( trap, label, hdlr )
- .globl label##_common;
- label##_common:
- EXCEPTION_PROLOG_COMMON;
- addi r3,r1,STACK_FRAME_OVERHEAD;
- li r20,0;
- li r6,trap;
- bl .save_remaining_regs;
- bl hdlr;
- b .ret_from_except
- /*
- * Start of pSeries system interrupt routines
- */
- . = 0x100
- .globl __start_interupts
- __start_interupts:
- STD_EXCEPTION_PSERIES( 0x100, SystemReset )
- STD_EXCEPTION_PSERIES( 0x200, MachineCheck )
- STD_EXCEPTION_PSERIES( 0x300, DataAccess )
- STD_EXCEPTION_PSERIES( 0x380, DataAccessSLB )
- STD_EXCEPTION_PSERIES( 0x400, InstructionAccess )
- STD_EXCEPTION_PSERIES( 0x480, InstructionAccessSLB )
- STD_EXCEPTION_PSERIES( 0x500, HardwareInterrupt )
- STD_EXCEPTION_PSERIES( 0x600, Alignment )
- STD_EXCEPTION_PSERIES( 0x700, ProgramCheck )
- STD_EXCEPTION_PSERIES( 0x800, FPUnavailable )
- STD_EXCEPTION_PSERIES( 0x900, Decrementer )
- STD_EXCEPTION_PSERIES( 0xa00, Trap_0a )
- STD_EXCEPTION_PSERIES( 0xb00, Trap_0b )
- STD_EXCEPTION_PSERIES( 0xc00, SystemCall )
- STD_EXCEPTION_PSERIES( 0xd00, SingleStep )
- STD_EXCEPTION_PSERIES( 0xe00, Trap_0e )
- STD_EXCEPTION_PSERIES( 0xf00, PerformanceMonitor )
- STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint )
- /* Space for the naca. Architected to be located at real address
- * 0x4000. Various tools rely on this location being fixed.
- * The first dword of the naca is required by iSeries LPAR to
- * point to itVpdAreas. On pSeries native, this value is not used.
- */
- . = 0x4000
- .globl __end_interupts
- .globl __start_naca
- __end_interupts:
- __start_naca:
- .llong itVpdAreas
- .llong 0x0
- .llong 0x0
- .llong paca
- /*
- * Space for the initial segment table
- * For LPAR, the hypervisor must fill in at least one entry
- * before we get control (with relocate on)
- */
- . = 0x5000
- .globl __end_naca
- .globl __start_stab
- __end_naca:
- __start_stab:
- . = 0x6000
- .globl __end_stab
- __end_stab:
- /*
- * The iSeries LPAR map is at this fixed address
- * so that the HvReleaseData structure can address
- * it with a 32-bit offset.
- *
- * The VSID values below are dependent on the
- * VSID generation algorithm. See include/asm/mmu_context.h.
- */
- .llong 1 /* # ESIDs to be mapped by hypervisor */
- .llong 1 /* # memory ranges to be mapped by hypervisor */
- .llong 5 /* Page # of segment table within load area */
- .llong 0 /* Reserved */
- .llong 0 /* Reserved */
- .llong 0 /* Reserved */
- .llong 0 /* Reserved */
- .llong 0 /* Reserved */
- .llong 0x0c00000000 /* ESID to map (Kernel at EA = 0xC000000000000000) */
- .llong 0x06a99b4b14 /* VSID to map (Kernel at VA = 0x6a99b4b140000000) */
- .llong 8192 /* # pages to map (32 MB) */
- .llong 0 /* Offset from start of loadarea to start of map */
- .llong 0x0006a99b4b140000 /* VPN of first page to map */
- . = 0x6100
- /*** ISeries-LPAR interrupt handlers ***/
- STD_EXCEPTION_ISERIES( 0x200, MachineCheck )
- STD_EXCEPTION_ISERIES( 0x300, DataAccess )
- STD_EXCEPTION_ISERIES( 0x380, DataAccessSLB )
- STD_EXCEPTION_ISERIES( 0x400, InstructionAccess )
- STD_EXCEPTION_ISERIES( 0x480, InstructionAccessSLB )
- MASKABLE_EXCEPTION_ISERIES( 0x500, HardwareInterrupt )
- STD_EXCEPTION_ISERIES( 0x600, Alignment )
- STD_EXCEPTION_ISERIES( 0x700, ProgramCheck )
- STD_EXCEPTION_ISERIES( 0x800, FPUnavailable )
- MASKABLE_EXCEPTION_ISERIES( 0x900, Decrementer )
- STD_EXCEPTION_ISERIES( 0xa00, Trap_0a )
- STD_EXCEPTION_ISERIES( 0xb00, Trap_0b )
- STD_EXCEPTION_ISERIES( 0xc00, SystemCall )
- STD_EXCEPTION_ISERIES( 0xd00, SingleStep )
- STD_EXCEPTION_ISERIES( 0xe00, Trap_0e )
- MASKABLE_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
- .globl SystemReset_Iseries
- SystemReset_Iseries:
- mfspr 25,SPRG3 /* Get paca address */
- lhz r24,PACAPACAINDEX(r25) /* Get processor # */
- cmpi 0,r24,0 /* Are we processor 0? */
- beq .__start_initialization_iSeries /* Start up the first processor */
- mfspr r4,CTRLF
- li r5,RUNLATCH /* Turn off the run light */
- andc r4,r4,r5
- mtspr CTRLT,r4
- 1:
- HMT_LOW
- #ifdef CONFIG_SMP
- lbz r23,PACAPROCSTART(r25) /* Test if this processor
- * should start */
- sync
- LOADADDR(r3,current_set)
- sldi r28,r24,4 /* get current_set[cpu#] */
- ldx r3,r3,r28
- addi r1,r3,TASK_UNION_SIZE
- subi r1,r1,STACK_FRAME_OVERHEAD
- cmpi 0,r23,0
- beq iseries_secondary_smp_loop /* Loop until told to go */
- #ifdef SECONDARY_PROCESSORS
- bne .__secondary_start /* Loop until told to go */
- #endif
- iseries_secondary_smp_loop:
- /* Let the Hypervisor know we are alive */
- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
- lis r3,0x8002
- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
- #else /* CONFIG_SMP */
- /* Yield the processor. This is required for non-SMP kernels
- which are running on multi-threaded machines. */
- lis r3,0x8000
- rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
- addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
- li r4,0 /* "yield timed" */
- li r5,-1 /* "yield forever" */
- #endif /* CONFIG_SMP */
- li r0,-1 /* r0=-1 indicates a Hypervisor call */
- sc /* Invoke the hypervisor via a system call */
- mfspr r25,SPRG3 /* Put r25 back ???? */
- b 1b /* If SMP not configured, secondaries
- * loop forever */
- .globl HardwareInterrupt_Iseries_masked
- HardwareInterrupt_Iseries_masked:
- b maskable_exception_exit
- .globl PerformanceMonitor_Iseries_masked
- PerformanceMonitor_Iseries_masked:
- li r22,1
- stb r22,PACALPPACA+LPPACAPDCINT(r20)
- b maskable_exception_exit
- .globl Decrementer_Iseries_masked
- Decrementer_Iseries_masked:
- li r22,1
- stb r22,PACALPPACA+LPPACADECRINT(r20)
- lwz r22,PACADEFAULTDECR(r20)
- mtspr DEC,r22
- maskable_exception_exit:
- mtcrf 0xff,r23 /* Restore regs and free exception frame */
- ld r22,EX_SRR0(r21)
- ld r23,EX_SRR1(r21)
- mtspr SRR0,r22
- mtspr SRR1,r23
- ld r22,EX_R22(r21)
- ld r23,EX_R23(r21)
- mfspr r21,SPRG1
- mfspr r20,SPRG2
- rfid
- /*
- * Data area reserved for FWNMI option.
- */
- .= 0x7000
- .globl fwnmi_data_area
- fwnmi_data_area:
- /*
- * Vectors for the FWNMI option. Share common code.
- */
- . = 0x8000
- .globl SystemReset_FWNMI
- SystemReset_FWNMI:
- EXCEPTION_PROLOG_PSERIES(0x100, SystemReset_common)
- .globl MachineCheck_FWNMI
- MachineCheck_FWNMI:
- EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
- /*** Common interrupt handlers ***/
- STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
- STD_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException )
- STD_EXCEPTION_COMMON( 0x900, Decrementer, .timer_interrupt )
- STD_EXCEPTION_COMMON( 0xa00, Trap_0a, .UnknownException )
- STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
- STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException )
- STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
- STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException )
- /*
- * Return from an exception which is handled without calling
- * save_remaining_regs. The caller is assumed to have done
- * EXCEPTION_PROLOG_COMMON.
- */
- fast_exception_return:
- ld r3,_CCR(r1)
- ld r4,_LINK(r1)
- ld r5,_CTR(r1)
- ld r6,_XER(r1)
- mtcr r3
- mtlr r4
- mtctr r5
- mtspr XER,r6
- REST_GPR(0, r1)
- REST_8GPRS(2, r1)
- REST_4GPRS(10, r1)
- mtspr SRR1,r23
- mtspr SRR0,r22
- REST_4GPRS(20, r1)
- ld r1,GPR1(r1)
- rfid
- /*
- * Here r20 points to the PACA, r21 to the exception frame,
- * r23 contains the saved CR.
- * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
- */
- .globl DataAccess_common
- DataAccess_common:
- mfspr r22,DAR
- srdi r22,r22,60
- cmpi 0,r22,0xc
- beq .do_stab_bolted
- cmpi 0,r22,0xb
- beq .do_stab_bolted
- stab_bolted_user_return:
- EXCEPTION_PROLOG_COMMON
- ld r3,_DSISR(r1)
- andis. r0,r3,0xa450 /* weird error? */
- bne 1f /* if not, try to put a PTE */
- andis. r0,r3,0x0020 /* Is it a page table fault? */
- rlwinm r4,r3,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
- ld r3,_DAR(r1) /* into the hash table */
- beq 2f /* If so handle it */
- li r4,0x300 /* Trap number */
- bl .do_stab_SI
- b 1f
- 2: li r5,0x300
- bl .do_hash_page_DSI /* Try to handle as hpte fault */
- 1:
- ld r4,_DAR(r1)
- ld r5,_DSISR(r1)
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1) /* Copy saved SOFTE bit */
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x300
- bl .save_remaining_regs
- bl .do_page_fault
- b .ret_from_except
- .globl DataAccessSLB_common
- DataAccessSLB_common:
- mfspr r22,DAR
- srdi r22,r22,60
- cmpi 0,r22,0xc
- beq .do_slb_bolted
- cmpi 0,r22,0xb
- beq .do_slb_bolted
- EXCEPTION_PROLOG_COMMON
- ld r3,_DAR(r1)
- li r4,0x380 /* Exception vector */
- bl .ste_allocate
- or. r3,r3,r3 /* Check return code */
- beq fast_exception_return /* Return if we succeeded */
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x380
- bl .save_remaining_regs
- bl .do_page_fault
- b .ret_from_except
- .globl InstructionAccess_common
- InstructionAccess_common:
- EXCEPTION_PROLOG_COMMON
- andis. r0,r23,0x0020 /* no ste found? */
- beq 2f
- mr r3,r22 /* SRR0 at interrupt */
- li r4,0x400 /* Trap number */
- bl .do_stab_SI
- b 1f
- 2: andis. r0,r23,0x4000 /* no pte found? */
- beq 1f /* if so, try to put a PTE */
- mr r3,r22 /* into the hash table */
- bl .do_hash_page_ISI /* Try to handle as hpte fault */
- 1:
- mr r4,r22
- mr r5,r23
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x400
- bl .save_remaining_regs
- bl .do_page_fault
- b .ret_from_except
- .globl InstructionAccessSLB_common
- InstructionAccessSLB_common:
- EXCEPTION_PROLOG_COMMON
- mr r3,r22 /* SRR0 = NIA */
- li r4,0x480 /* Exception vector */
- bl .ste_allocate
- or. r3,r3,r3 /* Check return code */
- beq fast_exception_return /* Return if we succeeded */
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x480
- bl .save_remaining_regs
- bl .do_page_fault
- b .ret_from_except
- .globl HardwareInterrupt_common
- HardwareInterrupt_common:
- EXCEPTION_PROLOG_COMMON
- HardwareInterrupt_entry:
- addi r3,r1,STACK_FRAME_OVERHEAD
- li r20,0
- li r6,0x500
- bl .save_remaining_regs
- /* Determine if need to run do_irq on a hardware interrupt stack */
- /* The first invocation of do_irq will occur on the kernel */
- /* stack in the current stack */
- /* All other invocations of do_irq will run on the hardware */
- /* interrupt stack associated with the PACA of the current */
- /* processor. */
- /* */
- /* The call to do_irq will preserve the value of r14 - r31 */
- /* */
- mfspr r20,SPRG3 /* get paca */
- lbz r21,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */
- cmpi 0,r21,0 /* */
- addi r21,r21,1 /* incr hardware interrupt cnt*/
- stb r21,PACAHRDWINTCOUNT(r20) /* */
- bne 2f /* */
- mr r14,r1 /* preserve current r1 */
- ld r1,PACAHRDWINTSTACK(r20) /* */
- std r14,0(r1) /* set the back chain */
- bl .do_IRQ
- lbz r22,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */
- cmp 0,r22,r21 /* debug test */
- bne 3f
- subi r21,r21,1
- stb r21,PACAHRDWINTCOUNT(r20) /* */
- mr r1,r14 /* */
- b .ret_from_except
- 2:
- bl .do_IRQ
- lbz r22,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */
- cmp 0,r22,r21 /* debug test */
- bne 3f /* */
- subi r21,r21,1 /* decr hardware interrupt cnt*/
- stb r21,PACAHRDWINTCOUNT(r20) /* */
- b .ret_from_except
- 3:
- /* error - counts out of sync */
- #ifdef CONFIG_XMON
- bl .xmon
- #endif
- 4: b 4b
- .globl Alignment_common
- Alignment_common:
- EXCEPTION_PROLOG_COMMON
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x600
- bl .save_remaining_regs
- bl .AlignmentException
- b .ret_from_except
- .globl ProgramCheck_common
- ProgramCheck_common:
- EXCEPTION_PROLOG_COMMON
- addi r3,r1,STACK_FRAME_OVERHEAD
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0x700
- bl .save_remaining_regs
- bl .ProgramCheckException
- b .ret_from_except
- .globl FPUnavailable_common
- FPUnavailable_common:
- EXCEPTION_PROLOG_COMMON
- bne .load_up_fpu /* if from user, just load it up */
- li r20,0
- li r6,0x800
- bl .save_remaining_regs /* if from kernel, take a trap */
- bl .KernelFP
- b .ret_from_except
- .globl SystemCall_common
- SystemCall_common:
- EXCEPTION_PROLOG_COMMON
- #ifdef CONFIG_PPC_ISERIES
- cmpi 0,r0,0x5555 /* Special syscall to handle pending */
- bne+ 1f /* interrupts */
- andi. r6,r23,MSR_PR /* Only allowed from kernel */
- beq+ HardwareInterrupt_entry
- 1:
- #endif
- std r3,ORIG_GPR3(r1)
- #ifdef DO_SOFT_DISABLE
- ld r20,SOFTE(r1)
- #else
- rldicl r20,r23,49,63 /* copy EE bit from saved MSR */
- #endif
- li r6,0xC00
- bl .save_remaining_regs
- bl .DoSyscall
- b .ret_from_except
- .globl PerformanceMonitor_common
- PerformanceMonitor_common:
- EXCEPTION_PROLOG_COMMON
- bl .PerformanceMonitorException
- b fast_exception_return
-
- _GLOBAL(PerformanceMonitorException)
- mfspr r7,SPRG3
- lbz r8,PACAPROFMODE(r7)
- cmpi 0,r8,PMC_STATE_PROFILE_KERN
- beq 5f
- cmpi 0,r8,PMC_STATE_TRACE_KERN
- beq 6f
- cmpi 0,r8,PMC_STATE_TRACE_USER
- beq 9f
- blr
- /* PMC Profile Kernel */
- 5: mfspr r9,SIAR
- srdi r8,r9,60
- cmpi 0,r8,0xc
- beq 3f
- li r9,0xc
- sldi r9,r9,60
- 3: ld r8,PACAPROFSTEXT(r7) /* _stext */
- subf r9,r8,r9 /* offset into kernel */
- lwz r8,PACAPROFSHIFT(r7)
- srd r9,r9,r8
- lwz r8,PACAPROFLEN(r7) /* length of profile table (-1) */
- srdi r8,r8,2
- cmpd r9,r8 /* off end? */
- ble 1f
- mr r9,r8 /* force into last entry */
- srdi r9,r9,2
- 1: sldi r9,r9,2 /* convert to offset into buffer */
- ld r8,PACAPROFBUFFER(r7) /* profile buffer */
- add r8,r8,r9
- 2: lwarx r9,0,r8 /* atomically increment */
- addi r9,r9,1
- stwcx. r9,0,r8
- bne- 2b
- addi r10,r7,PACAPMC1
- addi r7,r7,PACAPMCC1
- b 7f
- /* PMC Trace Kernel */
- 6: LOADADDR(r11, perfmon_base)
- addi r8,r11,32
- ld r12,24(r11)
- subi r12,r12,1
- 8: ldarx r10,0,r8
- addi r9,r10,16
- and r9,r9,r12
- stdcx. r9,0,r8
- bne- 8b
- ld r9,16(r11) /* profile buffer */
- add r8,r9,r10
- mfspr r9,SIAR
- std r9,0(r8)
- mfspr r9,SDAR
- std r9,8(r8)
- addi r10,r7,PACAPMC1
- addi r7,r7,PACAPMCC1
- b 7f
- /* PMC Trace User */
- 9: LOADADDR(r11, perfmon_base)
- #if 0
- addi r8,r11,32
- ld r12,24(r11)
- subi r12,r12,1
- 8: ldarx r10,0,r8
- addi r9,r10,16
- and r9,r9,r12
- stdcx. r9,0,r8
- bne- 8b
- ld r9,16(r11) /* profile buffer */
- add r8,r9,r10
- mfspr r9,SIAR
- std r9,0(r8)
- mfspr r9,SDAR
- std r9,8(r8)
- addi r10,r13,THREAD+THREAD_PMC1
- addi r7,r13,THREAD+THREAD_PMCC1
- #endif
- /* Accumulate counter values for kernel traces */
- 7: ld r9,0(r7)
- mfspr r8,PMC1
- add r9,r9,r8
- std r9,0(r7)
- ld r9,8(r7)
- mfspr r8,PMC2
- add r9,r9,r8
- std r9,8(r7)
- ld r9,16(r7)
- mfspr r8,PMC3
- add r9,r9,r8
- std r9,16(r7)
- ld r9,24(r7)
- mfspr r8,PMC4
- add r9,r9,r8
- std r9,24(r7)
- ld r9,32(r7)
- mfspr r8,PMC5
- add r9,r9,r8
- std r9,32(r7)
- ld r9,40(r7)
- mfspr r8,PMC6
- add r9,r9,r8
- std r9,40(r7)
- ld r9,48(r7)
- mfspr r8,PMC7
- add r9,r9,r8
- std r9,48(r7)
- ld r9,56(r7)
- mfspr r8,PMC8
- add r9,r9,r8
- std r9,56(r7)
- /* Reset all counters for kernel traces */
- lwz r9,0(r10)
- mtspr PMC1,r9
- lwz r9,4(r10)
- mtspr PMC2,r9
- lwz r9,8(r10)
- mtspr PMC3,r9
- lwz r9,12(r10)
- mtspr PMC4,r9
- lwz r9,16(r10)
- mtspr PMC5,r9
- lwz r9,20(r10)
- mtspr PMC6,r9
- lwz r9,24(r10)
- mtspr PMC7,r9
- lwz r9,28(r10)
- mtspr PMC8,r9
- lwz r9,32(r10)
- mtspr MMCR0,r9
- lwz r9,36(r10)
- mtspr MMCR1,r9
- lwz r9,40(r10)
- mtspr MMCRA,r9
- blr
- _GLOBAL(do_hash_page_ISI)
- li r4,0
- _GLOBAL(do_hash_page_DSI)
- rlwimi r4,r23,32-13,30,30 /* Insert MSR_PR as _PAGE_USER */
- ori r4,r4,1 /* add _PAGE_PRESENT */
- mflr r21 /* Save LR in r21 */
- #ifdef DO_SOFT_DISABLE
- /*
- * We hard enable here (but first soft disable) so that the hash_page
- * code can spin on the hash_table_lock with problem on a shared
- * processor.
- */
- li r0,0
- stb r0,PACAPROCENABLED(r20) /* Soft Disabled */
- mfmsr r0
- ori r0,r0,MSR_EE+MSR_RI
- mtmsrd r0 /* Hard Enable, RI on */
- #endif
- /*
- * r3 contains the faulting address
- * r4 contains the required access permissions
- * r5 contains the trap number
- *
- * at return r3 = 0 for success
- */
- bl .hash_page /* build HPTE if possible */
- #ifdef DO_SOFT_DISABLE
- /*
- * Now go back to hard disabled.
- */
- mfmsr r0
- li r4,0
- ori r4,r4,MSR_EE+MSR_RI
- andc r0,r0,r4
- mtmsrd r0 /* Hard Disable, RI off */
- ld r0,SOFTE(r1)
- cmpdi 0,r0,0 /* See if we will soft enable in */
- /* save_remaining_regs */
- beq 5f
- CHECKANYINT(r4,r5)
- bne- HardwareInterrupt_entry /* Convert this DSI into an External */
- /* to process interrupts which occurred */
- /* during hash_page */
- 5:
- stb r0,PACAPROCENABLED(r20) /* Restore soft enable/disable status */
- #endif
- or. r3,r3,r3 /* Check return code */
- beq fast_exception_return /* Return from exception on success */
- mtlr r21 /* restore LR */
- blr /* Return to DSI or ISI on failure */
- /*
- * r20 points to the PACA, r21 to the exception frame,
- * r23 contains the saved CR.
- * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
- * We assume we aren't going to take any exceptions during this procedure.
- */
- _GLOBAL(do_stab_bolted)
- stw r23,EX_CCR(r21) /* save CR in exc. frame */
- mfspr r22,DSISR
- andis. r22,r22,0x0020
- bne+ 2f
- ld r22,8(r21) /* get SRR1 */
- andi. r22,r22,MSR_PR /* check if from user */
- bne+ stab_bolted_user_return /* from user, send the error on up */
- li r3,0
- #ifdef CONFIG_XMON
- bl .xmon
- #endif
- 1: b 1b
- 2:
- /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
- mfspr r21,DAR
- rldicl r20,r21,36,32 /* Permits a full 32b of ESID */
- rldicr r20,r20,15,48
- rldicl r21,r21,4,60
- or r20,r20,r21
- li r21,9 /* VSID_RANDOMIZER */
- sldi r21,r21,32
- oris r21,r21,58231
- ori r21,r21,39831
- mulld r20,r20,r21
- clrldi r20,r20,28 /* r20 = vsid */
- mfsprg r21,3
- ld r21,PACASTABVIRT(r21)
- /* Hash to the primary group */
- mfspr r22,DAR
- rldicl r22,r22,36,59
- rldicr r22,r22,7,56
- or r21,r21,r22 /* r21 = first ste of the group */
- /* Search the primary group for a free entry */
- li r22,0
- 1:
- ld r23,0(r21) /* Test valid bit of the current ste */
- rldicl r23,r23,57,63
- cmpwi r23,0
- bne 2f
- ld r23,8(r21) /* Get the current vsid part of the ste */
- rldimi r23,r20,12,0 /* Insert the new vsid value */
- std r23,8(r21) /* Put new entry back into the stab */
- eieio /* Order vsid update */
- ld r23,0(r21) /* Get the esid part of the ste */
- mfspr r20,DAR /* Get the new esid */
- rldicl r20,r20,36,28 /* Permits a full 36b of ESID */
- rldimi r23,r20,28,0 /* Insert the new esid value */
- ori r23,r23,144 /* Turn on valid and kp */
- std r23,0(r21) /* Put new entry back into the stab */
- sync /* Order the update */
- b 3f
- 2:
- addi r22,r22,1
- addi r21,r21,16
- cmpldi r22,7
- ble 1b
- /* Stick for only searching the primary group for now. */
- /* At least for now, we use a very simple random castout scheme */
- /* Use the TB as a random number ; OR in 1 to avoid entry 0 */
- mftb r22
- andi. r22,r22,7
- ori r22,r22,1
- sldi r22,r22,4
- /* r21 currently points to and ste one past the group of interest */
- /* make it point to the randomly selected entry */
- subi r21,r21,128
- or r21,r21,r22 /* r21 is the entry to invalidate */
- isync /* mark the entry invalid */
- ld r23,0(r21)
- li r22,-129
- and r23,r23,r22
- std r23,0(r21)
- sync
- ld r23,8(r21)
- rldimi r23,r20,12,0
- std r23,8(r21)
- eieio
- ld r23,0(r21) /* Get the esid part of the ste */
- mr r22,r23
- mfspr r20,DAR /* Get the new esid */
- rldicl r20,r20,36,28 /* Permits a full 32b of ESID */
- rldimi r23,r20,28,0 /* Insert the new esid value */
- ori r23,r23,144 /* Turn on valid and kp */
- std r23,0(r21) /* Put new entry back into the stab */
- rldicl r22,r22,36,28
- rldicr r22,r22,28,35
- slbie r22
- sync
- 3:
- /* All done -- return from exception. */
- mfsprg r20,3 /* Load the PACA pointer */
- ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */
- addi r21,r21,EXC_FRAME_SIZE
- lwz r23,EX_CCR(r21) /* get saved CR */
- /* note that this is almost identical to maskable_exception_exit */
- mtcr r23 /* restore CR */
- ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */
- ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */
- mtspr SRR0,r22
- mtspr SRR1,r23
- ld r22,EX_R22(r21) /* restore r22 and r23 */
- ld r23,EX_R23(r21)
- mfspr r20,SPRG2
- mfspr r21,SPRG1
- rfid
- _TRACEBACK(do_stab_bolted)
- /*
- * r20 points to the PACA, r21 to the exception frame,
- * r23 contains the saved CR.
- * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
- * We assume we aren't going to take any exceptions during this procedure.
- */
- _GLOBAL(do_slb_bolted)
- stw r23,EX_CCR(r21) /* save CR in exc. frame */
- /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
- mfspr r21,DAR
- rldicl r20,r21,36,32 /* Permits a full 32b of ESID */
- rldicr r20,r20,15,48
- rldicl r21,r21,4,60
- or r20,r20,r21
- li r21,9 /* VSID_RANDOMIZER */
- sldi r21,r21,32
- oris r21,r21,58231
- ori r21,r21,39831
- mulld r20,r20,r21
- clrldi r20,r20,28 /* r20 = vsid */
- /* Search the SLB for a free entry */
- li r22,1
- 1:
- slbmfee r23,r22
- rldicl r23,r23,37,63
- cmpwi r23,0
- beq 3f /* Found an invalid entry */
- addi r22,r22,1
- cmpldi r22,64
- blt 1b
- /* No free entry - just take the next entry, round-robin */
- /* XXX we should get the number of SLB entries from the naca */
- SLB_NUM_ENTRIES = 64
- mfspr r21,SPRG3
- ld r22,PACASTABRR(r21)
- addi r23,r22,1
- cmpdi r23,SLB_NUM_ENTRIES
- blt 2f
- li r23,1
- 2: std r23,PACASTABRR(r21)
- /* r20 = vsid, r22 = entry */
- 3:
- /* Put together the vsid portion of the entry. */
- li r21,0
- rldimi r21,r20,12,0
- ori r20,r21,1024
- #ifndef CONFIG_PPC_ISERIES
- ori r20,r20,256 /* map kernel region with large ptes */
- #endif
-
- /* Invalidate the old entry */
- slbmfee r21,r22
- lis r23,-2049
- ori r23,r23,65535
- and r21,r21,r23
- slbie r21
- /* Put together the esid portion of the entry. */
- mfspr r21,DAR /* Get the new esid */
- rldicl r21,r21,36,28 /* Permits a full 36b of ESID */
- li r23,0
- rldimi r23,r21,28,0 /* Insert esid */
- oris r21,r23,2048 /* valid bit */
- rldimi r21,r22,0,52 /* Insert entry */
- isync
- slbmte r20,r21
- isync
- /* All done -- return from exception. */
- mfsprg r20,3 /* Load the PACA pointer */
- ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */
- addi r21,r21,EXC_FRAME_SIZE
- lwz r23,EX_CCR(r21) /* get saved CR */
- /* note that this is almost identical to maskable_exception_exit */
- mtcr r23 /* restore CR */
- ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */
- ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */
- mtspr SRR0,r22
- mtspr SRR1,r23
- ld r22,EX_R22(r21) /* restore r22 and r23 */
- ld r23,EX_R23(r21)
- mfspr r20,SPRG2
- mfspr r21,SPRG1
- rfid
- _TRACEBACK(do_slb_bolted)
- _GLOBAL(do_stab_SI)
- mflr r21 /* Save LR in r21 */
- /*
- * r3 contains the faulting address
- * r4 contains the required access permissions
- *
- * at return r3 = 0 for success
- */
- bl .ste_allocate /* build STE if possible */
- or. r3,r3,r3 /* Check return code */
- beq fast_exception_return /* Return from exception on success */
- mtlr r21 /* restore LR */
- blr /* Return to DSI or ISI on failure */
- /*
- * This code finishes saving the registers to the exception frame.
- * Address translation is already on.
- */
- _GLOBAL(save_remaining_regs)
- /*
- * Save the rest of the registers into the pt_regs structure
- */
- std r22,_NIP(r1)
- std r23,_MSR(r1)
- std r6,TRAP(r1)
- ld r6,GPR6(r1)
- SAVE_2GPRS(14, r1)
- SAVE_4GPRS(16, r1)
- SAVE_8GPRS(24, r1)
- /*
- * Clear the RESULT field
- */
- li r22,0
- std r22,RESULT(r1)
- /*
- * Test if from user state; result will be tested later
- */
- andi. r23,r23,MSR_PR /* Set CR for later branch */
- /*
- * Indicate that r1 contains the kernel stack and
- * get the Kernel TOC and CURRENT pointers from the paca
- */
- mfspr r23,SPRG3 /* Get PACA */
- std r22,PACAKSAVE(r23) /* r1 is now kernel sp */
- ld r2,PACATOC(r23) /* Get Kernel TOC pointer */
- /*
- * If from user state, update THREAD.regs
- */
- beq 2f /* Modify THREAD.regs if from user */
- addi r24,r1,STACK_FRAME_OVERHEAD
- std r24,THREAD+PT_REGS(r13)
- 2:
- SET_REG_TO_CONST(r22, MSR_KERNEL)
- #ifdef DO_SOFT_DISABLE
- stb r20,PACAPROCENABLED(r23) /* possibly soft enable */
- ori r22,r22,MSR_EE /* always hard enable */
- #else
- rldimi r22,r20,15,48 /* Insert desired EE value */
- #endif
- mtmsrd r22
- blr
- /*
- * Kernel profiling with soft disable on iSeries
- */
- do_profile:
- ld r22,8(r21) /* Get SRR1 */
- andi. r22,r22,MSR_PR /* Test if in kernel */
- bnelr /* return if not in kernel */
- ld r22,0(r21) /* Get SRR0 */
- ld r25,PACAPROFSTEXT(r20) /* _stext */
- subf r22,r25,r22 /* offset into kernel */
- lwz r25,PACAPROFSHIFT(r20)
- srd r22,r22,r25
- lwz r25,PACAPROFLEN(r20) /* length of profile table (-1) */
- cmp 0,r22,r25 /* off end? */
- ble 1f
- mr r22,r25 /* force into last entry */
- 1: sldi r22,r22,2 /* convert to offset into buffer */
- ld r25,PACAPROFBUFFER(r20) /* profile buffer */
- add r25,r25,r22
- 2: lwarx r22,0,r25 /* atomically increment */
- addi r22,r22,1
- stwcx. r22,0,r25
- bne- 2b
- blr
- /*
- * On pSeries, secondary processors spin in the following code.
- * At entry, r3 = this processor's number (in Linux terms, not hardware).
- */
- _GLOBAL(pseries_secondary_smp_init)
- /* turn on 64-bit mode */
- bl .enable_64b_mode
- isync
- /* Set up a paca value for this processor. */
- LOADADDR(r24, paca) /* Get base vaddr of Paca array */
- mulli r25,r3,PACA_SIZE /* Calculate vaddr of right Paca */
- add r25,r25,r24 /* for this processor. */
- mtspr SPRG3,r25 /* Save vaddr of Paca in SPRG3 */
- mr r24,r3 /* __secondary_start needs cpu# */
- 1:
- HMT_LOW
- lbz r23,PACAPROCSTART(r25) /* Test if this processor should */
- /* start. */
- sync
- /* Create a temp kernel stack for use before relocation is on. */
- mr r1,r25
- addi r1,r1,PACAGUARD
- addi r1,r1,0x1000
- subi r1,r1,STACK_FRAME_OVERHEAD
- cmpi 0,r23,0
- #ifdef CONFIG_SMP
- #ifdef SECONDARY_PROCESSORS
- bne .__secondary_start
- #endif
- #endif
- b 1b /* Loop until told to go */
- _GLOBAL(__start_initialization_iSeries)
- LOADADDR(r1,init_task_union)
- addi r1,r1,TASK_UNION_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- LOADADDR(r9,naca)
- SET_REG_TO_CONST(r4, KERNELBASE)
- addi r4,r4,0x4000
- std r4,0(r9) /* set the naca pointer */
- /* Get the pointer to the segment table */
- ld r6,PACA(r4) /* Get the base paca pointer */
- ld r4,PACASTABVIRT(r6)
- bl .iSeries_fixup_klimit
- b .start_here_common
- _GLOBAL(__start_initialization_pSeries)
- mr r31,r3 /* save parameters */
- mr r30,r4
- mr r29,r5
- mr r28,r6
- mr r27,r7
- mr r26,r8 /* YABOOT: debug_print() routine */
- mr r25,r9 /* YABOOT: debug_delay() routine */
- mr r24,r10 /* YABOOT: debug_prom() routine */
- bl .enable_64b_mode
- /* put a relocation offset into r3 */
- bl .reloc_offset
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- /* Relocate the TOC from a virt addr to a real addr */
- sub r2,r2,r3
- /* setup the naca pointer which is needed by prom_init */
- LOADADDR(r9,naca)
- sub r9,r9,r3 /* addr of the variable naca */
- SET_REG_TO_CONST(r4, KERNELBASE)
- sub r4,r4,r3
- addi r4,r4,0x4000
- std r4,0(r9) /* set the value of naca */
- /* DRENG / PPPBBB Fix the following comment!!! -Peter */
- /* The following copies the first 0x100 bytes of code from the */
- /* load addr to physical addr 0x0. This code causes secondary */
- /* processors to spin until a flag in the PACA is set. This */
- /* is done at this time rather than with the entire kernel */
- /* relocation which is done below because we need to cause the */
- /* processors to spin on code that is not going to move while OF */
- /* is still alive. Although the spin code is not actually run on */
- /* a uniprocessor, we always do this copy. */
- SET_REG_TO_CONST(r4, KERNELBASE)/* Src addr */
- sub r4,r4,r3 /* current address of __start */
- /* the source addr */
- li r3,0 /* Dest addr */
- li r5,0x100 /* # bytes of memory to copy */
- li r6,0 /* Destination offset */
- bl .copy_and_flush /* copy the first 0x100 bytes */
- mr r3,r31
- mr r4,r30
- mr r5,r29
- mr r6,r28
- mr r7,r27
- mr r8,r26
- mr r9,r25
- mr r10,r24
- bl .prom_init
- li r24,0 /* cpu # */
- /*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
- _STATIC(__after_prom_start)
- /*
- * We need to run with __start at physical address 0.
- * This will leave some code in the first 256B of
- * real memory, which are reserved for software use.
- * The remainder of the first page is loaded with the fixed
- * interrupt vectors. The next two pages are filled with
- * unknown exception placeholders.
- *
- * Note: This process overwrites the OF exception vectors.
- * r26 == relocation offset
- * r27 == KERNELBASE
- */
- bl .reloc_offset
- mr r26,r3
- SET_REG_TO_CONST(r27,KERNELBASE)
- li r3,0 /* target addr */
- sub r4,r27,r26 /* source addr */
- /* current address of _start */
- /* i.e. where we are running */
- /* the source addr */
- LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */
- sub r5,r5,r27
- li r6,0x100 /* Start offset, the first 0x100 */
- /* bytes were copied earlier. */
- bl .copy_and_flush /* copy the first n bytes */
- /* this includes the code being */
- /* executed here. */
- LOADADDR(r0, 4f) /* Jump to the copy of this code */
- mtctr r0 /* that we just made/relocated */
- bctr
- 4: LOADADDR(r5,klimit)
- sub r5,r5,r26
- ld r5,0(r5) /* get the value of klimit */
- sub r5,r5,r27
- bl .copy_and_flush /* copy the rest */
- b .start_here_pSeries
- /*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- *
- * Note: this routine *only* clobbers r0, r6 and lr
- */
- _STATIC(copy_and_flush)
- addi r5,r5,-8
- addi r6,r6,-8
- 4: li r0,16 /* Use the least common */
- /* denominator cache line */
- /* size. This results in */
- /* extra cache line flushes */
- /* but operation is correct. */
- /* Can't get cache line size */
- /* from NACA as it is being */
- /* moved too. */
- mtctr r0 /* put # words/line in ctr */
- 3: addi r6,r6,8 /* copy a cache line */
- ldx r0,r6,r4
- stdx r0,r6,r3
- bdnz 3b
- dcbst r6,r3 /* write it to memory */
- sync
- icbi r6,r3 /* flush the icache line */
- cmpld 0,r6,r5
- blt 4b
- sync
- addi r5,r5,8
- addi r6,r6,8
- blr
- .align 8
- copy_to_here:
- /*
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- * On SMP we know the fpu is free, since we give it up every
- * switch. -- Cort
- */
- _STATIC(load_up_fpu)
- mfmsr r5 /* grab the current MSR */
- ori r5,r5,MSR_FP
- mtmsrd r5 /* enable use of fpu now */
- isync
- /*
- * For SMP, we don't do lazy FPU switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_fpu in switch_to.
- *
- */
- #ifndef CONFIG_SMP
- LOADBASE(r3,last_task_used_math)
- ld r4,last_task_used_math@l(r3)
- cmpi 0,r4,0
- beq 1f
- addi r4,r4,THREAD /* want THREAD of last_task_used_math */
- SAVE_32FPRS(0, r4)
- mffs fr0
- stfd fr0,THREAD_FPSCR-4(r4)
- ld r5,PT_REGS(r4)
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r20,MSR_FP|MSR_FE0|MSR_FE1
- andc r4,r4,r20 /* disable FP for previous task */
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- 1:
- #endif /* CONFIG_SMP */
- /* enable use of FP after return */
- ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1
- addi r5,r13,THREAD /* Get THREAD */
- lfd fr0,THREAD_FPSCR-4(r5)
- mtfsf 0xff,fr0
- REST_32FPRS(0, r5)
- #ifndef CONFIG_SMP
- subi r4,r5,THREAD /* Back to 'current' */
- std r4,last_task_used_math@l(r3)
- #endif /* CONFIG_SMP */
- /* restore registers and return */
- b fast_exception_return
- /*
- * FP unavailable trap from kernel - print a message, but let
- * the task use FP in the kernel until it returns to user mode.
- */
- _GLOBAL(KernelFP)
- ld r3,_MSR(r1)
- ori r3,r3,MSR_FP
- std r3,_MSR(r1) /* enable use of FP after return */
- LOADADDR(r3,86f)
- mfspr r4,SPRG3 /* Get PACA */
- ld r4,PACACURRENT(r4) /* current */
- ld r5,_NIP(r1)
- b .ret_from_except
- 86: .string "floating point used in kernel (task=%p, pc=%x)n"
- .align 4
- /*
- * giveup_fpu(tsk)
- * Disable FP for the task given as the argument,
- * and save the floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- */
- _GLOBAL(giveup_fpu)
- mfmsr r5
- ori r5,r5,MSR_FP
- mtmsrd r5 /* enable use of fpu now */
- isync
- cmpi 0,r3,0
- beqlr- /* if no previous owner, done */
- addi r3,r3,THREAD /* want THREAD of task */
- ld r5,PT_REGS(r3)
- cmpi 0,r5,0
- SAVE_32FPRS(0, r3)
- mffs fr0
- stfd fr0,THREAD_FPSCR-4(r3)
- beq 1f
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r3,MSR_FP|MSR_FE0|MSR_FE1
- andc r4,r4,r3 /* disable FP for previous task */
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- 1:
- #ifndef CONFIG_SMP
- li r5,0
- LOADBASE(r4,last_task_used_math)
- std r5,last_task_used_math@l(r4)
- #endif /* CONFIG_SMP */
- blr
- #ifdef CONFIG_SMP
- /*
- * This function is called after the master CPU has released the
- * secondary processors. The execution environment is relocation off.
- * The paca for this processor has the following fields initialized at
- * this point:
- * 1. Processor number
- * 2. Segment table pointer (virtual address)
- * On entry the following are set:
- * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries
- * r24 = cpu# (in Linux terms)
- * r25 = paca virtual address
- * SPRG3 = paca virtual address
- */
- _GLOBAL(__secondary_start)
- HMT_MEDIUM /* Set thread priority to MEDIUM */
- /* set up the TOC (virtual address) */
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- std r2,PACATOC(r25)
- li r6,0
- std r6,PACAKSAVE(r25)
- stb r6,PACAPROCENABLED(r25)
- #ifndef CONFIG_PPC_ISERIES
- /* Initialize the page table pointer register. */
- LOADADDR(r6,_SDR1)
- ld r6,0(r6) /* get the value of _SDR1 */
- mtspr SDR1,r6 /* set the htab location */
- #endif
- /* Initialize the first segment table (or SLB) entry */
- ld r3,PACASTABVIRT(r25) /* get addr of segment table */
- bl .stab_initialize
- /* Initialize the kernel stack. Just a repeat for iSeries. */
- LOADADDR(r3,current_set)
- sldi r28,r24,4 /* get current_set[cpu#] */
- ldx r13,r3,r28
- std r13,PACACURRENT(r25)
- addi r1,r13,TASK_UNION_SIZE
- subi r1,r1,STACK_FRAME_OVERHEAD
- ld r3,PACASTABREAL(r25) /* get raddr of segment table */
- ori r4,r3,1 /* turn on valid bit */
- #ifdef CONFIG_PPC_ISERIES
- li r0,-1 /* hypervisor call */
- li r3,1
- sldi r3,r3,63 /* 0x8000000000000000 */
- ori r3,r3,4 /* 0x8000000000000004 */
- sc /* HvCall_setASR */
- #else
- /* set the ASR */
- addi r3,0,0x4000 /* r3 = ptr to naca */
- lhz r3,PLATFORM(r3) /* r3 = platform flags */
- cmpldi r3,PLATFORM_PSERIES_LPAR
- bne 98f
- mfspr r3,PVR
- srwi r3,r3,16
- cmpwi r3,0x37 /* SStar */
- bne 98f
- li r3,H_SET_ASR /* hcall = H_SET_ASR */
- HSC /* Invoking hcall */
- b 99f
- 98: /* !(rpa hypervisor) || !(sstar) */
- mtasr r4 /* set the stab location */
- 99:
- #endif
- li r7,0
- mtlr r7
- /* enable MMU and jump to start_secondary */
- LOADADDR(r3,.start_secondary_prolog)
- SET_REG_TO_CONST(r4, MSR_KERNEL)
- #ifdef DO_SOFT_DISABLE
- ori r4,r4,MSR_EE
- #endif
- mtspr SRR0,r3
- mtspr SRR1,r4
- rfid
- #endif /* CONFIG_SMP */
- /*
- * Running with relocation on at this point. All we want to do is
- * zero the stack back-chain pointer before going into C code.
- */
- _GLOBAL(start_secondary_prolog)
- li r3,0
- std r3,0(r1) /* Zero the stack frame pointer */
- bl .start_secondary
- /*
- * This subroutine clobbers r11, r12 and the LR
- */
- _GLOBAL(enable_64b_mode)
- mfmsr r11 /* grab the current MSR */
- li r12,1
- rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
- or r11,r11,r12
- li r12,1
- rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
- or r11,r11,r12
- mtmsrd r11
- isync
- blr
- /*
- * This subroutine clobbers r11, r12 and the LR
- */
- _GLOBAL(enable_32b_mode)
- mfmsr r11 /* grab the current MSR */
- li r12,1
- rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
- andc r11,r11,r12
- li r12,1
- rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
- andc r11,r11,r12
- mtmsrd r11
- isync
- blr
- /*
- * This is where the main kernel code starts.
- */
- _STATIC(start_here_pSeries)
- /* get a new offset, now that the kernel has moved. */
- bl .reloc_offset
- mr r26,r3
- /* setup the naca pointer which is needed by *tab_initialize */
- LOADADDR(r6,naca)
- sub r6,r6,r26 /* addr of the variable naca */
- li r27,0x4000
- std r27,0(r6) /* set the value of naca */
- #ifdef CONFIG_HMT
- /* Start up the second thread on cpu 0 */
- mfspr r3,PVR
- srwi r3,r3,16
- cmpwi r3,0x34 /* Pulsar */
- beq 90f
- cmpwi r3,0x36 /* Icestar */
- beq 90f
- cmpwi r3,0x37 /* SStar */
- beq 90f
- b 91f /* HMT not supported */
- 90: li r3,0
- bl .hmt_start_secondary
- 91:
- #endif
- #ifdef CONFIG_SMP
- /* All secondary cpus are now spinning on a common
- * spinloop, release them all now so they can start
- * to spin on their individual paca spinloops.
- * For non SMP kernels, the secondary cpus never
- * get out of the common spinloop.
- */
- li r3,1
- LOADADDR(r5,__secondary_hold_spinloop)
- tophys(r4,r5)
- std r3,0(r4)
- #endif
- /* The following gets the stack and TOC set up with the regs */
- /* pointing to the real addr of the kernel stack. This is */
- /* all done to support the C function call below which sets */
- /* up the htab. This is done because we have relocated the */
- /* kernel but are still running in real mode. */
- /* real ptr to current */
- LOADADDR(r3,init_task_union)
- sub r3,r3,r26
- /* set up a stack pointer (physical address) */
- addi r1,r3,TASK_UNION_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- /* set up the TOC (physical address) */
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- sub r2,r2,r26
- /* Get the pointer to the segment table which is used by */
- /* stab_initialize */
- li r27,0x4000
- ld r6,PACA(r27) /* Get the base paca pointer */
- sub r6,r6,r26 /* convert to physical addr */
- mtspr SPRG3,r6 /* PPPBBB: Temp... -Peter */
- ld r3,PACASTABREAL(r6)
- ori r4,r3,1 /* turn on valid bit */
- /* set the ASR */
- addi r3,0,0x4000 /* r3 = ptr to naca */
- lhz r3,PLATFORM(r3) /* r3 = platform flags */
- cmpldi r3,PLATFORM_PSERIES_LPAR
- bne 98f
- mfspr r3,PVR
- srwi r3,r3,16
- cmpwi r3,0x37 /* SStar */
- bne 98f
- li r3,H_SET_ASR /* hcall = H_SET_ASR */
- HSC /* Invoking hcall */
- b 99f
- 98: /* This is not a hypervisor machine */
- mtasr r4 /* set the stab location */
- 99:
- mfspr r6,SPRG3
- ld r3,PACASTABREAL(r6) /* restore r3 for stab_initialize */
- /* Initialize an initial memory mapping and turn on relocation. */
- bl .stab_initialize
- bl .htab_initialize
- addi r3,0,0x4000 /* r3 = ptr to naca */
- lhz r3,PLATFORM(r3) /* r3 = platform flags */
- cmpldi r3,PLATFORM_PSERIES
- bne 98f
- LOADADDR(r6,_SDR1) /* Only if NOT LPAR */
- sub r6,r6,r26
- ld r6,0(r6) /* get the value of _SDR1 */
- mtspr SDR1,r6 /* set the htab location */
- 98:
- LOADADDR(r3,.start_here_common)
- SET_REG_TO_CONST(r4, MSR_KERNEL)
- mtspr SRR0,r3
- mtspr SRR1,r4
- rfid
- /* This is where all platforms converge execution */
- _STATIC(start_here_common)
- /* relocation is on at this point */
- /* Clear out the BSS */
- LOADADDR(r11,_end)
- LOADADDR(r8,__bss_start)
- sub r11,r11,r8 /* bss size */
- addi r11,r11,7 /* round up to an even double word */
- rldicl. r11,r11,61,3 /* shift right by 3 */
- beq 4f
- addi r8,r8,-8
- li r0,0
- mtctr r11 /* zero this many doublewords */
- 3: stdu r0,8(r8)
- bdnz 3b
- 4:
- /* The following code sets up the SP and TOC now that we are */
- /* running with translation enabled. */
- /* ptr to current */
- LOADADDR(r3,init_task_union)
- /* set up the stack */
- addi r1,r3,TASK_UNION_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- /* set up the TOC */
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- /* setup the naca pointer */
- LOADADDR(r9,naca)
- SET_REG_TO_CONST(r8, KERNELBASE)
- addi r8,r8,0x4000
- std r8,0(r9) /* set the value of the naca ptr */
- LOADADDR(r4,naca) /* Get naca ptr address */
- ld r4,0(r4) /* Get the location of the naca */
- ld r4,PACA(r4) /* Get the base paca pointer */
- mtspr SPRG3,r4
- /* ptr to current */
- LOADADDR(r13,init_task_union)
- std r13,PACACURRENT(r4)
- std r2,PACATOC(r4)
- li r5,0
- std r0,PACAKSAVE(r4)
- /* ptr to hardware interrupt stack for processor 0 */
- LOADADDR(r3, hardware_int_paca0)
- li r5,0x1000
- sldi r5,r5,3
- subi r5,r5,STACK_FRAME_OVERHEAD
- add r3,r3,r5
- std r3,PACAHRDWINTSTACK(r4)
- li r3,0
- stb r3,PACAHRDWINTCOUNT(r4)
- /* Restore the parms passed in from the bootloader. */
- mr r3,r31
- mr r4,r30
- mr r5,r29
- mr r6,r28
- mr r7,r27
- bl .setup_system
- /* Load up the kernel context */
- 5:
- #ifdef DO_SOFT_DISABLE
- mfspr r4,SPRG3
- li r5,0
- stb r5,PACAPROCENABLED(r4) /* Soft Disabled */
- mfmsr r5
- ori r5,r5,MSR_EE /* Hard Enabled */
- mtmsrd r5
- #endif
- bl .start_kernel
- _GLOBAL(hmt_init)
- #ifdef CONFIG_HMT
- LOADADDR(r5, hmt_thread_data)
- mfspr r7,PVR
- srwi r7,r7,16
- cmpwi r7,0x34 /* Pulsar */
- beq 90f
- cmpwi r7,0x36 /* Icestar */
- beq 91f
- cmpwi r7,0x37 /* SStar */
- beq 91f
- b 101f
- 90: mfspr r6,PIR
- andi. r6,r6,0x1f
- b 92f
- 91: mfspr r6,PIR
- andi. r6,r6,0x3ff
- 92: sldi r4,r24,3
- stwx r6,r5,r4
- bl .hmt_start_secondary
- b 101f
- __hmt_secondary_hold:
- LOADADDR(r5, hmt_thread_data)
- clrldi r5,r5,4
- li r7,0
- mfspr r6,PIR
- mfspr r8,PVR
- srwi r8,r8,16
- cmpwi r8,0x34
- bne 93f
- andi. r6,r6,0x1f
- b 103f
- 93: andi. r6,r6,0x3f
- 103: lwzx r8,r5,r7
- cmpw r8,r6
- beq 104f
- addi r7,r7,8
- b 103b
- 104: addi r7,r7,4
- lwzx r9,r5,r7
- mr r24,r9
- 101:
- #endif
- mr r3,r24
- b .pseries_secondary_smp_init
- #ifdef CONFIG_HMT
- _GLOBAL(hmt_start_secondary)
- LOADADDR(r4,__hmt_secondary_hold)
- clrldi r4,r4,4
- mtspr NIADORM, r4
- mfspr r4, MSRDORM
- li r5, -65
- and r4, r4, r5
- mtspr MSRDORM, r4
- lis r4,0xffef
- ori r4,r4,0x7403
- mtspr TSC, r4
- li r4,0x1f4
- mtspr TST, r4
- mfspr r4, HID0
- ori r4, r4, 0x1
- mtspr HID0, r4
- mfspr r4, CTRLF
- oris r4, r4, 0x40
- mtspr CTRLT, r4
- blr
- #endif
- /*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
- .data
- .align 12
- .globl sdata
- sdata:
- .globl empty_zero_page
- empty_zero_page:
- .space 4096
- .globl swapper_pg_dir
- swapper_pg_dir:
- .space 4096
- .globl ioremap_dir
- ioremap_dir:
- .space 4096
- .globl bolted_dir
- bolted_dir:
- .space 4096
- .globl hardware_int_paca0
- hardware_int_paca0:
- .space 8*4096
- /* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
- .globl stab_array
- stab_array:
- .space 4096 * (48 - 1)