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#include <asm/cache.h> 20 21! NOTE: 22! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address 23! to be jumped is too far, but it causes illegal slot exception. 24 25/* 26 * entry.S contains the system-call and fault low-level handling routines. 27 * This also contains the timer-interrupt handler, as well as all interrupts 28 * and faults that can result in a task-switch. 29 * 30 * NOTE: This code handles signal-recognition, which happens every time 31 * after a timer-interrupt and after each system call. 32 * 33 * NOTE: This code uses a convention that instructions in the delay slot 34 * of a transfer-control instruction are indented by an extra space, thus: 35 * 36 * jmp @k0 ! control-transfer instruction 37 * ldc k1, ssr ! delay slot 38 * 39 * Stack layout in 'ret_from_syscall': 40 * ptrace needs to have all regs on the stack. 41 * if the order here is changed, it needs to be 42 * updated in ptrace.c and ptrace.h 43 * 44 * r0 45 * ... 46 * r15 = stack pointer 47 * spc 48 * pr 49 * ssr 50 * gbr 51 * mach 52 * macl 53 * syscall # 54 * 55 */ 56/* Offsets to the stack */ 57OFF_R0 = 0 /* Return value. New ABI also arg4 */ 58OFF_R1 = 4 /* New ABI: arg5 */ 59OFF_R2 = 8 /* New ABI: arg6 */ 60OFF_R3 = 12 /* New ABI: syscall_nr */ 61OFF_R4 = 16 /* New ABI: arg0 */ 62OFF_R5 = 20 /* New ABI: arg1 */ 63OFF_R6 = 24 /* New ABI: arg2 */ 64OFF_R7 = 28 /* New ABI: arg3 */ 65OFF_SP = (15*4) 66OFF_PC = (16*4) 67OFF_SR = (16*4+8) 68OFF_TRA = (16*4+6*4) 69 70#define k0 r0 71#define k1 r1 72#define k2 r2 73#define k3 r3 74#define k4 r4 75 76#define g_imask r6 /* r6_bank1 */ 77#define k_g_imask r6_bank /* r6_bank1 */ 78#define current r7 /* r7_bank1 */ 79 80#include <asm/entry-macros.S> 81 82/* 83 * Kernel mode register usage: 84 * k0 scratch 85 * k1 scratch 86 * k2 scratch (Exception code) 87 * k3 scratch (Return address) 88 * k4 scratch 89 * k5 reserved 90 * k6 Global Interrupt Mask (0--15 << 4) 91 * k7 CURRENT_THREAD_INFO (pointer to current thread info) 92 */ 93 94! 95! TLB Miss / Initial Page write exception handling 96! _and_ 97! TLB hits, but the access violate the protection. 98! It can be valid access, such as stack grow and/or C-O-W. 99! 100! 101! Find the pmd/pte entry and loadtlb 102! If it's not found, cause address error (SEGV) 103! 104! Although this could be written in assembly language (and it'd be faster), 105! this first version depends *much* on C implementation. 106! 107 108#if defined(CONFIG_MMU) 109 .align 2 110ENTRY(tlb_miss_load) 111 bra call_handle_tlbmiss 112 mov #0, r5 113 114 .align 2 115ENTRY(tlb_miss_store) 116 bra call_handle_tlbmiss 117 mov #1, r5 118 119 .align 2 120ENTRY(initial_page_write) 121 bra call_handle_tlbmiss 122 mov #2, r5 123 124 .align 2 125ENTRY(tlb_protection_violation_load) 126 bra call_do_page_fault 127 mov #0, r5 128 129 .align 2 130ENTRY(tlb_protection_violation_store) 131 bra call_do_page_fault 132 mov #1, r5 133 134call_handle_tlbmiss: 135 setup_frame_reg 136 mov.l 1f, r0 137 mov r5, r8 138 mov.l @r0, r6 139 mov.l 2f, r0 140 sts pr, r10 141 jsr @r0 142 mov r15, r4 143 ! 144 tst r0, r0 145 bf/s 0f 146 lds r10, pr 147 rts 148 nop 1490: 150 mov r8, r5 151call_do_page_fault: 152 mov.l 1f, r0 153 mov.l @r0, r6 154 155 mov.l 3f, r0 156 mov.l 4f, r1 157 mov r15, r4 158 jmp @r0 159 lds r1, pr 160 161 .align 2 1621: .long MMU_TEA 1632: .long handle_tlbmiss 1643: .long do_page_fault 1654: .long ret_from_exception 166 167 .align 2 168ENTRY(address_error_load) 169 bra call_dae 170 mov #0,r5 ! writeaccess = 0 171 172 .align 2 173ENTRY(address_error_store) 174 bra call_dae 175 mov #1,r5 ! writeaccess = 1 176 177 .align 2 178call_dae: 179 mov.l 1f, r0 180 mov.l @r0, r6 ! address 181 mov.l 2f, r0 182 jmp @r0 183 mov r15, r4 ! regs 184 185 .align 2 1861: .long MMU_TEA 1872: .long do_address_error 188#endif /* CONFIG_MMU */ 189 190#if defined(CONFIG_SH_STANDARD_BIOS) 191 /* Unwind the stack and jmp to the debug entry */ 192ENTRY(sh_bios_handler) 193 mov.l 1f, r8 194 bsr restore_regs 195 nop 196 197 lds k2, pr ! restore pr 198 mov k4, r15 199 ! 200 mov.l 2f, k0 201 mov.l @k0, k0 202 jmp @k0 203 ldc k3, ssr 204 .align 2 2051: .long 0x300000f0 2062: .long gdb_vbr_vector 207#endif /* CONFIG_SH_STANDARD_BIOS */ 208 209! restore_regs() 210! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack 211! - switch bank 212! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack 213! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra 214! k2 returns original pr 215! k3 returns original sr 216! k4 returns original stack pointer 217! r8 passes SR bitmask, overwritten with restored data on return 218! r9 trashed 219! BL=0 on entry, on exit BL=1 (depending on r8). 220 221ENTRY(restore_regs) 222 mov.l @r15+, r0 223 mov.l @r15+, r1 224 mov.l @r15+, r2 225 mov.l @r15+, r3 226 mov.l @r15+, r4 227 mov.l @r15+, r5 228 mov.l @r15+, r6 229 mov.l @r15+, r7 230 ! 231 stc sr, r9 232 or r8, r9 233 ldc r9, sr 234 ! 235 mov.l @r15+, r8 236 mov.l @r15+, r9 237 mov.l @r15+, r10 238 mov.l @r15+, r11 239 mov.l @r15+, r12 240 mov.l @r15+, r13 241 mov.l @r15+, r14 242 mov.l @r15+, k4 ! original stack pointer 243 ldc.l @r15+, spc 244 mov.l @r15+, k2 ! original PR 245 mov.l @r15+, k3 ! original SR 246 ldc.l @r15+, gbr 247 lds.l @r15+, mach 248 lds.l @r15+, macl 249 rts 250 add #4, r15 ! Skip syscall number 251 252restore_all: 253 mov.l 7f, r8 254 bsr restore_regs 255 nop 256 257 lds k2, pr ! restore pr 258 ! 259 ! Calculate new SR value 260 mov k3, k2 ! original SR value 261 mov #0xfffffff0, k1 262 extu.b k1, k1 263 not k1, k1 264 and k1, k2 ! Mask original SR value 265 ! 266 mov k3, k0 ! Calculate IMASK-bits 267 shlr2 k0 268 and #0x3c, k0 269 cmp/eq #0x3c, k0 270 bt/s 6f 271 shll2 k0 272 mov g_imask, k0 273 ! 2746: or k0, k2 ! Set the IMASK-bits 275 ldc k2, ssr 276 ! 277 mov k4, r15 278 rte 279 nop 280 281 .align 2 2825: .long 0x00001000 ! DSP 2837: .long 0x30000000 284 285! common exception handler 286#include "../../entry-common.S" 287 288! Exception Vector Base 289! 290! Should be aligned page boundary. 291! 292 .balign 4096,0,4096 293ENTRY(vbr_base) 294 .long 0 295! 296! 0x100: General exception vector 297! 298 .balign 256,0,256 299general_exception: 300#ifndef CONFIG_CPU_SUBTYPE_SHX3 301 bra handle_exception 302 sts pr, k3 ! save original pr value in k3 303#else 304 mov.l 1f, k4 305 mov.l @k4, k4 306 307 ! Is EXPEVT larger than 0x800? 308 mov #0x8, k0 309 shll8 k0 310 cmp/hs k0, k4 311 bf 0f 312 313 ! then add 0x580 (k2 is 0xd80 or 0xda0) 314 mov #0x58, k0 315 shll2 k0 316 shll2 k0 317 add k0, k4 3180: 319 ! Setup stack and save DSP context (k0 contains original r15 on return) 320 bsr prepare_stack 321 nop 322 323 ! Save registers / Switch to bank 0 324 mov k4, k2 ! keep vector in k2 325 mov.l 1f, k4 ! SR bits to clear in k4 326 bsr save_regs ! needs original pr value in k3 327 nop 328 329 bra handle_exception_special 330 nop 331 332 .align 2 3331: .long EXPEVT 334#endif 335 336! prepare_stack() 337! - roll back gRB 338! - switch to kernel stack 339! k0 returns original sp (after roll back) 340! k1 trashed 341! k2 trashed 342 343prepare_stack: 344#ifdef CONFIG_GUSA 345 ! Check for roll back gRB (User and Kernel) 346 mov r15, k0 347 shll k0 348 bf/s 1f 349 shll k0 350 bf/s 1f 351 stc spc, k1 352 stc r0_bank, k0 353 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) 354 bt/s 2f 355 stc r1_bank, k1 356 357 add #-2, k0 358 add r15, k0 359 ldc k0, spc ! PC = saved r0 + r15 - 2 3602: mov k1, r15 ! SP = r1 3611: 362#endif 363 ! Switch to kernel stack if needed 364 stc ssr, k0 ! Is it from kernel space? 365 shll k0 ! Check MD bit (bit30) by shifting it into... 366 shll k0 ! ...the T bit 367 bt/s 1f ! It's a kernel to kernel transition. 368 mov r15, k0 ! save original stack to k0 369 /* User space to kernel */ 370 mov #(THREAD_SIZE >> 10), k1 371 shll8 k1 ! k1 := THREAD_SIZE 372 shll2 k1 373 add current, k1 374 mov k1, r15 ! change to kernel stack 375 ! 3761: 377 rts 378 nop 379 380! 381! 0x400: Instruction and Data TLB miss exception vector 382! 383 .balign 1024,0,1024 384tlb_miss: 385 sts pr, k3 ! save original pr value in k3 386 387handle_exception: 388 mova exception_data, k0 389 390 ! Setup stack and save DSP context (k0 contains original r15 on return) 391 bsr prepare_stack 392 PREF(k0) 393 394 ! Save registers / Switch to bank 0 395 mov.l 5f, k2 ! vector register address 396 mov.l 1f, k4 ! SR bits to clear in k4 397 bsr save_regs ! needs original pr value in k3 398 mov.l @k2, k2 ! read out vector and keep in k2 399 400handle_exception_special: 401 ! Setup return address and jump to exception handler 402 mov.l 7f, r9 ! fetch return address 403 stc r2_bank, r0 ! k2 (vector) 404 mov.l 6f, r10 405 shlr2 r0 406 shlr r0 407 mov.l @(r0, r10), r10 408 jmp @r10 409 lds r9, pr ! put return address in pr 410 411 .align L1_CACHE_SHIFT 412 413! save_regs() 414! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack 415! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack 416! - switch bank 417! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 418! k0 contains original stack pointer* 419! k1 trashed 420! k3 passes original pr* 421! k4 passes SR bitmask 422! BL=1 on entry, on exit BL=0. 423 424ENTRY(save_regs) 425 mov #-1, r1 426 mov.l k1, @-r15 ! set TRA (default: -1) 427 sts.l macl, @-r15 428 sts.l mach, @-r15 429 stc.l gbr, @-r15 430 stc.l ssr, @-r15 431 mov.l k3, @-r15 ! original pr in k3 432 stc.l spc, @-r15 433 434 mov.l k0, @-r15 ! original stack pointer in k0 435 mov.l r14, @-r15 436 mov.l r13, @-r15 437 mov.l r12, @-r15 438 mov.l r11, @-r15 439 mov.l r10, @-r15 440 mov.l r9, @-r15 441 mov.l r8, @-r15 442 443 mov.l 0f, k3 ! SR bits to set in k3 444 445 ! fall-through 446 447! save_low_regs() 448! - modify SR for bank switch 449! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 450! k3 passes bits to set in SR 451! k4 passes bits to clear in SR 452 453ENTRY(save_low_regs) 454 stc sr, r8 455 or k3, r8 456 and k4, r8 457 ldc r8, sr 458 459 mov.l r7, @-r15 460 mov.l r6, @-r15 461 mov.l r5, @-r15 462 mov.l r4, @-r15 463 mov.l r3, @-r15 464 mov.l r2, @-r15 465 mov.l r1, @-r15 466 rts 467 mov.l r0, @-r15 468 469! 470! 0x600: Interrupt / NMI vector 471! 472 .balign 512,0,512 473ENTRY(handle_interrupt) 474 sts pr, k3 ! save original pr value in k3 475 mova exception_data, k0 476 477 ! Setup stack and save DSP context (k0 contains original r15 on return) 478 bsr prepare_stack 479 PREF(k0) 480 481 ! Save registers / Switch to bank 0 482 mov.l 1f, k4 ! SR bits to clear in k4 483 bsr save_regs ! needs original pr value in k3 484 mov #-1, k2 ! default vector kept in k2 485 486 setup_frame_reg 487 488 stc sr, r0 ! get status register 489 shlr2 r0 490 and #0x3c, r0 491 cmp/eq #0x3c, r0 492 bf 9f 493 TRACE_IRQS_OFF 4949: 495 496 ! Setup return address and jump to do_IRQ 497 mov.l 4f, r9 ! fetch return address 498 lds r9, pr ! put return address in pr 499 mov.l 2f, r4 500 mov.l 3f, r9 501 mov.l @r4, r4 ! pass INTEVT vector as arg0 502 503 shlr2 r4 504 shlr r4 505 mov r4, r0 ! save vector->jmp table offset for later 506 507 shlr2 r4 ! vector to IRQ# conversion 508 add #-0x10, r4 509 510 cmp/pz r4 ! is it a valid IRQ? 511 bt 10f 512 513 /* 514 * We got here as a result of taking the INTEVT path for something 515 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ() 516 * path and special case the event dispatch instead. This is the 517 * expected path for the NMI (and any other brilliantly implemented 518 * exception), which effectively wants regular exception dispatch 519 * but is unfortunately reported through INTEVT rather than 520 * EXPEVT. Grr. 521 */ 522 mov.l 6f, r9 523 mov.l @(r0, r9), r9 524 jmp @r9 525 mov r15, r8 ! trap handlers take saved regs in r8 526 52710: 528 jmp @r9 ! Off to do_IRQ() we go. 529 mov r15, r5 ! pass saved registers as arg1 530 531ENTRY(exception_none) 532 rts 533 nop 534 535 .align L1_CACHE_SHIFT 536exception_data: 5370: .long 0x000080f0 ! FD=1, IMASK=15 5381: .long 0xcfffffff ! RB=0, BL=0 5392: .long INTEVT 5403: .long do_IRQ 5414: .long ret_from_irq 5425: .long EXPEVT 5436: .long exception_handling_table 5447: .long ret_from_exception 545