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