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