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        LDIMM   (r4, PREEMPT_ACTIVE)
 186        st      r4, @(TI_PRE_COUNT, r8)
 187        ENABLE_INTERRUPTS(r4)
 188        bl      schedule
 189        ldi     r4, #0
 190        st      r4, @(TI_PRE_COUNT, r8)
 191        DISABLE_INTERRUPTS(r4)
 192        bra     need_resched
 193#endif
 194
 195        ; system call handler stub
 196ENTRY(system_call)
 197        SWITCH_TO_KERNEL_STACK
 198        SAVE_ALL
 199        ENABLE_INTERRUPTS(r4)           ; Enable interrupt
 200        st      sp, PTREGS(sp)          ; implicit pt_regs parameter
 201        cmpui   r7, #NR_syscalls
 202        bnc     syscall_badsys
 203        st      r7, SYSCALL_NR(sp)      ; syscall_nr
 204                                        ; system call tracing in operation
 205        GET_THREAD_INFO(r8)
 206        ld      r9, @(TI_FLAGS, r8)
 207        and3    r4, r9, #_TIF_SYSCALL_TRACE
 208        bnez    r4, syscall_trace_entry
 209syscall_call:
 210        slli    r7, #2                  ; table jump for the system call
 211        LDIMM   (r4, sys_call_table)
 212        add     r7, r4
 213        ld      r7, @r7
 214        jl      r7                      ; execute system call
 215        st      r0, R0(sp)              ; save the return value
 216syscall_exit:
 217        DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
 218                                        ; setting need_resched or sigpending
 219                                        ; between sampling and the iret
 220        ld      r9, @(TI_FLAGS, r8)
 221        and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
 222        bnez    r4, syscall_exit_work
 223restore_all:
 224        RESTORE_ALL
 225
 226        # perform work that needs to be done immediately before resumption
 227        # r9 : flags
 228        ALIGN
 229work_pending:
 230        and3    r4, r9, #_TIF_NEED_RESCHED
 231        beqz    r4, work_notifysig
 232work_resched:
 233        bl      schedule
 234        DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
 235                                        ; setting need_resched or sigpending
 236                                        ; between sampling and the iret
 237        ld      r9, @(TI_FLAGS, r8)
 238        and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
 239                                        ; than syscall tracing?
 240        beqz    r4, restore_all
 241        and3    r4, r4, #_TIF_NEED_RESCHED
 242        bnez    r4, work_resched
 243
 244work_notifysig:                         ; deal with pending signals and
 245                                        ; notify-resume requests
 246        mv      r0, sp                  ; arg1 : struct pt_regs *regs
 247        mv      r1, r9                  ; arg2 : __u32 thread_info_flags
 248        bl      do_notify_resume
 249        bra     resume_userspace
 250
 251        ; perform syscall exit tracing
 252        ALIGN
 253syscall_trace_entry:
 254        ldi     r4, #-ENOSYS
 255        st      r4, R0(sp)
 256        bl      do_syscall_trace
 257        ld      r0, ORIG_R0(sp)
 258        ld      r1, R1(sp)
 259        ld      r2, R2(sp)
 260        ld      r3, R3(sp)
 261        ld      r4, R4(sp)
 262        ld      r5, R5(sp)
 263        ld      r6, R6(sp)
 264        ld      r7, SYSCALL_NR(sp)
 265        cmpui   r7, #NR_syscalls
 266        bc      syscall_call
 267        bra     syscall_exit
 268
 269        ; perform syscall exit tracing
 270        ALIGN
 271syscall_exit_work:
 272        ld      r9, @(TI_FLAGS, r8)
 273        and3    r4, r9, #_TIF_SYSCALL_TRACE
 274        beqz    r4, work_pending
 275        ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
 276                                        ; schedule() instead
 277        bl      do_syscall_trace
 278        bra     resume_userspace
 279
 280        ALIGN
 281syscall_fault:
 282        SAVE_ALL
 283        GET_THREAD_INFO(r8)
 284        ldi     r4, #-EFAULT
 285        st      r4, R0(sp)
 286        bra     resume_userspace
 287
 288        ALIGN
 289syscall_badsys:
 290        ldi     r4, #-ENOSYS
 291        st      r4, R0(sp)
 292        bra     resume_userspace
 293
 294        .global eit_vector
 295
 296        .equ ei_vec_table, eit_vector + 0x0200
 297
 298/*
 299 * EI handler routine
 300 */
 301ENTRY(ei_handler)
 302#if defined(CONFIG_CHIP_M32700)
 303        ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
 304        SWITCH_TO_KERNEL_STACK
 305#endif
 306        SAVE_ALL
 307        mv      r1, sp                  ; arg1(regs)
 308        ; get ICU status
 309        seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
 310        ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
 311        push    r0
 312#if defined(CONFIG_SMP)
 313        /*
 314         * If IRQ == 0      --> Nothing to do,  Not write IMASK
 315         * If IRQ == IPI    --> Do IPI handler, Not write IMASK
 316         * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
 317         */
 318        slli    r0, #4
 319        srli    r0, #24                 ; r0(irq_num<<2)
 320        ;; IRQ exist check
 321#if defined(CONFIG_CHIP_M32700)
 322        /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
 323        bnez    r0, 0f
 324        ld24    r14, #0x00070000
 325        seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
 326        st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
 327        bra     1f
 328        .fillinsn
 3290:
 330#endif /* CONFIG_CHIP_M32700 */
 331        beqz    r0, 1f                  ; if (!irq_num) goto exit
 332        ;; IPI check
 333        cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
 334        bc      2f
 335        cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
 336        bnc     2f
 337        LDIMM   (r2, ei_vec_table)
 338        add     r2, r0
 339        ld      r2, @r2
 340        beqz    r2, 1f                  ; if (no IPI handler) goto exit
 341        mv      r0, r1                  ; arg0(regs)
 342        jl      r2
 343        .fillinsn
 3441:
 345        addi    sp, #4
 346        bra     restore_all
 347        .fillinsn
 3482:
 349        srli    r0, #2
 350#else /* not CONFIG_SMP */
 351        srli    r0, #22                 ; r0(irq)
 352#endif /* not CONFIG_SMP */
 353
 354#if defined(CONFIG_PLAT_HAS_INT1ICU)
 355        add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
 356        bnez    r2, 3f
 357        seth    r0, #shigh(M32R_INT1ICU_ISTS)
 358        lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
 359        slli    r0, #21
 360        srli    r0, #27                         ; ISN
 361        addi    r0, #(M32R_INT1ICU_IRQ_BASE)
 362        bra     check_end
 363        .fillinsn
 3643:
 365#endif /* CONFIG_PLAT_HAS_INT1ICU */
 366#if defined(CONFIG_PLAT_HAS_INT0ICU)
 367        add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
 368        bnez    r2, 4f
 369        seth    r0, #shigh(M32R_INT0ICU_ISTS)
 370        lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
 371        slli    r0, #21
 372        srli    r0, #27                         ; ISN
 373        add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
 374        bra     check_end
 375        .fillinsn
 3764:
 377#endif /* CONFIG_PLAT_HAS_INT0ICU */
 378#if defined(CONFIG_PLAT_HAS_INT2ICU)
 379        add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
 380        bnez    r2, 5f
 381        seth    r0, #shigh(M32R_INT2ICU_ISTS)
 382        lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
 383        slli    r0, #21
 384        srli    r0, #27                         ; ISN
 385        add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
 386        ; bra   check_end
 387        .fillinsn
 3885:
 389#endif /* CONFIG_PLAT_HAS_INT2ICU */
 390
 391check_end:
 392        bl      do_IRQ
 393        pop     r14
 394        seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
 395        st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
 396        bra  ret_from_intr
 397
 398/*
 399 * Default EIT handler
 400 */
 401        ALIGN
 402int_msg:
 403        .asciz  "Unknown interrupt\n"
 404        .byte   0
 405
 406ENTRY(default_eit_handler)
 407        push    r0
 408        mvfc    r0, psw
 409        push    r1
 410        push    r2
 411        push    r3
 412        push    r0
 413        LDIMM   (r0, __KERNEL_DS)
 414        mv      r0, r1
 415        mv      r0, r2
 416        LDIMM   (r0, int_msg)
 417        bl      printk
 418        pop     r0
 419        pop     r3
 420        pop     r2
 421        pop     r1
 422        mvtc    r0, psw
 423        pop     r0
 424infinit:
 425        bra     infinit
 426
 427#ifdef CONFIG_MMU
 428/*
 429 * Access Exception handler
 430 */
 431ENTRY(ace_handler)
 432        SWITCH_TO_KERNEL_STACK
 433        SAVE_ALL
 434
 435        seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
 436        ld      r4, @(low(MESTS_offset),r2)
 437        st      r4, @(low(MESTS_offset),r2)
 438        srl3    r1, r4, #4
 439#ifdef CONFIG_CHIP_M32700
 440        and3    r1, r1, #0x0000ffff
 441        ; WORKAROUND: ignore TME bit for the M32700(TS1).
 442#endif /* CONFIG_CHIP_M32700 */
 443        beqz    r1, inst
 444oprand:
 445        ld      r2, @(low(MDEVA_offset),r2)     ; set address
 446        srli    r1, #1
 447        bra     1f
 448inst:
 449        and3    r1, r4, #2
 450        srli    r1, #1
 451        or3     r1, r1, #8
 452        mvfc    r2, bpc                         ; set address
 453        .fillinsn
 4541:
 455        mvfc    r3, psw
 456        mv      r0, sp
 457        and3    r3, r3, 0x800
 458        srli    r3, #9
 459        or      r1, r3
 460        /*
 461         * do_page_fault():
 462         *    r0 : struct pt_regs *regs
 463         *    r1 : unsigned long error-code
 464         *    r2 : unsigned long address
 465         * error-code:
 466         *    +------+------+------+------+
 467         *    | bit3 | bit2 | bit1 | bit0 |
 468         *    +------+------+------+------+
 469         *    bit 3 == 0:means data,          1:means instruction
 470         *    bit 2 == 0:means kernel,        1:means user-mode
 471         *    bit 1 == 0:means read,          1:means write
 472         *    bit 0 == 0:means no page found  1:means protection fault
 473         *
 474         */
 475        bl      do_page_fault
 476        bra     ret_from_intr
 477#endif  /* CONFIG_MMU */
 478
 479
 480ENTRY(alignment_check)
 481        /* void alignment_check(int error_code) */
 482        SWITCH_TO_KERNEL_STACK
 483        SAVE_ALL
 484        ldi     r1, #0x30                       ; error_code
 485        mv      r0, sp                          ; pt_regs
 486        bl      do_alignment_check
 487error_code:
 488        bra     ret_from_exception
 489
 490ENTRY(rie_handler)
 491        /* void rie_handler(int error_code) */
 492        SWITCH_TO_KERNEL_STACK
 493        SAVE_ALL
 494        ldi     r1, #0x20                       ; error_code
 495        mv      r0, sp                          ; pt_regs
 496        bl      do_rie_handler
 497        bra     error_code
 498
 499ENTRY(pie_handler)
 500        /* void pie_handler(int error_code) */
 501        SWITCH_TO_KERNEL_STACK
 502        SAVE_ALL
 503        ldi     r1, #0                          ; error_code ; FIXME
 504        mv      r0, sp                          ; pt_regs
 505        bl      do_pie_handler
 506        bra     error_code
 507
 508ENTRY(debug_trap)
 509        /* void debug_trap(void) */
 510        .global withdraw_debug_trap
 511        SWITCH_TO_KERNEL_STACK
 512        SAVE_ALL
 513        mv      r0, sp                          ; pt_regs
 514        bl      withdraw_debug_trap
 515        ldi     r1, #0                          ; error_code
 516        mv      r0, sp                          ; pt_regs
 517        bl      do_debug_trap
 518        bra     error_code
 519
 520ENTRY(ill_trap)
 521        /* void ill_trap(void) */
 522        SWITCH_TO_KERNEL_STACK
 523        SAVE_ALL
 524        ldi     r1, #0                          ; error_code ; FIXME
 525        mv      r0, sp                          ; pt_regs
 526        bl      do_ill_trap
 527        bra     error_code
 528
 529ENTRY(cache_flushing_handler)
 530        /* void _flush_cache_all(void); */
 531        .global _flush_cache_all
 532        SWITCH_TO_KERNEL_STACK
 533        push    r0
 534        push    r1
 535        push    r2
 536        push    r3
 537        push    r4
 538        push    r5
 539        push    r6
 540        push    r7
 541        push    lr
 542        bl      _flush_cache_all
 543        pop     lr
 544        pop     r7
 545        pop     r6
 546        pop     r5
 547        pop     r4
 548        pop     r3
 549        pop     r2
 550        pop     r1
 551        pop     r0
 552        rte
 553
 554        .section .rodata,"a"
 555#include "syscall_table.S"
 556
 557syscall_table_size=(.-sys_call_table)
 558