1/* 2 * arch/sh/kernel/cpu/sh3/entry.S 3 * 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 5 * Copyright (C) 2003 - 2006 Paul Mundt 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file "COPYING" in the main directory of this archive 9 * for more details. 10 */ 11#include <linux/sys.h> 12#include <linux/errno.h> 13#include <linux/linkage.h> 14#include <asm/asm-offsets.h> 15#include <asm/thread_info.h> 16#include <asm/unistd.h> 17#include <cpu/mmu_context.h> 18#include <asm/page.h> 19 20! NOTE: 21! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address 22! to be jumped is too far, but it causes illegal slot exception. 23 24/* 25 * entry.S contains the system-call and fault low-level handling routines. 26 * This also contains the timer-interrupt handler, as well as all interrupts 27 * and faults that can result in a task-switch. 28 * 29 * NOTE: This code handles signal-recognition, which happens every time 30 * after a timer-interrupt and after each system call. 31 * 32 * NOTE: This code uses a convention that instructions in the delay slot 33 * of a transfer-control instruction are indented by an extra space, thus: 34 * 35 * jmp @k0 ! control-transfer instruction 36 * ldc k1, ssr ! delay slot 37 * 38 * Stack layout in 'ret_from_syscall': 39 * ptrace needs to have all regs on the stack. 40 * if the order here is changed, it needs to be 41 * updated in ptrace.c and ptrace.h 42 * 43 * r0 44 * ... 45 * r15 = stack pointer 46 * spc 47 * pr 48 * ssr 49 * gbr 50 * mach 51 * macl 52 * syscall # 53 * 54 */ 55#if defined(CONFIG_KGDB) 56NMI_VEC = 0x1c0 ! Must catch early for debounce 57#endif 58 59/* Offsets to the stack */ 60OFF_R0 = 0 /* Return value. New ABI also arg4 */ 61OFF_R1 = 4 /* New ABI: arg5 */ 62OFF_R2 = 8 /* New ABI: arg6 */ 63OFF_R3 = 12 /* New ABI: syscall_nr */ 64OFF_R4 = 16 /* New ABI: arg0 */ 65OFF_R5 = 20 /* New ABI: arg1 */ 66OFF_R6 = 24 /* New ABI: arg2 */ 67OFF_R7 = 28 /* New ABI: arg3 */ 68OFF_SP = (15*4) 69OFF_PC = (16*4) 70OFF_SR = (16*4+8) 71OFF_TRA = (16*4+6*4) 72 73 74#define k0 r0 75#define k1 r1 76#define k2 r2 77#define k3 r3 78#define k4 r4 79 80#define g_imask r6 /* r6_bank1 */ 81#define k_g_imask r6_bank /* r6_bank1 */ 82#define current r7 /* r7_bank1 */ 83 84#include <asm/entry-macros.S> 85 86/* 87 * Kernel mode register usage: 88 * k0 scratch 89 * k1 scratch 90 * k2 scratch (Exception code) 91 * k3 scratch (Return address) 92 * k4 scratch 93 * k5 reserved 94 * k6 Global Interrupt Mask (0--15 << 4) 95 * k7 CURRENT_THREAD_INFO (pointer to current thread info) 96 */ 97 98! 99! TLB Miss / Initial Page write exception handling 100! _and_ 101! TLB hits, but the access violate the protection. 102! It can be valid access, such as stack grow and/or C-O-W. 103! 104! 105! Find the pmd/pte entry and loadtlb 106! If it's not found, cause address error (SEGV) 107! 108! Although this could be written in assembly language (and it'd be faster), 109! this first version depends *much* on C implementation. 110! 111 112#if defined(CONFIG_MMU) 113 .align 2 114ENTRY(tlb_miss_load) 115 bra call_dpf 116 mov #0, r5 117 118 .align 2 119ENTRY(tlb_miss_store) 120 bra call_dpf 121 mov #1, r5 122 123 .align 2 124ENTRY(initial_page_write) 125 bra call_dpf 126 mov #1, r5 127 128 .align 2 129ENTRY(tlb_protection_violation_load) 130 bra call_dpf 131 mov #0, r5 132 133 .align 2 134ENTRY(tlb_protection_violation_store) 135 bra call_dpf 136 mov #1, r5 137 138call_dpf: 139 mov.l 1f, r0 140 mov r5, r8 141 mov.l @r0, r6 142 mov r6, r9 143 mov.l 2f, r0 144 sts pr, r10 145 jsr @r0 146 mov r15, r4 147 ! 148 tst r0, r0 149 bf/s 0f 150 lds r10, pr 151 rts 152 nop 1530: mov.l 3f, r0 154 mov r9, r6 155 mov r8, r5 156 jmp @r0 157 mov r15, r4 158 159 .align 2 1601: .long MMU_TEA 1612: .long __do_page_fault 1623: .long do_page_fault 163 164 .align 2 165ENTRY(address_error_load) 166 bra call_dae 167 mov #0,r5 ! writeaccess = 0 168 169 .align 2 170ENTRY(address_error_store) 171 bra call_dae 172 mov #1,r5 ! writeaccess = 1 173 174 .align 2 175call_dae: 176 mov.l 1f, r0 177 mov.l @r0, r6 ! address 178 mov.l 2f, r0 179 jmp @r0 180 mov r15, r4 ! regs 181 182 .align 2 1831: .long MMU_TEA 1842: .long do_address_error 185#endif /* CONFIG_MMU */ 186 187#if defined(CONFIG_SH_STANDARD_BIOS) 188 /* Unwind the stack and jmp to the debug entry */ 189ENTRY(sh_bios_handler) 190 mov.l @r15+, r0 191 mov.l @r15+, r1 192 mov.l @r15+, r2 193 mov.l @r15+, r3 194 mov.l @r15+, r4 195 mov.l @r15+, r5 196 mov.l @r15+, r6 197 mov.l @r15+, r7 198 stc sr, r8 199 mov.l 1f, r9 ! BL =1, RB=1, IMASK=0x0F 200 or r9, r8 201 ldc r8, sr ! here, change the register bank 202 mov.l @r15+, r8 203 mov.l @r15+, r9 204 mov.l @r15+, r10 205 mov.l @r15+, r11 206 mov.l @r15+, r12 207 mov.l @r15+, r13 208 mov.l @r15+, r14 209 mov.l @r15+, k0 210 ldc.l @r15+, spc 211 lds.l @r15+, pr 212 mov.l @r15+, k1 213 ldc.l @r15+, gbr 214 lds.l @r15+, mach 215 lds.l @r15+, macl 216 mov k0, r15 217 ! 218 mov.l 2f, k0 219 mov.l @k0, k0 220 jmp @k0 221 ldc k1, ssr 222 .align 2 2231: .long 0x300000f0 2242: .long gdb_vbr_vector 225#endif /* CONFIG_SH_STANDARD_BIOS */ 226 227restore_all: 228 mov.l @r15+, r0 229 mov.l @r15+, r1 230 mov.l @r15+, r2 231 mov.l @r15+, r3 232 mov.l @r15+, r4 233 mov.l @r15+, r5 234 mov.l @r15+, r6 235 mov.l @r15+, r7 236 ! 237 stc sr, r8 238 mov.l 7f, r9 239 or r9, r8 ! BL =1, RB=1 240 ldc r8, sr ! here, change the register bank 241 ! 242 mov.l @r15+, r8 243 mov.l @r15+, r9 244 mov.l @r15+, r10 245 mov.l @r15+, r11 246 mov.l @r15+, r12 247 mov.l @r15+, r13 248 mov.l @r15+, r14 249 mov.l @r15+, k4 ! original stack pointer 250 ldc.l @r15+, spc 251 lds.l @r15+, pr 252 mov.l @r15+, k3 ! original SR 253 ldc.l @r15+, gbr 254 lds.l @r15+, mach 255 lds.l @r15+, macl 256 add #4, r15 ! Skip syscall number 257 ! 258#ifdef CONFIG_SH_DSP 259 mov.l @r15+, k0 ! DSP mode marker 260 mov.l 5f, k1 261 cmp/eq k0, k1 ! Do we have a DSP stack frame? 262 bf skip_restore 263 264 stc sr, k0 ! Enable CPU DSP mode 265 or k1, k0 ! (within kernel it may be disabled) 266 ldc k0, sr 267 mov r2, k0 ! Backup r2 268 269 ! Restore DSP registers from stack 270 mov r15, r2 271 movs.l @r2+, a1 272 movs.l @r2+, a0g 273 movs.l @r2+, a1g 274 movs.l @r2+, m0 275 movs.l @r2+, m1 276 mov r2, r15 277 278 lds.l @r15+, a0 279 lds.l @r15+, x0 280 lds.l @r15+, x1 281 lds.l @r15+, y0 282 lds.l @r15+, y1 283 lds.l @r15+, dsr 284 ldc.l @r15+, rs 285 ldc.l @r15+, re 286 ldc.l @r15+, mod 287 288 mov k0, r2 ! Restore r2 289skip_restore: 290#endif 291 ! 292 ! Calculate new SR value 293 mov k3, k2 ! original SR value 294 mov #0xf0, k1 295 extu.b k1, k1 296 not k1, k1 297 and k1, k2 ! Mask orignal SR value 298 ! 299 mov k3, k0 ! Calculate IMASK-bits 300 shlr2 k0 301 and #0x3c, k0 302 cmp/eq #0x3c, k0 303 bt/s 6f 304 shll2 k0 305 mov g_imask, k0 306 ! 3076: or k0, k2 ! Set the IMASK-bits 308 ldc k2, ssr 309 ! 310#if defined(CONFIG_KGDB) 311 ! Clear in_nmi 312 mov.l 6f, k0 313 mov #0, k1 314 mov.b k1, @k0 315#endif 316 mov.l @r15+, k2 ! restore EXPEVT 317 mov k4, r15 318 rte 319 nop 320 321 .align 2 3225: .long 0x00001000 ! DSP 323#ifdef CONFIG_KGDB 3246: .long in_nmi 325#endif 3267: .long 0x30000000 327 328! common exception handler 329#include "../../entry-common.S" 330 331! Exception Vector Base 332! 333! Should be aligned page boundary. 334! 335 .balign 4096,0,4096 336ENTRY(vbr_base) 337 .long 0 338! 339 .balign 256,0,256 340general_exception: 341 mov.l 1f, k2 342 mov.l 2f, k3 343#ifdef CONFIG_CPU_SUBTYPE_SHX3 344 mov.l @k2, k2 345 346 ! Is EXPEVT larger than 0x800? 347 mov #0x8, k0 348 shll8 k0 349 cmp/hs k0, k2 350 bf 0f 351 352 ! then add 0x580 (k2 is 0xd80 or 0xda0) 353 mov #0x58, k0 354 shll2 k0 355 shll2 k0 356 add k0, k2 3570: 358 bra handle_exception 359 nop 360#else 361 bra handle_exception 362 mov.l @k2, k2 363#endif 364 .align 2 3651: .long EXPEVT 3662: .long ret_from_exception 367! 368! 369 370 .balign 1024,0,1024 371tlb_miss: 372 mov.l 1f, k2 373 mov.l 4f, k3 374 bra handle_exception 375 mov.l @k2, k2 376! 377 .balign 512,0,512 378interrupt: 379 mov.l 3f, k3 380#if defined(CONFIG_KGDB) 381 mov.l 2f, k2 382 ! Debounce (filter nested NMI) 383 mov.l @k2, k0 384 mov.l 5f, k1 385 cmp/eq k1, k0 386 bf 0f 387 mov.l 6f, k1 388 tas.b @k1 389 bt 0f 390 rte 391 nop 392 .align 2 3932: .long INTEVT 3945: .long NMI_VEC 3956: .long in_nmi 3960: 397#endif /* defined(CONFIG_KGDB) */ 398 bra handle_exception 399 mov #-1, k2 ! interrupt exception marker 400 401 .align 2 4021: .long EXPEVT 4033: .long ret_from_irq 4044: .long ret_from_exception 405 406! 407! 408 .align 2 409ENTRY(handle_exception) 410 ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), 411 ! save all registers onto stack. 412 ! 413 414#ifdef CONFIG_GUSA 415 ! Check for roll back gRB (User and Kernel) 416 mov r15, k0 417 shll k0 418 bf/s 1f 419 shll k0 420 bf/s 1f 421 stc spc, k1 422 stc r0_bank, k0 423 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) 424 bt/s 2f 425 stc r1_bank, k1 426 427 add #-2, k0 428 add r15, k0 429 ldc k0, spc ! PC = saved r0 + r15 - 2 4302: mov k1, r15 ! SP = r1 4311: 432#endif 433 434 stc ssr, k0 ! Is it from kernel space? 435 shll k0 ! Check MD bit (bit30) by shifting it into... 436 shll k0 ! ...the T bit 437 bt/s 1f ! It's a kernel to kernel transition. 438 mov r15, k0 ! save original stack to k0 439 /* User space to kernel */ 440 mov #(THREAD_SIZE >> 10), k1 441 shll8 k1 ! k1 := THREAD_SIZE 442 shll2 k1 443 add current, k1 444 mov k1, r15 ! change to kernel stack 445 ! 4461: mov.l 2f, k1 447 ! 448#ifdef CONFIG_SH_DSP 449 mov.l r2, @-r15 ! Save r2, we need another reg 450 stc sr, k4 451 mov.l 1f, r2 452 tst r2, k4 ! Check if in DSP mode 453 mov.l @r15+, r2 ! Restore r2 now 454 bt/s skip_save 455 mov #0, k4 ! Set marker for no stack frame 456 457 mov r2, k4 ! Backup r2 (in k4) for later 458 459 ! Save DSP registers on stack 460 stc.l mod, @-r15 461 stc.l re, @-r15 462 stc.l rs, @-r15 463 sts.l dsr, @-r15 464 sts.l y1, @-r15 465 sts.l y0, @-r15 466 sts.l x1, @-r15 467 sts.l x0, @-r15 468 sts.l a0, @-r15 469 470 ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr. 471 472 ! FIXME: Make sure that this is still the case with newer toolchains, 473 ! as we're not at all interested in supporting ancient toolchains at 474 ! this point. -- PFM. 475 476 mov r15, r2 477 .word 0xf653 ! movs.l a1, @-r2 478 .word 0xf6f3 ! movs.l a0g, @-r2 479 .word 0xf6d3 ! movs.l a1g, @-r2 480 .word 0xf6c3 ! movs.l m0, @-r2 481 .word 0xf6e3 ! movs.l m1, @-r2 482 mov r2, r15 483 484 mov k4, r2 ! Restore r2 485 mov.l 1f, k4 ! Force DSP stack frame 486skip_save: 487 mov.l k4, @-r15 ! Push DSP mode marker onto stack 488#endif 489 ! Save the user registers on the stack. 490 mov.l k2, @-r15 ! EXPEVT 491 492 mov #-1, k4 493 mov.l k4, @-r15 ! set TRA (default: -1) 494 ! 495 sts.l macl, @-r15 496 sts.l mach, @-r15 497 stc.l gbr, @-r15 498 stc.l ssr, @-r15 499 sts.l pr, @-r15 500 stc.l spc, @-r15 501 ! 502 lds k3, pr ! Set the return address to pr 503 ! 504 mov.l k0, @-r15 ! save orignal stack 505 mov.l r14, @-r15 506 mov.l r13, @-r15 507 mov.l r12, @-r15 508 mov.l r11, @-r15 509 mov.l r10, @-r15 510 mov.l r9, @-r15 511 mov.l r8, @-r15 512 ! 513 stc sr, r8 ! Back to normal register bank, and 514 or k1, r8 ! Block all interrupts 515 mov.l 3f, k1 516 and k1, r8 ! ... 517 ldc r8, sr ! ...changed here. 518 ! 519 mov.l r7, @-r15 520 mov.l r6, @-r15 521 mov.l r5, @-r15 522 mov.l r4, @-r15 523 mov.l r3, @-r15 524 mov.l r2, @-r15 525 mov.l r1, @-r15 526 mov.l r0, @-r15 527 528 /* 529 * This gets a bit tricky.. in the INTEVT case we don't want to use 530 * the VBR offset as a destination in the jump call table, since all 531 * of the destinations are the same. In this case, (interrupt) sets 532 * a marker in r2 (now r2_bank since SR.RB changed), which we check 533 * to determine the exception type. For all other exceptions, we 534 * forcibly read EXPEVT from memory and fix up the jump address, in 535 * the interrupt exception case we jump to do_IRQ() and defer the 536 * INTEVT read until there. As a bonus, we can also clean up the SR.RB 537 * checks that do_IRQ() was doing.. 538 */ 539 stc r2_bank, r8 540 cmp/pz r8 541 bf interrupt_exception 542 shlr2 r8 543 shlr r8 544 mov.l 4f, r9 545 add r8, r9 546 mov.l @r9, r9 547 jmp @r9 548 nop 549 rts 550 nop 551 552 .align 2 5531: .long 0x00001000 ! DSP=1 5542: .long 0x000080f0 ! FD=1, IMASK=15 5553: .long 0xcfffffff ! RB=0, BL=0 5564: .long exception_handling_table 557 558interrupt_exception: 559 mov.l 1f, r9 560 mov.l 2f, r4 561 mov.l @r4, r4 562 jmp @r9 563 mov r15, r5 564 rts 565 nop 566 567 .align 2 5681: .long do_IRQ 5692: .long INTEVT 570 571 .align 2 572ENTRY(exception_none) 573 rts 574 nop 575