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