xref: /openbmc/linux/arch/powerpc/kernel/rtas_entry.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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	li	r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
28838ee286SNicholas Piggin	mtlr	r6
29838ee286SNicholas Piggin	stw	r1, THREAD + RTAS_SP(r2)
30838ee286SNicholas Piggin	mtspr	SPRN_SRR0,r8
31838ee286SNicholas Piggin	mtspr	SPRN_SRR1,r9
32838ee286SNicholas Piggin	rfi
33838ee286SNicholas Piggin1:
34838ee286SNicholas Piggin	lis	r8, 1f@h
35838ee286SNicholas Piggin	ori	r8, r8, 1f@l
36838ee286SNicholas Piggin	LOAD_REG_IMMEDIATE(r9,MSR_KERNEL)
37838ee286SNicholas Piggin	mtspr	SPRN_SRR0,r8
38838ee286SNicholas Piggin	mtspr	SPRN_SRR1,r9
39838ee286SNicholas Piggin	rfi			/* Reactivate MMU translation */
40838ee286SNicholas Piggin1:
41838ee286SNicholas Piggin	lwz	r8,INT_FRAME_SIZE+4(r1)	/* get return address */
42838ee286SNicholas Piggin	lwz	r9,8(r1)	/* original msr value */
43838ee286SNicholas Piggin	addi	r1,r1,INT_FRAME_SIZE
44838ee286SNicholas Piggin	li	r0,0
45838ee286SNicholas Piggin	stw	r0, THREAD + RTAS_SP(r2)
46838ee286SNicholas Piggin	mtlr	r8
47838ee286SNicholas Piggin	mtmsr	r9
48838ee286SNicholas Piggin	blr			/* return to caller */
49838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(enter_rtas)
50838ee286SNicholas Piggin
51838ee286SNicholas Piggin#else /* CONFIG_PPC32 */
52838ee286SNicholas Piggin#include <asm/exception-64s.h>
53838ee286SNicholas Piggin
54838ee286SNicholas Piggin/*
55838ee286SNicholas Piggin * 32-bit rtas on 64-bit machines has the additional problem that RTAS may
56838ee286SNicholas Piggin * not preserve the upper parts of registers it uses.
57838ee286SNicholas Piggin */
58838ee286SNicholas Piggin_GLOBAL(enter_rtas)
59838ee286SNicholas Piggin	mflr	r0
60838ee286SNicholas Piggin	std	r0,16(r1)
61838ee286SNicholas Piggin	stdu	r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space. */
62838ee286SNicholas Piggin
63838ee286SNicholas Piggin	/* Because RTAS is running in 32b mode, it clobbers the high order half
64838ee286SNicholas Piggin	 * of all registers that it saves.  We therefore save those registers
655c86bd02SNicholas Piggin	 * RTAS might touch to the stack.  (r0, r3-r12 are caller saved)
66838ee286SNicholas Piggin	 */
67838ee286SNicholas Piggin	SAVE_GPR(2, r1)			/* Save the TOC */
68838ee286SNicholas Piggin	SAVE_NVGPRS(r1)			/* Save the non-volatiles */
69838ee286SNicholas Piggin
70838ee286SNicholas Piggin	mfcr	r4
71838ee286SNicholas Piggin	std	r4,_CCR(r1)
72838ee286SNicholas Piggin	mfctr	r5
73838ee286SNicholas Piggin	std	r5,_CTR(r1)
74838ee286SNicholas Piggin	mfspr	r6,SPRN_XER
75838ee286SNicholas Piggin	std	r6,_XER(r1)
76838ee286SNicholas Piggin	mfdar	r7
77838ee286SNicholas Piggin	std	r7,_DAR(r1)
78838ee286SNicholas Piggin	mfdsisr	r8
79838ee286SNicholas Piggin	std	r8,_DSISR(r1)
80838ee286SNicholas Piggin
81838ee286SNicholas Piggin	/* Temporary workaround to clear CR until RTAS can be modified to
82838ee286SNicholas Piggin	 * ignore all bits.
83838ee286SNicholas Piggin	 */
84838ee286SNicholas Piggin	li	r0,0
85838ee286SNicholas Piggin	mtcr	r0
86838ee286SNicholas Piggin
87838ee286SNicholas Piggin	mfmsr	r6
88838ee286SNicholas Piggin
89838ee286SNicholas Piggin	/* Unfortunately, the stack pointer and the MSR are also clobbered,
90838ee286SNicholas Piggin	 * so they are saved in the PACA which allows us to restore
91838ee286SNicholas Piggin	 * our original state after RTAS returns.
92838ee286SNicholas Piggin	 */
93838ee286SNicholas Piggin	std	r1,PACAR1(r13)
94838ee286SNicholas Piggin	std	r6,PACASAVEDMSR(r13)
95838ee286SNicholas Piggin
96838ee286SNicholas Piggin	/* Setup our real return addr */
97838ee286SNicholas Piggin	LOAD_REG_ADDR(r4,rtas_return_loc)
98838ee286SNicholas Piggin	clrldi	r4,r4,2			/* convert to realmode address */
99838ee286SNicholas Piggin	mtlr	r4
100838ee286SNicholas Piggin
101838ee286SNicholas Piggin__enter_rtas:
102838ee286SNicholas Piggin	LOAD_REG_ADDR(r4, rtas)
103838ee286SNicholas Piggin	ld	r5,RTASENTRY(r4)	/* get the rtas->entry value */
104838ee286SNicholas Piggin	ld	r4,RTASBASE(r4)		/* get the rtas->base value */
105838ee286SNicholas Piggin
106838ee286SNicholas Piggin	/*
107838ee286SNicholas Piggin	 * RTAS runs in 32-bit big endian real mode, but leave MSR[RI] on as we
108838ee286SNicholas Piggin	 * may hit NMI (SRESET or MCE) while in RTAS. RTAS should disable RI in
109838ee286SNicholas Piggin	 * its critical regions (as specified in PAPR+ section 7.2.1). MSR[S]
110838ee286SNicholas Piggin	 * is not impacted by RFI_TO_KERNEL (only urfid can unset it). So if
111838ee286SNicholas Piggin	 * MSR[S] is set, it will remain when entering RTAS.
112*91926d8bSMichael Ellerman	 * If we're in HV mode, RTAS must also run in HV mode, so extract MSR_HV
113*91926d8bSMichael Ellerman	 * from the saved MSR value and insert into the value RTAS will use.
114838ee286SNicholas Piggin	 */
115*91926d8bSMichael Ellerman	extrdi	r0, r6, 1, 63 - MSR_HV_LG
116838ee286SNicholas Piggin	LOAD_REG_IMMEDIATE(r6, MSR_ME | MSR_RI)
117*91926d8bSMichael Ellerman	insrdi	r6, r0, 1, 63 - MSR_HV_LG
118838ee286SNicholas Piggin
119838ee286SNicholas Piggin	li      r0,0
120838ee286SNicholas Piggin	mtmsrd  r0,1                    /* disable RI before using SRR0/1 */
121838ee286SNicholas Piggin
122838ee286SNicholas Piggin	mtspr	SPRN_SRR0,r5
123838ee286SNicholas Piggin	mtspr	SPRN_SRR1,r6
124838ee286SNicholas Piggin	RFI_TO_KERNEL
125838ee286SNicholas Piggin	b	.	/* prevent speculative execution */
126838ee286SNicholas Pigginrtas_return_loc:
127838ee286SNicholas Piggin	FIXUP_ENDIAN
128838ee286SNicholas Piggin
129014b2e89SNicholas Piggin	/* Set SF before anything. */
130014b2e89SNicholas Piggin	LOAD_REG_IMMEDIATE(r6, MSR_KERNEL & ~(MSR_IR|MSR_DR))
131838ee286SNicholas Piggin	mtmsrd	r6
132838ee286SNicholas Piggin
133838ee286SNicholas Piggin	/* relocation is off at this point */
1345c86bd02SNicholas Piggin	GET_PACA(r13)
135838ee286SNicholas Piggin
136838ee286SNicholas Piggin	bcl	20,31,$+4
137838ee286SNicholas Piggin0:	mflr	r3
138838ee286SNicholas Piggin	ld	r3,(1f-0b)(r3)		/* get &rtas_restore_regs */
139838ee286SNicholas Piggin
1405c86bd02SNicholas Piggin	ld	r1,PACAR1(r13)		/* Restore our SP */
1415c86bd02SNicholas Piggin	ld	r4,PACASAVEDMSR(r13)	/* Restore our MSR */
142838ee286SNicholas Piggin
143838ee286SNicholas Piggin	mtspr	SPRN_SRR0,r3
144838ee286SNicholas Piggin	mtspr	SPRN_SRR1,r4
145838ee286SNicholas Piggin	RFI_TO_KERNEL
146838ee286SNicholas Piggin	b	.	/* prevent speculative execution */
14707940b4bSNicholas Piggin_ASM_NOKPROBE_SYMBOL(enter_rtas)
148838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(__enter_rtas)
149838ee286SNicholas Piggin_ASM_NOKPROBE_SYMBOL(rtas_return_loc)
150838ee286SNicholas Piggin
151838ee286SNicholas Piggin	.align	3
152838ee286SNicholas Piggin1:	.8byte	rtas_restore_regs
153838ee286SNicholas Piggin
154838ee286SNicholas Pigginrtas_restore_regs:
155838ee286SNicholas Piggin	/* relocation is on at this point */
156838ee286SNicholas Piggin	REST_GPR(2, r1)			/* Restore the TOC */
157838ee286SNicholas Piggin	REST_NVGPRS(r1)			/* Restore the non-volatiles */
158838ee286SNicholas Piggin
159838ee286SNicholas Piggin	ld	r4,_CCR(r1)
160838ee286SNicholas Piggin	mtcr	r4
161838ee286SNicholas Piggin	ld	r5,_CTR(r1)
162838ee286SNicholas Piggin	mtctr	r5
163838ee286SNicholas Piggin	ld	r6,_XER(r1)
164838ee286SNicholas Piggin	mtspr	SPRN_XER,r6
165838ee286SNicholas Piggin	ld	r7,_DAR(r1)
166838ee286SNicholas Piggin	mtdar	r7
167838ee286SNicholas Piggin	ld	r8,_DSISR(r1)
168838ee286SNicholas Piggin	mtdsisr	r8
169838ee286SNicholas Piggin
170838ee286SNicholas Piggin	addi	r1,r1,SWITCH_FRAME_SIZE	/* Unstack our frame */
171838ee286SNicholas Piggin	ld	r0,16(r1)		/* get return address */
172838ee286SNicholas Piggin
173838ee286SNicholas Piggin	mtlr	r0
174838ee286SNicholas Piggin	blr				/* return to caller */
175838ee286SNicholas Piggin
176838ee286SNicholas Piggin#endif /* CONFIG_PPC32 */
177