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