1838ee286SNicholas Piggin/* SPDX-License-Identifier: GPL-2.0-or-later */ 2838ee286SNicholas Piggin 3838ee286SNicholas Piggin#include <asm/asm-offsets.h> 4838ee286SNicholas Piggin#include <asm/bug.h> 5838ee286SNicholas Piggin#include <asm/page.h> 6838ee286SNicholas Piggin#include <asm/ppc_asm.h> 7838ee286SNicholas Piggin 8838ee286SNicholas Piggin/* 9838ee286SNicholas Piggin * RTAS is called with MSR IR, DR, EE disabled, and LR in the return address. 10838ee286SNicholas Piggin * 11838ee286SNicholas Piggin * Note: r3 is an input parameter to rtas, so don't trash it... 12838ee286SNicholas Piggin */ 13838ee286SNicholas Piggin 14838ee286SNicholas Piggin#ifdef CONFIG_PPC32 15838ee286SNicholas Piggin_GLOBAL(enter_rtas) 16838ee286SNicholas Piggin stwu r1,-INT_FRAME_SIZE(r1) 17838ee286SNicholas Piggin mflr r0 18838ee286SNicholas Piggin stw r0,INT_FRAME_SIZE+4(r1) 19838ee286SNicholas Piggin LOAD_REG_ADDR(r4, rtas) 20838ee286SNicholas Piggin lis r6,1f@ha /* physical return address for rtas */ 21838ee286SNicholas Piggin addi r6,r6,1f@l 22838ee286SNicholas Piggin tophys(r6,r6) 23838ee286SNicholas Piggin lwz r8,RTASENTRY(r4) 24838ee286SNicholas Piggin lwz r4,RTASBASE(r4) 25838ee286SNicholas Piggin mfmsr r9 26838ee286SNicholas Piggin stw r9,8(r1) 27838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r0,MSR_KERNEL) 28838ee286SNicholas Piggin mtmsr r0 /* disable interrupts so SRR0/1 don't get trashed */ 29838ee286SNicholas Piggin li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) 30838ee286SNicholas Piggin mtlr r6 31838ee286SNicholas Piggin stw r1, THREAD + RTAS_SP(r2) 32838ee286SNicholas Piggin mtspr SPRN_SRR0,r8 33838ee286SNicholas Piggin mtspr SPRN_SRR1,r9 34838ee286SNicholas Piggin rfi 35838ee286SNicholas Piggin1: 36838ee286SNicholas Piggin lis r8, 1f@h 37838ee286SNicholas Piggin ori r8, r8, 1f@l 38838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r9,MSR_KERNEL) 39838ee286SNicholas Piggin mtspr SPRN_SRR0,r8 40838ee286SNicholas Piggin mtspr SPRN_SRR1,r9 41838ee286SNicholas Piggin rfi /* Reactivate MMU translation */ 42838ee286SNicholas Piggin1: 43838ee286SNicholas Piggin lwz r8,INT_FRAME_SIZE+4(r1) /* get return address */ 44838ee286SNicholas Piggin lwz r9,8(r1) /* original msr value */ 45838ee286SNicholas Piggin addi r1,r1,INT_FRAME_SIZE 46838ee286SNicholas Piggin li r0,0 47838ee286SNicholas Piggin stw r0, THREAD + RTAS_SP(r2) 48838ee286SNicholas Piggin mtlr r8 49838ee286SNicholas Piggin mtmsr r9 50838ee286SNicholas Piggin blr /* return to caller */ 51838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(enter_rtas) 52838ee286SNicholas Piggin 53838ee286SNicholas Piggin#else /* CONFIG_PPC32 */ 54838ee286SNicholas Piggin#include <asm/exception-64s.h> 55838ee286SNicholas Piggin 56838ee286SNicholas Piggin/* 57838ee286SNicholas Piggin * 32-bit rtas on 64-bit machines has the additional problem that RTAS may 58838ee286SNicholas Piggin * not preserve the upper parts of registers it uses. 59838ee286SNicholas Piggin */ 60838ee286SNicholas Piggin_GLOBAL(enter_rtas) 61838ee286SNicholas Piggin mflr r0 62838ee286SNicholas Piggin std r0,16(r1) 63838ee286SNicholas Piggin stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space. */ 64838ee286SNicholas Piggin 65838ee286SNicholas Piggin /* Because RTAS is running in 32b mode, it clobbers the high order half 66838ee286SNicholas Piggin * of all registers that it saves. We therefore save those registers 67838ee286SNicholas Piggin * RTAS might touch to the stack. (r0, r3-r13 are caller saved) 68838ee286SNicholas Piggin */ 69838ee286SNicholas Piggin SAVE_GPR(2, r1) /* Save the TOC */ 70838ee286SNicholas Piggin SAVE_GPR(13, r1) /* Save paca */ 71838ee286SNicholas Piggin SAVE_NVGPRS(r1) /* Save the non-volatiles */ 72838ee286SNicholas Piggin 73838ee286SNicholas Piggin mfcr r4 74838ee286SNicholas Piggin std r4,_CCR(r1) 75838ee286SNicholas Piggin mfctr r5 76838ee286SNicholas Piggin std r5,_CTR(r1) 77838ee286SNicholas Piggin mfspr r6,SPRN_XER 78838ee286SNicholas Piggin std r6,_XER(r1) 79838ee286SNicholas Piggin mfdar r7 80838ee286SNicholas Piggin std r7,_DAR(r1) 81838ee286SNicholas Piggin mfdsisr r8 82838ee286SNicholas Piggin std r8,_DSISR(r1) 83838ee286SNicholas Piggin 84838ee286SNicholas Piggin /* Temporary workaround to clear CR until RTAS can be modified to 85838ee286SNicholas Piggin * ignore all bits. 86838ee286SNicholas Piggin */ 87838ee286SNicholas Piggin li r0,0 88838ee286SNicholas Piggin mtcr r0 89838ee286SNicholas Piggin 90838ee286SNicholas Piggin#ifdef CONFIG_BUG 91838ee286SNicholas Piggin /* There is no way it is acceptable to get here with interrupts enabled, 92838ee286SNicholas Piggin * check it with the asm equivalent of WARN_ON 93838ee286SNicholas Piggin */ 94838ee286SNicholas Piggin lbz r0,PACAIRQSOFTMASK(r13) 95838ee286SNicholas Piggin1: tdeqi r0,IRQS_ENABLED 96838ee286SNicholas Piggin EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING 97838ee286SNicholas Piggin#endif 98838ee286SNicholas Piggin 99838ee286SNicholas Piggin /* Hard-disable interrupts */ 100838ee286SNicholas Piggin mfmsr r6 101838ee286SNicholas Piggin rldicl r7,r6,48,1 102838ee286SNicholas Piggin rotldi r7,r7,16 103838ee286SNicholas Piggin mtmsrd r7,1 104838ee286SNicholas Piggin 105838ee286SNicholas Piggin /* Unfortunately, the stack pointer and the MSR are also clobbered, 106838ee286SNicholas Piggin * so they are saved in the PACA which allows us to restore 107838ee286SNicholas Piggin * our original state after RTAS returns. 108838ee286SNicholas Piggin */ 109838ee286SNicholas Piggin std r1,PACAR1(r13) 110838ee286SNicholas Piggin std r6,PACASAVEDMSR(r13) 111838ee286SNicholas Piggin 112838ee286SNicholas Piggin /* Setup our real return addr */ 113838ee286SNicholas Piggin LOAD_REG_ADDR(r4,rtas_return_loc) 114838ee286SNicholas Piggin clrldi r4,r4,2 /* convert to realmode address */ 115838ee286SNicholas Piggin mtlr r4 116838ee286SNicholas Piggin 117838ee286SNicholas Piggin__enter_rtas: 118838ee286SNicholas Piggin LOAD_REG_ADDR(r4, rtas) 119838ee286SNicholas Piggin ld r5,RTASENTRY(r4) /* get the rtas->entry value */ 120838ee286SNicholas Piggin ld r4,RTASBASE(r4) /* get the rtas->base value */ 121838ee286SNicholas Piggin 122838ee286SNicholas Piggin /* 123838ee286SNicholas Piggin * RTAS runs in 32-bit big endian real mode, but leave MSR[RI] on as we 124838ee286SNicholas Piggin * may hit NMI (SRESET or MCE) while in RTAS. RTAS should disable RI in 125838ee286SNicholas Piggin * its critical regions (as specified in PAPR+ section 7.2.1). MSR[S] 126838ee286SNicholas Piggin * is not impacted by RFI_TO_KERNEL (only urfid can unset it). So if 127838ee286SNicholas Piggin * MSR[S] is set, it will remain when entering RTAS. 128838ee286SNicholas Piggin */ 129838ee286SNicholas Piggin LOAD_REG_IMMEDIATE(r6, MSR_ME | MSR_RI) 130838ee286SNicholas Piggin 131838ee286SNicholas Piggin li r0,0 132838ee286SNicholas Piggin mtmsrd r0,1 /* disable RI before using SRR0/1 */ 133838ee286SNicholas Piggin 134838ee286SNicholas Piggin mtspr SPRN_SRR0,r5 135838ee286SNicholas Piggin mtspr SPRN_SRR1,r6 136838ee286SNicholas Piggin RFI_TO_KERNEL 137838ee286SNicholas Piggin b . /* prevent speculative execution */ 138838ee286SNicholas Pigginrtas_return_loc: 139838ee286SNicholas Piggin FIXUP_ENDIAN 140838ee286SNicholas Piggin 141838ee286SNicholas Piggin /* 142838ee286SNicholas Piggin * Clear RI and set SF before anything. 143838ee286SNicholas Piggin */ 144838ee286SNicholas Piggin mfmsr r6 145838ee286SNicholas Piggin li r0,MSR_RI 146838ee286SNicholas Piggin andc r6,r6,r0 147838ee286SNicholas Piggin sldi r0,r0,(MSR_SF_LG - MSR_RI_LG) 148838ee286SNicholas Piggin or r6,r6,r0 149838ee286SNicholas Piggin sync 150838ee286SNicholas Piggin mtmsrd r6 151838ee286SNicholas Piggin 152838ee286SNicholas Piggin /* relocation is off at this point */ 153838ee286SNicholas Piggin GET_PACA(r4) 154838ee286SNicholas Piggin clrldi r4,r4,2 /* convert to realmode address */ 155838ee286SNicholas Piggin 156838ee286SNicholas Piggin bcl 20,31,$+4 157838ee286SNicholas Piggin0: mflr r3 158838ee286SNicholas Piggin ld r3,(1f-0b)(r3) /* get &rtas_restore_regs */ 159838ee286SNicholas Piggin 160838ee286SNicholas Piggin ld r1,PACAR1(r4) /* Restore our SP */ 161838ee286SNicholas Piggin ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ 162838ee286SNicholas Piggin 163838ee286SNicholas Piggin mtspr SPRN_SRR0,r3 164838ee286SNicholas Piggin mtspr SPRN_SRR1,r4 165838ee286SNicholas Piggin RFI_TO_KERNEL 166838ee286SNicholas Piggin b . /* prevent speculative execution */ 167*07940b4bSNicholas Piggin_ASM_NOKPROBE_SYMBOL(enter_rtas) 168838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(__enter_rtas) 169838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(rtas_return_loc) 170838ee286SNicholas Piggin 171838ee286SNicholas Piggin .align 3 172838ee286SNicholas Piggin1: .8byte rtas_restore_regs 173838ee286SNicholas Piggin 174838ee286SNicholas Pigginrtas_restore_regs: 175838ee286SNicholas Piggin /* relocation is on at this point */ 176838ee286SNicholas Piggin REST_GPR(2, r1) /* Restore the TOC */ 177838ee286SNicholas Piggin REST_GPR(13, r1) /* Restore paca */ 178838ee286SNicholas Piggin REST_NVGPRS(r1) /* Restore the non-volatiles */ 179838ee286SNicholas Piggin 180838ee286SNicholas Piggin GET_PACA(r13) 181838ee286SNicholas Piggin 182838ee286SNicholas Piggin ld r4,_CCR(r1) 183838ee286SNicholas Piggin mtcr r4 184838ee286SNicholas Piggin ld r5,_CTR(r1) 185838ee286SNicholas Piggin mtctr r5 186838ee286SNicholas Piggin ld r6,_XER(r1) 187838ee286SNicholas Piggin mtspr SPRN_XER,r6 188838ee286SNicholas Piggin ld r7,_DAR(r1) 189838ee286SNicholas Piggin mtdar r7 190838ee286SNicholas Piggin ld r8,_DSISR(r1) 191838ee286SNicholas Piggin mtdsisr r8 192838ee286SNicholas Piggin 193838ee286SNicholas Piggin addi r1,r1,SWITCH_FRAME_SIZE /* Unstack our frame */ 194838ee286SNicholas Piggin ld r0,16(r1) /* get return address */ 195838ee286SNicholas Piggin 196838ee286SNicholas Piggin mtlr r0 197838ee286SNicholas Piggin blr /* return to caller */ 198838ee286SNicholas Piggin 199838ee286SNicholas Piggin#endif /* CONFIG_PPC32 */ 200