Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | /* * ARCv2 ISA based core Low Level Intr/Traps/Exceptions(non-TLB) Handling * * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */ #include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */ #include <asm/errno.h> #include <asm/arcregs.h> #include <asm/irqflags.h> ; A maximum number of supported interrupts in the core interrupt controller. ; This number is not equal to the maximum interrupt number (256) because ; first 16 lines are reserved for exceptions and are not configurable. #define NR_CPU_IRQS 240 .cpu HS #define VECTOR .word ;############################ Vector Table ################################# .section .vector,"a",@progbits .align 4 # Initial 16 slots are Exception Vectors VECTOR res_service ; Reset Vector VECTOR mem_service ; Mem exception VECTOR instr_service ; Instrn Error VECTOR EV_MachineCheck ; Fatal Machine check VECTOR EV_TLBMissI ; Intruction TLB miss VECTOR EV_TLBMissD ; Data TLB miss VECTOR EV_TLBProtV ; Protection Violation VECTOR EV_PrivilegeV ; Privilege Violation VECTOR EV_SWI ; Software Breakpoint VECTOR EV_Trap ; Trap exception VECTOR EV_Extension ; Extn Instruction Exception VECTOR EV_DivZero ; Divide by Zero VECTOR EV_DCError ; Data Cache Error VECTOR EV_Misaligned ; Misaligned Data Access VECTOR reserved ; Reserved slots VECTOR reserved ; Reserved slots # Begin Interrupt Vectors VECTOR handle_interrupt ; (16) Timer0 VECTOR handle_interrupt ; unused (Timer1) VECTOR handle_interrupt ; unused (WDT) VECTOR handle_interrupt ; (19) Inter core Interrupt (IPI) VECTOR handle_interrupt ; (20) perf Interrupt VECTOR handle_interrupt ; (21) Software Triggered Intr (Self IPI) VECTOR handle_interrupt ; unused VECTOR handle_interrupt ; (23) unused # End of fixed IRQs .rept NR_CPU_IRQS - 8 VECTOR handle_interrupt .endr .section .text, "ax",@progbits reserved: flag 1 ; Unexpected event, halt ;##################### Interrupt Handling ############################## ENTRY(handle_interrupt) INTERRUPT_PROLOGUE irq # irq control APIs local_irq_save/restore/disable/enable fiddle with # global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio) # However a taken interrupt doesn't clear these bits. Thus irqs_disabled() # query in hard ISR path would return false (since .IE is set) which would # trips genirq interrupt handling asserts. # # So do a "soft" disable of interrutps here. # # Note this disable is only for consistent book-keeping as further interrupts # will be disabled anyways even w/o this. Hardware tracks active interrupts # seperately in AUX_IRQ_ACTIVE.active and will not take new interrupts # unless this one returns (or higher prio becomes pending in 2-prio scheme) IRQ_DISABLE ; icause is banked: one per priority level ; so a higher prio interrupt taken here won't clobber prev prio icause lr r0, [ICAUSE] mov blink, ret_from_exception b.d arch_do_IRQ mov r1, sp END(handle_interrupt) ;################### Non TLB Exception Handling ############################# ENTRY(EV_SWI) ; TODO: implement this EXCEPTION_PROLOGUE b ret_from_exception END(EV_SWI) ENTRY(EV_DivZero) ; TODO: implement this EXCEPTION_PROLOGUE b ret_from_exception END(EV_DivZero) ENTRY(EV_DCError) ; TODO: implement this EXCEPTION_PROLOGUE b ret_from_exception END(EV_DCError) ; --------------------------------------------- ; Memory Error Exception Handler ; - Unlike ARCompact, handles Bus errors for both User/Kernel mode, ; Instruction fetch or Data access, under a single Exception Vector ; --------------------------------------------- ENTRY(mem_service) EXCEPTION_PROLOGUE lr r0, [efa] mov r1, sp FAKE_RET_FROM_EXCPN bl do_memory_error b ret_from_exception END(mem_service) ENTRY(EV_Misaligned) EXCEPTION_PROLOGUE lr r0, [efa] ; Faulting Data address mov r1, sp FAKE_RET_FROM_EXCPN SAVE_CALLEE_SAVED_USER mov r2, sp ; callee_regs bl do_misaligned_access ; TBD: optimize - do this only if a callee reg was involved ; either a dst of emulated LD/ST or src with address-writeback RESTORE_CALLEE_SAVED_USER b ret_from_exception END(EV_Misaligned) ; --------------------------------------------- ; Protection Violation Exception Handler ; --------------------------------------------- ENTRY(EV_TLBProtV) EXCEPTION_PROLOGUE lr r0, [efa] ; Faulting Data address mov r1, sp ; pt_regs FAKE_RET_FROM_EXCPN mov blink, ret_from_exception b do_page_fault END(EV_TLBProtV) ; From Linux standpoint Slow Path I/D TLB Miss is same a ProtV as they ; need to call do_page_fault(). ; ECR in pt_regs provides whether access was R/W/X .global call_do_page_fault .set call_do_page_fault, EV_TLBProtV ;############# Common Handlers for ARCompact and ARCv2 ############## #include "entry.S" ;############# Return from Intr/Excp/Trap (ARCv2 ISA Specifics) ############## ; ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap) ; IRQ shd definitely not happen between now and rtie ; All 2 entry points to here already disable interrupts .Lrestore_regs: restore_regs: # Interrpts are actually disabled from this point on, but will get # reenabled after we return from interrupt/exception. # But irq tracer needs to be told now... TRACE_ASM_IRQ_ENABLE ld r0, [sp, PT_status32] ; U/K mode at time of entry lr r10, [AUX_IRQ_ACT] bmsk r11, r10, 15 ; AUX_IRQ_ACT.ACTIVE breq r11, 0, .Lexcept_ret ; No intr active, ret from Exception ;####### Return from Intr ####### debug_marker_l1: bbit1.nt r0, STATUS_DE_BIT, .Lintr_ret_to_delay_slot .Lisr_ret_fast_path: ; Handle special case #1: (Entry via Exception, Return via IRQ) ; ; Exception in U mode, preempted in kernel, Intr taken (K mode), orig ; task now returning to U mode (riding the Intr) ; AUX_IRQ_ACTIVE won't have U bit set (since intr in K mode), hence SP ; won't be switched to correct U mode value (from AUX_SP) ; So force AUX_IRQ_ACT.U for such a case btst r0, STATUS_U_BIT ; Z flag set if K (Z clear for U) bset.nz r11, r11, AUX_IRQ_ACT_BIT_U ; NZ means U sr r11, [AUX_IRQ_ACT] INTERRUPT_EPILOGUE irq rtie ;####### Return from Exception / pure kernel mode ####### .Lexcept_ret: ; Expects r0 has PT_status32 debug_marker_syscall: EXCEPTION_EPILOGUE rtie ;####### Return from Intr to insn in delay slot ####### ; Handle special case #2: (Entry via Exception in Delay Slot, Return via IRQ) ; ; Intr returning to a Delay Slot (DS) insn ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig ; entry was via Exception in DS which got preempted in kernel). ; ; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround ; ; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline ; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly .Lintr_ret_to_delay_slot: debug_marker_ds: ld r2, [@intr_to_DE_cnt] add r2, r2, 1 st r2, [@intr_to_DE_cnt] ld r2, [sp, PT_ret] ld r3, [sp, PT_status32] ; STAT32 for Int return created from scratch ; (No delay dlot, disable Further intr in trampoline) bic r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK st r0, [sp, PT_status32] mov r1, .Lintr_ret_to_delay_slot_2 st r1, [sp, PT_ret] ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots st r2, [sp, 0] st r3, [sp, 4] b .Lisr_ret_fast_path .Lintr_ret_to_delay_slot_2: ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP sub sp, sp, SZ_PT_REGS st r9, [sp, -4] ld r9, [sp, 0] sr r9, [eret] ld r9, [sp, 4] sr r9, [erstatus] ; restore AUX_USER_SP if returning to U mode bbit0 r9, STATUS_U_BIT, 1f ld r9, [sp, PT_sp] sr r9, [AUX_USER_SP] 1: ld r9, [sp, 8] sr r9, [erbta] ld r9, [sp, -4] add sp, sp, SZ_PT_REGS ; return from pure kernel mode to delay slot rtie END(ret_from_exception) |