1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <util.h>
9
10#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
11
12#include <machine/assembler.h>
13
14.code 32
15.section .vectors, "ax"
16
17BEGIN_FUNC(arm_vector_table)
18    ldr pc, =arm_reset_exception
19    ldr pc, =arm_undefined_inst_exception
20    ldr pc, =arm_swi_syscall
21    ldr pc, =arm_prefetch_abort_exception
22    ldr pc, =arm_data_abort_exception
23    ldr pc, =arm_reset_exception
24    ldr pc, =arm_irq_exception
25    ldr pc, =arm_fiq_exception
26
27.ltorg
28END_FUNC(arm_vector_table)
29
30.section .vectors.text, "ax"
31
32#include <arch/api/syscall.h>
33#include <arch/machine/hardware.h>
34
35#include <arch/machine/registerset.h>
36#include <sel4/sel4_arch/constants.h>
37
38BEGIN_FUNC(arm_undefined_inst_exception)
39    /* Full save/restore, documented in arm_swi_syscall */
40    srsia #PMODE_SUPERVISOR
41    cps #PMODE_SUPERVISOR
42#if defined(CONFIG_ARCH_ARM_V6) && defined(CONFIG_DANGEROUS_CODE_INJECTION_ON_UNDEF_INSTR)
43    /* Call whatever's in r8. See Kconfig for the purpose of this. */
44    blx r8
45    rfeia sp
46#else
47    stmdb sp, {r0-lr}^
48    ldr r8, [sp]
49    sub r8, r8, #4
50    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
51#ifdef CONFIG_ARCH_ARM_V6
52    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
53#else
54    mrc p15, 0, sp, c13, c0, 4
55#endif /* CONFIG_ARCH_ARM_V6 */
56    b c_handle_undefined_instruction
57#endif
58END_FUNC(arm_undefined_inst_exception)
59
60BEGIN_FUNC(arm_swi_syscall)
61    /* Store CPSR and NextIP on supervisor stack, which currently points
62       at the end of the current thread's user context */
63    srsia #PMODE_SUPERVISOR
64
65    /* Set the FaultIP address, which in ARM mode is the NextIP - 4.
66     * NOTE: This is completely wrong and broken in thumb mode.
67     */
68    sub lr, lr, #4
69
70    /* Store FaultIP */
71    str lr, [sp, #(PT_FaultIP - PT_NextIP)]
72
73    /* Stack all user registers */
74    stmdb sp, {r0-lr}^
75
76    /* Load the kernel's real stack pointer */
77#ifdef CONFIG_ARCH_ARM_V6
78    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
79#else
80    mrc p15, 0, sp, c13, c0, 4
81#endif /* CONFIG_ARCH_ARM_V6 */
82
83    /* Load system call number as a c_handle_syscall argument. r0 and r1 are passed
84     * unmodified (cptr and msgInfo) respectively.  On MCS configurations we also
85     * pass the reply cptr in r2 for fastpath_reply_recv.
86     */
87
88#ifdef CONFIG_FASTPATH
89    cmp r7, #SYSCALL_CALL
90    beq c_handle_fastpath_call
91    cmp r7, #SYSCALL_REPLY_RECV
92#ifdef CONFIG_KERNEL_MCS
93    moveq r2, r6
94#endif
95    beq c_handle_fastpath_reply_recv
96#endif
97
98    mov r2, r7
99    b c_handle_syscall
100
101END_FUNC(arm_swi_syscall)
102
103BEGIN_FUNC(arm_prefetch_abort_exception)
104    /* Full save/restore, documented in arm_swi_syscall */
105    srsia #PMODE_SUPERVISOR
106    cps #PMODE_SUPERVISOR
107    stmdb sp, {r0-lr}^
108
109    /* Load PC and SPSR saved by the "srs" instruction above. */
110    ldmia   sp, {r8,r9}
111
112    /* Ensure the bottom 4 bits of SPSR are zero, indicating we came from
113     * userspace. If not, something has gone amiss in the kernel. */
114    tst     r9, #0xf
115
116    /* Compute the faulting address. */
117    sub r8, r8, #4
118
119    bne     kernel_prefetch_fault
120
121    /* Store faulting address in TCB and call handleVMFaultEvent. */
122    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
123
124#ifdef CONFIG_ARCH_ARM_V6
125    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
126#else
127    mrc p15, 0, sp, c13, c0, 4
128#endif /* CONFIG_ARCH_ARM_V6 */
129
130    b c_handle_instruction_fault
131
132kernel_prefetch_fault:
133#ifdef CONFIG_DEBUG_BUILD
134    mov r0, r8
135#ifdef CONFIG_ARCH_ARM_V6
136    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
137#else
138    mrc p15, 0, sp, c13, c0, 4
139#endif /* CONFIG_ARCH_ARM_V6 */
140    blx kernelPrefetchAbort
141    /* Fallthrough to infinite loop should we foolishly return. */
142#endif
143    /* To aid finding faults in non-debug mode, catch kernel faults here.
144     * - r8 will contain the faulting address.
145     * - r9 will contain the IFSR register.
146     * - lr might contain something useful too if we followed a function
147     *   call.
148     * - the original values of r8 and r9 will be obliterated.
149     */
150    mrc p15, 0, r9, c5, c0, 1    /* Get ISFR. */
1511:  b 1b /* Infinite loop. You'd better have a watchdog. */
152END_FUNC(arm_prefetch_abort_exception)
153
154BEGIN_FUNC(arm_data_abort_exception)
155    /* Full save/restore, documented in arm_swi_syscall */
156    srsia #PMODE_SUPERVISOR
157    cps #PMODE_SUPERVISOR
158    stmdb sp, {r0-lr}^
159
160    /* Load PC and SPSR saved by the "srs" instruction above. */
161    ldmia   sp, {r8,r9}
162
163    /* Ensure the bottom 4 bits of SPSR are zero, indicating we came from
164     * userspace. If not, something has gone amiss in the kernel. */
165    tst     r9, #0xf
166
167    /* Compute the faulting address.
168     * For a Data abort, LR_abt points at PC+8. */
169    sub r8, r8, #8
170
171    bne     kernel_data_fault
172
173    /* Store faulting address in TCB and call handleVMFaultEvent. */
174    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
175#ifdef CONFIG_ARCH_ARM_V6
176    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
177#else
178    mrc p15, 0, sp, c13, c0, 4
179#endif /* CONFIG_ARCH_ARM_V6 */
180
181    b c_handle_data_fault
182
183
184kernel_data_fault:
185#ifdef CONFIG_DEBUG_BUILD
186    mov r0, r8
187#ifdef CONFIG_ARCH_ARM_V6
188    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
189#else
190    mrc p15, 0, sp, c13, c0, 4
191#endif /* CONFIG_ARCH_ARM_V6 */
192    blx kernelDataAbort
193    /* Fallthrough to infinite loop should we foolishly return. */
194#endif
195    /* To aid finding faults in non-debug mode, catch kernel faults here.
196     * - r8 will contain the faulting instruction.
197     * - r9 will contain the memory address that faulted.
198     * - r10 will contain the fault status register (DFSR).
199     * - the original values of r8, r9 and r10 will be obliterated.
200     */
201    mrc p15, 0, r9, c5, c0, 0    /* Get data fault status register. */
202    mrc p15, 0, r10, c6, c0, 0   /* Get fault address register. */
2031:  b 1b /* Infinite loop. You'd better have a watchdog. */
204END_FUNC(arm_data_abort_exception)
205
206BEGIN_FUNC(arm_irq_exception)
207    /* Full save/restore, documented in arm_swi_syscall */
208    srsia #PMODE_SUPERVISOR
209    cps #PMODE_SUPERVISOR
210    stmdb sp, {r0-lr}^
211    ldr r8, [sp]
212    sub r8, r8, #4
213    str r8, [sp]
214    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
215#ifdef CONFIG_ARCH_ARM_V6
216    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
217#else
218    mrc p15, 0, sp, c13, c0, 4
219#endif /* CONFIG_ARCH_ARM_V6 */
220    b c_handle_interrupt
221END_FUNC(arm_irq_exception)
222
223BEGIN_FUNC(arm_reset_exception)
224    blx halt
225END_FUNC(arm_reset_exception)
226
227BEGIN_FUNC(arm_fiq_exception)
228    blx halt
229END_FUNC(arm_fiq_exception)
230
231#endif /* !CONFIG_ARM_HYP */
232