📄 head_64.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/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>#include <asm/firmware.h>#include <asm/page_64.h>#include <asm/exception.h>#define DO_SOFT_DISABLE/* * 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:_GLOBAL(__start) /* NOP this out unconditionally */BEGIN_FTR_SECTION b .__start_initialization_multiplatformEND_FTR_SECTION(0, 1) /* Catch branch to 0 in real mode */ trap /* 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#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#endif /* CONFIG_PPC_ISERIES */ . = 0x60/* * The following code is used to hold secondary processors * in a spin loop after they have entered the kernel, 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 physical 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#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) LOAD_REG_IMMEDIATE(r4, .generic_secondary_smp_init) mtctr r4 mr r3,r24 bctr#else BUG_OPCODE#endif/* This value is used to mark exception frames on the stack. */ .section ".toc","aw"exception_marker: .tc ID_72656773_68657265[TC],0x7265677368657265 .text/* * This is the start of the interrupt handlers for pSeries * This code runs with relocation off. */ . = 0x100 .globl __start_interrupts__start_interrupts: STD_EXCEPTION_PSERIES(0x100, system_reset) . = 0x200_machine_check_pSeries: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save 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 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 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 */ MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt) STD_EXCEPTION_PSERIES(0x600, alignment) STD_EXCEPTION_PSERIES(0x700, program_check) STD_EXCEPTION_PSERIES(0x800, fp_unavailable) MASKABLE_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 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)#ifdef CONFIG_CBE_RAS HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error)#endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)#ifdef CONFIG_CBE_RAS HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance)#endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1700, altivec_assist)#ifdef CONFIG_CBE_RAS HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal)#endif /* CONFIG_CBE_RAS */ . = 0x3000/*** pSeries interrupt support ***/ /* moved from 0xf00 */ STD_EXCEPTION_PSERIES(., performance_monitor)/* * An interrupt came in while soft-disabled; clear EE in SRR1, * clear paca->hard_enabled and return. */masked_interrupt: stb r10,PACAHARDIRQEN(r13) mtcrf 0x80,r9 ld r9,PACA_EXGEN+EX_R9(r13) mfspr r10,SPRN_SRR1 rldicl r10,r10,48,1 /* clear MSR_EE */ rotldi r10,r10,16 mtspr SPRN_SRR1,r10 ld r10,PACA_EXGEN+EX_R10(r13) mfspr r13,SPRN_SPRG1 rfid b . .align 7do_stab_bolted_pSeries: mtcrf 0x80,r12 mfspr r12,SPRN_SPRG2 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)/* * We have some room here we use that to put * the peries slb miss user trampoline code so it's reasonably * away from slb_miss_user_common to avoid problems with rfid * * This is used for when the SLB miss handler has to go virtual, * which doesn't happen for now anymore but will once we re-implement * dynamic VSIDs for shared page tables */#ifdef __DISABLED__slb_miss_user_pseries: std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R11(r13) std r12,PACA_EXGEN+EX_R12(r13) mfspr r10,SPRG1 ld r11,PACA_EXSLB+EX_R9(r13) ld r12,PACA_EXSLB+EX_R3(r13) std r10,PACA_EXGEN+EX_R13(r13) std r11,PACA_EXGEN+EX_R9(r13) std r12,PACA_EXGEN+EX_R3(r13) clrrdi r12,r13,32 mfmsr r10 mfspr r11,SRR0 /* save SRR0 */ ori r12,r12,slb_miss_user_common@l /* virt addr of handler */ ori r10,r10,MSR_IR|MSR_DR|MSR_RI mtspr SRR0,r12 mfspr r12,SRR1 /* and SRR1 */ mtspr SRR1,r10 rfid b . /* prevent spec. execution */#endif /* __DISABLED__ */#ifdef CONFIG_PPC_PSERIES/* * Vectors for the FWNMI option. Share common code. */ .globl system_reset_fwnmi .align 7system_reset_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXGEN, system_reset_common) .globl machine_check_fwnmi .align 7machine_check_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common)#endif /* CONFIG_PPC_PSERIES *//*** Common interrupt handlers ***/ STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) /* * Machine check is different because we use a different * save area: PACA_EXMC instead of PACA_EXGEN. */ .align 7 .globl machine_check_commonmachine_check_common: EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) FINISH_NAP DISABLE_INTS bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD bl .machine_check_exception b .ret_from_except STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)#ifdef CONFIG_ALTIVEC STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception)#else STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception)#endif#ifdef CONFIG_CBE_RAS STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception) STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception) STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)#endif /* CONFIG_CBE_RAS *//* * Here we have detected that the kernel stack pointer is bad. * R9 contains the saved CR, r13 points to the paca, * r10 contains the (bad) kernel stack pointer, * r11 and r12 contain the saved SRR0 and SRR1. * We switch to using an emergency stack, save the registers there, * and call kernel_bad_stack(), which panics. */bad_stack: ld r1,PACAEMERGSP(r13) subi r1,r1,64+INT_FRAME_SIZE std r9,_CCR(r1) std r10,GPR1(r1) std r11,_NIP(r1) std r12,_MSR(r1) mfspr r11,SPRN_DAR mfspr r12,SPRN_DSISR std r11,_DAR(r1) std r12,_DSISR(r1) mflr r10 mfctr r11 mfxer r12 std r10,_LINK(r1) std r11,_CTR(r1) std r12,_XER(r1) SAVE_GPR(0,r1) SAVE_GPR(2,r1) SAVE_4GPRS(3,r1) SAVE_2GPRS(7,r1) SAVE_10GPRS(12,r1) SAVE_10GPRS(22,r1) lhz r12,PACA_TRAP_SAVE(r13) std r12,_TRAP(r1) addi r11,r1,INT_FRAME_SIZE std r11,0(r1) li r12,0 std r12,0(r11) ld r2,PACATOC(r13)1: addi r3,r1,STACK_FRAME_OVERHEAD bl .kernel_bad_stack b 1b/* * Return from an exception with minimal checks. * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. * If interrupts have been enabled, or anything has been * done that might have changed the scheduling status of * any task or sent any task a signal, you should use * ret_from_except or ret_from_except_lite instead of this. */fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) ld r12,_MSR(r1) stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ b 1f .globl fast_exception_returnfast_exception_return: ld r12,_MSR(r1)1: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer#ifdef CONFIG_VIRT_CPU_ACCOUNTING andi. r3,r12,MSR_PR beq 2f ACCOUNT_CPU_USER_EXIT(r3, r4)2:#endif ld r3,_CCR(r1) ld r4,_LINK(r1) ld r5,_CTR(r1) ld r6,_XER(r1) mtcr r3 mtlr r4 mtctr r5 mtxer r6 REST_GPR(0, r1) REST_8GPRS(2, r1) mfmsr r10 rldicl r10,r10,48,1 /* clear EE */ rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ mtmsrd r10,1 mtspr SPRN_SRR1,r12 mtspr SPRN_SRR0,r11 REST_4GPRS(10, r1) ld r1,GPR1(r1) rfid b . /* prevent speculative execution */unrecov_fer: bl .save_nvgprs1: addi r3,r1,STACK_FRAME_OVERHEAD bl .unrecoverable_exception b 1b/* * Here r13 points to the paca, r9 contains the saved CR, * SRR0 and SRR1 are saved in r11 and r12, * r9 - r13 are saved in paca->exgen. */ .align 7 .globl data_access_commondata_access_common: mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) ld r3,PACA_EXGEN+EX_DAR(r13) lwz r4,PACA_EXGEN+EX_DSISR(r13) li r5,0x300
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -