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