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