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