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 sti 156 157 mov.l 3f, r0 158 mov.l 4f, r1 159 mov r15, r4 160 jmp @r0 161 lds r1, pr 162 163 .align 2 1641: .long MMU_TEA 1652: .long handle_tlbmiss 1663: .long do_page_fault 1674: .long ret_from_exception 168 169 .align 2 170ENTRY(address_error_load) 171 bra call_dae 172 mov #0,r5 ! writeaccess = 0 173 174 .align 2 175ENTRY(address_error_store) 176 bra call_dae 177 mov #1,r5 ! writeaccess = 1 178 179 .align 2 180call_dae: 181 mov.l 1f, r0 182 mov.l @r0, r6 ! address 183 mov.l 2f, r0 184 jmp @r0 185 mov r15, r4 ! regs 186 187 .align 2 1881: .long MMU_TEA 1892: .long do_address_error 190#endif /* CONFIG_MMU */ 191 192#if defined(CONFIG_SH_STANDARD_BIOS) 193 /* Unwind the stack and jmp to the debug entry */ 194ENTRY(sh_bios_handler) 195 mov.l 1f, r8 196 bsr restore_regs 197 nop 198 199 lds k2, pr ! restore pr 200 mov k4, r15 201 ! 202 mov.l 2f, k0 203 mov.l @k0, k0 204 jmp @k0 205 ldc k3, ssr 206 .align 2 2071: .long 0x300000f0 2082: .long gdb_vbr_vector 209#endif /* CONFIG_SH_STANDARD_BIOS */ 210 211! restore_regs() 212! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack 213! - switch bank 214! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack 215! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra 216! k2 returns original pr 217! k3 returns original sr 218! k4 returns original stack pointer 219! r8 passes SR bitmask, overwritten with restored data on return 220! r9 trashed 221! BL=0 on entry, on exit BL=1 (depending on r8). 222 223ENTRY(restore_regs) 224 mov.l @r15+, r0 225 mov.l @r15+, r1 226 mov.l @r15+, r2 227 mov.l @r15+, r3 228 mov.l @r15+, r4 229 mov.l @r15+, r5 230 mov.l @r15+, r6 231 mov.l @r15+, r7 232 ! 233 stc sr, r9 234 or r8, r9 235 ldc r9, sr 236 ! 237 mov.l @r15+, r8 238 mov.l @r15+, r9 239 mov.l @r15+, r10 240 mov.l @r15+, r11 241 mov.l @r15+, r12 242 mov.l @r15+, r13 243 mov.l @r15+, r14 244 mov.l @r15+, k4 ! original stack pointer 245 ldc.l @r15+, spc 246 mov.l @r15+, k2 ! original PR 247 mov.l @r15+, k3 ! original SR 248 ldc.l @r15+, gbr 249 lds.l @r15+, mach 250 lds.l @r15+, macl 251 rts 252 add #4, r15 ! Skip syscall number 253 254restore_all: 255 mov.l 7f, r8 256 bsr restore_regs 257 nop 258 259 lds k2, pr ! restore pr 260 ! 261 ! Calculate new SR value 262 mov k3, k2 ! original SR value 263 mov #0xfffffff0, k1 264 extu.b k1, k1 265 not k1, k1 266 and k1, k2 ! Mask original SR value 267 ! 268 mov k3, k0 ! Calculate IMASK-bits 269 shlr2 k0 270 and #0x3c, k0 271 cmp/eq #0x3c, k0 272 bt/s 6f 273 shll2 k0 274 mov g_imask, k0 275 ! 2766: or k0, k2 ! Set the IMASK-bits 277 ldc k2, ssr 278 ! 279 mov k4, r15 280 rte 281 nop 282 283 .align 2 2845: .long 0x00001000 ! DSP 2857: .long 0x30000000 286 287! common exception handler 288#include "../../entry-common.S" 289 290! Exception Vector Base 291! 292! Should be aligned page boundary. 293! 294 .balign 4096,0,4096 295ENTRY(vbr_base) 296 .long 0 297! 298! 0x100: General exception vector 299! 300 .balign 256,0,256 301general_exception: 302#ifndef CONFIG_CPU_SUBTYPE_SHX3 303 bra handle_exception 304 sts pr, k3 ! save original pr value in k3 305#else 306 mov.l 1f, k4 307 mov.l @k4, k4 308 309 ! Is EXPEVT larger than 0x800? 310 mov #0x8, k0 311 shll8 k0 312 cmp/hs k0, k4 313 bf 0f 314 315 ! then add 0x580 (k2 is 0xd80 or 0xda0) 316 mov #0x58, k0 317 shll2 k0 318 shll2 k0 319 add k0, k4 3200: 321 ! Setup stack and save DSP context (k0 contains original r15 on return) 322 bsr prepare_stack 323 nop 324 325 ! Save registers / Switch to bank 0 326 mov k4, k2 ! keep vector in k2 327 mov.l 1f, k4 ! SR bits to clear in k4 328 bsr save_regs ! needs original pr value in k3 329 nop 330 331 bra handle_exception_special 332 nop 333 334 .align 2 3351: .long EXPEVT 336#endif 337 338! prepare_stack() 339! - roll back gRB 340! - switch to kernel stack 341! k0 returns original sp (after roll back) 342! k1 trashed 343! k2 trashed 344 345prepare_stack: 346#ifdef CONFIG_GUSA 347 ! Check for roll back gRB (User and Kernel) 348 mov r15, k0 349 shll k0 350 bf/s 1f 351 shll k0 352 bf/s 1f 353 stc spc, k1 354 stc r0_bank, k0 355 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) 356 bt/s 2f 357 stc r1_bank, k1 358 359 add #-2, k0 360 add r15, k0 361 ldc k0, spc ! PC = saved r0 + r15 - 2 3622: mov k1, r15 ! SP = r1 3631: 364#endif 365 ! Switch to kernel stack if needed 366 stc ssr, k0 ! Is it from kernel space? 367 shll k0 ! Check MD bit (bit30) by shifting it into... 368 shll k0 ! ...the T bit 369 bt/s 1f ! It's a kernel to kernel transition. 370 mov r15, k0 ! save original stack to k0 371 /* User space to kernel */ 372 mov #(THREAD_SIZE >> 10), k1 373 shll8 k1 ! k1 := THREAD_SIZE 374 shll2 k1 375 add current, k1 376 mov k1, r15 ! change to kernel stack 377 ! 3781: 379 rts 380 nop 381 382! 383! 0x400: Instruction and Data TLB miss exception vector 384! 385 .balign 1024,0,1024 386tlb_miss: 387 sts pr, k3 ! save original pr value in k3 388 389handle_exception: 390 mova exception_data, k0 391 392 ! Setup stack and save DSP context (k0 contains original r15 on return) 393 bsr prepare_stack 394 PREF(k0) 395 396 ! Save registers / Switch to bank 0 397 mov.l 5f, k2 ! vector register address 398 mov.l 1f, k4 ! SR bits to clear in k4 399 bsr save_regs ! needs original pr value in k3 400 mov.l @k2, k2 ! read out vector and keep in k2 401 402handle_exception_special: 403 ! Setup return address and jump to exception handler 404 mov.l 7f, r9 ! fetch return address 405 stc r2_bank, r0 ! k2 (vector) 406 mov.l 6f, r10 407 shlr2 r0 408 shlr r0 409 mov.l @(r0, r10), r10 410 jmp @r10 411 lds r9, pr ! put return address in pr 412 413 .align L1_CACHE_SHIFT 414 415! save_regs() 416! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack 417! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack 418! - switch bank 419! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 420! k0 contains original stack pointer* 421! k1 trashed 422! k3 passes original pr* 423! k4 passes SR bitmask 424! BL=1 on entry, on exit BL=0. 425 426ENTRY(save_regs) 427 mov #-1, r1 428 mov.l k1, @-r15 ! set TRA (default: -1) 429 sts.l macl, @-r15 430 sts.l mach, @-r15 431 stc.l gbr, @-r15 432 stc.l ssr, @-r15 433 mov.l k3, @-r15 ! original pr in k3 434 stc.l spc, @-r15 435 436 mov.l k0, @-r15 ! original stack pointer in k0 437 mov.l r14, @-r15 438 mov.l r13, @-r15 439 mov.l r12, @-r15 440 mov.l r11, @-r15 441 mov.l r10, @-r15 442 mov.l r9, @-r15 443 mov.l r8, @-r15 444 445 mov.l 0f, k3 ! SR bits to set in k3 446 447 ! fall-through 448 449! save_low_regs() 450! - modify SR for bank switch 451! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 452! k3 passes bits to set in SR 453! k4 passes bits to clear in SR 454 455ENTRY(save_low_regs) 456 stc sr, r8 457 or k3, r8 458 and k4, r8 459 ldc r8, sr 460 461 mov.l r7, @-r15 462 mov.l r6, @-r15 463 mov.l r5, @-r15 464 mov.l r4, @-r15 465 mov.l r3, @-r15 466 mov.l r2, @-r15 467 mov.l r1, @-r15 468 rts 469 mov.l r0, @-r15 470 471! 472! 0x600: Interrupt / NMI vector 473! 474 .balign 512,0,512 475ENTRY(handle_interrupt) 476 sts pr, k3 ! save original pr value in k3 477 mova exception_data, k0 478 479 ! Setup stack and save DSP context (k0 contains original r15 on return) 480 bsr prepare_stack 481 PREF(k0) 482 483 ! Save registers / Switch to bank 0 484 mov.l 1f, k4 ! SR bits to clear in k4 485 bsr save_regs ! needs original pr value in k3 486 mov #-1, k2 ! default vector kept in k2 487 488 setup_frame_reg 489 490 stc sr, r0 ! get status register 491 shlr2 r0 492 and #0x3c, r0 493 cmp/eq #0x3c, r0 494 bf 9f 495 TRACE_IRQS_OFF 4969: 497 498 ! Setup return address and jump to do_IRQ 499 mov.l 4f, r9 ! fetch return address 500 lds r9, pr ! put return address in pr 501 mov.l 2f, r4 502 mov.l 3f, r9 503 mov.l @r4, r4 ! pass INTEVT vector as arg0 504 505 shlr2 r4 506 shlr r4 507 mov r4, r0 ! save vector->jmp table offset for later 508 509 shlr2 r4 ! vector to IRQ# conversion 510 add #-0x10, r4 511 512 cmp/pz r4 ! is it a valid IRQ? 513 bt 10f 514 515 /* 516 * We got here as a result of taking the INTEVT path for something 517 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ() 518 * path and special case the event dispatch instead. This is the 519 * expected path for the NMI (and any other brilliantly implemented 520 * exception), which effectively wants regular exception dispatch 521 * but is unfortunately reported through INTEVT rather than 522 * EXPEVT. Grr. 523 */ 524 mov.l 6f, r9 525 mov.l @(r0, r9), r9 526 jmp @r9 527 mov r15, r8 ! trap handlers take saved regs in r8 528 52910: 530 jmp @r9 ! Off to do_IRQ() we go. 531 mov r15, r5 ! pass saved registers as arg1 532 533ENTRY(exception_none) 534 rts 535 nop 536 537 .align L1_CACHE_SHIFT 538exception_data: 5390: .long 0x000080f0 ! FD=1, IMASK=15 5401: .long 0xcfffffff ! RB=0, BL=0 5412: .long INTEVT 5423: .long do_IRQ 5434: .long ret_from_irq 5445: .long EXPEVT 5456: .long exception_handling_table 5467: .long ret_from_exception 547