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