xref: /openbmc/linux/arch/powerpc/kernel/rtas_entry.S (revision 838ee286ecc9a3c76e6bd8f5aaad0c8c5c66b9ca)
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