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#if defined(CONFIG_KGDB) 57NMI_VEC = 0x1c0 ! Must catch early for debounce 58#endif 59 60/* Offsets to the stack */ 61OFF_R0 = 0 /* Return value. New ABI also arg4 */ 62OFF_R1 = 4 /* New ABI: arg5 */ 63OFF_R2 = 8 /* New ABI: arg6 */ 64OFF_R3 = 12 /* New ABI: syscall_nr */ 65OFF_R4 = 16 /* New ABI: arg0 */ 66OFF_R5 = 20 /* New ABI: arg1 */ 67OFF_R6 = 24 /* New ABI: arg2 */ 68OFF_R7 = 28 /* New ABI: arg3 */ 69OFF_SP = (15*4) 70OFF_PC = (16*4) 71OFF_SR = (16*4+8) 72OFF_TRA = (16*4+6*4) 73 74 75#define k0 r0 76#define k1 r1 77#define k2 r2 78#define k3 r3 79#define k4 r4 80 81#define g_imask r6 /* r6_bank1 */ 82#define k_g_imask r6_bank /* r6_bank1 */ 83#define current r7 /* r7_bank1 */ 84 85#include <asm/entry-macros.S> 86 87/* 88 * Kernel mode register usage: 89 * k0 scratch 90 * k1 scratch 91 * k2 scratch (Exception code) 92 * k3 scratch (Return address) 93 * k4 scratch 94 * k5 reserved 95 * k6 Global Interrupt Mask (0--15 << 4) 96 * k7 CURRENT_THREAD_INFO (pointer to current thread info) 97 */ 98 99! 100! TLB Miss / Initial Page write exception handling 101! _and_ 102! TLB hits, but the access violate the protection. 103! It can be valid access, such as stack grow and/or C-O-W. 104! 105! 106! Find the pmd/pte entry and loadtlb 107! If it's not found, cause address error (SEGV) 108! 109! Although this could be written in assembly language (and it'd be faster), 110! this first version depends *much* on C implementation. 111! 112 113#if defined(CONFIG_MMU) 114 .align 2 115ENTRY(tlb_miss_load) 116 bra call_handle_tlbmiss 117 mov #0, r5 118 119 .align 2 120ENTRY(tlb_miss_store) 121 bra call_handle_tlbmiss 122 mov #1, r5 123 124 .align 2 125ENTRY(initial_page_write) 126 bra call_handle_tlbmiss 127 mov #2, r5 128 129 .align 2 130ENTRY(tlb_protection_violation_load) 131 bra call_do_page_fault 132 mov #0, r5 133 134 .align 2 135ENTRY(tlb_protection_violation_store) 136 bra call_do_page_fault 137 mov #1, r5 138 139call_handle_tlbmiss: 140 setup_frame_reg 141 mov.l 1f, r0 142 mov r5, r8 143 mov.l @r0, r6 144 mov.l 2f, r0 145 sts pr, r10 146 jsr @r0 147 mov r15, r4 148 ! 149 tst r0, r0 150 bf/s 0f 151 lds r10, pr 152 rts 153 nop 1540: 155 mov r8, r5 156call_do_page_fault: 157 mov.l 1f, r0 158 mov.l @r0, r6 159 160 sti 161 162 mov.l 3f, r0 163 mov.l 4f, r1 164 mov r15, r4 165 jmp @r0 166 lds r1, pr 167 168 .align 2 1691: .long MMU_TEA 1702: .long handle_tlbmiss 1713: .long do_page_fault 1724: .long ret_from_exception 173 174 .align 2 175ENTRY(address_error_load) 176 bra call_dae 177 mov #0,r5 ! writeaccess = 0 178 179 .align 2 180ENTRY(address_error_store) 181 bra call_dae 182 mov #1,r5 ! writeaccess = 1 183 184 .align 2 185call_dae: 186 mov.l 1f, r0 187 mov.l @r0, r6 ! address 188 mov.l 2f, r0 189 jmp @r0 190 mov r15, r4 ! regs 191 192 .align 2 1931: .long MMU_TEA 1942: .long do_address_error 195#endif /* CONFIG_MMU */ 196 197#if defined(CONFIG_SH_STANDARD_BIOS) 198 /* Unwind the stack and jmp to the debug entry */ 199ENTRY(sh_bios_handler) 200 mov.l 1f, r8 201 bsr restore_regs 202 nop 203 204 lds k2, pr ! restore pr 205 mov k4, r15 206 ! 207 mov.l 2f, k0 208 mov.l @k0, k0 209 jmp @k0 210 ldc k3, ssr 211 .align 2 2121: .long 0x300000f0 2132: .long gdb_vbr_vector 214#endif /* CONFIG_SH_STANDARD_BIOS */ 215 216! restore_regs() 217! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack 218! - switch bank 219! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack 220! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra 221! k2 returns original pr 222! k3 returns original sr 223! k4 returns original stack pointer 224! r8 passes SR bitmask, overwritten with restored data on return 225! r9 trashed 226! BL=0 on entry, on exit BL=1 (depending on r8). 227 228ENTRY(restore_regs) 229 mov.l @r15+, r0 230 mov.l @r15+, r1 231 mov.l @r15+, r2 232 mov.l @r15+, r3 233 mov.l @r15+, r4 234 mov.l @r15+, r5 235 mov.l @r15+, r6 236 mov.l @r15+, r7 237 ! 238 stc sr, r9 239 or r8, r9 240 ldc r9, sr 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 mov.l @r15+, k2 ! original PR 252 mov.l @r15+, k3 ! original SR 253 ldc.l @r15+, gbr 254 lds.l @r15+, mach 255 lds.l @r15+, macl 256 rts 257 add #4, r15 ! Skip syscall number 258 259restore_all: 260 mov.l 7f, r8 261 bsr restore_regs 262 nop 263 264 lds k2, pr ! restore pr 265 ! 266 ! Calculate new SR value 267 mov k3, k2 ! original SR value 268 mov #0xfffffff0, k1 269 extu.b k1, k1 270 not k1, k1 271 and k1, k2 ! Mask original SR value 272 ! 273 mov k3, k0 ! Calculate IMASK-bits 274 shlr2 k0 275 and #0x3c, k0 276 cmp/eq #0x3c, k0 277 bt/s 6f 278 shll2 k0 279 mov g_imask, k0 280 ! 2816: or k0, k2 ! Set the IMASK-bits 282 ldc k2, ssr 283 ! 284#if defined(CONFIG_KGDB) 285 ! Clear in_nmi 286 mov.l 6f, k0 287 mov #0, k1 288 mov.b k1, @k0 289#endif 290 mov k4, r15 291 rte 292 nop 293 294 .align 2 2955: .long 0x00001000 ! DSP 296#ifdef CONFIG_KGDB 2976: .long in_nmi 298#endif 2997: .long 0x30000000 300 301! common exception handler 302#include "../../entry-common.S" 303 304! Exception Vector Base 305! 306! Should be aligned page boundary. 307! 308 .balign 4096,0,4096 309ENTRY(vbr_base) 310 .long 0 311! 312! 0x100: General exception vector 313! 314 .balign 256,0,256 315general_exception: 316#ifndef CONFIG_CPU_SUBTYPE_SHX3 317 bra handle_exception 318 sts pr, k3 ! save original pr value in k3 319#else 320 mov.l 1f, k4 321 mov.l @k4, k4 322 323 ! Is EXPEVT larger than 0x800? 324 mov #0x8, k0 325 shll8 k0 326 cmp/hs k0, k4 327 bf 0f 328 329 ! then add 0x580 (k2 is 0xd80 or 0xda0) 330 mov #0x58, k0 331 shll2 k0 332 shll2 k0 333 add k0, k4 3340: 335 ! Setup stack and save DSP context (k0 contains original r15 on return) 336 bsr prepare_stack 337 nop 338 339 ! Save registers / Switch to bank 0 340 mov k4, k2 ! keep vector in k2 341 mov.l 1f, k4 ! SR bits to clear in k4 342 bsr save_regs ! needs original pr value in k3 343 nop 344 345 bra handle_exception_special 346 nop 347 348 .align 2 3491: .long EXPEVT 350#endif 351 352! prepare_stack() 353! - roll back gRB 354! - switch to kernel stack 355! k0 returns original sp (after roll back) 356! k1 trashed 357! k2 trashed 358 359prepare_stack: 360#ifdef CONFIG_GUSA 361 ! Check for roll back gRB (User and Kernel) 362 mov r15, k0 363 shll k0 364 bf/s 1f 365 shll k0 366 bf/s 1f 367 stc spc, k1 368 stc r0_bank, k0 369 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) 370 bt/s 2f 371 stc r1_bank, k1 372 373 add #-2, k0 374 add r15, k0 375 ldc k0, spc ! PC = saved r0 + r15 - 2 3762: mov k1, r15 ! SP = r1 3771: 378#endif 379 ! Switch to kernel stack if needed 380 stc ssr, k0 ! Is it from kernel space? 381 shll k0 ! Check MD bit (bit30) by shifting it into... 382 shll k0 ! ...the T bit 383 bt/s 1f ! It's a kernel to kernel transition. 384 mov r15, k0 ! save original stack to k0 385 /* User space to kernel */ 386 mov #(THREAD_SIZE >> 10), k1 387 shll8 k1 ! k1 := THREAD_SIZE 388 shll2 k1 389 add current, k1 390 mov k1, r15 ! change to kernel stack 391 ! 3921: 393 rts 394 nop 395 396! 397! 0x400: Instruction and Data TLB miss exception vector 398! 399 .balign 1024,0,1024 400tlb_miss: 401 sts pr, k3 ! save original pr value in k3 402 403handle_exception: 404 mova exception_data, k0 405 406 ! Setup stack and save DSP context (k0 contains original r15 on return) 407 bsr prepare_stack 408 PREF(k0) 409 410 ! Save registers / Switch to bank 0 411 mov.l 5f, k2 ! vector register address 412 mov.l 1f, k4 ! SR bits to clear in k4 413 bsr save_regs ! needs original pr value in k3 414 mov.l @k2, k2 ! read out vector and keep in k2 415 416handle_exception_special: 417 ! Setup return address and jump to exception handler 418 mov.l 7f, r9 ! fetch return address 419 stc r2_bank, r0 ! k2 (vector) 420 mov.l 6f, r10 421 shlr2 r0 422 shlr r0 423 mov.l @(r0, r10), r10 424 jmp @r10 425 lds r9, pr ! put return address in pr 426 427 .align L1_CACHE_SHIFT 428 429! save_regs() 430! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack 431! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack 432! - switch bank 433! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 434! k0 contains original stack pointer* 435! k1 trashed 436! k3 passes original pr* 437! k4 passes SR bitmask 438! BL=1 on entry, on exit BL=0. 439 440ENTRY(save_regs) 441 mov #-1, r1 442 mov.l k1, @-r15 ! set TRA (default: -1) 443 sts.l macl, @-r15 444 sts.l mach, @-r15 445 stc.l gbr, @-r15 446 stc.l ssr, @-r15 447 mov.l k3, @-r15 ! original pr in k3 448 stc.l spc, @-r15 449 450 mov.l k0, @-r15 ! original stack pointer in k0 451 mov.l r14, @-r15 452 mov.l r13, @-r15 453 mov.l r12, @-r15 454 mov.l r11, @-r15 455 mov.l r10, @-r15 456 mov.l r9, @-r15 457 mov.l r8, @-r15 458 459 mov.l 0f, k3 ! SR bits to set in k3 460 461 ! fall-through 462 463! save_low_regs() 464! - modify SR for bank switch 465! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 466! k3 passes bits to set in SR 467! k4 passes bits to clear in SR 468 469ENTRY(save_low_regs) 470 stc sr, r8 471 or k3, r8 472 and k4, r8 473 ldc r8, sr 474 475 mov.l r7, @-r15 476 mov.l r6, @-r15 477 mov.l r5, @-r15 478 mov.l r4, @-r15 479 mov.l r3, @-r15 480 mov.l r2, @-r15 481 mov.l r1, @-r15 482 rts 483 mov.l r0, @-r15 484 485! 486! 0x600: Interrupt / NMI vector 487! 488 .balign 512,0,512 489ENTRY(handle_interrupt) 490#if defined(CONFIG_KGDB) 491 mov.l 2f, k2 492 ! Debounce (filter nested NMI) 493 mov.l @k2, k0 494 mov.l 9f, k1 495 cmp/eq k1, k0 496 bf 11f 497 mov.l 10f, k1 498 tas.b @k1 499 bt 11f 500 rte 501 nop 502 .align 2 5039: .long NMI_VEC 50410: .long in_nmi 50511: 506#endif /* defined(CONFIG_KGDB) */ 507 sts pr, k3 ! save original pr value in k3 508 mova exception_data, k0 509 510 ! Setup stack and save DSP context (k0 contains original r15 on return) 511 bsr prepare_stack 512 PREF(k0) 513 514 ! Save registers / Switch to bank 0 515 mov.l 1f, k4 ! SR bits to clear in k4 516 bsr save_regs ! needs original pr value in k3 517 mov #-1, k2 ! default vector kept in k2 518 519 setup_frame_reg 520 521 stc sr, r0 ! get status register 522 shlr2 r0 523 and #0x3c, r0 524 cmp/eq #0x3c, r0 525 bf 9f 526 TRACE_IRQS_OFF 5279: 528 529 ! Setup return address and jump to do_IRQ 530 mov.l 4f, r9 ! fetch return address 531 lds r9, pr ! put return address in pr 532 mov.l 2f, r4 533 mov.l 3f, r9 534 mov.l @r4, r4 ! pass INTEVT vector as arg0 535 jmp @r9 536 mov r15, r5 ! pass saved registers as arg1 537 538ENTRY(exception_none) 539 rts 540 nop 541 542 .align L1_CACHE_SHIFT 543exception_data: 5440: .long 0x000080f0 ! FD=1, IMASK=15 5451: .long 0xcfffffff ! RB=0, BL=0 5462: .long INTEVT 5473: .long do_IRQ 5484: .long ret_from_irq 5495: .long EXPEVT 5506: .long exception_handling_table 5517: .long ret_from_exception 552