Back to home page

LXR

 
 

    


0001 /*
0002  *  linux/arch/m32r/kernel/entry.S
0003  *
0004  *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
0005  *  Copyright (c) 2003  Hitoshi Yamamoto
0006  *  Copyright (c) 2004  Hirokazu Takata <takata at linux-m32r.org>
0007  *
0008  *  Taken from i386 version.
0009  *    Copyright (C) 1991, 1992  Linus Torvalds
0010  */
0011 
0012 /*
0013  * entry.S contains the system-call and fault low-level handling routines.
0014  * This also contains the timer-interrupt handler, as well as all interrupts
0015  * and faults that can result in a task-switch.
0016  *
0017  * NOTE: This code handles signal-recognition, which happens every time
0018  * after a timer-interrupt and after each system call.
0019  *
0020  * Stack layout in 'ret_from_system_call':
0021  *  ptrace needs to have all regs on the stack.
0022  *  if the order here is changed, it needs to be
0023  *  updated in fork.c:copy_thread, signal.c:do_signal,
0024  *  ptrace.c and ptrace.h
0025  *
0026  * M32R/M32Rx/M32R2
0027  *       @(sp)      - r4
0028  *       @(0x04,sp) - r5
0029  *       @(0x08,sp) - r6
0030  *       @(0x0c,sp) - *pt_regs
0031  *       @(0x10,sp) - r0
0032  *       @(0x14,sp) - r1
0033  *       @(0x18,sp) - r2
0034  *       @(0x1c,sp) - r3
0035  *       @(0x20,sp) - r7
0036  *       @(0x24,sp) - r8
0037  *       @(0x28,sp) - r9
0038  *       @(0x2c,sp) - r10
0039  *       @(0x30,sp) - r11
0040  *       @(0x34,sp) - r12
0041  *       @(0x38,sp) - syscall_nr
0042  *       @(0x3c,sp) - acc0h
0043  *       @(0x40,sp) - acc0l
0044  *       @(0x44,sp) - acc1h     ; ISA_DSP_LEVEL2 only
0045  *       @(0x48,sp) - acc1l     ; ISA_DSP_LEVEL2 only
0046  *       @(0x4c,sp) - psw
0047  *       @(0x50,sp) - bpc
0048  *       @(0x54,sp) - bbpsw
0049  *       @(0x58,sp) - bbpc
0050  *       @(0x5c,sp) - spu (cr3)
0051  *       @(0x60,sp) - fp (r13)
0052  *       @(0x64,sp) - lr (r14)
0053  *       @(0x68,sp) - spi (cr2)
0054  *       @(0x6c,sp) - orig_r0
0055  */
0056 
0057 #include <linux/linkage.h>
0058 #include <asm/irq.h>
0059 #include <asm/unistd.h>
0060 #include <asm/assembler.h>
0061 #include <asm/thread_info.h>
0062 #include <asm/errno.h>
0063 #include <asm/segment.h>
0064 #include <asm/smp.h>
0065 #include <asm/page.h>
0066 #include <asm/m32r.h>
0067 #include <asm/mmu_context.h>
0068 #include <asm/asm-offsets.h>
0069 
0070 #if !defined(CONFIG_MMU)
0071 #define sys_madvise     sys_ni_syscall
0072 #define sys_readahead       sys_ni_syscall
0073 #define sys_mprotect        sys_ni_syscall
0074 #define sys_msync       sys_ni_syscall
0075 #define sys_mlock       sys_ni_syscall
0076 #define sys_munlock     sys_ni_syscall
0077 #define sys_mlockall        sys_ni_syscall
0078 #define sys_munlockall      sys_ni_syscall
0079 #define sys_mremap      sys_ni_syscall
0080 #define sys_mincore     sys_ni_syscall
0081 #define sys_remap_file_pages    sys_ni_syscall
0082 #endif /* CONFIG_MMU */
0083 
0084 #define R4(reg)         @reg
0085 #define R5(reg)         @(0x04,reg)
0086 #define R6(reg)         @(0x08,reg)
0087 #define PTREGS(reg)     @(0x0C,reg)
0088 #define R0(reg)         @(0x10,reg)
0089 #define R1(reg)         @(0x14,reg)
0090 #define R2(reg)         @(0x18,reg)
0091 #define R3(reg)         @(0x1C,reg)
0092 #define R7(reg)         @(0x20,reg)
0093 #define R8(reg)         @(0x24,reg)
0094 #define R9(reg)         @(0x28,reg)
0095 #define R10(reg)        @(0x2C,reg)
0096 #define R11(reg)        @(0x30,reg)
0097 #define R12(reg)        @(0x34,reg)
0098 #define SYSCALL_NR(reg)     @(0x38,reg)
0099 #define ACC0H(reg)      @(0x3C,reg)
0100 #define ACC0L(reg)      @(0x40,reg)
0101 #define ACC1H(reg)      @(0x44,reg)
0102 #define ACC1L(reg)      @(0x48,reg)
0103 #define PSW(reg)        @(0x4C,reg)
0104 #define BPC(reg)        @(0x50,reg)
0105 #define BBPSW(reg)      @(0x54,reg)
0106 #define BBPC(reg)       @(0x58,reg)
0107 #define SPU(reg)        @(0x5C,reg)
0108 #define FP(reg)         @(0x60,reg)  /* FP = R13 */
0109 #define LR(reg)         @(0x64,reg)
0110 #define SP(reg)         @(0x68,reg)
0111 #define ORIG_R0(reg)        @(0x6C,reg)
0112 
0113 #define nr_syscalls ((syscall_table_size)/4)
0114 
0115 #ifdef CONFIG_PREEMPT
0116 #define preempt_stop(x)     DISABLE_INTERRUPTS(x)
0117 #else
0118 #define preempt_stop(x)
0119 #define resume_kernel       restore_all
0120 #endif
0121 
0122 /* how to get the thread information struct from ASM */
0123 #define GET_THREAD_INFO(reg)    GET_THREAD_INFO reg
0124     .macro GET_THREAD_INFO reg
0125     ldi \reg, #-THREAD_SIZE
0126     and \reg, sp
0127     .endm
0128 
0129 ENTRY(ret_from_kernel_thread)
0130     pop r0
0131     bl  schedule_tail
0132     GET_THREAD_INFO(r8)
0133     ld  r0, R0(r8)
0134     ld  r1, R1(r8)
0135     jl  r1
0136     bra syscall_exit
0137 
0138 ENTRY(ret_from_fork)
0139     pop r0
0140     bl  schedule_tail
0141     GET_THREAD_INFO(r8)
0142     bra syscall_exit
0143 
0144 /*
0145  * Return to user mode is not as complex as all this looks,
0146  * but we want the default path for a system call return to
0147  * go as quickly as possible which is why some of this is
0148  * less clear than it otherwise should be.
0149  */
0150 
0151     ; userspace resumption stub bypassing syscall exit tracing
0152     ALIGN
0153 ret_from_exception:
0154     preempt_stop(r4)
0155 ret_from_intr:
0156     ld  r4, PSW(sp)
0157 #ifdef CONFIG_ISA_M32R2
0158     and3    r4, r4, #0x8800     ; check BSM and BPM bits
0159 #else
0160     and3    r4, r4, #0x8000     ; check BSM bit
0161 #endif
0162     beqz    r4, resume_kernel
0163 resume_userspace:
0164     DISABLE_INTERRUPTS(r4)      ; make sure we don't miss an interrupt
0165                     ; setting need_resched or sigpending
0166                     ; between sampling and the iret
0167     GET_THREAD_INFO(r8)
0168     ld  r9, @(TI_FLAGS, r8)
0169     and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
0170                     ; int/exception return?
0171     bnez    r4, work_pending
0172     bra restore_all
0173 
0174 #ifdef CONFIG_PREEMPT
0175 ENTRY(resume_kernel)
0176     GET_THREAD_INFO(r8)
0177     ld  r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
0178     bnez    r9, restore_all
0179 need_resched:
0180     ld  r9, @(TI_FLAGS, r8) ; need_resched set ?
0181     and3    r4, r9, #_TIF_NEED_RESCHED
0182     beqz    r4, restore_all
0183     ld  r4, PSW(sp)     ; interrupts off (exception path) ?
0184     and3    r4, r4, #0x4000
0185     beqz    r4, restore_all
0186     bl  preempt_schedule_irq
0187     bra need_resched
0188 #endif
0189 
0190     ; system call handler stub
0191 ENTRY(system_call)
0192     SWITCH_TO_KERNEL_STACK
0193     SAVE_ALL
0194     ENABLE_INTERRUPTS(r4)       ; Enable interrupt
0195     st  sp, PTREGS(sp)      ; implicit pt_regs parameter
0196     cmpui   r7, #NR_syscalls
0197     bnc syscall_badsys
0198     st  r7, SYSCALL_NR(sp)  ; syscall_nr
0199                     ; system call tracing in operation
0200     GET_THREAD_INFO(r8)
0201     ld  r9, @(TI_FLAGS, r8)
0202     and3    r4, r9, #_TIF_SYSCALL_TRACE
0203     bnez    r4, syscall_trace_entry
0204 syscall_call:
0205     slli    r7, #2          ; table jump for the system call
0206     LDIMM   (r4, sys_call_table)
0207     add r7, r4
0208     ld  r7, @r7
0209     jl  r7          ; execute system call
0210     st  r0, R0(sp)      ; save the return value
0211 syscall_exit:
0212     DISABLE_INTERRUPTS(r4)      ; make sure we don't miss an interrupt
0213                     ; setting need_resched or sigpending
0214                     ; between sampling and the iret
0215     ld  r9, @(TI_FLAGS, r8)
0216     and3    r4, r9, #_TIF_ALLWORK_MASK  ; current->work
0217     bnez    r4, syscall_exit_work
0218 restore_all:
0219     RESTORE_ALL
0220 
0221     # perform work that needs to be done immediately before resumption
0222     # r9 : flags
0223     ALIGN
0224 work_pending:
0225     and3    r4, r9, #_TIF_NEED_RESCHED
0226     beqz    r4, work_notifysig
0227 work_resched:
0228     bl  schedule
0229     DISABLE_INTERRUPTS(r4)      ; make sure we don't miss an interrupt
0230                     ; setting need_resched or sigpending
0231                     ; between sampling and the iret
0232     ld  r9, @(TI_FLAGS, r8)
0233     and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
0234                     ; than syscall tracing?
0235     beqz    r4, restore_all
0236     and3    r4, r4, #_TIF_NEED_RESCHED
0237     bnez    r4, work_resched
0238 
0239 work_notifysig:             ; deal with pending signals and
0240                     ; notify-resume requests
0241     mv  r0, sp          ; arg1 : struct pt_regs *regs
0242     mv  r1, r9          ; arg2 : __u32 thread_info_flags
0243     bl  do_notify_resume
0244     bra resume_userspace
0245 
0246     ; perform syscall exit tracing
0247     ALIGN
0248 syscall_trace_entry:
0249     ldi r4, #-ENOSYS
0250     st  r4, R0(sp)
0251     bl  do_syscall_trace
0252     ld  r0, ORIG_R0(sp)
0253     ld  r1, R1(sp)
0254     ld  r2, R2(sp)
0255     ld  r3, R3(sp)
0256     ld  r4, R4(sp)
0257     ld  r5, R5(sp)
0258     ld  r6, R6(sp)
0259     ld  r7, SYSCALL_NR(sp)
0260     cmpui   r7, #NR_syscalls
0261     bc  syscall_call
0262     bra syscall_exit
0263 
0264     ; perform syscall exit tracing
0265     ALIGN
0266 syscall_exit_work:
0267     ld  r9, @(TI_FLAGS, r8)
0268     and3    r4, r9, #_TIF_SYSCALL_TRACE
0269     beqz    r4, work_pending
0270     ENABLE_INTERRUPTS(r4)       ; could let do_syscall_trace() call
0271                     ; schedule() instead
0272     bl  do_syscall_trace
0273     bra resume_userspace
0274 
0275     ALIGN
0276 syscall_fault:
0277     SAVE_ALL
0278     GET_THREAD_INFO(r8)
0279     ldi r4, #-EFAULT
0280     st  r4, R0(sp)
0281     bra resume_userspace
0282 
0283     ALIGN
0284 syscall_badsys:
0285     ldi r4, #-ENOSYS
0286     st  r4, R0(sp)
0287     bra resume_userspace
0288 
0289     .global eit_vector
0290 
0291     .equ ei_vec_table, eit_vector + 0x0200
0292 
0293 /*
0294  * EI handler routine
0295  */
0296 ENTRY(ei_handler)
0297 #if defined(CONFIG_CHIP_M32700)
0298     ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
0299     SWITCH_TO_KERNEL_STACK
0300 #endif
0301     SAVE_ALL
0302     mv  r1, sp          ; arg1(regs)
0303     ; get ICU status
0304     seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
0305     ld  r0, @(low(M32R_ICU_ISTS_ADDR),r0)
0306     push    r0
0307 #if defined(CONFIG_SMP)
0308     /*
0309      * If IRQ == 0      --> Nothing to do,  Not write IMASK
0310      * If IRQ == IPI    --> Do IPI handler, Not write IMASK
0311      * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
0312      */
0313     slli    r0, #4
0314     srli    r0, #24         ; r0(irq_num<<2)
0315     ;; IRQ exist check
0316 #if defined(CONFIG_CHIP_M32700)
0317     /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
0318     bnez    r0, 0f
0319     ld24    r14, #0x00070000
0320     seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
0321     st  r14, @(low(M32R_ICU_IMASK_ADDR),r0)
0322     bra 1f
0323     .fillinsn
0324 0:
0325 #endif /* CONFIG_CHIP_M32700 */
0326     beqz    r0, 1f          ; if (!irq_num) goto exit
0327     ;; IPI check
0328     cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
0329     bc  2f
0330     cmpi    r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check
0331     bnc 2f
0332     LDIMM   (r2, ei_vec_table)
0333     add r2, r0
0334     ld  r2, @r2
0335     beqz    r2, 1f          ; if (no IPI handler) goto exit
0336     mv  r0, r1          ; arg0(regs)
0337     jl  r2
0338     .fillinsn
0339 1:
0340     addi    sp, #4
0341     bra restore_all
0342     .fillinsn
0343 2:
0344     srli    r0, #2
0345 #else /* not CONFIG_SMP */
0346     srli    r0, #22         ; r0(irq)
0347 #endif /* not CONFIG_SMP */
0348 
0349 #if defined(CONFIG_PLAT_HAS_INT1ICU)
0350     add3    r2, r0, #-(M32R_IRQ_INT1)   ; INT1# interrupt
0351     bnez    r2, 3f
0352     seth    r0, #shigh(M32R_INT1ICU_ISTS)
0353     lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)    ; bit10-6 : ISN
0354     slli    r0, #21
0355     srli    r0, #27             ; ISN
0356     addi    r0, #(M32R_INT1ICU_IRQ_BASE)
0357     bra check_end
0358     .fillinsn
0359 3:
0360 #endif /* CONFIG_PLAT_HAS_INT1ICU */
0361 #if defined(CONFIG_PLAT_HAS_INT0ICU)
0362     add3    r2, r0, #-(M32R_IRQ_INT0)   ; INT0# interrupt
0363     bnez    r2, 4f
0364     seth    r0, #shigh(M32R_INT0ICU_ISTS)
0365     lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)    ; bit10-6 : ISN
0366     slli    r0, #21
0367     srli    r0, #27             ; ISN
0368     add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
0369     bra check_end
0370     .fillinsn
0371 4:
0372 #endif /* CONFIG_PLAT_HAS_INT0ICU */
0373 #if defined(CONFIG_PLAT_HAS_INT2ICU)
0374     add3    r2, r0, #-(M32R_IRQ_INT2)   ; INT2# interrupt
0375     bnez    r2, 5f
0376     seth    r0, #shigh(M32R_INT2ICU_ISTS)
0377     lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)    ; bit10-6 : ISN
0378     slli    r0, #21
0379     srli    r0, #27             ; ISN
0380     add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
0381     ; bra   check_end
0382     .fillinsn
0383 5:
0384 #endif /* CONFIG_PLAT_HAS_INT2ICU */
0385 
0386 check_end:
0387     bl  do_IRQ
0388     pop r14
0389     seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
0390     st  r14, @(low(M32R_ICU_IMASK_ADDR),r0)
0391     bra  ret_from_intr
0392 
0393 /*
0394  * Default EIT handler
0395  */
0396     ALIGN
0397 int_msg:
0398     .asciz  "Unknown interrupt\n"
0399     .byte   0
0400 
0401 ENTRY(default_eit_handler)
0402     push    r0
0403     mvfc    r0, psw
0404     push    r1
0405     push    r2
0406     push    r3
0407     push    r0
0408     LDIMM   (r0, __KERNEL_DS)
0409     mv  r0, r1
0410     mv  r0, r2
0411     LDIMM   (r0, int_msg)
0412     bl  printk
0413     pop r0
0414     pop r3
0415     pop r2
0416     pop r1
0417     mvtc    r0, psw
0418     pop r0
0419 infinit:
0420     bra infinit
0421 
0422 #ifdef CONFIG_MMU
0423 /*
0424  * Access Exception handler
0425  */
0426 ENTRY(ace_handler)
0427     SWITCH_TO_KERNEL_STACK
0428     SAVE_ALL
0429 
0430     seth    r2, #shigh(MMU_REG_BASE)    /* Check status register */
0431     ld  r4, @(low(MESTS_offset),r2)
0432     st  r4, @(low(MESTS_offset),r2)
0433     srl3    r1, r4, #4
0434 #ifdef CONFIG_CHIP_M32700
0435     and3    r1, r1, #0x0000ffff
0436     ; WORKAROUND: ignore TME bit for the M32700(TS1).
0437 #endif /* CONFIG_CHIP_M32700 */
0438     beqz    r1, inst
0439 oprand:
0440     ld  r2, @(low(MDEVA_offset),r2) ; set address
0441     srli    r1, #1
0442     bra 1f
0443 inst:
0444     and3    r1, r4, #2
0445     srli    r1, #1
0446     or3 r1, r1, #8
0447     mvfc    r2, bpc             ; set address
0448     .fillinsn
0449 1:
0450     mvfc    r3, psw
0451     mv  r0, sp
0452     and3    r3, r3, 0x800
0453     srli    r3, #9
0454     or  r1, r3
0455     /*
0456      * do_page_fault():
0457      *    r0 : struct pt_regs *regs
0458      *    r1 : unsigned long error-code
0459      *    r2 : unsigned long address
0460      * error-code:
0461      *    +------+------+------+------+
0462      *    | bit3 | bit2 | bit1 | bit0 |
0463      *    +------+------+------+------+
0464      *    bit 3 == 0:means data,          1:means instruction
0465      *    bit 2 == 0:means kernel,        1:means user-mode
0466      *    bit 1 == 0:means read,          1:means write
0467      *    bit 0 == 0:means no page found  1:means protection fault
0468      *
0469      */
0470     bl  do_page_fault
0471     bra ret_from_intr
0472 #endif  /* CONFIG_MMU */
0473 
0474 
0475 ENTRY(alignment_check)
0476     /* void alignment_check(int error_code) */
0477     SWITCH_TO_KERNEL_STACK
0478     SAVE_ALL
0479     ldi r1, #0x30           ; error_code
0480     mv  r0, sp              ; pt_regs
0481     bl  do_alignment_check
0482 error_code:
0483     bra ret_from_exception
0484 
0485 ENTRY(rie_handler)
0486     /* void rie_handler(int error_code) */
0487     SWITCH_TO_KERNEL_STACK
0488     SAVE_ALL
0489     ldi r1, #0x20           ; error_code
0490     mv  r0, sp              ; pt_regs
0491     bl  do_rie_handler
0492     bra error_code
0493 
0494 ENTRY(pie_handler)
0495     /* void pie_handler(int error_code) */
0496     SWITCH_TO_KERNEL_STACK
0497     SAVE_ALL
0498     ldi r1, #0              ; error_code ; FIXME
0499     mv  r0, sp              ; pt_regs
0500     bl  do_pie_handler
0501     bra error_code
0502 
0503 ENTRY(debug_trap)
0504     /* void debug_trap(void) */
0505     .global withdraw_debug_trap
0506     SWITCH_TO_KERNEL_STACK
0507     SAVE_ALL
0508     mv  r0, sp              ; pt_regs
0509     bl  withdraw_debug_trap
0510     ldi r1, #0              ; error_code
0511     mv  r0, sp              ; pt_regs
0512     bl  do_debug_trap
0513     bra error_code
0514 
0515 ENTRY(ill_trap)
0516     /* void ill_trap(void) */
0517     SWITCH_TO_KERNEL_STACK
0518     SAVE_ALL
0519     ldi r1, #0              ; error_code ; FIXME
0520     mv  r0, sp              ; pt_regs
0521     bl  do_ill_trap
0522     bra error_code
0523 
0524 ENTRY(cache_flushing_handler)
0525     /* void _flush_cache_all(void); */
0526     .global _flush_cache_all
0527     SWITCH_TO_KERNEL_STACK
0528     push    r0
0529     push    r1
0530     push    r2
0531     push    r3
0532     push    r4
0533     push    r5
0534     push    r6
0535     push    r7
0536     push    lr
0537     bl  _flush_cache_all
0538     pop lr
0539     pop r7
0540     pop r6
0541     pop r5
0542     pop r4
0543     pop r3
0544     pop r2
0545     pop r1
0546     pop r0
0547     rte
0548 
0549     .section .rodata,"a"
0550 #include "syscall_table.S"
0551 
0552 syscall_table_size=(.-sys_call_table)