0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 #include <linux/errno.h>
0059 #include <linux/linkage.h> /* {ENTRY,EXIT} */
0060 #include <asm/entry.h>
0061 #include <asm/irqflags.h>
0062
0063 .cpu A7
0064
0065 ;############################ Vector Table #################################
0066
0067 .macro VECTOR lbl
0068 #if 1
0069 j \lbl
0070 #else
0071 b \lbl
0072 nop
0073 #endif
0074 .endm
0075
0076 .section .vector, "ax",@progbits
0077 .align 4
0078
0079
0080
0081
0082
0083
0084
0085 ; ********* Critical System Events **********************
0086 VECTOR res_service ; 0x0, Reset Vector (0x0)
0087 VECTOR mem_service ; 0x8, Mem exception (0x1)
0088 VECTOR instr_service ; 0x10, Instrn Error (0x2)
0089
0090 ; ******************** Device ISRs **********************
0091 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
0092 VECTOR handle_interrupt_level2
0093 #else
0094 VECTOR handle_interrupt_level1
0095 #endif
0096
0097 .rept 28
0098 VECTOR handle_interrupt_level1 ; Other devices
0099 .endr
0100
0101
0102
0103 ; ******************** Exceptions **********************
0104 VECTOR EV_MachineCheck ; 0x100, Fatal Machine check (0x20)
0105 VECTOR EV_TLBMissI ; 0x108, Instruction TLB miss (0x21)
0106 VECTOR EV_TLBMissD ; 0x110, Data TLB miss (0x22)
0107 VECTOR EV_TLBProtV ; 0x118, Protection Violation (0x23)
0108 ; or Misaligned Access
0109 VECTOR EV_PrivilegeV ; 0x120, Privilege Violation (0x24)
0110 VECTOR EV_Trap ; 0x128, Trap exception (0x25)
0111 VECTOR EV_Extension ; 0x130, Extn Instruction Excp (0x26)
0112
0113 .rept 24
0114 VECTOR reserved ; Reserved Exceptions
0115 .endr
0116
0117
0118 ;##################### Scratch Mem for IRQ stack switching #############
0119
0120 ARCFP_DATA int1_saved_reg
0121 .align 32
0122 .type int1_saved_reg, @object
0123 .size int1_saved_reg, 4
0124 int1_saved_reg:
0125 .zero 4
0126
0127
0128 ARCFP_DATA int2_saved_reg
0129 .type int2_saved_reg, @object
0130 .size int2_saved_reg, 4
0131 int2_saved_reg:
0132 .zero 4
0133
0134 ; ---------------------------------------------
0135 .section .text, "ax",@progbits
0136
0137
0138 reserved:
0139 flag 1 ; Unexpected event, halt
0140
0141 ;##################### Interrupt Handling ##############################
0142
0143 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
0144 ; ---------------------------------------------
0145 ; Level 2 ISR: Can interrupt a Level 1 ISR
0146 ; ---------------------------------------------
0147 ENTRY(handle_interrupt_level2)
0148
0149 INTERRUPT_PROLOGUE 2
0150
0151 ;------------------------------------------------------
0152 ; if L2 IRQ interrupted a L1 ISR, disable preemption
0153 ;
0154 ; This is to avoid a potential L1-L2-L1 scenario
0155 ; -L1 IRQ taken
0156 ; -L2 interrupts L1 (before L1 ISR could run)
0157 ; -preemption off IRQ, user task in syscall picked to run
0158 ; -RTIE to userspace
0159 ; Returns from L2 context fine
0160 ; But both L1 and L2 re-enabled, so another L1 can be taken
0161 ; while prev L1 is still unserviced
0162 ;
0163 ;------------------------------------------------------
0164
0165 ; L2 interrupting L1 implies both L2 and L1 active
0166 ; However both A2 and A1 are NOT set in STATUS32, thus
0167 ; need to check STATUS32_L2 to determine if L1 was active
0168
0169 ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
0170 bbit0 r9, STATUS_A1_BIT, 1f ; L1 not active when L2 IRQ, so normal
0171
0172 ; bump thread_info->preempt_count (Disable preemption)
0173 GET_CURR_THR_INFO_FROM_SP r10
0174 ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
0175 add r9, r9, 1
0176 st r9, [r10, THREAD_INFO_PREEMPT_COUNT]
0177
0178 1:
0179 ;------------------------------------------------------
0180 ; setup params for Linux common ISR and invoke it
0181 ;------------------------------------------------------
0182 lr r0, [icause2]
0183 and r0, r0, 0x1f
0184
0185 bl.d @arch_do_IRQ
0186 mov r1, sp
0187
0188 mov r8,0x2
0189 sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg
0190
0191 b ret_from_exception
0192
0193 END(handle_interrupt_level2)
0194
0195 #endif
0196
0197 ; ---------------------------------------------
0198 ; User Mode Memory Bus Error Interrupt Handler
0199 ; (Kernel mode memory errors handled via separate exception vectors)
0200 ; ---------------------------------------------
0201 ENTRY(mem_service)
0202
0203 INTERRUPT_PROLOGUE 2
0204
0205 mov r0, ilink2
0206 mov r1, sp
0207
0208 ; User process needs to be killed with SIGBUS, but first need to get
0209 ; out of the L2 interrupt context (drop to pure kernel mode) and jump
0210 ; off to "C" code where SIGBUS in enqueued
0211 lr r3, [status32]
0212 bclr r3, r3, STATUS_A2_BIT
0213 or r3, r3, (STATUS_E1_MASK|STATUS_E2_MASK)
0214 sr r3, [status32_l2]
0215 mov ilink2, 1f
0216 rtie
0217 1:
0218 bl do_memory_error
0219 b ret_from_exception
0220 END(mem_service)
0221
0222 ; ---------------------------------------------
0223 ; Level 1 ISR
0224 ; ---------------------------------------------
0225 ENTRY(handle_interrupt_level1)
0226
0227 INTERRUPT_PROLOGUE 1
0228
0229 lr r0, [icause1]
0230 and r0, r0, 0x1f
0231
0232 #ifdef CONFIG_TRACE_IRQFLAGS
0233 ; icause1 needs to be read early, before calling tracing, which
0234 ; can clobber scratch regs, hence use of stack to stash it
0235 push r0
0236 TRACE_ASM_IRQ_DISABLE
0237 pop r0
0238 #endif
0239
0240 bl.d @arch_do_IRQ
0241 mov r1, sp
0242
0243 mov r8,0x1
0244 sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg
0245
0246 b ret_from_exception
0247 END(handle_interrupt_level1)
0248
0249 ;################### Non TLB Exception Handling #############################
0250
0251 ; ---------------------------------------------
0252 ; Protection Violation Exception Handler
0253 ; ---------------------------------------------
0254
0255 ENTRY(EV_TLBProtV)
0256
0257 EXCEPTION_PROLOGUE
0258
0259 mov r2, r10 ; ECR set into r10 already
0260 lr r0, [efa] ; Faulting Data address (not part of pt_regs saved above)
0261
0262 ; Exception auto-disables further Intr/exceptions.
0263 ; Re-enable them by pretending to return from exception
0264 ; (so rest of handler executes in pure K mode)
0265
0266 FAKE_RET_FROM_EXCPN
0267
0268 mov r1, sp ; Handle to pt_regs
0269
0270 ;------ (5) Type of Protection Violation? ----------
0271 ;
0272 ; ProtV Hardware Exception is triggered for Access Faults of 2 types
0273 ; -Access Violation : 00_23_(00|01|02|03)_00
0274 ; x r w r+w
0275 ; -Unaligned Access : 00_23_04_00
0276 ;
0277 bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
0278
0279 ;========= (6a) Access Violation Processing ========
0280 bl do_page_fault
0281 b ret_from_exception
0282
0283 ;========== (6b) Non aligned access ============
0284 4:
0285
0286 SAVE_CALLEE_SAVED_USER
0287 mov r2, sp ; callee_regs
0288
0289 bl do_misaligned_access
0290
0291 ; TBD: optimize - do this only if a callee reg was involved
0292 ; either a dst of emulated LD/ST or src with address-writeback
0293 RESTORE_CALLEE_SAVED_USER
0294
0295 b ret_from_exception
0296
0297 END(EV_TLBProtV)
0298
0299 ; Wrapper for Linux page fault handler called from EV_TLBMiss*
0300 ; Very similar to ProtV handler case (6a) above, but avoids the extra checks
0301 ; for Misaligned access
0302 ;
0303 ENTRY(call_do_page_fault)
0304
0305 EXCEPTION_PROLOGUE
0306 lr r0, [efa] ; Faulting Data address
0307 mov r1, sp
0308 FAKE_RET_FROM_EXCPN
0309
0310 mov blink, ret_from_exception
0311 b do_page_fault
0312
0313 END(call_do_page_fault)
0314
0315 ;############# Common Handlers for ARCompact and ARCv2 ##############
0316
0317 #include "entry.S"
0318
0319 ;############# Return from Intr/Excp/Trap (ARC Specifics) ##############
0320 ;
0321 ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
0322 ; IRQ shd definitely not happen between now and rtie
0323 ; All 2 entry points to here already disable interrupts
0324
0325 .Lrestore_regs:
0326
0327 # Interrupts are actually disabled from this point on, but will get
0328 # reenabled after we return from interrupt/exception.
0329 # But irq tracer needs to be told now...
0330 TRACE_ASM_IRQ_ENABLE
0331
0332 lr r10, [status32]
0333
0334 ; Restore REG File. In case multiple Events outstanding,
0335 ; use the same priority as rtie: EXCPN, L2 IRQ, L1 IRQ, None
0336 ; Note that we use realtime STATUS32 (not pt_regs->status32) to
0337 ; decide that.
0338
0339 and.f 0, r10, (STATUS_A1_MASK|STATUS_A2_MASK)
0340 bz .Lexcep_or_pure_K_ret
0341
0342 ; Returning from Interrupts (Level 1 or 2)
0343
0344 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
0345
0346 ; Level 2 interrupt return Path - from hardware standpoint
0347 bbit0 r10, STATUS_A2_BIT, not_level2_interrupt
0348
0349 ;------------------------------------------------------------------
0350 ; However the context returning might not have taken L2 intr itself
0351 ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
0352 ; Special considerations needed for the context which took L2 intr
0353
0354 ld r9, [sp, PT_event] ; Ensure this is L2 intr context
0355 brne r9, event_IRQ2, 149f
0356
0357 ;------------------------------------------------------------------
0358 ; if L2 IRQ interrupted an L1 ISR, we'd disabled preemption earlier
0359 ; so that sched doesn't move to new task, causing L1 to be delayed
0360 ; undeterministically. Now that we've achieved that, let's reset
0361 ; things to what they were, before returning from L2 context
0362 ;----------------------------------------------------------------
0363
0364 ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
0365 bbit0 r9, STATUS_A1_BIT, 149f ; L1 not active when L2 IRQ, so normal
0366
0367 ; decrement thread_info->preempt_count (re-enable preemption)
0368 GET_CURR_THR_INFO_FROM_SP r10
0369 ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
0370
0371 ; paranoid check, given A1 was active when A2 happened, preempt count
0372 ; must not be 0 because we would have incremented it.
0373 ; If this does happen we simply HALT as it means a BUG !!!
0374 cmp r9, 0
0375 bnz 2f
0376 flag 1
0377
0378 2:
0379 sub r9, r9, 1
0380 st r9, [r10, THREAD_INFO_PREEMPT_COUNT]
0381
0382 149:
0383 INTERRUPT_EPILOGUE 2 ; return from level 2 interrupt
0384 debug_marker_l2:
0385 rtie
0386
0387 not_level2_interrupt:
0388
0389 #endif
0390
0391 INTERRUPT_EPILOGUE 1 ; return from level 1 interrupt
0392 debug_marker_l1:
0393 rtie
0394
0395 .Lexcep_or_pure_K_ret:
0396
0397 ;this case is for syscalls or Exceptions or pure kernel mode
0398
0399 EXCEPTION_EPILOGUE
0400 debug_marker_syscall:
0401 rtie
0402
0403 END(ret_from_exception)