Back to home page

LXR

 
 

    


0001 /*
0002  * arch/sh/kernel/cpu/sh3/entry.S
0003  *
0004  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
0005  *  Copyright (C) 2003 - 2012  Paul Mundt
0006  *
0007  * This file is subject to the terms and conditions of the GNU General Public
0008  * License.  See the file "COPYING" in the main directory of this archive
0009  * for more details.
0010  */
0011 #include <linux/sys.h>
0012 #include <linux/errno.h>
0013 #include <linux/linkage.h>
0014 #include <asm/asm-offsets.h>
0015 #include <asm/thread_info.h>
0016 #include <asm/unistd.h>
0017 #include <cpu/mmu_context.h>
0018 #include <asm/page.h>
0019 #include <asm/cache.h>
0020 #include <asm/thread_info.h>
0021 
0022 ! NOTE:
0023 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
0024 ! to be jumped is too far, but it causes illegal slot exception.
0025 
0026 /*  
0027  * entry.S contains the system-call and fault low-level handling routines.
0028  * This also contains the timer-interrupt handler, as well as all interrupts
0029  * and faults that can result in a task-switch.
0030  *
0031  * NOTE: This code handles signal-recognition, which happens every time
0032  * after a timer-interrupt and after each system call.
0033  *
0034  * NOTE: This code uses a convention that instructions in the delay slot
0035  * of a transfer-control instruction are indented by an extra space, thus:
0036  *
0037  *    jmp   @k0     ! control-transfer instruction
0038  *     ldc  k1, ssr     ! delay slot
0039  *
0040  * Stack layout in 'ret_from_syscall':
0041  *  ptrace needs to have all regs on the stack.
0042  *  if the order here is changed, it needs to be
0043  *  updated in ptrace.c and ptrace.h
0044  *
0045  *  r0
0046  *      ...
0047  *  r15 = stack pointer
0048  *  spc
0049  *  pr
0050  *  ssr
0051  *  gbr
0052  *  mach
0053  *  macl
0054  *  syscall #
0055  *
0056  */
0057 /* Offsets to the stack */
0058 OFF_R0  =  0        /* Return value. New ABI also arg4 */
0059 OFF_R1  =  4        /* New ABI: arg5 */
0060 OFF_R2  =  8        /* New ABI: arg6 */
0061 OFF_R3  =  12       /* New ABI: syscall_nr */
0062 OFF_R4  =  16       /* New ABI: arg0 */
0063 OFF_R5  =  20       /* New ABI: arg1 */
0064 OFF_R6  =  24       /* New ABI: arg2 */
0065 OFF_R7  =  28       /* New ABI: arg3 */
0066 OFF_SP  =  (15*4)
0067 OFF_PC  =  (16*4)
0068 OFF_SR  =  (16*4+8)
0069 OFF_TRA =  (16*4+6*4)
0070 
0071 #define k0  r0
0072 #define k1  r1
0073 #define k2  r2
0074 #define k3  r3
0075 #define k4  r4
0076 
0077 #define g_imask     r6  /* r6_bank1 */
0078 #define k_g_imask   r6_bank /* r6_bank1 */
0079 #define current     r7  /* r7_bank1 */
0080 
0081 #include <asm/entry-macros.S>
0082     
0083 /*
0084  * Kernel mode register usage:
0085  *  k0  scratch
0086  *  k1  scratch
0087  *  k2  scratch (Exception code)
0088  *  k3  scratch (Return address)
0089  *  k4  scratch
0090  *  k5  reserved
0091  *  k6  Global Interrupt Mask (0--15 << 4)
0092  *  k7  CURRENT_THREAD_INFO (pointer to current thread info)
0093  */
0094 
0095 !
0096 ! TLB Miss / Initial Page write exception handling
0097 !           _and_
0098 ! TLB hits, but the access violate the protection.
0099 ! It can be valid access, such as stack grow and/or C-O-W.
0100 !
0101 !
0102 ! Find the pmd/pte entry and loadtlb
0103 ! If it's not found, cause address error (SEGV)
0104 !
0105 ! Although this could be written in assembly language (and it'd be faster),
0106 ! this first version depends *much* on C implementation.
0107 !
0108 
0109 #if defined(CONFIG_MMU)
0110     .align  2
0111 ENTRY(tlb_miss_load)
0112     bra call_handle_tlbmiss
0113      mov    #0, r5
0114 
0115     .align  2
0116 ENTRY(tlb_miss_store)
0117     bra call_handle_tlbmiss
0118      mov    #FAULT_CODE_WRITE, r5
0119 
0120     .align  2
0121 ENTRY(initial_page_write)
0122     bra call_handle_tlbmiss
0123      mov    #FAULT_CODE_INITIAL, r5
0124 
0125     .align  2
0126 ENTRY(tlb_protection_violation_load)
0127     bra call_do_page_fault
0128      mov    #FAULT_CODE_PROT, r5
0129 
0130     .align  2
0131 ENTRY(tlb_protection_violation_store)
0132     bra call_do_page_fault
0133      mov    #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
0134 
0135 call_handle_tlbmiss:
0136     mov.l   1f, r0
0137     mov r5, r8
0138     mov.l   @r0, r6
0139     mov.l   2f, r0
0140     sts pr, r10
0141     jsr @r0
0142      mov    r15, r4
0143     !
0144     tst r0, r0
0145     bf/s    0f
0146      lds    r10, pr
0147     rts
0148      nop
0149 0:
0150     mov r8, r5
0151 call_do_page_fault:
0152     mov.l   1f, r0
0153     mov.l   @r0, r6
0154 
0155     mov.l   3f, r0
0156     mov.l   4f, r1
0157     mov r15, r4
0158     jmp @r0
0159      lds    r1, pr
0160 
0161     .align 2
0162 1:  .long   MMU_TEA
0163 2:  .long   handle_tlbmiss
0164 3:  .long   do_page_fault
0165 4:  .long   ret_from_exception
0166 
0167     .align  2
0168 ENTRY(address_error_load)
0169     bra call_dae
0170      mov    #0,r5       ! writeaccess = 0
0171 
0172     .align  2
0173 ENTRY(address_error_store)
0174     bra call_dae
0175      mov    #1,r5       ! writeaccess = 1
0176 
0177     .align  2
0178 call_dae:
0179     mov.l   1f, r0
0180     mov.l   @r0, r6     ! address
0181     mov.l   2f, r0
0182     jmp @r0
0183      mov    r15, r4     ! regs
0184 
0185     .align 2
0186 1:  .long   MMU_TEA
0187 2:  .long   do_address_error
0188 #endif /* CONFIG_MMU */
0189 
0190 #if defined(CONFIG_SH_STANDARD_BIOS)
0191     /* Unwind the stack and jmp to the debug entry */
0192 ENTRY(sh_bios_handler)
0193     mov.l   1f, r8
0194     bsr restore_regs
0195      nop
0196 
0197     lds k2, pr          ! restore pr
0198     mov k4, r15
0199     !
0200     mov.l   2f, k0
0201     mov.l   @k0, k0
0202     jmp @k0
0203      ldc    k3, ssr
0204     .align  2
0205 1:  .long   0x300000f0
0206 2:  .long   gdb_vbr_vector
0207 #endif /* CONFIG_SH_STANDARD_BIOS */
0208 
0209 ! restore_regs()
0210 ! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
0211 ! - switch bank
0212 ! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
0213 ! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
0214 ! k2 returns original pr
0215 ! k3 returns original sr
0216 ! k4 returns original stack pointer
0217 ! r8 passes SR bitmask, overwritten with restored data on return
0218 ! r9 trashed
0219 ! BL=0 on entry, on exit BL=1 (depending on r8).
0220 
0221 ENTRY(restore_regs)
0222     mov.l   @r15+, r0
0223     mov.l   @r15+, r1
0224     mov.l   @r15+, r2
0225     mov.l   @r15+, r3
0226     mov.l   @r15+, r4
0227     mov.l   @r15+, r5
0228     mov.l   @r15+, r6
0229     mov.l   @r15+, r7
0230     !
0231     stc sr, r9
0232     or  r8, r9
0233     ldc r9, sr
0234     !
0235     mov.l   @r15+, r8
0236     mov.l   @r15+, r9
0237     mov.l   @r15+, r10
0238     mov.l   @r15+, r11
0239     mov.l   @r15+, r12
0240     mov.l   @r15+, r13
0241     mov.l   @r15+, r14
0242     mov.l   @r15+, k4       ! original stack pointer
0243     ldc.l   @r15+, spc
0244     mov.l   @r15+, k2       ! original PR
0245     mov.l   @r15+, k3       ! original SR
0246     ldc.l   @r15+, gbr
0247     lds.l   @r15+, mach
0248     lds.l   @r15+, macl
0249     rts
0250      add    #4, r15         ! Skip syscall number
0251 
0252 restore_all:
0253     mov.l   7f, r8
0254     bsr restore_regs
0255      nop
0256 
0257     lds k2, pr          ! restore pr
0258     !
0259     ! Calculate new SR value
0260     mov k3, k2          ! original SR value
0261     mov #0xfffffff0, k1
0262     extu.b  k1, k1
0263     not k1, k1
0264     and k1, k2          ! Mask original SR value
0265     !
0266     mov k3, k0          ! Calculate IMASK-bits
0267     shlr2   k0
0268     and #0x3c, k0
0269     cmp/eq  #0x3c, k0
0270     bt/s    6f
0271      shll2  k0
0272     mov g_imask, k0
0273     !
0274 6:  or  k0, k2          ! Set the IMASK-bits
0275     ldc k2, ssr
0276     !
0277     mov k4, r15
0278     rte
0279      nop
0280 
0281     .align  2
0282 5:  .long   0x00001000  ! DSP
0283 7:  .long   0x30000000
0284 
0285 ! common exception handler
0286 #include "../../entry-common.S"
0287     
0288 ! Exception Vector Base
0289 !
0290 !   Should be aligned page boundary.
0291 !
0292     .balign     4096,0,4096
0293 ENTRY(vbr_base)
0294     .long   0
0295 !
0296 ! 0x100: General exception vector
0297 !
0298     .balign     256,0,256
0299 general_exception:
0300     bra handle_exception
0301      sts    pr, k3      ! save original pr value in k3
0302 
0303 ! prepare_stack()
0304 ! - roll back gRB
0305 ! - switch to kernel stack
0306 ! k0 returns original sp (after roll back)
0307 ! k1 trashed
0308 ! k2 trashed
0309 
0310 prepare_stack:
0311 #ifdef CONFIG_GUSA
0312     ! Check for roll back gRB (User and Kernel)
0313     mov r15, k0
0314     shll    k0
0315     bf/s    1f
0316      shll   k0
0317     bf/s    1f
0318      stc    spc, k1
0319     stc r0_bank, k0
0320     cmp/hs  k0, k1      ! test k1 (saved PC) >= k0 (saved r0)
0321     bt/s    2f
0322      stc    r1_bank, k1
0323 
0324     add #-2, k0
0325     add r15, k0
0326     ldc k0, spc     ! PC = saved r0 + r15 - 2
0327 2:  mov k1, r15     ! SP = r1
0328 1:
0329 #endif
0330     ! Switch to kernel stack if needed
0331     stc ssr, k0     ! Is it from kernel space?
0332     shll    k0      ! Check MD bit (bit30) by shifting it into...
0333     shll    k0      !       ...the T bit
0334     bt/s    1f      ! It's a kernel to kernel transition.
0335      mov    r15, k0     ! save original stack to k0
0336     /* User space to kernel */
0337     mov #(THREAD_SIZE >> 10), k1
0338     shll8   k1      ! k1 := THREAD_SIZE
0339     shll2   k1
0340     add current, k1
0341     mov k1, r15     ! change to kernel stack
0342     !
0343 1:
0344     rts
0345      nop
0346 
0347 !
0348 ! 0x400: Instruction and Data TLB miss exception vector
0349 !
0350     .balign     1024,0,1024
0351 tlb_miss:
0352     sts pr, k3      ! save original pr value in k3
0353 
0354 handle_exception:
0355     mova    exception_data, k0
0356 
0357     ! Setup stack and save DSP context (k0 contains original r15 on return)
0358     bsr prepare_stack
0359      PREF(k0)
0360 
0361     ! Save registers / Switch to bank 0
0362     mov.l   5f, k2      ! vector register address
0363     mov.l   1f, k4      ! SR bits to clear in k4
0364     bsr save_regs   ! needs original pr value in k3
0365      mov.l  @k2, k2     ! read out vector and keep in k2
0366 
0367 handle_exception_special:
0368     setup_frame_reg
0369 
0370     ! Setup return address and jump to exception handler
0371     mov.l   7f, r9      ! fetch return address
0372     stc r2_bank, r0 ! k2 (vector)
0373     mov.l   6f, r10
0374     shlr2   r0
0375     shlr    r0
0376     mov.l   @(r0, r10), r10
0377     jmp @r10
0378      lds    r9, pr      ! put return address in pr
0379 
0380     .align  L1_CACHE_SHIFT
0381 
0382 ! save_regs()
0383 ! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
0384 ! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
0385 ! - switch bank
0386 ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
0387 ! k0 contains original stack pointer*
0388 ! k1 trashed
0389 ! k3 passes original pr*
0390 ! k4 passes SR bitmask
0391 ! BL=1 on entry, on exit BL=0.
0392 
0393 ENTRY(save_regs)
0394     mov #-1, r1
0395     mov.l   k1, @-r15   ! set TRA (default: -1)
0396     sts.l   macl, @-r15
0397     sts.l   mach, @-r15
0398     stc.l   gbr, @-r15
0399     stc.l   ssr, @-r15
0400     mov.l   k3, @-r15   ! original pr in k3
0401     stc.l   spc, @-r15
0402 
0403     mov.l   k0, @-r15   ! original stack pointer in k0
0404     mov.l   r14, @-r15
0405     mov.l   r13, @-r15
0406     mov.l   r12, @-r15
0407     mov.l   r11, @-r15
0408     mov.l   r10, @-r15
0409     mov.l   r9, @-r15
0410     mov.l   r8, @-r15
0411 
0412     mov.l   0f, k3      ! SR bits to set in k3
0413 
0414     ! fall-through
0415 
0416 ! save_low_regs()
0417 ! - modify SR for bank switch
0418 ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
0419 ! k3 passes bits to set in SR
0420 ! k4 passes bits to clear in SR
0421 
0422 ENTRY(save_low_regs)
0423     stc sr, r8
0424     or  k3, r8
0425     and k4, r8
0426     ldc r8, sr
0427 
0428     mov.l   r7, @-r15
0429     mov.l   r6, @-r15
0430     mov.l   r5, @-r15
0431     mov.l   r4, @-r15
0432     mov.l   r3, @-r15
0433     mov.l   r2, @-r15
0434     mov.l   r1, @-r15
0435     rts
0436      mov.l  r0, @-r15
0437 
0438 !
0439 ! 0x600: Interrupt / NMI vector
0440 !
0441     .balign     512,0,512
0442 ENTRY(handle_interrupt)
0443     sts pr, k3      ! save original pr value in k3
0444     mova    exception_data, k0
0445 
0446     ! Setup stack and save DSP context (k0 contains original r15 on return)
0447     bsr prepare_stack
0448      PREF(k0)
0449 
0450     ! Save registers / Switch to bank 0
0451     mov.l   1f, k4      ! SR bits to clear in k4
0452     bsr save_regs   ! needs original pr value in k3
0453      mov    #-1, k2     ! default vector kept in k2
0454 
0455     setup_frame_reg
0456 
0457     stc sr, r0  ! get status register
0458     shlr2   r0
0459     and #0x3c, r0
0460     cmp/eq  #0x3c, r0
0461     bf  9f
0462     TRACE_IRQS_OFF
0463 9:
0464 
0465     ! Setup return address and jump to do_IRQ
0466     mov.l   4f, r9      ! fetch return address
0467     lds r9, pr      ! put return address in pr
0468     mov.l   2f, r4
0469     mov.l   3f, r9
0470     mov.l   @r4, r4     ! pass INTEVT vector as arg0
0471 
0472     shlr2   r4
0473     shlr    r4
0474     mov r4, r0      ! save vector->jmp table offset for later
0475 
0476     shlr2   r4      ! vector to IRQ# conversion
0477     add #-0x10, r4
0478 
0479     cmp/pz  r4      ! is it a valid IRQ?
0480     bt  10f
0481 
0482     /*
0483      * We got here as a result of taking the INTEVT path for something
0484      * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
0485      * path and special case the event dispatch instead.  This is the
0486      * expected path for the NMI (and any other brilliantly implemented
0487      * exception), which effectively wants regular exception dispatch
0488      * but is unfortunately reported through INTEVT rather than
0489      * EXPEVT.  Grr.
0490      */
0491     mov.l   6f, r9
0492     mov.l   @(r0, r9), r9
0493     jmp @r9
0494      mov    r15, r8     ! trap handlers take saved regs in r8
0495 
0496 10:
0497     jmp @r9     ! Off to do_IRQ() we go.
0498      mov    r15, r5     ! pass saved registers as arg1
0499 
0500 ENTRY(exception_none)
0501     rts
0502      nop
0503 
0504     .align  L1_CACHE_SHIFT
0505 exception_data:
0506 0:  .long   0x000080f0  ! FD=1, IMASK=15
0507 1:  .long   0xcfffffff  ! RB=0, BL=0
0508 2:  .long   INTEVT
0509 3:  .long   do_IRQ
0510 4:  .long   ret_from_irq
0511 5:  .long   EXPEVT
0512 6:  .long   exception_handling_table
0513 7:  .long   ret_from_exception