1*838ee286SNicholas Piggin/* SPDX-License-Identifier: GPL-2.0-or-later */ 2*838ee286SNicholas Piggin 3*838ee286SNicholas Piggin#include <asm/asm-offsets.h> 4*838ee286SNicholas Piggin#include <asm/bug.h> 5*838ee286SNicholas Piggin#include <asm/page.h> 6*838ee286SNicholas Piggin#include <asm/ppc_asm.h> 7*838ee286SNicholas Piggin 8*838ee286SNicholas Piggin/* 9*838ee286SNicholas Piggin * RTAS is called with MSR IR, DR, EE disabled, and LR in the return address. 10*838ee286SNicholas Piggin * 11*838ee286SNicholas Piggin * Note: r3 is an input parameter to rtas, so don't trash it... 12*838ee286SNicholas Piggin */ 13*838ee286SNicholas Piggin 14*838ee286SNicholas Piggin#ifdef CONFIG_PPC32 15*838ee286SNicholas Piggin_GLOBAL(enter_rtas) 16*838ee286SNicholas Piggin stwu r1,-INT_FRAME_SIZE(r1) 17*838ee286SNicholas Piggin mflr r0 18*838ee286SNicholas Piggin stw r0,INT_FRAME_SIZE+4(r1) 19*838ee286SNicholas Piggin LOAD_REG_ADDR(r4, rtas) 20*838ee286SNicholas Piggin lis r6,1f@ha /* physical return address for rtas */ 21*838ee286SNicholas Piggin addi r6,r6,1f@l 22*838ee286SNicholas Piggin tophys(r6,r6) 23*838ee286SNicholas Piggin lwz r8,RTASENTRY(r4) 24*838ee286SNicholas Piggin lwz r4,RTASBASE(r4) 25*838ee286SNicholas Piggin mfmsr r9 26*838ee286SNicholas Piggin stw r9,8(r1) 27*838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r0,MSR_KERNEL) 28*838ee286SNicholas Piggin mtmsr r0 /* disable interrupts so SRR0/1 don't get trashed */ 29*838ee286SNicholas Piggin li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) 30*838ee286SNicholas Piggin mtlr r6 31*838ee286SNicholas Piggin stw r1, THREAD + RTAS_SP(r2) 32*838ee286SNicholas Piggin mtspr SPRN_SRR0,r8 33*838ee286SNicholas Piggin mtspr SPRN_SRR1,r9 34*838ee286SNicholas Piggin rfi 35*838ee286SNicholas Piggin1: 36*838ee286SNicholas Piggin lis r8, 1f@h 37*838ee286SNicholas Piggin ori r8, r8, 1f@l 38*838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r9,MSR_KERNEL) 39*838ee286SNicholas Piggin mtspr SPRN_SRR0,r8 40*838ee286SNicholas Piggin mtspr SPRN_SRR1,r9 41*838ee286SNicholas Piggin rfi /* Reactivate MMU translation */ 42*838ee286SNicholas Piggin1: 43*838ee286SNicholas Piggin lwz r8,INT_FRAME_SIZE+4(r1) /* get return address */ 44*838ee286SNicholas Piggin lwz r9,8(r1) /* original msr value */ 45*838ee286SNicholas Piggin addi r1,r1,INT_FRAME_SIZE 46*838ee286SNicholas Piggin li r0,0 47*838ee286SNicholas Piggin stw r0, THREAD + RTAS_SP(r2) 48*838ee286SNicholas Piggin mtlr r8 49*838ee286SNicholas Piggin mtmsr r9 50*838ee286SNicholas Piggin blr /* return to caller */ 51*838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(enter_rtas) 52*838ee286SNicholas Piggin 53*838ee286SNicholas Piggin#else /* CONFIG_PPC32 */ 54*838ee286SNicholas Piggin#include <asm/exception-64s.h> 55*838ee286SNicholas Piggin 56*838ee286SNicholas Piggin/* 57*838ee286SNicholas Piggin * 32-bit rtas on 64-bit machines has the additional problem that RTAS may 58*838ee286SNicholas Piggin * not preserve the upper parts of registers it uses. 59*838ee286SNicholas Piggin */ 60*838ee286SNicholas Piggin_GLOBAL(enter_rtas) 61*838ee286SNicholas Piggin mflr r0 62*838ee286SNicholas Piggin std r0,16(r1) 63*838ee286SNicholas Piggin stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space. */ 64*838ee286SNicholas Piggin 65*838ee286SNicholas Piggin /* Because RTAS is running in 32b mode, it clobbers the high order half 66*838ee286SNicholas Piggin * of all registers that it saves. We therefore save those registers 67*838ee286SNicholas Piggin * RTAS might touch to the stack. (r0, r3-r13 are caller saved) 68*838ee286SNicholas Piggin */ 69*838ee286SNicholas Piggin SAVE_GPR(2, r1) /* Save the TOC */ 70*838ee286SNicholas Piggin SAVE_GPR(13, r1) /* Save paca */ 71*838ee286SNicholas Piggin SAVE_NVGPRS(r1) /* Save the non-volatiles */ 72*838ee286SNicholas Piggin 73*838ee286SNicholas Piggin mfcr r4 74*838ee286SNicholas Piggin std r4,_CCR(r1) 75*838ee286SNicholas Piggin mfctr r5 76*838ee286SNicholas Piggin std r5,_CTR(r1) 77*838ee286SNicholas Piggin mfspr r6,SPRN_XER 78*838ee286SNicholas Piggin std r6,_XER(r1) 79*838ee286SNicholas Piggin mfdar r7 80*838ee286SNicholas Piggin std r7,_DAR(r1) 81*838ee286SNicholas Piggin mfdsisr r8 82*838ee286SNicholas Piggin std r8,_DSISR(r1) 83*838ee286SNicholas Piggin 84*838ee286SNicholas Piggin /* Temporary workaround to clear CR until RTAS can be modified to 85*838ee286SNicholas Piggin * ignore all bits. 86*838ee286SNicholas Piggin */ 87*838ee286SNicholas Piggin li r0,0 88*838ee286SNicholas Piggin mtcr r0 89*838ee286SNicholas Piggin 90*838ee286SNicholas Piggin#ifdef CONFIG_BUG 91*838ee286SNicholas Piggin /* There is no way it is acceptable to get here with interrupts enabled, 92*838ee286SNicholas Piggin * check it with the asm equivalent of WARN_ON 93*838ee286SNicholas Piggin */ 94*838ee286SNicholas Piggin lbz r0,PACAIRQSOFTMASK(r13) 95*838ee286SNicholas Piggin1: tdeqi r0,IRQS_ENABLED 96*838ee286SNicholas Piggin EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING 97*838ee286SNicholas Piggin#endif 98*838ee286SNicholas Piggin 99*838ee286SNicholas Piggin /* Hard-disable interrupts */ 100*838ee286SNicholas Piggin mfmsr r6 101*838ee286SNicholas Piggin rldicl r7,r6,48,1 102*838ee286SNicholas Piggin rotldi r7,r7,16 103*838ee286SNicholas Piggin mtmsrd r7,1 104*838ee286SNicholas Piggin 105*838ee286SNicholas Piggin /* Unfortunately, the stack pointer and the MSR are also clobbered, 106*838ee286SNicholas Piggin * so they are saved in the PACA which allows us to restore 107*838ee286SNicholas Piggin * our original state after RTAS returns. 108*838ee286SNicholas Piggin */ 109*838ee286SNicholas Piggin std r1,PACAR1(r13) 110*838ee286SNicholas Piggin std r6,PACASAVEDMSR(r13) 111*838ee286SNicholas Piggin 112*838ee286SNicholas Piggin /* Setup our real return addr */ 113*838ee286SNicholas Piggin LOAD_REG_ADDR(r4,rtas_return_loc) 114*838ee286SNicholas Piggin clrldi r4,r4,2 /* convert to realmode address */ 115*838ee286SNicholas Piggin mtlr r4 116*838ee286SNicholas Piggin 117*838ee286SNicholas Piggin__enter_rtas: 118*838ee286SNicholas Piggin LOAD_REG_ADDR(r4, rtas) 119*838ee286SNicholas Piggin ld r5,RTASENTRY(r4) /* get the rtas->entry value */ 120*838ee286SNicholas Piggin ld r4,RTASBASE(r4) /* get the rtas->base value */ 121*838ee286SNicholas Piggin 122*838ee286SNicholas Piggin /* 123*838ee286SNicholas Piggin * RTAS runs in 32-bit big endian real mode, but leave MSR[RI] on as we 124*838ee286SNicholas Piggin * may hit NMI (SRESET or MCE) while in RTAS. RTAS should disable RI in 125*838ee286SNicholas Piggin * its critical regions (as specified in PAPR+ section 7.2.1). MSR[S] 126*838ee286SNicholas Piggin * is not impacted by RFI_TO_KERNEL (only urfid can unset it). So if 127*838ee286SNicholas Piggin * MSR[S] is set, it will remain when entering RTAS. 128*838ee286SNicholas Piggin */ 129*838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r6, MSR_ME | MSR_RI) 130*838ee286SNicholas Piggin 131*838ee286SNicholas Piggin li r0,0 132*838ee286SNicholas Piggin mtmsrd r0,1 /* disable RI before using SRR0/1 */ 133*838ee286SNicholas Piggin 134*838ee286SNicholas Piggin mtspr SPRN_SRR0,r5 135*838ee286SNicholas Piggin mtspr SPRN_SRR1,r6 136*838ee286SNicholas Piggin RFI_TO_KERNEL 137*838ee286SNicholas Piggin b . /* prevent speculative execution */ 138*838ee286SNicholas Pigginrtas_return_loc: 139*838ee286SNicholas Piggin FIXUP_ENDIAN 140*838ee286SNicholas Piggin 141*838ee286SNicholas Piggin /* 142*838ee286SNicholas Piggin * Clear RI and set SF before anything. 143*838ee286SNicholas Piggin */ 144*838ee286SNicholas Piggin mfmsr r6 145*838ee286SNicholas Piggin li r0,MSR_RI 146*838ee286SNicholas Piggin andc r6,r6,r0 147*838ee286SNicholas Piggin sldi r0,r0,(MSR_SF_LG - MSR_RI_LG) 148*838ee286SNicholas Piggin or r6,r6,r0 149*838ee286SNicholas Piggin sync 150*838ee286SNicholas Piggin mtmsrd r6 151*838ee286SNicholas Piggin 152*838ee286SNicholas Piggin /* relocation is off at this point */ 153*838ee286SNicholas Piggin GET_PACA(r4) 154*838ee286SNicholas Piggin clrldi r4,r4,2 /* convert to realmode address */ 155*838ee286SNicholas Piggin 156*838ee286SNicholas Piggin bcl 20,31,$+4 157*838ee286SNicholas Piggin0: mflr r3 158*838ee286SNicholas Piggin ld r3,(1f-0b)(r3) /* get &rtas_restore_regs */ 159*838ee286SNicholas Piggin 160*838ee286SNicholas Piggin ld r1,PACAR1(r4) /* Restore our SP */ 161*838ee286SNicholas Piggin ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ 162*838ee286SNicholas Piggin 163*838ee286SNicholas Piggin mtspr SPRN_SRR0,r3 164*838ee286SNicholas Piggin mtspr SPRN_SRR1,r4 165*838ee286SNicholas Piggin RFI_TO_KERNEL 166*838ee286SNicholas Piggin b . /* prevent speculative execution */ 167*838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(__enter_rtas) 168*838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(rtas_return_loc) 169*838ee286SNicholas Piggin 170*838ee286SNicholas Piggin .align 3 171*838ee286SNicholas Piggin1: .8byte rtas_restore_regs 172*838ee286SNicholas Piggin 173*838ee286SNicholas Pigginrtas_restore_regs: 174*838ee286SNicholas Piggin /* relocation is on at this point */ 175*838ee286SNicholas Piggin REST_GPR(2, r1) /* Restore the TOC */ 176*838ee286SNicholas Piggin REST_GPR(13, r1) /* Restore paca */ 177*838ee286SNicholas Piggin REST_NVGPRS(r1) /* Restore the non-volatiles */ 178*838ee286SNicholas Piggin 179*838ee286SNicholas Piggin GET_PACA(r13) 180*838ee286SNicholas Piggin 181*838ee286SNicholas Piggin ld r4,_CCR(r1) 182*838ee286SNicholas Piggin mtcr r4 183*838ee286SNicholas Piggin ld r5,_CTR(r1) 184*838ee286SNicholas Piggin mtctr r5 185*838ee286SNicholas Piggin ld r6,_XER(r1) 186*838ee286SNicholas Piggin mtspr SPRN_XER,r6 187*838ee286SNicholas Piggin ld r7,_DAR(r1) 188*838ee286SNicholas Piggin mtdar r7 189*838ee286SNicholas Piggin ld r8,_DSISR(r1) 190*838ee286SNicholas Piggin mtdsisr r8 191*838ee286SNicholas Piggin 192*838ee286SNicholas Piggin addi r1,r1,SWITCH_FRAME_SIZE /* Unstack our frame */ 193*838ee286SNicholas Piggin ld r0,16(r1) /* get return address */ 194*838ee286SNicholas Piggin 195*838ee286SNicholas Piggin mtlr r0 196*838ee286SNicholas Piggin blr /* return to caller */ 197*838ee286SNicholas Piggin 198*838ee286SNicholas Piggin#endif /* CONFIG_PPC32 */ 199