📄 head.s
字号:
/* * 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_startembedded_sysmap_start: .llong 0 /* Offset 0x40 - Pointer to end of embedded System.map */ .globl embedded_sysmap_endembedded_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_IseriesSystemReset_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,r41: 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 */#endifiseries_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_maskedHardwareInterrupt_Iseries_masked: b maskable_exception_exit .globl PerformanceMonitor_Iseries_maskedPerformanceMonitor_Iseries_masked: li r22,1 stb r22,PACALPPACA+LPPACAPDCINT(r20) b maskable_exception_exit .globl Decrementer_Iseries_maskedDecrementer_Iseries_masked: li r22,1 stb r22,PACALPPACA+LPPACADECRINT(r20) lwz r22,PACADEFAULTDECR(r20) mtspr DEC,r22maskable_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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -