| 1 |
|
| 2 | |
| 3 | * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
|
| 4 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
|
| 5 | *
|
| 6 | * Vineetg: March 2009 (Supporting 2 levels of Interrupts)
|
| 7 | * Stack switching code can no longer reliably rely on the fact that
|
| 8 | * if we are NOT in user mode, stack is switched to kernel mode.
|
| 9 | * e.g. L2 IRQ interrupted a L1 ISR which had not yet completed
|
| 10 | * its prologue including stack switching from user mode
|
| 11 | *
|
| 12 | * Vineetg: Aug 28th 2008: Bug #94984
|
| 13 | * -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap
|
| 14 | * Normally CPU does this automatically, however when doing FAKE rtie,
|
| 15 | * we also need to explicitly do this. The problem in macros
|
| 16 | * FAKE_RET_FROM_EXCPN and FAKE_RET_FROM_EXCPN_LOCK_IRQ was that this bit
|
| 17 | * was being "CLEARED" rather then "SET". Actually "SET" clears ZOL context
|
| 18 | *
|
| 19 | * Vineetg: May 5th 2008
|
| 20 | * -Modified CALLEE_REG save/restore macros to handle the fact that
|
| 21 | * r25 contains the kernel current task ptr
|
| 22 | * - Defined Stack Switching Macro to be reused in all intr/excp hdlrs
|
| 23 | * - Shaved off 11 instructions from RESTORE_ALL_INT1 by using the
|
| 24 | * address Write back load ld.ab instead of separate ld/add instn
|
| 25 | *
|
| 26 | * Amit Bhor, Sameer Dhavale: Codito Technologies 2004
|
| 27 |
|
| 28 |
|
| 29 | #ifndef __ASM_ARC_ENTRY_COMPACT_H
|
| 30 | #define __ASM_ARC_ENTRY_COMPACT_H
|
| 31 |
|
| 32 | #include <asm/asm-offsets.h>
|
| 33 | #include <asm/irqflags-compact.h>
|
| 34 | #include <asm/thread_info.h>
|
| 35 |
|
| 36 | |
| 37 | *
|
| 38 | * LD.a same as LD.aw
|
| 39 | *
|
| 40 | * LD.a reg1, [reg2, x] => Pre Incr
|
| 41 | * Eff Addr for load = [reg2 + x]
|
| 42 | *
|
| 43 | * LD.ab reg1, [reg2, x] => Post Incr
|
| 44 | * Eff Addr for load = [reg2]
|
| 45 |
|
| 46 |
|
| 47 | .macro PUSHAX aux
|
| 48 | lr r9, [\aux]
|
| 49 | push r9
|
| 50 | .endm
|
| 51 |
|
| 52 | .macro POPAX aux
|
| 53 | pop r9
|
| 54 | sr r9, [\aux]
|
| 55 | .endm
|
| 56 |
|
| 57 | .macro SAVE_R0_TO_R12
|
| 58 | push r0
|
| 59 | push r1
|
| 60 | push r2
|
| 61 | push r3
|
| 62 | push r4
|
| 63 | push r5
|
| 64 | push r6
|
| 65 | push r7
|
| 66 | push r8
|
| 67 | push r9
|
| 68 | push r10
|
| 69 | push r11
|
| 70 | push r12
|
| 71 | .endm
|
| 72 |
|
| 73 | .macro RESTORE_R12_TO_R0
|
| 74 | pop r12
|
| 75 | pop r11
|
| 76 | pop r10
|
| 77 | pop r9
|
| 78 | pop r8
|
| 79 | pop r7
|
| 80 | pop r6
|
| 81 | pop r5
|
| 82 | pop r4
|
| 83 | pop r3
|
| 84 | pop r2
|
| 85 | pop r1
|
| 86 | pop r0
|
| 87 | .endm
|
| 88 |
|
| 89 | .macro SAVE_ABI_CALLEE_REGS
|
| 90 | push r13
|
| 91 | push r14
|
| 92 | push r15
|
| 93 | push r16
|
| 94 | push r17
|
| 95 | push r18
|
| 96 | push r19
|
| 97 | push r20
|
| 98 | push r21
|
| 99 | push r22
|
| 100 | push r23
|
| 101 | push r24
|
| 102 | push r25
|
| 103 | .endm
|
| 104 |
|
| 105 | .macro RESTORE_ABI_CALLEE_REGS
|
| 106 | pop r25
|
| 107 | pop r24
|
| 108 | pop r23
|
| 109 | pop r22
|
| 110 | pop r21
|
| 111 | pop r20
|
| 112 | pop r19
|
| 113 | pop r18
|
| 114 | pop r17
|
| 115 | pop r16
|
| 116 | pop r15
|
| 117 | pop r14
|
| 118 | pop r13
|
| 119 | .endm
|
| 120 |
|
| 121 | |
| 122 | * Switch to Kernel Mode stack if SP points to User Mode stack
|
| 123 | *
|
| 124 | * Entry : r9 contains pre-IRQ/exception/trap status32
|
| 125 | * Exit : SP set to K mode stack
|
| 126 | * SP at the time of entry (K/U) saved @ pt_regs->sp
|
| 127 | * Clobbers: r9
|
| 128 | *-------------------------------------------------------------
|
| 129 |
|
| 130 | .macro SWITCH_TO_KERNEL_STK
|
| 131 |
|
| 132 |
|
| 133 | bbit1 r9, STATUS_U_BIT, 88f
|
| 134 |
|
| 135 | |
| 136 | * assume SP is kernel mode SP. _NO_ need to do any stack switching
|
| 137 |
|
| 138 |
|
| 139 | #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
|
| 140 | |
| 141 | * If Level 2 Interrupts enabled, we may end up with a corner case:
|
| 142 | * 1. User Task executing
|
| 143 | * 2. L1 IRQ taken, ISR starts (CPU auto-switched to KERNEL mode)
|
| 144 | * 3. But before it could switch SP from USER to KERNEL stack
|
| 145 | * a L2 IRQ "Interrupts" L1
|
| 146 | * That way although L2 IRQ happened in Kernel mode, stack is still
|
| 147 | * not switched.
|
| 148 | * To handle this, we may need to switch stack even if in kernel mode
|
| 149 | * provided SP has values in range of USER mode stack ( < 0x7000_0000 )
|
| 150 |
|
| 151 | brlo sp, VMALLOC_START, 88f
|
| 152 |
|
| 153 | |
| 154 | * We need to be a bit more cautious here. What if a kernel bug in
|
| 155 | * L1 ISR, caused SP to go whaco (some small value which looks like
|
| 156 | * USER stk) and then we take L2 ISR.
|
| 157 | * Above brlo alone would treat it as a valid L1-L2 scenario
|
| 158 | * instead of shouting around
|
| 159 | * The only feasible way is to make sure this L2 happened in
|
| 160 | * L1 prelogue ONLY i.e. ilink2 is less than a pre-set marker in
|
| 161 | * L1 ISR before it switches stack
|
| 162 |
|
| 163 |
|
| 164 | #endif
|
| 165 |
|
| 166 |
|
| 167 |
|
| 168 |
|
| 169 | b.d 66f
|
| 170 | st sp, [sp, PT_sp - SZ_PT_REGS]
|
| 171 |
|
| 172 | 88:
|
| 173 |
|
| 174 | GET_CURR_TASK_ON_CPU r9
|
| 175 |
|
| 176 |
|
| 177 | GET_TSK_STACK_BASE r9, r9
|
| 178 |
|
| 179 |
|
| 180 | st sp, [r9, PT_sp - SZ_PT_REGS]
|
| 181 |
|
| 182 |
|
| 183 | mov sp, r9
|
| 184 | 66:
|
| 185 | .endm
|
| 186 |
|
| 187 | |
| 188 | * "FAKE" a rtie to return from CPU Exception context
|
| 189 | * This is to re-enable Exceptions within exception
|
| 190 | * Look at EV_ProtV to see how this is actually used
|
| 191 | *-------------------------------------------------------------
|
| 192 |
|
| 193 | .macro FAKE_RET_FROM_EXCPN
|
| 194 |
|
| 195 | lr r9, [status32]
|
| 196 | bclr r9, r9, STATUS_AE_BIT
|
| 197 | or r9, r9, (STATUS_E1_MASK|STATUS_E2_MASK)
|
| 198 | sr r9, [erstatus]
|
| 199 | mov r9, 55f
|
| 200 | sr r9, [eret]
|
| 201 | rtie
|
| 202 | 55:
|
| 203 | .endm
|
| 204 |
|
| 205 | |
| 206 | * For early Exception/ISR Prologue, a core reg is temporarily needed to
|
| 207 | * code the rest of prolog (stack switching). This is done by stashing
|
| 208 | * it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP).
|
| 209 | *
|
| 210 | * Before saving the full regfile - this reg is restored back, only
|
| 211 | * to be saved again on kernel mode stack, as part of pt_regs.
|
| 212 | *-------------------------------------------------------------
|
| 213 | .macro PROLOG_FREEUP_REG reg, mem
|
| 214 | st \reg, [\mem]
|
| 215 | .endm
|
| 216 |
|
| 217 | .macro PROLOG_RESTORE_REG reg, mem
|
| 218 | ld \reg, [\mem]
|
| 219 | .endm
|
| 220 |
|
| 221 | |
| 222 | * Exception Entry prologue
|
| 223 | * -Switches stack to K mode (if not already)
|
| 224 | * -Saves the register file
|
| 225 | *
|
| 226 | * After this it is safe to call the "C" handlers
|
| 227 | *-------------------------------------------------------------
|
| 228 | .macro EXCEPTION_PROLOGUE_KEEP_AE
|
| 229 |
|
| 230 |
|
| 231 | PROLOG_FREEUP_REG r9, @ex_saved_reg1
|
| 232 |
|
| 233 |
|
| 234 | lr r9, [erstatus]
|
| 235 |
|
| 236 |
|
| 237 | SWITCH_TO_KERNEL_STK
|
| 238 |
|
| 239 | st.a r0, [sp, -8]
|
| 240 | sub sp, sp, 4
|
| 241 |
|
| 242 |
|
| 243 | PROLOG_RESTORE_REG r9, @ex_saved_reg1
|
| 244 |
|
| 245 |
|
| 246 | SAVE_R0_TO_R12
|
| 247 | PUSH gp
|
| 248 | PUSH fp
|
| 249 | PUSH blink
|
| 250 | PUSHAX eret
|
| 251 | PUSHAX erstatus
|
| 252 | PUSH lp_count
|
| 253 | PUSHAX lp_end
|
| 254 | PUSHAX lp_start
|
| 255 | PUSHAX erbta
|
| 256 |
|
| 257 | lr r10, [ecr]
|
| 258 | st r10, [sp, PT_event]
|
| 259 |
|
| 260 | #ifdef CONFIG_ARC_CURR_IN_REG
|
| 261 |
|
| 262 | GET_CURR_TASK_ON_CPU gp
|
| 263 | #endif
|
| 264 | ; OUTPUT: r10 has ECR expected by EV_Trap
|
| 265 | .endm
|
| 266 |
|
| 267 | .macro EXCEPTION_PROLOGUE
|
| 268 |
|
| 269 | EXCEPTION_PROLOGUE_KEEP_AE ; return ECR in r10
|
| 270 |
|
| 271 | lr r0, [efa]
|
| 272 | mov r1, sp
|
| 273 |
|
| 274 | FAKE_RET_FROM_EXCPN ; clobbers r9
|
| 275 | .endm
|
| 276 |
|
| 277 | |
| 278 | * Restore all registers used by system call or Exceptions
|
| 279 | * SP should always be pointing to the next free stack element
|
| 280 | * when entering this macro.
|
| 281 | *
|
| 282 | * NOTE:
|
| 283 | *
|
| 284 | * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg
|
| 285 | * for memory load operations. If used in that way interrupts are deferred
|
| 286 | * by hardware and that is not good.
|
| 287 | *-------------------------------------------------------------
|
| 288 | .macro EXCEPTION_EPILOGUE
|
| 289 |
|
| 290 | POPAX erbta
|
| 291 | POPAX lp_start
|
| 292 | POPAX lp_end
|
| 293 |
|
| 294 | POP r9
|
| 295 | mov lp_count, r9 ;LD to lp_count is not allowed
|
| 296 |
|
| 297 | POPAX erstatus
|
| 298 | POPAX eret
|
| 299 | POP blink
|
| 300 | POP fp
|
| 301 | POP gp
|
| 302 | RESTORE_R12_TO_R0
|
| 303 |
|
| 304 | ld sp, [sp]
|
| 305 |
|
| 306 | .endm
|
| 307 |
|
| 308 |
|
| 309 | #define event_IRQ1 0x0031abcd
|
| 310 | #define event_IRQ2 0x0032abcd
|
| 311 |
|
| 312 | .macro INTERRUPT_PROLOGUE LVL
|
| 313 |
|
| 314 |
|
| 315 | PROLOG_FREEUP_REG r9, @int\LVL\()_saved_reg
|
| 316 |
|
| 317 |
|
| 318 | lr r9, [status32_l\LVL\()]
|
| 319 |
|
| 320 | SWITCH_TO_KERNEL_STK
|
| 321 |
|
| 322 |
|
| 323 | st.a 0x003\LVL\()abcd, [sp, -4]
|
| 324 | sub sp, sp, 8 |
| 325 | skip pt_regs->sp, already saved above
|
| 326 |
|
| 327 |
|
| 328 | PROLOG_RESTORE_REG r9, @int\LVL\()_saved_reg
|
| 329 |
|
| 330 | SAVE_R0_TO_R12
|
| 331 | PUSH gp
|
| 332 | PUSH fp
|
| 333 | PUSH blink
|
| 334 | PUSH ilink\LVL\()
|
| 335 | PUSHAX status32_l\LVL\()
|
| 336 | PUSH lp_count
|
| 337 | PUSHAX lp_end
|
| 338 | PUSHAX lp_start
|
| 339 | PUSHAX bta_l\LVL\()
|
| 340 |
|
| 341 | #ifdef CONFIG_ARC_CURR_IN_REG
|
| 342 |
|
| 343 | GET_CURR_TASK_ON_CPU gp
|
| 344 | #endif
|
| 345 | .endm
|
| 346 |
|
| 347 | |
| 348 | * Restore all registers used by interrupt handlers.
|
| 349 | *
|
| 350 | * NOTE:
|
| 351 | *
|
| 352 | * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg
|
| 353 | * for memory load operations. If used in that way interrupts are deferred
|
| 354 | * by hardware and that is not good.
|
| 355 | *-------------------------------------------------------------
|
| 356 | .macro INTERRUPT_EPILOGUE LVL
|
| 357 |
|
| 358 | POPAX bta_l\LVL\()
|
| 359 | POPAX lp_start
|
| 360 | POPAX lp_end
|
| 361 |
|
| 362 | POP r9
|
| 363 | mov lp_count, r9 ;LD to lp_count is not allowed
|
| 364 |
|
| 365 | POPAX status32_l\LVL\()
|
| 366 | POP ilink\LVL\()
|
| 367 | POP blink
|
| 368 | POP fp
|
| 369 | POP gp
|
| 370 | RESTORE_R12_TO_R0
|
| 371 |
|
| 372 | ld sp, [sp]
|
| 373 | .endm
|
| 374 |
|
| 375 |
|
| 376 | .macro GET_CURR_THR_INFO_FROM_SP reg
|
| 377 | bic \reg, sp, (THREAD_SIZE - 1)
|
| 378 | .endm
|
| 379 |
|
| 380 |
|
| 381 | .macro GET_CPU_ID reg
|
| 382 | lr \reg, [identity]
|
| 383 | lsr \reg, \reg, 8
|
| 384 | bmsk \reg, \reg, 7
|
| 385 | .endm
|
| 386 |
|
| 387 | #endif
|