blob: 86ef83cf0a7524432ab536a4352038202848b317 [file] [log] [blame]
Andrew Walbrandfb73372022-04-21 10:52:27 +00001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Saves the volatile registers onto the stack. This currently takes 14
19 * instructions, so it can be used in exception handlers with 18 instructions
20 * left.
21 *
22 * On return, x0 and x1 are initialised to elr_el2 and spsr_el2 respectively,
23 * which can be used as the first and second arguments of a subsequent call.
24 */
25.macro save_volatile_to_stack
26 /* Reserve stack space and save registers x0-x18, x29 & x30. */
27 stp x0, x1, [sp, #-(8 * 24)]!
28 stp x2, x3, [sp, #8 * 2]
29 stp x4, x5, [sp, #8 * 4]
30 stp x6, x7, [sp, #8 * 6]
31 stp x8, x9, [sp, #8 * 8]
32 stp x10, x11, [sp, #8 * 10]
33 stp x12, x13, [sp, #8 * 12]
34 stp x14, x15, [sp, #8 * 14]
35 stp x16, x17, [sp, #8 * 16]
36 str x18, [sp, #8 * 18]
37 stp x29, x30, [sp, #8 * 20]
38
39 /*
40 * Save elr_el1 & spsr_el1. This such that we can take nested exception
41 * and still be able to unwind.
42 */
43 mrs x0, elr_el1
44 mrs x1, spsr_el1
45 stp x0, x1, [sp, #8 * 22]
46.endm
47
48/**
49 * Restores the volatile registers from the stack. This currently takes 14
50 * instructions, so it can be used in exception handlers while still leaving 18
51 * instructions left; if paired with save_volatile_to_stack, there are 4
52 * instructions to spare.
53 */
54.macro restore_volatile_from_stack
55 /* Restore registers x2-x18, x29 & x30. */
56 ldp x2, x3, [sp, #8 * 2]
57 ldp x4, x5, [sp, #8 * 4]
58 ldp x6, x7, [sp, #8 * 6]
59 ldp x8, x9, [sp, #8 * 8]
60 ldp x10, x11, [sp, #8 * 10]
61 ldp x12, x13, [sp, #8 * 12]
62 ldp x14, x15, [sp, #8 * 14]
63 ldp x16, x17, [sp, #8 * 16]
64 ldr x18, [sp, #8 * 18]
65 ldp x29, x30, [sp, #8 * 20]
66
67 /* Restore registers elr_el1 & spsr_el1, using x0 & x1 as scratch. */
68 ldp x0, x1, [sp, #8 * 22]
69 msr elr_el1, x0
70 msr spsr_el1, x1
71
72 /* Restore x0 & x1, and release stack space. */
73 ldp x0, x1, [sp], #8 * 24
74.endm
75
76/**
77 * This is a generic handler for exceptions taken at the current EL while using
78 * SP0. It behaves similarly to the SPx case by first switching to SPx, doing
79 * the work, then switching back to SP0 before returning.
80 *
81 * Switching to SPx and calling the Rust handler takes 16 instructions. To
82 * restore and return we need an additional 16 instructions, so we can implement
83 * the whole handler within the allotted 32 instructions.
84 */
85.macro current_exception_sp0 handler:req
86 msr spsel, #1
87 save_volatile_to_stack
88 bl \handler
89 restore_volatile_from_stack
90 msr spsel, #0
91 eret
92.endm
93
94/**
95 * This is a generic handler for exceptions taken at the current EL while using
96 * SPx. It saves volatile registers, calls the Rust handler, restores volatile
97 * registers, then returns.
98 *
99 * This also works for exceptions taken from EL0, if we don't care about
100 * non-volatile registers.
101 *
102 * Saving state and jumping to the Rust handler takes 15 instructions, and
103 * restoring and returning also takes 15 instructions, so we can fit the whole
104 * handler in 30 instructions, under the limit of 32.
105 */
106.macro current_exception_spx handler:req
107 save_volatile_to_stack
108 bl \handler
109 restore_volatile_from_stack
110 eret
111.endm
112
113.section .text.vector_table_el1, "ax"
114.global vector_table_el1
115.balign 0x800
116vector_table_el1:
117sync_cur_sp0:
118 current_exception_sp0 sync_exception_current
119
120.balign 0x80
121irq_cur_sp0:
122 current_exception_sp0 irq_current
123
124.balign 0x80
125fiq_cur_sp0:
126 current_exception_sp0 fiq_current
127
128.balign 0x80
129serr_cur_sp0:
130 current_exception_sp0 serr_current
131
132.balign 0x80
133sync_cur_spx:
134 current_exception_spx sync_exception_current
135
136.balign 0x80
137irq_cur_spx:
138 current_exception_spx irq_current
139
140.balign 0x80
141fiq_cur_spx:
142 current_exception_spx fiq_current
143
144.balign 0x80
145serr_cur_spx:
146 current_exception_spx serr_current
147
148.balign 0x80
149sync_lower_64:
150 current_exception_spx sync_lower
151
152.balign 0x80
153irq_lower_64:
154 current_exception_spx irq_lower
155
156.balign 0x80
157fiq_lower_64:
158 current_exception_spx fiq_lower
159
160.balign 0x80
161serr_lower_64:
162 current_exception_spx serr_lower
163
164.balign 0x80
165sync_lower_32:
166 current_exception_spx sync_lower
167
168.balign 0x80
169irq_lower_32:
170 current_exception_spx irq_lower
171
172.balign 0x80
173fiq_lower_32:
174 current_exception_spx fiq_lower
175
176.balign 0x80
177serr_lower_32:
178 current_exception_spx serr_lower