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 mv r1, r9 ; arg2 : __u32 thread_info_flags 239 bl do_notify_resume 240 bra resume_userspace 241 242 ; perform syscall exit tracing 243 ALIGN 244syscall_trace_entry: 245 ldi r4, #-ENOSYS 246 st r4, R0(sp) 247 bl do_syscall_trace 248 ld r0, ORIG_R0(sp) 249 ld r1, R1(sp) 250 ld r2, R2(sp) 251 ld r3, R3(sp) 252 ld r4, R4(sp) 253 ld r5, R5(sp) 254 ld r6, R6(sp) 255 ld r7, SYSCALL_NR(sp) 256 cmpui r7, #NR_syscalls 257 bc syscall_call 258 bra syscall_exit 259 260 ; perform syscall exit tracing 261 ALIGN 262syscall_exit_work: 263 ld r9, @(TI_FLAGS, r8) 264 and3 r4, r9, #_TIF_SYSCALL_TRACE 265 beqz r4, work_pending 266 ENABLE_INTERRUPTS(r4) ; could let do_syscall_trace() call 267 ; schedule() instead 268 bl do_syscall_trace 269 bra resume_userspace 270 271 ALIGN 272syscall_fault: 273 SAVE_ALL 274 GET_THREAD_INFO(r8) 275 ldi r4, #-EFAULT 276 st r4, R0(sp) 277 bra resume_userspace 278 279 ALIGN 280syscall_badsys: 281 ldi r4, #-ENOSYS 282 st r4, R0(sp) 283 bra resume_userspace 284 285 .global eit_vector 286 287 .equ ei_vec_table, eit_vector + 0x0200 288 289/* 290 * EI handler routine 291 */ 292ENTRY(ei_handler) 293#if defined(CONFIG_CHIP_M32700) 294 ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI). 295 SWITCH_TO_KERNEL_STACK 296#endif 297 SAVE_ALL 298 mv r1, sp ; arg1(regs) 299 ; get ICU status 300 seth r0, #shigh(M32R_ICU_ISTS_ADDR) 301 ld r0, @(low(M32R_ICU_ISTS_ADDR),r0) 302 push r0 303#if defined(CONFIG_SMP) 304 /* 305 * If IRQ == 0 --> Nothing to do, Not write IMASK 306 * If IRQ == IPI --> Do IPI handler, Not write IMASK 307 * If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK 308 */ 309 slli r0, #4 310 srli r0, #24 ; r0(irq_num<<2) 311 ;; IRQ exist check 312#if defined(CONFIG_CHIP_M32700) 313 /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ 314 bnez r0, 0f 315 ld24 r14, #0x00070000 316 seth r0, #shigh(M32R_ICU_IMASK_ADDR) 317 st r14, @(low(M32R_ICU_IMASK_ADDR),r0) 318 bra 1f 319 .fillinsn 3200: 321#endif /* CONFIG_CHIP_M32700 */ 322 beqz r0, 1f ; if (!irq_num) goto exit 323 ;; IPI check 324 cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check 325 bc 2f 326 cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check 327 bnc 2f 328 LDIMM (r2, ei_vec_table) 329 add r2, r0 330 ld r2, @r2 331 beqz r2, 1f ; if (no IPI handler) goto exit 332 mv r0, r1 ; arg0(regs) 333 jl r2 334 .fillinsn 3351: 336 addi sp, #4 337 bra restore_all 338 .fillinsn 3392: 340 srli r0, #2 341#else /* not CONFIG_SMP */ 342 srli r0, #22 ; r0(irq) 343#endif /* not CONFIG_SMP */ 344 345#if defined(CONFIG_PLAT_HAS_INT1ICU) 346 add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt 347 bnez r2, 3f 348 seth r0, #shigh(M32R_INT1ICU_ISTS) 349 lduh r0, @(low(M32R_INT1ICU_ISTS),r0) ; bit10-6 : ISN 350 slli r0, #21 351 srli r0, #27 ; ISN 352 addi r0, #(M32R_INT1ICU_IRQ_BASE) 353 bra check_end 354 .fillinsn 3553: 356#endif /* CONFIG_PLAT_HAS_INT1ICU */ 357#if defined(CONFIG_PLAT_HAS_INT0ICU) 358 add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt 359 bnez r2, 4f 360 seth r0, #shigh(M32R_INT0ICU_ISTS) 361 lduh r0, @(low(M32R_INT0ICU_ISTS),r0) ; bit10-6 : ISN 362 slli r0, #21 363 srli r0, #27 ; ISN 364 add3 r0, r0, #(M32R_INT0ICU_IRQ_BASE) 365 bra check_end 366 .fillinsn 3674: 368#endif /* CONFIG_PLAT_HAS_INT0ICU */ 369#if defined(CONFIG_PLAT_HAS_INT2ICU) 370 add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt 371 bnez r2, 5f 372 seth r0, #shigh(M32R_INT2ICU_ISTS) 373 lduh r0, @(low(M32R_INT2ICU_ISTS),r0) ; bit10-6 : ISN 374 slli r0, #21 375 srli r0, #27 ; ISN 376 add3 r0, r0, #(M32R_INT2ICU_IRQ_BASE) 377 ; bra check_end 378 .fillinsn 3795: 380#endif /* CONFIG_PLAT_HAS_INT2ICU */ 381 382check_end: 383 bl do_IRQ 384 pop r14 385 seth r0, #shigh(M32R_ICU_IMASK_ADDR) 386 st r14, @(low(M32R_ICU_IMASK_ADDR),r0) 387 bra ret_from_intr 388 389/* 390 * Default EIT handler 391 */ 392 ALIGN 393int_msg: 394 .asciz "Unknown interrupt\n" 395 .byte 0 396 397ENTRY(default_eit_handler) 398 push r0 399 mvfc r0, psw 400 push r1 401 push r2 402 push r3 403 push r0 404 LDIMM (r0, __KERNEL_DS) 405 mv r0, r1 406 mv r0, r2 407 LDIMM (r0, int_msg) 408 bl printk 409 pop r0 410 pop r3 411 pop r2 412 pop r1 413 mvtc r0, psw 414 pop r0 415infinit: 416 bra infinit 417 418#ifdef CONFIG_MMU 419/* 420 * Access Exception handler 421 */ 422ENTRY(ace_handler) 423 SWITCH_TO_KERNEL_STACK 424 SAVE_ALL 425 426 seth r2, #shigh(MMU_REG_BASE) /* Check status register */ 427 ld r4, @(low(MESTS_offset),r2) 428 st r4, @(low(MESTS_offset),r2) 429 srl3 r1, r4, #4 430#ifdef CONFIG_CHIP_M32700 431 and3 r1, r1, #0x0000ffff 432 ; WORKAROUND: ignore TME bit for the M32700(TS1). 433#endif /* CONFIG_CHIP_M32700 */ 434 beqz r1, inst 435oprand: 436 ld r2, @(low(MDEVA_offset),r2) ; set address 437 srli r1, #1 438 bra 1f 439inst: 440 and3 r1, r4, #2 441 srli r1, #1 442 or3 r1, r1, #8 443 mvfc r2, bpc ; set address 444 .fillinsn 4451: 446 mvfc r3, psw 447 mv r0, sp 448 and3 r3, r3, 0x800 449 srli r3, #9 450 or r1, r3 451 /* 452 * do_page_fault(): 453 * r0 : struct pt_regs *regs 454 * r1 : unsigned long error-code 455 * r2 : unsigned long address 456 * error-code: 457 * +------+------+------+------+ 458 * | bit3 | bit2 | bit1 | bit0 | 459 * +------+------+------+------+ 460 * bit 3 == 0:means data, 1:means instruction 461 * bit 2 == 0:means kernel, 1:means user-mode 462 * bit 1 == 0:means read, 1:means write 463 * bit 0 == 0:means no page found 1:means protection fault 464 * 465 */ 466 bl do_page_fault 467 bra ret_from_intr 468#endif /* CONFIG_MMU */ 469 470 471ENTRY(alignment_check) 472 /* void alignment_check(int error_code) */ 473 SWITCH_TO_KERNEL_STACK 474 SAVE_ALL 475 ldi r1, #0x30 ; error_code 476 mv r0, sp ; pt_regs 477 bl do_alignment_check 478error_code: 479 bra ret_from_exception 480 481ENTRY(rie_handler) 482 /* void rie_handler(int error_code) */ 483 SWITCH_TO_KERNEL_STACK 484 SAVE_ALL 485 ldi r1, #0x20 ; error_code 486 mv r0, sp ; pt_regs 487 bl do_rie_handler 488 bra error_code 489 490ENTRY(pie_handler) 491 /* void pie_handler(int error_code) */ 492 SWITCH_TO_KERNEL_STACK 493 SAVE_ALL 494 ldi r1, #0 ; error_code ; FIXME 495 mv r0, sp ; pt_regs 496 bl do_pie_handler 497 bra error_code 498 499ENTRY(debug_trap) 500 /* void debug_trap(void) */ 501 .global withdraw_debug_trap 502 SWITCH_TO_KERNEL_STACK 503 SAVE_ALL 504 mv r0, sp ; pt_regs 505 bl withdraw_debug_trap 506 ldi r1, #0 ; error_code 507 mv r0, sp ; pt_regs 508 bl do_debug_trap 509 bra error_code 510 511ENTRY(ill_trap) 512 /* void ill_trap(void) */ 513 SWITCH_TO_KERNEL_STACK 514 SAVE_ALL 515 ldi r1, #0 ; error_code ; FIXME 516 mv r0, sp ; pt_regs 517 bl do_ill_trap 518 bra error_code 519 520ENTRY(cache_flushing_handler) 521 /* void _flush_cache_all(void); */ 522 .global _flush_cache_all 523 SWITCH_TO_KERNEL_STACK 524 push r0 525 push r1 526 push r2 527 push r3 528 push r4 529 push r5 530 push r6 531 push r7 532 push lr 533 bl _flush_cache_all 534 pop lr 535 pop r7 536 pop r6 537 pop r5 538 pop r4 539 pop r3 540 pop r2 541 pop r1 542 pop r0 543 rte 544 545 .section .rodata,"a" 546#include "syscall_table.S" 547 548syscall_table_size=(.-sys_call_table) 549