linux/arch/m32r/kernel/entry.S
<<
>>
Prefs
   1/*
   2 *  linux/arch/m32r/kernel/entry.S
   3 *
   4 *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
   5 *  Copyright (c) 2003  Hitoshi Yamamoto
   6 *  Copyright (c) 2004  Hirokazu Takata <takata at linux-m32r.org>
   7 *
   8 *  Taken from i386 version.
   9 *    Copyright (C) 1991, 1992  Linus Torvalds
  10 */
  11
  12/*
  13 * entry.S contains the system-call and fault low-level handling routines.
  14 * This also contains the timer-interrupt handler, as well as all interrupts
  15 * and faults that can result in a task-switch.
  16 *
  17 * NOTE: This code handles signal-recognition, which happens every time
  18 * after a timer-interrupt and after each system call.
  19 *
  20 * Stack layout in 'ret_from_system_call':
  21 *      ptrace needs to have all regs on the stack.
  22 *      if the order here is changed, it needs to be
  23 *      updated in fork.c:copy_thread, signal.c:do_signal,
  24 *      ptrace.c and ptrace.h
  25 *
  26 * M32R/M32Rx/M32R2
  27 *       @(sp)      - r4
  28 *       @(0x04,sp) - r5
  29 *       @(0x08,sp) - r6
  30 *       @(0x0c,sp) - *pt_regs
  31 *       @(0x10,sp) - r0
  32 *       @(0x14,sp) - r1
  33 *       @(0x18,sp) - r2
  34 *       @(0x1c,sp) - r3
  35 *       @(0x20,sp) - r7
  36 *       @(0x24,sp) - r8
  37 *       @(0x28,sp) - r9
  38 *       @(0x2c,sp) - r10
  39 *       @(0x30,sp) - r11
  40 *       @(0x34,sp) - r12
  41 *       @(0x38,sp) - syscall_nr
  42 *       @(0x3c,sp) - acc0h
  43 *       @(0x40,sp) - acc0l
  44 *       @(0x44,sp) - acc1h             ; ISA_DSP_LEVEL2 only
  45 *       @(0x48,sp) - acc1l             ; ISA_DSP_LEVEL2 only
  46 *       @(0x4c,sp) - psw
  47 *       @(0x50,sp) - bpc
  48 *       @(0x54,sp) - bbpsw
  49 *       @(0x58,sp) - bbpc
  50 *       @(0x5c,sp) - spu (cr3)
  51 *       @(0x60,sp) - fp (r13)
  52 *       @(0x64,sp) - lr (r14)
  53 *       @(0x68,sp) - spi (cr2)
  54 *       @(0x6c,sp) - orig_r0
  55 */
  56
  57#include <linux/linkage.h>
  58#include <asm/irq.h>
  59#include <asm/unistd.h>
  60#include <asm/assembler.h>
  61#include <asm/thread_info.h>
  62#include <asm/errno.h>
  63#include <asm/segment.h>
  64#include <asm/smp.h>
  65#include <asm/page.h>
  66#include <asm/m32r.h>
  67#include <asm/mmu_context.h>
  68
  69#if !defined(CONFIG_MMU)
  70#define sys_madvise             sys_ni_syscall
  71#define sys_readahead           sys_ni_syscall
  72#define sys_mprotect            sys_ni_syscall
  73#define sys_msync               sys_ni_syscall
  74#define sys_mlock               sys_ni_syscall
  75#define sys_munlock             sys_ni_syscall
  76#define sys_mlockall            sys_ni_syscall
  77#define sys_munlockall          sys_ni_syscall
  78#define sys_mremap              sys_ni_syscall
  79#define sys_mincore             sys_ni_syscall
  80#define sys_remap_file_pages    sys_ni_syscall
  81#endif /* CONFIG_MMU */
  82
  83#define R4(reg)                 @reg
  84#define R5(reg)                 @(0x04,reg)
  85#define R6(reg)                 @(0x08,reg)
  86#define PTREGS(reg)             @(0x0C,reg)
  87#define R0(reg)                 @(0x10,reg)
  88#define R1(reg)                 @(0x14,reg)
  89#define R2(reg)                 @(0x18,reg)
  90#define R3(reg)                 @(0x1C,reg)
  91#define R7(reg)                 @(0x20,reg)
  92#define R8(reg)                 @(0x24,reg)
  93#define R9(reg)                 @(0x28,reg)
  94#define R10(reg)                @(0x2C,reg)
  95#define R11(reg)                @(0x30,reg)
  96#define R12(reg)                @(0x34,reg)
  97#define SYSCALL_NR(reg)         @(0x38,reg)
  98#define ACC0H(reg)              @(0x3C,reg)
  99#define ACC0L(reg)              @(0x40,reg)
 100#define ACC1H(reg)              @(0x44,reg)
 101#define ACC1L(reg)              @(0x48,reg)
 102#define PSW(reg)                @(0x4C,reg)
 103#define BPC(reg)                @(0x50,reg)
 104#define BBPSW(reg)              @(0x54,reg)
 105#define BBPC(reg)               @(0x58,reg)
 106#define SPU(reg)                @(0x5C,reg)
 107#define FP(reg)                 @(0x60,reg)  /* FP = R13 */
 108#define LR(reg)                 @(0x64,reg)
 109#define SP(reg)                 @(0x68,reg)
 110#define ORIG_R0(reg)            @(0x6C,reg)
 111
 112#define nr_syscalls ((syscall_table_size)/4)
 113
 114#ifdef CONFIG_PREEMPT
 115#define preempt_stop(x)         DISABLE_INTERRUPTS(x)
 116#else
 117#define preempt_stop(x)
 118#define resume_kernel           restore_all
 119#endif
 120
 121/* how to get the thread information struct from ASM */
 122#define GET_THREAD_INFO(reg)    GET_THREAD_INFO reg
 123        .macro GET_THREAD_INFO reg
 124        ldi     \reg, #-THREAD_SIZE
 125        and     \reg, sp
 126        .endm
 127
 128ENTRY(ret_from_kernel_thread)
 129        pop     r0
 130        bl      schedule_tail
 131        GET_THREAD_INFO(r8)
 132        ld      r0, R0(r8)
 133        ld      r1, R1(r8)
 134        jl      r1
 135        bra     syscall_exit
 136
 137ENTRY(ret_from_fork)
 138        pop     r0
 139        bl      schedule_tail
 140        GET_THREAD_INFO(r8)
 141        bra     syscall_exit
 142
 143/*
 144 * Return to user mode is not as complex as all this looks,
 145 * but we want the default path for a system call return to
 146 * go as quickly as possible which is why some of this is
 147 * less clear than it otherwise should be.
 148 */
 149
 150        ; userspace resumption stub bypassing syscall exit tracing
 151        ALIGN
 152ret_from_exception:
 153        preempt_stop(r4)
 154ret_from_intr:
 155        ld      r4, PSW(sp)
 156#ifdef CONFIG_ISA_M32R2
 157        and3    r4, r4, #0x8800         ; check BSM and BPM bits
 158#else
 159        and3    r4, r4, #0x8000         ; check BSM bit
 160#endif
 161        beqz    r4, resume_kernel
 162resume_userspace:
 163        DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
 164                                        ; setting need_resched or sigpending
 165                                        ; between sampling and the iret
 166        GET_THREAD_INFO(r8)
 167        ld      r9, @(TI_FLAGS, r8)
 168        and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
 169                                        ; int/exception return?
 170        bnez    r4, work_pending
 171        bra     restore_all
 172
 173#ifdef CONFIG_PREEMPT
 174ENTRY(resume_kernel)
 175        GET_THREAD_INFO(r8)
 176        ld      r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
 177        bnez    r9, restore_all
 178need_resched:
 179        ld      r9, @(TI_FLAGS, r8)     ; need_resched set ?
 180        and3    r4, r9, #_TIF_NEED_RESCHED
 181        beqz    r4, restore_all
 182        ld      r4, PSW(sp)             ; interrupts off (exception path) ?
 183        and3    r4, r4, #0x4000
 184        beqz    r4, restore_all
 185        bl      preempt_schedule_irq
 186        bra     need_resched
 187#endif
 188
 189        ; system call handler stub
 190ENTRY(system_call)
 191        SWITCH_TO_KERNEL_STACK
 192        SAVE_ALL
 193        ENABLE_INTERRUPTS(r4)           ; Enable interrupt
 194        st      sp, PTREGS(sp)          ; implicit pt_regs parameter
 195        cmpui   r7, #NR_syscalls
 196        bnc     syscall_badsys
 197        st      r7, SYSCALL_NR(sp)      ; syscall_nr
 198                                        ; system call tracing in operation
 199        GET_THREAD_INFO(r8)
 200        ld      r9, @(TI_FLAGS, r8)
 201        and3    r4, r9, #_TIF_SYSCALL_TRACE
 202        bnez    r4, syscall_trace_entry
 203syscall_call:
 204        slli    r7, #2                  ; table jump for the system call
 205        LDIMM   (r4, sys_call_table)
 206        add     r7, r4
 207        ld      r7, @r7
 208        jl      r7                      ; execute system call
 209        st      r0, R0(sp)              ; save the return value
 210syscall_exit:
 211        DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
 212                                        ; setting need_resched or sigpending
 213                                        ; between sampling and the iret
 214        ld      r9, @(TI_FLAGS, r8)
 215        and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
 216        bnez    r4, syscall_exit_work
 217restore_all:
 218        RESTORE_ALL
 219
 220        # perform work that needs to be done immediately before resumption
 221        # r9 : flags
 222        ALIGN
 223work_pending:
 224        and3    r4, r9, #_TIF_NEED_RESCHED
 225        beqz    r4, work_notifysig
 226work_resched:
 227        bl      schedule
 228        DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
 229                                        ; setting need_resched or sigpending
 230                                        ; between sampling and the iret
 231        ld      r9, @(TI_FLAGS, r8)
 232        and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
 233                                        ; than syscall tracing?
 234        beqz    r4, restore_all
 235        and3    r4, r4, #_TIF_NEED_RESCHED
 236        bnez    r4, work_resched
 237
 238work_notifysig:                         ; deal with pending signals and
 239                                        ; notify-resume requests
 240        mv      r0, sp                  ; arg1 : struct pt_regs *regs
 241        mv      r1, r9                  ; arg2 : __u32 thread_info_flags
 242        bl      do_notify_resume
 243        bra     resume_userspace
 244
 245        ; perform syscall exit tracing
 246        ALIGN
 247syscall_trace_entry:
 248        ldi     r4, #-ENOSYS
 249        st      r4, R0(sp)
 250        bl      do_syscall_trace
 251        ld      r0, ORIG_R0(sp)
 252        ld      r1, R1(sp)
 253        ld      r2, R2(sp)
 254        ld      r3, R3(sp)
 255        ld      r4, R4(sp)
 256        ld      r5, R5(sp)
 257        ld      r6, R6(sp)
 258        ld      r7, SYSCALL_NR(sp)
 259        cmpui   r7, #NR_syscalls
 260        bc      syscall_call
 261        bra     syscall_exit
 262
 263        ; perform syscall exit tracing
 264        ALIGN
 265syscall_exit_work:
 266        ld      r9, @(TI_FLAGS, r8)
 267        and3    r4, r9, #_TIF_SYSCALL_TRACE
 268        beqz    r4, work_pending
 269        ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
 270                                        ; schedule() instead
 271        bl      do_syscall_trace
 272        bra     resume_userspace
 273
 274        ALIGN
 275syscall_fault:
 276        SAVE_ALL
 277        GET_THREAD_INFO(r8)
 278        ldi     r4, #-EFAULT
 279        st      r4, R0(sp)
 280        bra     resume_userspace
 281
 282        ALIGN
 283syscall_badsys:
 284        ldi     r4, #-ENOSYS
 285        st      r4, R0(sp)
 286        bra     resume_userspace
 287
 288        .global eit_vector
 289
 290        .equ ei_vec_table, eit_vector + 0x0200
 291
 292/*
 293 * EI handler routine
 294 */
 295ENTRY(ei_handler)
 296#if defined(CONFIG_CHIP_M32700)
 297        ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
 298        SWITCH_TO_KERNEL_STACK
 299#endif
 300        SAVE_ALL
 301        mv      r1, sp                  ; arg1(regs)
 302        ; get ICU status
 303        seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
 304        ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
 305        push    r0
 306#if defined(CONFIG_SMP)
 307        /*
 308         * If IRQ == 0      --> Nothing to do,  Not write IMASK
 309         * If IRQ == IPI    --> Do IPI handler, Not write IMASK
 310         * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
 311         */
 312        slli    r0, #4
 313        srli    r0, #24                 ; r0(irq_num<<2)
 314        ;; IRQ exist check
 315#if defined(CONFIG_CHIP_M32700)
 316        /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
 317        bnez    r0, 0f
 318        ld24    r14, #0x00070000
 319        seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
 320        st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
 321        bra     1f
 322        .fillinsn
 3230:
 324#endif /* CONFIG_CHIP_M32700 */
 325        beqz    r0, 1f                  ; if (!irq_num) goto exit
 326        ;; IPI check
 327        cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
 328        bc      2f
 329        cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
 330        bnc     2f
 331        LDIMM   (r2, ei_vec_table)
 332        add     r2, r0
 333        ld      r2, @r2
 334        beqz    r2, 1f                  ; if (no IPI handler) goto exit
 335        mv      r0, r1                  ; arg0(regs)
 336        jl      r2
 337        .fillinsn
 3381:
 339        addi    sp, #4
 340        bra     restore_all
 341        .fillinsn
 3422:
 343        srli    r0, #2
 344#else /* not CONFIG_SMP */
 345        srli    r0, #22                 ; r0(irq)
 346#endif /* not CONFIG_SMP */
 347
 348#if defined(CONFIG_PLAT_HAS_INT1ICU)
 349        add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
 350        bnez    r2, 3f
 351        seth    r0, #shigh(M32R_INT1ICU_ISTS)
 352        lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
 353        slli    r0, #21
 354        srli    r0, #27                         ; ISN
 355        addi    r0, #(M32R_INT1ICU_IRQ_BASE)
 356        bra     check_end
 357        .fillinsn
 3583:
 359#endif /* CONFIG_PLAT_HAS_INT1ICU */
 360#if defined(CONFIG_PLAT_HAS_INT0ICU)
 361        add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
 362        bnez    r2, 4f
 363        seth    r0, #shigh(M32R_INT0ICU_ISTS)
 364        lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
 365        slli    r0, #21
 366        srli    r0, #27                         ; ISN
 367        add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
 368        bra     check_end
 369        .fillinsn
 3704:
 371#endif /* CONFIG_PLAT_HAS_INT0ICU */
 372#if defined(CONFIG_PLAT_HAS_INT2ICU)
 373        add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
 374        bnez    r2, 5f
 375        seth    r0, #shigh(M32R_INT2ICU_ISTS)
 376        lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
 377        slli    r0, #21
 378        srli    r0, #27                         ; ISN
 379        add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
 380        ; bra   check_end
 381        .fillinsn
 3825:
 383#endif /* CONFIG_PLAT_HAS_INT2ICU */
 384
 385check_end:
 386        bl      do_IRQ
 387        pop     r14
 388        seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
 389        st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
 390        bra  ret_from_intr
 391
 392/*
 393 * Default EIT handler
 394 */
 395        ALIGN
 396int_msg:
 397        .asciz  "Unknown interrupt\n"
 398        .byte   0
 399
 400ENTRY(default_eit_handler)
 401        push    r0
 402        mvfc    r0, psw
 403        push    r1
 404        push    r2
 405        push    r3
 406        push    r0
 407        LDIMM   (r0, __KERNEL_DS)
 408        mv      r0, r1
 409        mv      r0, r2
 410        LDIMM   (r0, int_msg)
 411        bl      printk
 412        pop     r0
 413        pop     r3
 414        pop     r2
 415        pop     r1
 416        mvtc    r0, psw
 417        pop     r0
 418infinit:
 419        bra     infinit
 420
 421#ifdef CONFIG_MMU
 422/*
 423 * Access Exception handler
 424 */
 425ENTRY(ace_handler)
 426        SWITCH_TO_KERNEL_STACK
 427        SAVE_ALL
 428
 429        seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
 430        ld      r4, @(low(MESTS_offset),r2)
 431        st      r4, @(low(MESTS_offset),r2)
 432        srl3    r1, r4, #4
 433#ifdef CONFIG_CHIP_M32700
 434        and3    r1, r1, #0x0000ffff
 435        ; WORKAROUND: ignore TME bit for the M32700(TS1).
 436#endif /* CONFIG_CHIP_M32700 */
 437        beqz    r1, inst
 438oprand:
 439        ld      r2, @(low(MDEVA_offset),r2)     ; set address
 440        srli    r1, #1
 441        bra     1f
 442inst:
 443        and3    r1, r4, #2
 444        srli    r1, #1
 445        or3     r1, r1, #8
 446        mvfc    r2, bpc                         ; set address
 447        .fillinsn
 4481:
 449        mvfc    r3, psw
 450        mv      r0, sp
 451        and3    r3, r3, 0x800
 452        srli    r3, #9
 453        or      r1, r3
 454        /*
 455         * do_page_fault():
 456         *    r0 : struct pt_regs *regs
 457         *    r1 : unsigned long error-code
 458         *    r2 : unsigned long address
 459         * error-code:
 460         *    +------+------+------+------+
 461         *    | bit3 | bit2 | bit1 | bit0 |
 462         *    +------+------+------+------+
 463         *    bit 3 == 0:means data,          1:means instruction
 464         *    bit 2 == 0:means kernel,        1:means user-mode
 465         *    bit 1 == 0:means read,          1:means write
 466         *    bit 0 == 0:means no page found  1:means protection fault
 467         *
 468         */
 469        bl      do_page_fault
 470        bra     ret_from_intr
 471#endif  /* CONFIG_MMU */
 472
 473
 474ENTRY(alignment_check)
 475        /* void alignment_check(int error_code) */
 476        SWITCH_TO_KERNEL_STACK
 477        SAVE_ALL
 478        ldi     r1, #0x30                       ; error_code
 479        mv      r0, sp                          ; pt_regs
 480        bl      do_alignment_check
 481error_code:
 482        bra     ret_from_exception
 483
 484ENTRY(rie_handler)
 485        /* void rie_handler(int error_code) */
 486        SWITCH_TO_KERNEL_STACK
 487        SAVE_ALL
 488        ldi     r1, #0x20                       ; error_code
 489        mv      r0, sp                          ; pt_regs
 490        bl      do_rie_handler
 491        bra     error_code
 492
 493ENTRY(pie_handler)
 494        /* void pie_handler(int error_code) */
 495        SWITCH_TO_KERNEL_STACK
 496        SAVE_ALL
 497        ldi     r1, #0                          ; error_code ; FIXME
 498        mv      r0, sp                          ; pt_regs
 499        bl      do_pie_handler
 500        bra     error_code
 501
 502ENTRY(debug_trap)
 503        /* void debug_trap(void) */
 504        .global withdraw_debug_trap
 505        SWITCH_TO_KERNEL_STACK
 506        SAVE_ALL
 507        mv      r0, sp                          ; pt_regs
 508        bl      withdraw_debug_trap
 509        ldi     r1, #0                          ; error_code
 510        mv      r0, sp                          ; pt_regs
 511        bl      do_debug_trap
 512        bra     error_code
 513
 514ENTRY(ill_trap)
 515        /* void ill_trap(void) */
 516        SWITCH_TO_KERNEL_STACK
 517        SAVE_ALL
 518        ldi     r1, #0                          ; error_code ; FIXME
 519        mv      r0, sp                          ; pt_regs
 520        bl      do_ill_trap
 521        bra     error_code
 522
 523ENTRY(cache_flushing_handler)
 524        /* void _flush_cache_all(void); */
 525        .global _flush_cache_all
 526        SWITCH_TO_KERNEL_STACK
 527        push    r0
 528        push    r1
 529        push    r2
 530        push    r3
 531        push    r4
 532        push    r5
 533        push    r6
 534        push    r7
 535        push    lr
 536        bl      _flush_cache_all
 537        pop     lr
 538        pop     r7
 539        pop     r6
 540        pop     r5
 541        pop     r4
 542        pop     r3
 543        pop     r2
 544        pop     r1
 545        pop     r0
 546        rte
 547
 548        .section .rodata,"a"
 549#include "syscall_table.S"
 550
 551syscall_table_size=(.-sys_call_table)
 552