| /* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| #include <asm/asm-offsets.h> | |
| #include <asm/bug.h> | |
| #include <asm/page.h> | |
| #include <asm/ppc_asm.h> | |
| /* | |
| * RTAS is called with MSR IR, DR, EE disabled, and LR in the return address. | |
| * | |
| * Note: r3 is an input parameter to rtas, so don't trash it... | |
| */ | |
| #ifdef CONFIG_PPC32 | |
| _GLOBAL(enter_rtas) | |
| stwu r1,-INT_FRAME_SIZE(r1) | |
| mflr r0 | |
| stw r0,INT_FRAME_SIZE+4(r1) | |
| LOAD_REG_ADDR(r4, rtas) | |
| lis r6,1f@ha /* physical return address for rtas */ | |
| addi r6,r6,1f@l | |
| tophys(r6,r6) | |
| lwz r8,RTASENTRY(r4) | |
| lwz r4,RTASBASE(r4) | |
| mfmsr r9 | |
| stw r9,8(r1) | |
| li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) | |
| mtlr r6 | |
| stw r1, THREAD + RTAS_SP(r2) | |
| mtspr SPRN_SRR0,r8 | |
| mtspr SPRN_SRR1,r9 | |
| rfi | |
| 1: | |
| lis r8, 1f@h | |
| ori r8, r8, 1f@l | |
| LOAD_REG_IMMEDIATE(r9,MSR_KERNEL) | |
| mtspr SPRN_SRR0,r8 | |
| mtspr SPRN_SRR1,r9 | |
| rfi /* Reactivate MMU translation */ | |
| 1: | |
| lwz r8,INT_FRAME_SIZE+4(r1) /* get return address */ | |
| lwz r9,8(r1) /* original msr value */ | |
| addi r1,r1,INT_FRAME_SIZE | |
| li r0,0 | |
| stw r0, THREAD + RTAS_SP(r2) | |
| mtlr r8 | |
| mtmsr r9 | |
| blr /* return to caller */ | |
| _ASM_NOKPROBE_SYMBOL(enter_rtas) | |
| #else /* CONFIG_PPC32 */ | |
| #include <asm/exception-64s.h> | |
| /* | |
| * 32-bit rtas on 64-bit machines has the additional problem that RTAS may | |
| * not preserve the upper parts of registers it uses. | |
| */ | |
| _GLOBAL(enter_rtas) | |
| mflr r0 | |
| std r0,16(r1) | |
| stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space. */ | |
| /* Because RTAS is running in 32b mode, it clobbers the high order half | |
| * of all registers that it saves. We therefore save those registers | |
| * RTAS might touch to the stack. (r0, r3-r12 are caller saved) | |
| */ | |
| SAVE_GPR(2, r1) /* Save the TOC */ | |
| SAVE_NVGPRS(r1) /* Save the non-volatiles */ | |
| mfcr r4 | |
| std r4,_CCR(r1) | |
| mfctr r5 | |
| std r5,_CTR(r1) | |
| mfspr r6,SPRN_XER | |
| std r6,_XER(r1) | |
| mfdar r7 | |
| std r7,_DAR(r1) | |
| mfdsisr r8 | |
| std r8,_DSISR(r1) | |
| /* Temporary workaround to clear CR until RTAS can be modified to | |
| * ignore all bits. | |
| */ | |
| li r0,0 | |
| mtcr r0 | |
| mfmsr r6 | |
| /* Unfortunately, the stack pointer and the MSR are also clobbered, | |
| * so they are saved in the PACA which allows us to restore | |
| * our original state after RTAS returns. | |
| */ | |
| std r1,PACAR1(r13) | |
| std r6,PACASAVEDMSR(r13) | |
| /* Setup our real return addr */ | |
| LOAD_REG_ADDR(r4,rtas_return_loc) | |
| clrldi r4,r4,2 /* convert to realmode address */ | |
| mtlr r4 | |
| __enter_rtas: | |
| LOAD_REG_ADDR(r4, rtas) | |
| ld r5,RTASENTRY(r4) /* get the rtas->entry value */ | |
| ld r4,RTASBASE(r4) /* get the rtas->base value */ | |
| /* | |
| * RTAS runs in 32-bit big endian real mode, but leave MSR[RI] on as we | |
| * may hit NMI (SRESET or MCE) while in RTAS. RTAS should disable RI in | |
| * its critical regions (as specified in PAPR+ section 7.2.1). MSR[S] | |
| * is not impacted by RFI_TO_KERNEL (only urfid can unset it). So if | |
| * MSR[S] is set, it will remain when entering RTAS. | |
| * If we're in HV mode, RTAS must also run in HV mode, so extract MSR_HV | |
| * from the saved MSR value and insert into the value RTAS will use. | |
| */ | |
| extrdi r0, r6, 1, 63 - MSR_HV_LG | |
| LOAD_REG_IMMEDIATE(r6, MSR_ME | MSR_RI) | |
| insrdi r6, r0, 1, 63 - MSR_HV_LG | |
| li r0,0 | |
| mtmsrd r0,1 /* disable RI before using SRR0/1 */ | |
| mtspr SPRN_SRR0,r5 | |
| mtspr SPRN_SRR1,r6 | |
| RFI_TO_KERNEL | |
| b . /* prevent speculative execution */ | |
| rtas_return_loc: | |
| FIXUP_ENDIAN | |
| /* Set SF before anything. */ | |
| LOAD_REG_IMMEDIATE(r6, MSR_KERNEL & ~(MSR_IR|MSR_DR)) | |
| mtmsrd r6 | |
| /* relocation is off at this point */ | |
| GET_PACA(r13) | |
| bcl 20,31,$+4 | |
| 0: mflr r3 | |
| ld r3,(1f-0b)(r3) /* get &rtas_restore_regs */ | |
| ld r1,PACAR1(r13) /* Restore our SP */ | |
| ld r4,PACASAVEDMSR(r13) /* Restore our MSR */ | |
| mtspr SPRN_SRR0,r3 | |
| mtspr SPRN_SRR1,r4 | |
| RFI_TO_KERNEL | |
| b . /* prevent speculative execution */ | |
| _ASM_NOKPROBE_SYMBOL(enter_rtas) | |
| _ASM_NOKPROBE_SYMBOL(__enter_rtas) | |
| _ASM_NOKPROBE_SYMBOL(rtas_return_loc) | |
| .align 3 | |
| 1: .8byte rtas_restore_regs | |
| rtas_restore_regs: | |
| /* relocation is on at this point */ | |
| REST_GPR(2, r1) /* Restore the TOC */ | |
| REST_NVGPRS(r1) /* Restore the non-volatiles */ | |
| ld r4,_CCR(r1) | |
| mtcr r4 | |
| ld r5,_CTR(r1) | |
| mtctr r5 | |
| ld r6,_XER(r1) | |
| mtspr SPRN_XER,r6 | |
| ld r7,_DAR(r1) | |
| mtdar r7 | |
| ld r8,_DSISR(r1) | |
| mtdsisr r8 | |
| addi r1,r1,SWITCH_FRAME_SIZE /* Unstack our frame */ | |
| ld r0,16(r1) /* get return address */ | |
| mtlr r0 | |
| blr /* return to caller */ | |
| #endif /* CONFIG_PPC32 */ |