xref: /aosp_15_r20/external/coreboot/src/arch/arm64/transition_asm.S (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/* SPDX-License-Identifier: GPL-2.0-only */
2
3/*
4 * transition_asm.S: This file handles the entry and exit from an exception
5 *
6 * Flow: exception --> exc_vectors --> exc_entry --> exc_dispatch -->
7 * exc_exit
8 * Transition Flow: transition --> trans_switch --> exc_exit
9 *
10 * |---|		      Exception Entry				   |---|
11 *
12 * On exception entry, it saves all the xregs on SP_ELx since SP_ELx is
13 * selected on entry. Some dummy pushes are performed to create space for
14 * elx_state structure. It then passes pointer to this saved set of regs and
15 * a unique id(for identifying exception) to exc_entry.
16 *
17 * |---|		      Exception Transition Dispatch		   |---|
18 *
19 * This is the C-component of exception entry. It does the work of initializing
20 * the exc_state registers. Finally it calls exception dispatch implemented by
21 * the user. This is point of no-return.
22 *
23 * |---|		      Exception Dispatch			   |---|
24 *
25 * User of this functionality is expected to implement exc_dispatch which
26 * acts as entry point for it. Once exception handling is complete, the user
27 * needs to call exc_exit with pointer to struct regs.
28 *
29 * |---|		      Exception Exit				   |---|
30 *
31 * Once exc_dispatch is done with handling the exception based on the id passed
32 * to it, it needs to call exc_exit with pointer to struct regs. This is done to
33 * unwind the exception stack by popping off all the xregs.
34 *
35 * |---|		      Exception Transition Exit			   |---|
36 *
37 * This routine makes SP_EL0 point to the regs structure passed and continues
38 * onto the exception exit routine described above. This is the reason that
39 * transition library does not handle initialization of SP_EL0 for the program
40 * to be executed.
41 */
42
43#include <arch/asm.h>
44#include <arch/lib_helpers.h>
45#include <arch/transition.h>
46
47.macro eentry lbl id
48	.align 7
49\lbl:
50	stp	x29, x30, [sp, #STACK_PUSH_BYTES]!
51	bl	exc_prologue
52	mov	x1, \id
53	mov	x0, sp
54	b	exc_entry
55.endm
56
57/*
58 * exc_vectors: Entry point for an exception
59 */
60ENTRY_WITH_ALIGN(exc_vectors, 11)
61
62eentry	sync_curr_sp0, #EXC_VID_CUR_SP_EL0_SYNC
63eentry	irq_curr_sp0, #EXC_VID_CUR_SP_EL0_IRQ
64eentry	fiq_curr_sp0, #EXC_VID_CUR_SP_EL0_FIRQ
65eentry	serror_curr_sp0, #EXC_VID_CUR_SP_EL0_SERR
66eentry	sync_curr_spx, #EXC_VID_CUR_SP_ELX_SYNC
67eentry	irq_curr_spx, #EXC_VID_CUR_SP_ELX_IRQ
68eentry	fiq_curr_spx, #EXC_VID_CUR_SP_ELX_FIQ
69eentry	serror_curr_spx, #EXC_VID_CUR_SP_ELX_SERR
70eentry	sync_lower_64, #EXC_VID_LOW64_SYNC
71eentry	irq_lower_64, #EXC_VID_LOW64_IRQ
72eentry	fiq_lower_64, #EXC_VID_LOW64_FIQ
73eentry	serror_lower_64, #EXC_VID_LOW64_SERR
74eentry	sync_lower_32, #EXC_VID_LOW32_SYNC
75eentry	irq_lower_32, #EXC_VID_LOW32_IRQ
76eentry	fiq_lower_32, #EXC_VID_LOW32_FIQ
77eentry	serror_lower_32, #EXC_VID_LOW32_SERR
78
79ENDPROC(exc_vectors)
80
81ENTRY(exc_prologue)
82	stp	x27, x28, [sp, #STACK_PUSH_BYTES]!
83	stp	x25, x26, [sp, #STACK_PUSH_BYTES]!
84	stp	x23, x24, [sp, #STACK_PUSH_BYTES]!
85	stp	x21, x22, [sp, #STACK_PUSH_BYTES]!
86	stp	x19, x20, [sp, #STACK_PUSH_BYTES]!
87	stp	x17, x18, [sp, #STACK_PUSH_BYTES]!
88	stp	x15, x16, [sp, #STACK_PUSH_BYTES]!
89	stp	x13, x14, [sp, #STACK_PUSH_BYTES]!
90	stp	x11, x12, [sp, #STACK_PUSH_BYTES]!
91	stp	x9, x10, [sp, #STACK_PUSH_BYTES]!
92	stp	x7, x8, [sp, #STACK_PUSH_BYTES]!
93	stp	x5, x6, [sp, #STACK_PUSH_BYTES]!
94	stp	x3, x4, [sp, #STACK_PUSH_BYTES]!
95	stp	x1, x2, [sp, #STACK_PUSH_BYTES]!
96	/* xzr pushed as place holder for sp */
97	stp	xzr, x0, [sp, #STACK_PUSH_BYTES]!
98	/*
99	 * xzr pushed as place holder for:
100	 * 1. sp_elx and elr
101	 */
102	stp	xzr, xzr, [sp, #STACK_PUSH_BYTES]!
103	/* 2. spsr and sp_el0 */
104	stp	xzr, xzr, [sp, #STACK_PUSH_BYTES]!
105	ret
106ENDPROC(exc_prologue)
107
108/*
109 * trans_switch: Set SPSel to use SP_EL0
110 * x0 = regs structure
111 */
112ENTRY(trans_switch)
113	msr	SPSel, #SPSR_USE_L
114	b	exc_exit
115ENDPROC(trans_switch)
116
117/*
118 * exc_exit: Return from exception by restoring saved state of xregs
119 * x0 = regs structure
120 */
121ENTRY(exc_exit)
122	/* Unwind the stack by making sp point to regs structure */
123	mov	 sp, x0
124	/* Load registers x0-x30 */
125	ldp	 xzr, x0, [sp], #STACK_POP_BYTES
126	ldp	 x1, x2, [sp], #STACK_POP_BYTES
127	ldp	 x3, x4, [sp], #STACK_POP_BYTES
128	ldp	 x5, x6, [sp], #STACK_POP_BYTES
129	ldp	 x7, x8, [sp], #STACK_POP_BYTES
130	ldp	 x9, x10, [sp], #STACK_POP_BYTES
131	ldp	 x11, x12, [sp], #STACK_POP_BYTES
132	ldp	 x13, x14, [sp], #STACK_POP_BYTES
133	ldp	 x15, x16, [sp], #STACK_POP_BYTES
134	ldp	 x17, x18, [sp], #STACK_POP_BYTES
135	ldp	 x19, x20, [sp], #STACK_POP_BYTES
136	ldp	 x21, x22, [sp], #STACK_POP_BYTES
137	ldp	 x23, x24, [sp], #STACK_POP_BYTES
138	ldp	 x25, x26, [sp], #STACK_POP_BYTES
139	ldp	 x27, x28, [sp], #STACK_POP_BYTES
140	ldp	 x29, x30, [sp], #STACK_POP_BYTES
141	eret
142ENDPROC(exc_exit)
143
144/*
145 * exception_init_asm: Initialize VBAR and point SP_ELx to exception stack.
146 * Also unmask aborts now that we can report them. x0 = end of exception stack
147 */
148ENTRY(exception_init_asm)
149	msr	SPSel, #SPSR_USE_H
150	mov	sp, x0
151	msr	SPSel, #SPSR_USE_L
152	adr	x0, exc_vectors
153	msr	CURRENT_EL(vbar), x0
154	msr	DAIFClr, #0xf
155	dsb	sy
156	isb
157	ret
158ENDPROC(exception_init_asm)
159