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