📄 head_64.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. */#include <linux/config.h>#include <linux/threads.h>#include <asm/reg.h>#include <asm/page.h>#include <asm/mmu.h>#include <asm/ppc_asm.h>#include <asm/asm-offsets.h>#include <asm/bug.h>#include <asm/cputable.h>#include <asm/setup.h>#include <asm/hvcall.h>#include <asm/iseries/lpar_map.h>#include <asm/thread_info.h>#ifdef CONFIG_PPC_ISERIES#define DO_SOFT_DISABLE#endif/* * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code * 0x0100 - 0x2fff : pSeries Interrupt prologs * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs * 0x6000 - 0x6fff : Initial (CPU0) segment table * 0x7000 - 0x7fff : FWNMI data area * 0x8000 - : Early init and support code *//* * 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 system_reset_iSeries */ .text .globl _stext_stext:#ifdef CONFIG_PPC_MULTIPLATFORM_GLOBAL(__start) /* NOP this out unconditionally */BEGIN_FTR_SECTION b .__start_initialization_multiplatformEND_FTR_SECTION(0, 1)#endif /* CONFIG_PPC_MULTIPLATFORM */ /* Catch branch to 0 in real mode */ trap#ifdef CONFIG_PPC_ISERIES /* * 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_map * 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_map-KERNELBASE .llong 0 /* pidhash-KERNELBASE SFRXXX */ /* 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#endif /* CONFIG_PPC_ISERIES */ /* 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 immediately 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) mfmsr r24 ori r24,r24,MSR_RI mtmsrd r24 /* RI on */ /* 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) sync /* All secondary cpus 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/* This value is used to mark exception frames on the stack. */ .section ".toc","aw"exception_marker: .tc ID_72656773_68657265[TC],0x7265677368657265 .text/* * 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. * LOL. One day... - paulus *//* * 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_R9 0#define EX_R10 8#define EX_R11 16#define EX_R12 24#define EX_R13 32#define EX_SRR0 40#define EX_DAR 48#define EX_DSISR 56#define EX_CCR 60#define EX_R3 64#define EX_LR 72#define EXCEPTION_PROLOG_PSERIES(area, label) \ mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9; \ clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ mfspr r11,SPRN_SRR0; /* save SRR0 */ \ ori r12,r12,(label)@l; /* virt addr of handler */ \ ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ mtspr SPRN_SRR0,r12; \ mfspr r12,SPRN_SRR1; /* and SRR1 */ \ mtspr SPRN_SRR1,r10; \ rfid; \ b . /* prevent speculative execution *//* * This is the start of the interrupt handlers for iSeries * This code runs with relocation on. */#define EXCEPTION_PROLOG_ISERIES_1(area) \ mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9#define EXCEPTION_PROLOG_ISERIES_2 \ mfmsr r10; \ ld r11,PACALPPACA+LPPACASRR0(r13); \ ld r12,PACALPPACA+LPPACASRR1(r13); \ ori r10,r10,MSR_RI; \ mtmsrd r10,1/* * 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 r13 points to the paca, r9-r13 are saved in the paca, * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and * SRR1, and relocation is on. */#define EXCEPTION_PROLOG_COMMON(n, area) \ andi. r10,r12,MSR_PR; /* See if coming from user */ \ mr r10,r1; /* Save r1 */ \ subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ beq- 1f; \ ld r1,PACAKSAVE(r13); /* kernel stack to use */ \1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ bge- cr1,bad_stack; /* abort if it is */ \ std r9,_CCR(r1); /* save CR in stackframe */ \ std r11,_NIP(r1); /* save SRR0 in stackframe */ \ std r12,_MSR(r1); /* save SRR1 in stackframe */ \ std r10,0(r1); /* make stack chain pointer */ \ std r0,GPR0(r1); /* save r0 in stackframe */ \ std r10,GPR1(r1); /* save r1 in stackframe */ \ std r2,GPR2(r1); /* save r2 in stackframe */ \ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ ld r10,area+EX_R10(r13); \ std r9,GPR9(r1); \ std r10,GPR10(r1); \ ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \ ld r10,area+EX_R12(r13); \ ld r11,area+EX_R13(r13); \ std r9,GPR11(r1); \ std r10,GPR12(r1); \ std r11,GPR13(r1); \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ mflr r9; /* save LR in stackframe */ \ std r9,_LINK(r1); \ mfctr r10; /* save CTR in stackframe */ \ std r10,_CTR(r1); \ mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r11,_XER(r1); \ li r9,(n)+1; \ std r9,_TRAP(r1); /* set trap number */ \ li r10,0; \ ld r11,exception_marker@toc(r2); \ std r10,RESULT(r1); /* clear regs->result */ \ std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame *//* * Exception vectors. */#define STD_EXCEPTION_PSERIES(n, label) \ . = n; \ .globl label##_pSeries; \label##_pSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)#define STD_EXCEPTION_ISERIES(n, label, area) \ .globl label##_iSeries; \label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(area); \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common#define MASKABLE_EXCEPTION_ISERIES(n, label) \ .globl label##_iSeries; \label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ lbz r10,PACAPROCENABLED(r13); \ cmpwi 0,r10,0; \ beq- label##_iSeries_masked; \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \#ifdef DO_SOFT_DISABLE#define DISABLE_INTS \ lbz r10,PACAPROCENABLED(r13); \ li r11,0; \ std r10,SOFTE(r1); \ mfmsr r10; \ stb r11,PACAPROCENABLED(r13); \ ori r10,r10,MSR_EE; \ mtmsrd r10,1#define ENABLE_INTS \ lbz r10,PACAPROCENABLED(r13); \ mfmsr r11; \ std r10,SOFTE(r1); \ ori r11,r11,MSR_EE; \ mtmsrd r11,1#else /* hard enable/disable interrupts */#define DISABLE_INTS#define ENABLE_INTS \ ld r12,_MSR(r1); \ mfmsr r11; \ rlwimi r11,r12,0,MSR_EE; \ mtmsrd r11,1#endif#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ .align 7; \ .globl label##_common; \label##_common: \ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ DISABLE_INTS; \ bl .save_nvgprs; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ b .ret_from_except#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ .align 7; \ .globl label##_common; \label##_common: \ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ DISABLE_INTS; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ b .ret_from_except_lite/* * Start of pSeries system interrupt routines */ . = 0x100 .globl __start_interrupts__start_interrupts: STD_EXCEPTION_PSERIES(0x100, system_reset) . = 0x200_machine_check_pSeries: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save r13 */ RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) . = 0x300 .globl data_access_pSeriesdata_access_pSeries: HMT_MEDIUM mtspr SPRN_SPRG1,r13BEGIN_FTR_SECTION mtspr SPRN_SPRG2,r12 mfspr r13,SPRN_DAR mfspr r12,SPRN_DSISR srdi r13,r13,60 rlwimi r13,r12,16,0x20 mfcr r12 cmpwi r13,0x2c beq .do_stab_bolted_pSeries mtcrf 0x80,r12 mfspr r12,SPRN_SPRG2END_FTR_SECTION_IFCLR(CPU_FTR_SLB) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) . = 0x380 .globl data_access_slb_pSeriesdata_access_slb_pSeries: HMT_MEDIUM mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ mfcr r9#ifdef __DISABLED__ /* Keep that around for when we re-implement dynamic VSIDs */ cmpdi r3,0 bge slb_miss_user_pseries#endif /* __DISABLED__ */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) mfspr r10,SPRN_SPRG1 std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ b .slb_miss_realmode /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x400, instruction_access) . = 0x480 .globl instruction_access_slb_pSeriesinstruction_access_slb_pSeries: HMT_MEDIUM mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ mfcr r9#ifdef __DISABLED__ /* Keep that around for when we re-implement dynamic VSIDs */ cmpdi r3,0 bge slb_miss_user_pseries#endif /* __DISABLED__ */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) mfspr r10,SPRN_SPRG1 std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ b .slb_miss_realmode /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) STD_EXCEPTION_PSERIES(0x600, alignment) STD_EXCEPTION_PSERIES(0x700, program_check) STD_EXCEPTION_PSERIES(0x800, fp_unavailable) STD_EXCEPTION_PSERIES(0x900, decrementer) STD_EXCEPTION_PSERIES(0xa00, trap_0a) STD_EXCEPTION_PSERIES(0xb00, trap_0b) . = 0xc00 .globl system_call_pSeriessystem_call_pSeries: HMT_MEDIUM RUNLATCH_ON(r9) mr r9,r13 mfmsr r10 mfspr r13,SPRN_SPRG3 mfspr r11,SPRN_SRR0 clrrdi r12,r13,32 oris r12,r12,system_call_common@h ori r12,r12,system_call_common@l mtspr SPRN_SRR0,r12 ori r10,r10,MSR_IR|MSR_DR|MSR_RI mfspr r12,SPRN_SRR1 mtspr SPRN_SRR1,r10 rfid b . /* prevent speculative execution */ STD_EXCEPTION_PSERIES(0xd00, single_step) STD_EXCEPTION_PSERIES(0xe00, trap_0e) /* We need to deal with the Altivec unavailable exception * here which is at 0xf20, thus in the middle of the * prolog code of the PerformanceMonitor one. A little * trickery is thus necessary */ . = 0xf00 b performance_monitor_pSeries STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -