root/arch/arc/kernel/entry-compact.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-only */
   2 /*
   3  * Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARCompact ISA
   4  *
   5  * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
   6  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   7  *
   8  * vineetg: May 2011
   9  *  -Userspace unaligned access emulation
  10  *
  11  * vineetg: Feb 2011 (ptrace low level code fixes)
  12  *  -traced syscall return code (r0) was not saved into pt_regs for restoring
  13  *   into user reg-file when traded task rets to user space.
  14  *  -syscalls needing arch-wrappers (mainly for passing sp as pt_regs)
  15  *   were not invoking post-syscall trace hook (jumping directly into
  16  *   ret_from_system_call)
  17  *
  18  * vineetg: Nov 2010:
  19  *  -Vector table jumps (@8 bytes) converted into branches (@4 bytes)
  20  *  -To maintain the slot size of 8 bytes/vector, added nop, which is
  21  *   not executed at runtime.
  22  *
  23  * vineetg: Nov 2009 (Everything needed for TIF_RESTORE_SIGMASK)
  24  *  -do_signal()invoked upon TIF_RESTORE_SIGMASK as well
  25  *  -Wrappers for sys_{,rt_}sigsuspend() no longer needed as they don't
  26  *   need ptregs anymore
  27  *
  28  * Vineetg: Oct 2009
  29  *  -In a rare scenario, Process gets a Priv-V exception and gets scheduled
  30  *   out. Since we don't do FAKE RTIE for Priv-V, CPU exception state remains
  31  *   active (AE bit enabled).  This causes a double fault for a subseq valid
  32  *   exception. Thus FAKE RTIE needed in low level Priv-Violation handler.
  33  *   Instr Error could also cause similar scenario, so same there as well.
  34  *
  35  * Vineetg: March 2009 (Supporting 2 levels of Interrupts)
  36  *
  37  * Vineetg: Aug 28th 2008: Bug #94984
  38  *  -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap
  39  *   Normally CPU does this automatically, however when doing FAKE rtie,
  40  *   we need to explicitly do this. The problem in macros
  41  *   FAKE_RET_FROM_EXCPN and FAKE_RET_FROM_EXCPN_LOCK_IRQ was that this bit
  42  *   was being "CLEARED" rather then "SET". Since it is Loop INHIBIT Bit,
  43  *   setting it and not clearing it clears ZOL context
  44  *
  45  * Vineetg: May 16th, 2008
  46  *  - r25 now contains the Current Task when in kernel
  47  *
  48  * Vineetg: Dec 22, 2007
  49  *    Minor Surgery of Low Level ISR to make it SMP safe
  50  *    - MMU_SCRATCH0 Reg used for freeing up r9 in Level 1 ISR
  51  *    - _current_task is made an array of NR_CPUS
  52  *    - Access of _current_task wrapped inside a macro so that if hardware
  53  *       team agrees for a dedicated reg, no other code is touched
  54  *
  55  * Amit Bhor, Rahul Trivedi, Kanika Nema, Sameer Dhavale : Codito Tech 2004
  56  */
  57 
  58 #include <linux/errno.h>
  59 #include <linux/linkage.h>      /* {ENTRY,EXIT} */
  60 #include <asm/entry.h>
  61 #include <asm/irqflags.h>
  62 
  63         .cpu A7
  64 
  65 ;############################ Vector Table #################################
  66 
  67 .macro VECTOR  lbl
  68 #if 1   /* Just in case, build breaks */
  69         j   \lbl
  70 #else
  71         b   \lbl
  72         nop
  73 #endif
  74 .endm
  75 
  76         .section .vector, "ax",@progbits
  77         .align 4
  78 
  79 /* Each entry in the vector table must occupy 2 words. Since it is a jump
  80  * across sections (.vector to .text) we are guaranteed that 'j somewhere'
  81  * will use the 'j limm' form of the instruction as long as somewhere is in
  82  * a section other than .vector.
  83  */
  84 
  85 ; ********* Critical System Events **********************
  86 VECTOR   res_service             ; 0x0, Reset Vector    (0x0)
  87 VECTOR   mem_service             ; 0x8, Mem exception   (0x1)
  88 VECTOR   instr_service           ; 0x10, Instrn Error   (0x2)
  89 
  90 ; ******************** Device ISRs **********************
  91 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
  92 VECTOR   handle_interrupt_level2
  93 #else
  94 VECTOR   handle_interrupt_level1
  95 #endif
  96 
  97 .rept   28
  98 VECTOR   handle_interrupt_level1 ; Other devices
  99 .endr
 100 
 101 /* FOR ARC600: timer = 0x3, uart = 0x8, emac = 0x10 */
 102 
 103 ; ******************** Exceptions **********************
 104 VECTOR   EV_MachineCheck         ; 0x100, Fatal Machine check   (0x20)
 105 VECTOR   EV_TLBMissI             ; 0x108, Instruction TLB miss  (0x21)
 106 VECTOR   EV_TLBMissD             ; 0x110, Data TLB miss         (0x22)
 107 VECTOR   EV_TLBProtV             ; 0x118, Protection Violation  (0x23)
 108                                  ;         or Misaligned Access
 109 VECTOR   EV_PrivilegeV           ; 0x120, Privilege Violation   (0x24)
 110 VECTOR   EV_Trap                 ; 0x128, Trap exception        (0x25)
 111 VECTOR   EV_Extension            ; 0x130, Extn Instruction Excp (0x26)
 112 
 113 .rept   24
 114 VECTOR   reserved                ; Reserved Exceptions
 115 .endr
 116 
 117 
 118 ;##################### Scratch Mem for IRQ stack switching #############
 119 
 120 ARCFP_DATA int1_saved_reg
 121         .align 32
 122         .type   int1_saved_reg, @object
 123         .size   int1_saved_reg, 4
 124 int1_saved_reg:
 125         .zero 4
 126 
 127 /* Each Interrupt level needs its own scratch */
 128 ARCFP_DATA int2_saved_reg
 129         .type   int2_saved_reg, @object
 130         .size   int2_saved_reg, 4
 131 int2_saved_reg:
 132         .zero 4
 133 
 134 ; ---------------------------------------------
 135         .section .text, "ax",@progbits
 136 
 137 
 138 reserved:
 139         flag 1          ; Unexpected event, halt
 140 
 141 ;##################### Interrupt Handling ##############################
 142 
 143 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 144 ; ---------------------------------------------
 145 ;  Level 2 ISR: Can interrupt a Level 1 ISR
 146 ; ---------------------------------------------
 147 ENTRY(handle_interrupt_level2)
 148 
 149         INTERRUPT_PROLOGUE 2
 150 
 151         ;------------------------------------------------------
 152         ; if L2 IRQ interrupted a L1 ISR, disable preemption
 153         ;
 154         ; This is to avoid a potential L1-L2-L1 scenario
 155         ;  -L1 IRQ taken
 156         ;  -L2 interrupts L1 (before L1 ISR could run)
 157         ;  -preemption off IRQ, user task in syscall picked to run
 158         ;  -RTIE to userspace
 159         ;       Returns from L2 context fine
 160         ;       But both L1 and L2 re-enabled, so another L1 can be taken
 161         ;       while prev L1 is still unserviced
 162         ;
 163         ;------------------------------------------------------
 164 
 165         ; L2 interrupting L1 implies both L2 and L1 active
 166         ; However both A2 and A1 are NOT set in STATUS32, thus
 167         ; need to check STATUS32_L2 to determine if L1 was active
 168 
 169         ld r9, [sp, PT_status32]        ; get statu32_l2 (saved in pt_regs)
 170         bbit0 r9, STATUS_A1_BIT, 1f     ; L1 not active when L2 IRQ, so normal
 171 
 172         ; bump thread_info->preempt_count (Disable preemption)
 173         GET_CURR_THR_INFO_FROM_SP   r10
 174         ld      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 175         add     r9, r9, 1
 176         st      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 177 
 178 1:
 179         ;------------------------------------------------------
 180         ; setup params for Linux common ISR and invoke it
 181         ;------------------------------------------------------
 182         lr  r0, [icause2]
 183         and r0, r0, 0x1f
 184 
 185         bl.d  @arch_do_IRQ
 186         mov r1, sp
 187 
 188         mov r8,0x2
 189         sr r8, [AUX_IRQ_LV12]       ; clear bit in Sticky Status Reg
 190 
 191         b   ret_from_exception
 192 
 193 END(handle_interrupt_level2)
 194 
 195 #endif
 196 
 197 ; ---------------------------------------------
 198 ; User Mode Memory Bus Error Interrupt Handler
 199 ; (Kernel mode memory errors handled via separate exception vectors)
 200 ; ---------------------------------------------
 201 ENTRY(mem_service)
 202 
 203         INTERRUPT_PROLOGUE 2
 204 
 205         mov r0, ilink2
 206         mov r1, sp
 207 
 208         ; User process needs to be killed with SIGBUS, but first need to get
 209         ; out of the L2 interrupt context (drop to pure kernel mode) and jump
 210         ; off to "C" code where SIGBUS in enqueued
 211         lr  r3, [status32]
 212         bclr r3, r3, STATUS_A2_BIT
 213         or  r3, r3, (STATUS_E1_MASK|STATUS_E2_MASK)
 214         sr  r3, [status32_l2]
 215         mov ilink2, 1f
 216         rtie
 217 1:
 218         bl  do_memory_error
 219         b   ret_from_exception
 220 END(mem_service)
 221 
 222 ; ---------------------------------------------
 223 ;  Level 1 ISR
 224 ; ---------------------------------------------
 225 ENTRY(handle_interrupt_level1)
 226 
 227         INTERRUPT_PROLOGUE 1
 228 
 229         lr  r0, [icause1]
 230         and r0, r0, 0x1f
 231 
 232 #ifdef CONFIG_TRACE_IRQFLAGS
 233         ; icause1 needs to be read early, before calling tracing, which
 234         ; can clobber scratch regs, hence use of stack to stash it
 235         push r0
 236         TRACE_ASM_IRQ_DISABLE
 237         pop  r0
 238 #endif
 239 
 240         bl.d  @arch_do_IRQ
 241         mov r1, sp
 242 
 243         mov r8,0x1
 244         sr r8, [AUX_IRQ_LV12]       ; clear bit in Sticky Status Reg
 245 
 246         b   ret_from_exception
 247 END(handle_interrupt_level1)
 248 
 249 ;################### Non TLB Exception Handling #############################
 250 
 251 ; ---------------------------------------------
 252 ; Protection Violation Exception Handler
 253 ; ---------------------------------------------
 254 
 255 ENTRY(EV_TLBProtV)
 256 
 257         EXCEPTION_PROLOGUE
 258 
 259         mov r2, r10     ; ECR set into r10 already
 260         lr  r0, [efa]   ; Faulting Data address (not part of pt_regs saved above)
 261 
 262         ; Exception auto-disables further Intr/exceptions.
 263         ; Re-enable them by pretending to return from exception
 264         ; (so rest of handler executes in pure K mode)
 265 
 266         FAKE_RET_FROM_EXCPN
 267 
 268         mov   r1, sp    ; Handle to pt_regs
 269 
 270         ;------ (5) Type of Protection Violation? ----------
 271         ;
 272         ; ProtV Hardware Exception is triggered for Access Faults of 2 types
 273         ;   -Access Violation   : 00_23_(00|01|02|03)_00
 274         ;                                x  r  w  r+w
 275         ;   -Unaligned Access   : 00_23_04_00
 276         ;
 277         bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
 278 
 279         ;========= (6a) Access Violation Processing ========
 280         bl  do_page_fault
 281         b   ret_from_exception
 282 
 283         ;========== (6b) Non aligned access ============
 284 4:
 285 
 286         SAVE_CALLEE_SAVED_USER
 287         mov r2, sp              ; callee_regs
 288 
 289         bl  do_misaligned_access
 290 
 291         ; TBD: optimize - do this only if a callee reg was involved
 292         ; either a dst of emulated LD/ST or src with address-writeback
 293         RESTORE_CALLEE_SAVED_USER
 294 
 295         b   ret_from_exception
 296 
 297 END(EV_TLBProtV)
 298 
 299 ; Wrapper for Linux page fault handler called from EV_TLBMiss*
 300 ; Very similar to ProtV handler case (6a) above, but avoids the extra checks
 301 ; for Misaligned access
 302 ;
 303 ENTRY(call_do_page_fault)
 304 
 305         EXCEPTION_PROLOGUE
 306         lr  r0, [efa]   ; Faulting Data address
 307         mov   r1, sp
 308         FAKE_RET_FROM_EXCPN
 309 
 310         mov blink, ret_from_exception
 311         b  do_page_fault
 312 
 313 END(call_do_page_fault)
 314 
 315 ;############# Common Handlers for ARCompact and ARCv2 ##############
 316 
 317 #include "entry.S"
 318 
 319 ;############# Return from Intr/Excp/Trap (ARC Specifics) ##############
 320 ;
 321 ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
 322 ; IRQ shd definitely not happen between now and rtie
 323 ; All 2 entry points to here already disable interrupts
 324 
 325 .Lrestore_regs:
 326 
 327         # Interrupts are actually disabled from this point on, but will get
 328         # reenabled after we return from interrupt/exception.
 329         # But irq tracer needs to be told now...
 330         TRACE_ASM_IRQ_ENABLE
 331 
 332         lr      r10, [status32]
 333 
 334         ; Restore REG File. In case multiple Events outstanding,
 335         ; use the same priority as rtie: EXCPN, L2 IRQ, L1 IRQ, None
 336         ; Note that we use realtime STATUS32 (not pt_regs->status32) to
 337         ; decide that.
 338 
 339         and.f   0, r10, (STATUS_A1_MASK|STATUS_A2_MASK)
 340         bz      .Lexcep_or_pure_K_ret
 341 
 342         ; Returning from Interrupts (Level 1 or 2)
 343 
 344 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 345 
 346         ; Level 2 interrupt return Path - from hardware standpoint
 347         bbit0  r10, STATUS_A2_BIT, not_level2_interrupt
 348 
 349         ;------------------------------------------------------------------
 350         ; However the context returning might not have taken L2 intr itself
 351         ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
 352         ; Special considerations needed for the context which took L2 intr
 353 
 354         ld   r9, [sp, PT_event]        ; Ensure this is L2 intr context
 355         brne r9, event_IRQ2, 149f
 356 
 357         ;------------------------------------------------------------------
 358         ; if L2 IRQ interrupted an L1 ISR,  we'd disabled preemption earlier
 359         ; so that sched doesn't move to new task, causing L1 to be delayed
 360         ; undeterministically. Now that we've achieved that, let's reset
 361         ; things to what they were, before returning from L2 context
 362         ;----------------------------------------------------------------
 363 
 364         ld r9, [sp, PT_status32]       ; get statu32_l2 (saved in pt_regs)
 365         bbit0 r9, STATUS_A1_BIT, 149f  ; L1 not active when L2 IRQ, so normal
 366 
 367         ; decrement thread_info->preempt_count (re-enable preemption)
 368         GET_CURR_THR_INFO_FROM_SP   r10
 369         ld      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 370 
 371         ; paranoid check, given A1 was active when A2 happened, preempt count
 372         ; must not be 0 because we would have incremented it.
 373         ; If this does happen we simply HALT as it means a BUG !!!
 374         cmp     r9, 0
 375         bnz     2f
 376         flag 1
 377 
 378 2:
 379         sub     r9, r9, 1
 380         st      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 381 
 382 149:
 383         INTERRUPT_EPILOGUE 2    ; return from level 2 interrupt
 384 debug_marker_l2:
 385         rtie
 386 
 387 not_level2_interrupt:
 388 
 389 #endif
 390 
 391         INTERRUPT_EPILOGUE 1    ; return from level 1 interrupt
 392 debug_marker_l1:
 393         rtie
 394 
 395 .Lexcep_or_pure_K_ret:
 396 
 397         ;this case is for syscalls or Exceptions or pure kernel mode
 398 
 399         EXCEPTION_EPILOGUE
 400 debug_marker_syscall:
 401         rtie
 402 
 403 END(ret_from_exception)

/* [<][>][^][v][top][bottom][index][help] */