1/* 2 * Copyright (c) 2008-2015 Travis Geiselbrecht 3 * 4 * Use of this source code is governed by a MIT-style 5 * license that can be found in the LICENSE file or at 6 * https://opensource.org/licenses/MIT 7 */ 8#include <lk/asm.h> 9#include <arch/asm.h> 10#include <arch/arm/cores.h> 11 12/* exception handling glue. 13 * NOTE: only usable on armv6+ cores 14 */ 15 16#define TIMESTAMP_IRQ 0 17 18/* macros to align and unalign the stack on 8 byte boundary for ABI compliance */ 19.macro stack_align, tempreg 20 /* make sure the stack is aligned */ 21 mov \tempreg, sp 22 tst sp, #4 23 subeq sp, #4 24 push { \tempreg } 25 26 /* tempreg holds the original stack */ 27.endm 28 29.macro stack_restore, tempreg 30 /* restore the potentially unaligned stack */ 31 pop { \tempreg } 32 mov sp, \tempreg 33.endm 34 35/* save and disable the vfp unit */ 36.macro vfp_save, temp1 37 /* save old fpexc */ 38 vmrs \temp1, fpexc 39 40 push { \temp1 } 41 42 /* hard disable the vfp unit */ 43 bic \temp1, #(1<<30) 44 vmsr fpexc, \temp1 45.endm 46 47/* restore the vfp enable/disable state */ 48.macro vfp_restore, temp1 49 /* restore fpexc */ 50 pop { \temp1 } 51 52 vmsr fpexc, \temp1 53.endm 54 55/* Save callee trashed registers. 56 * At exit r0 contains a pointer to the register frame. 57 */ 58.macro save 59 /* save spsr and r14 onto the svc stack */ 60 srsdb #0x13! 61 62 /* switch to svc mode, interrupts disabled */ 63 cpsid i,#0x13 64 65 /* save callee trashed regs and lr */ 66 push { r0-r3, r12, lr } 67 68 /* save user space sp/lr */ 69 sub sp, #8 70 stmia sp, { r13, r14 }^ 71 72#if ARM_WITH_VFP 73 /* save and disable the vfp unit */ 74 vfp_save r0 75#endif 76 77 /* make sure the stack is 8 byte aligned */ 78 stack_align r0 79 80 /* r0 now holds the pointer to the original iframe (before alignment) */ 81.endm 82 83.macro save_offset, offset 84 sub lr, \offset 85 save 86.endm 87 88.macro restore 89 /* undo the stack alignment we did before */ 90 stack_restore r0 91 92#if ARM_WITH_VFP 93 /* restore the old state of the vfp unit */ 94 vfp_restore r0 95#endif 96 97 /* restore user space sp/lr */ 98 ldmia sp, { r13, r14 }^ 99 add sp, #8 100 101 pop { r0-r3, r12, lr } 102 103 /* return to whence we came from */ 104 rfeia sp! 105.endm 106 107/* Save all registers. 108 * At exit r0 contains a pointer to the register frame. 109 */ 110.macro saveall 111 /* save spsr and r14 onto the svc stack */ 112 srsdb #0x13! 113 114 /* switch to svc mode, interrupts disabled */ 115 cpsid i,#0x13 116 117 /* save all regs */ 118 push { r0-r12, lr } 119 120 /* save user space sp/lr */ 121 sub sp, #8 122 stmia sp, { r13, r14 }^ 123 124#if ARM_WITH_VFP 125 /* save and disable the vfp unit */ 126 vfp_save r0 127#endif 128 129 /* make sure the stack is 8 byte aligned */ 130 stack_align r0 131 132 /* r0 now holds the pointer to the original iframe (before alignment) */ 133.endm 134 135.macro saveall_offset, offset 136 sub lr, \offset 137 saveall 138.endm 139 140.macro restoreall 141 /* undo the stack alignment we did before */ 142 stack_restore r0 143 144#if ARM_WITH_VFP 145 /* restore the old state of the vfp unit */ 146 vfp_restore r0 147#endif 148 149 /* restore user space sp/lr */ 150 ldmia sp, { r13, r14 }^ 151 add sp, #8 152 153 pop { r0-r12, r14 } 154 155 /* return to whence we came from */ 156 rfeia sp! 157.endm 158 159FUNCTION(arm_undefined) 160 save 161 /* r0 now holds pointer to iframe */ 162 163 bl arm_undefined_handler 164 165 restore 166 167#ifndef WITH_LIB_SYSCALL 168FUNCTION(arm_syscall) 169 saveall 170 /* r0 now holds pointer to iframe */ 171 172 bl arm_syscall_handler 173 174 restoreall 175#endif 176 177FUNCTION(arm_prefetch_abort) 178 saveall_offset #4 179 /* r0 now holds pointer to iframe */ 180 181 bl arm_prefetch_abort_handler 182 183 restoreall 184 185FUNCTION(arm_data_abort) 186 saveall_offset #8 187 /* r0 now holds pointer to iframe */ 188 189 bl arm_data_abort_handler 190 191 restoreall 192 193FUNCTION(arm_reserved) 194 b . 195 196FUNCTION(arm_irq) 197#if TIMESTAMP_IRQ 198 /* read the cycle count */ 199 mrc p15, 0, sp, c9, c13, 0 200 str sp, [pc, #__irq_cycle_count - . - 8] 201#endif 202 203 save_offset #4 204 205 /* r0 now holds pointer to iframe */ 206 207 /* track that we're inside an irq handler */ 208 LOADCONST(r2, __arm_in_handler) 209 mov r1, #1 210 str r1, [r2] 211 212 /* call into higher level code */ 213 bl platform_irq 214 215 /* clear the irq handler status */ 216 LOADCONST(r1, __arm_in_handler) 217 mov r2, #0 218 str r2, [r1] 219 220 /* reschedule if the handler returns nonzero */ 221 cmp r0, #0 222 blne thread_preempt 223 224 restore 225 226FUNCTION(arm_fiq) 227 save_offset #4 228 /* r0 now holds pointer to iframe */ 229 230 bl platform_fiq 231 232 restore 233 234.ltorg 235 236#if TIMESTAMP_IRQ 237DATA(__irq_cycle_count) 238 .word 0 239#endif 240 241.data 242DATA(__arm_in_handler) 243 .word 0 244