soc/intel: Remove blank lines before '}' and after '{'
[coreboot2.git] / payloads / libpayload / arch / arm64 / exception_asm.S
blob7bd1f33cb12cf8b780177e1f41dc6bdfffe9bc0c
1 /*
2  *
3  * Copyright 2014 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
29 #include <arch/asm.h>
30 #include <arch/exception.h>
32         /* Macro for exception entry
33          * Store x30 before any branch
34          * Branch to exception_prologue to save rest and switch stacks
35          * Move exception id into x1
36          * Branch to exception_dispatch (exception C entry point)
37          * Branch to exception_return to return from exception
38          */
39 .macro eentry lbl id
40         .align 7
41 \lbl:
42         /* Note: SP points to exception_state (see exception_set_state_ptr) */
43         str     x30, [sp, #EXCEPTION_STATE_REG(30)]
44         bl      exception_prologue
45         mov     x1, \id
46         bl      exception_dispatch
47         b       exception_return
48 .endm
50         /* Exception table has 16 entries and each of 128 bytes
51          * Hence, 16 * 128 = 2048. Thus, 11 passed as parameter
52          * to align
53          */
55         .align  11
56         .global exception_table
57 exception_table:
59 eentry  sync_sp0,#0
60 eentry  irq_sp0,#1
61 eentry  fiq_sp0,#2
62 eentry  serror_sp0,#3
63 eentry  sync_spx,#4
64 eentry  irq_spx,#5
65 eentry  fiq_spx,#6
66 eentry  serror_spx,#7
67 eentry  sync_elx_64,#8
68 eentry  irq_elx_64,#9
69 eentry  fiq_elx_64,#10
70 eentry  serror_elx_64,#11
71 eentry  sync_elx_32,#12
72 eentry  irq_elx_32,#13
73 eentry  fiq_elx_32,#14
74 eentry  serror_elx_32,#15
76 /* This code must match the layout of struct exception_state (minus x30) */
77 ENTRY(exception_prologue)
78         /* Save registers x0-x29 */
79         stp     x28, x29, [sp, #EXCEPTION_STATE_REG(28)]
80         stp     x26, x27, [sp, #EXCEPTION_STATE_REG(26)]
81         stp     x24, x25, [sp, #EXCEPTION_STATE_REG(24)]
82         stp     x22, x23, [sp, #EXCEPTION_STATE_REG(22)]
83         stp     x20, x21, [sp, #EXCEPTION_STATE_REG(20)]
84         stp     x18, x19, [sp, #EXCEPTION_STATE_REG(18)]
85         stp     x16, x17, [sp, #EXCEPTION_STATE_REG(16)]
86         stp     x14, x15, [sp, #EXCEPTION_STATE_REG(14)]
87         stp     x12, x13, [sp, #EXCEPTION_STATE_REG(12)]
88         stp     x10, x11, [sp, #EXCEPTION_STATE_REG(10)]
89         stp     x8, x9, [sp, #EXCEPTION_STATE_REG(8)]
90         stp     x6, x7, [sp, #EXCEPTION_STATE_REG(6)]
91         stp     x4, x5, [sp, #EXCEPTION_STATE_REG(4)]
92         stp     x2, x3, [sp, #EXCEPTION_STATE_REG(2)]
93         stp     x0, x1, [sp, #EXCEPTION_STATE_REG(0)]
95         /* Save the stack pointer and SPSR */
96         mrs     x1, sp_el0
97         mrs     x0, spsr_el2
98         stp     x0, x1, [sp, #EXCEPTION_STATE_SPSR]
100         /* Save return address (ELR) and exception syndrome */
101         mrs     x1, esr_el2
102         mrs     x0, elr_el2
103         stp     x0, x1, [sp, #EXCEPTION_STATE_ELR]
105         /* Now switch to the actual exception stack. Keep a pointer to the
106            exception_state structure in x0 as an argument for dispatch(). */
107         mov     x0, sp
108         adrp    x1, exception_stack_end
109         ldr     x1, [x1, :lo12:exception_stack_end]
110         msr     SPSel, #0
111         mov     sp, x1
113         ret
114 ENDPROC(exception_prologue)
116 ENTRY(exception_return)
117         /* Switch SP back to the exception_state structure */
118         msr     SPSel, #1
120         /* Restore return address (ELR) -- skip ESR (unneeded for return) */
121         ldr     x0, [sp, #EXCEPTION_STATE_ELR]
122         msr     elr_el2, x0
124         /* Restore stack pointer and SPSR */
125         ldp     x0, x1, [sp, #EXCEPTION_STATE_SPSR]
126         msr     spsr_el2, x0
127         msr     sp_el0, x1
129         /* Restore all registers (x0-x30) */
130         ldp     x0, x1, [sp, #EXCEPTION_STATE_REG(0)]
131         ldp     x2, x3, [sp, #EXCEPTION_STATE_REG(2)]
132         ldp     x4, x5, [sp, #EXCEPTION_STATE_REG(4)]
133         ldp     x6, x7, [sp, #EXCEPTION_STATE_REG(6)]
134         ldp     x8, x9, [sp, #EXCEPTION_STATE_REG(8)]
135         ldp     x10, x11, [sp, #EXCEPTION_STATE_REG(10)]
136         ldp     x12, x13, [sp, #EXCEPTION_STATE_REG(12)]
137         ldp     x14, x15, [sp, #EXCEPTION_STATE_REG(14)]
138         ldp     x16, x17, [sp, #EXCEPTION_STATE_REG(16)]
139         ldp     x18, x19, [sp, #EXCEPTION_STATE_REG(18)]
140         ldp     x20, x21, [sp, #EXCEPTION_STATE_REG(20)]
141         ldp     x22, x23, [sp, #EXCEPTION_STATE_REG(22)]
142         ldp     x24, x25, [sp, #EXCEPTION_STATE_REG(24)]
143         ldp     x26, x27, [sp, #EXCEPTION_STATE_REG(26)]
144         ldp     x28, x29, [sp, #EXCEPTION_STATE_REG(28)]
145         ldr     x30, [sp, #EXCEPTION_STATE_REG(30)]
147         /* Return from exception */
148         eret
149 ENDPROC(exception_return)
151         /*
152          * We have two stack pointers on AArch64: SP_EL0 (which despite the
153          * naming is used in all ELs) and SP_EL2. We can select which one to
154          * use by writing to SPSel. Normally we're using SP_EL0, but on
155          * exception entry it automatically switches to SP_EL2.
156          *
157          * It is important for exception reentrancy to switch back to SP_EL0
158          * while handling the exception. We only need SP_EL2 for the assembly
159          * exception entry and exit code that stores all register state
160          * (including the old SP_EL0, before we switch to the real exception
161          * stack). Rather than having yet another stack to push/pop those
162          * register values on so that we can later sort them into the
163          * exception_state structure, it's much easier to just make SP_EL2 point
164          * directly to exception_state and just use it as a normal base register
165          * rather than a real stack. This function sets that up.
166          */
167 ENTRY(exception_set_state_ptr)
168         msr     SPSel, #1
169         mov     sp, x0
170         msr     SPSel, #0
171         ret
172 ENDPROC(exception_set_state_ptr)