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    stmdb sp, {r0-lr}^
43    ldr r8, [sp]
44    sub r8, r8, #4
45    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
46    mrc p15, 0, sp, c13, c0, 4
47    b c_handle_undefined_instruction
48END_FUNC(arm_undefined_inst_exception)
49
50BEGIN_FUNC(arm_swi_syscall)
51    /* Store CPSR and NextIP on supervisor stack, which currently points
52       at the end of the current thread's user context */
53    srsia #PMODE_SUPERVISOR
54
55    /* Set the FaultIP address, which in ARM mode is the NextIP - 4.
56     * NOTE: This is completely wrong and broken in thumb mode.
57     */
58    sub lr, lr, #4
59
60    /* Store FaultIP */
61    str lr, [sp, #(PT_FaultIP - PT_NextIP)]
62
63    /* Stack all user registers */
64    stmdb sp, {r0-lr}^
65
66    /* Load the kernel's real stack pointer */
67    mrc p15, 0, sp, c13, c0, 4
68
69    /* Load system call number as a c_handle_syscall argument. r0 and r1 are passed
70     * unmodified (cptr and msgInfo) respectively.  On MCS configurations we also
71     * pass the reply cptr in r2 for fastpath_reply_recv.
72     */
73
74#ifdef CONFIG_FASTPATH
75    cmp r7, #SYSCALL_CALL
76    beq c_handle_fastpath_call
77    cmp r7, #SYSCALL_REPLY_RECV
78#ifdef CONFIG_KERNEL_MCS
79    moveq r2, r6
80#endif
81    beq c_handle_fastpath_reply_recv
82#endif
83
84    mov r2, r7
85    b c_handle_syscall
86
87END_FUNC(arm_swi_syscall)
88
89BEGIN_FUNC(arm_prefetch_abort_exception)
90    /* Full save/restore, documented in arm_swi_syscall */
91    srsia #PMODE_SUPERVISOR
92    cps #PMODE_SUPERVISOR
93    stmdb sp, {r0-lr}^
94
95    /* Load PC and SPSR saved by the "srs" instruction above. */
96    ldmia   sp, {r8,r9}
97
98    /* Ensure the bottom 4 bits of SPSR are zero, indicating we came from
99     * userspace. If not, something has gone amiss in the kernel. */
100    tst     r9, #0xf
101
102    /* Compute the faulting address. */
103    sub r8, r8, #4
104
105    bne     kernel_prefetch_fault
106
107    /* Store faulting address in TCB and call handleVMFaultEvent. */
108    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
109
110    mrc p15, 0, sp, c13, c0, 4
111
112    b c_handle_instruction_fault
113
114kernel_prefetch_fault:
115#ifdef CONFIG_DEBUG_BUILD
116    mov r0, r8
117    mrc p15, 0, sp, c13, c0, 4
118    blx kernelPrefetchAbort
119    /* Fallthrough to infinite loop should we foolishly return. */
120#endif
121    /* To aid finding faults in non-debug mode, catch kernel faults here.
122     * - r8 will contain the faulting address.
123     * - r9 will contain the IFSR register.
124     * - lr might contain something useful too if we followed a function
125     *   call.
126     * - the original values of r8 and r9 will be obliterated.
127     */
128    mrc p15, 0, r9, c5, c0, 1    /* Get ISFR. */
1291:  b 1b /* Infinite loop. You'd better have a watchdog. */
130END_FUNC(arm_prefetch_abort_exception)
131
132BEGIN_FUNC(arm_data_abort_exception)
133    /* Full save/restore, documented in arm_swi_syscall */
134    srsia #PMODE_SUPERVISOR
135    cps #PMODE_SUPERVISOR
136    stmdb sp, {r0-lr}^
137
138    /* Load PC and SPSR saved by the "srs" instruction above. */
139    ldmia   sp, {r8,r9}
140
141    /* Ensure the bottom 4 bits of SPSR are zero, indicating we came from
142     * userspace. If not, something has gone amiss in the kernel. */
143    tst     r9, #0xf
144
145    /* Compute the faulting address.
146     * For a Data abort, LR_abt points at PC+8. */
147    sub r8, r8, #8
148
149    bne     kernel_data_fault
150
151    /* Store faulting address in TCB and call handleVMFaultEvent. */
152    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
153    mrc p15, 0, sp, c13, c0, 4
154
155    b c_handle_data_fault
156
157
158kernel_data_fault:
159#ifdef CONFIG_DEBUG_BUILD
160    mov r0, r8
161    mrc p15, 0, sp, c13, c0, 4
162    blx kernelDataAbort
163    /* Fallthrough to infinite loop should we foolishly return. */
164#endif
165    /* To aid finding faults in non-debug mode, catch kernel faults here.
166     * - r8 will contain the faulting instruction.
167     * - r9 will contain the memory address that faulted.
168     * - r10 will contain the fault status register (DFSR).
169     * - the original values of r8, r9 and r10 will be obliterated.
170     */
171    mrc p15, 0, r9, c5, c0, 0    /* Get data fault status register. */
172    mrc p15, 0, r10, c6, c0, 0   /* Get fault address register. */
1731:  b 1b /* Infinite loop. You'd better have a watchdog. */
174END_FUNC(arm_data_abort_exception)
175
176BEGIN_FUNC(arm_irq_exception)
177    /* Full save/restore, documented in arm_swi_syscall */
178    srsia #PMODE_SUPERVISOR
179    cps #PMODE_SUPERVISOR
180    stmdb sp, {r0-lr}^
181    ldr r8, [sp]
182    sub r8, r8, #4
183    str r8, [sp]
184    str r8, [sp, #(PT_FaultIP - PT_NextIP)]
185    mrc p15, 0, sp, c13, c0, 4
186    b c_handle_interrupt
187END_FUNC(arm_irq_exception)
188
189BEGIN_FUNC(arm_reset_exception)
190    blx halt
191END_FUNC(arm_reset_exception)
192
193BEGIN_FUNC(arm_fiq_exception)
194    blx halt
195END_FUNC(arm_fiq_exception)
196
197#endif /* !CONFIG_ARM_HYP */
198