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