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