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_dpf 117 mov #0, r5 118 119 .align 2 120ENTRY(tlb_miss_store) 121 bra call_dpf 122 mov #1, r5 123 124 .align 2 125ENTRY(initial_page_write) 126 bra call_dpf 127 mov #1, r5 128 129 .align 2 130ENTRY(tlb_protection_violation_load) 131 bra call_dpf 132 mov #0, r5 133 134 .align 2 135ENTRY(tlb_protection_violation_store) 136 bra call_dpf 137 mov #1, r5 138 139call_dpf: 140 mov.l 1f, r0 141 mov r5, r8 142 mov.l @r0, r6 143 mov r6, r9 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: mov.l 3f, r0 155 mov r9, r6 156 mov r8, r5 157 jmp @r0 158 mov r15, r4 159 160 .align 2 1611: .long MMU_TEA 1622: .long __do_page_fault 1633: .long do_page_fault 164 165 .align 2 166ENTRY(address_error_load) 167 bra call_dae 168 mov #0,r5 ! writeaccess = 0 169 170 .align 2 171ENTRY(address_error_store) 172 bra call_dae 173 mov #1,r5 ! writeaccess = 1 174 175 .align 2 176call_dae: 177 mov.l 1f, r0 178 mov.l @r0, r6 ! address 179 mov.l 2f, r0 180 jmp @r0 181 mov r15, r4 ! regs 182 183 .align 2 1841: .long MMU_TEA 1852: .long do_address_error 186#endif /* CONFIG_MMU */ 187 188#if defined(CONFIG_SH_STANDARD_BIOS) 189 /* Unwind the stack and jmp to the debug entry */ 190ENTRY(sh_bios_handler) 191 mov.l 1f, r8 192 bsr restore_regs 193 nop 194 195 lds k2, pr ! restore pr 196 mov k4, r15 197 ! 198 mov.l 2f, k0 199 mov.l @k0, k0 200 jmp @k0 201 ldc k3, ssr 202 .align 2 2031: .long 0x300000f0 2042: .long gdb_vbr_vector 205#endif /* CONFIG_SH_STANDARD_BIOS */ 206 207! restore_regs() 208! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack 209! - switch bank 210! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack 211! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra 212! k2 returns original pr 213! k3 returns original sr 214! k4 returns original stack pointer 215! r8 passes SR bitmask, overwritten with restored data on return 216! r9 trashed 217! BL=0 on entry, on exit BL=1 (depending on r8). 218 219ENTRY(restore_regs) 220 mov.l @r15+, r0 221 mov.l @r15+, r1 222 mov.l @r15+, r2 223 mov.l @r15+, r3 224 mov.l @r15+, r4 225 mov.l @r15+, r5 226 mov.l @r15+, r6 227 mov.l @r15+, r7 228 ! 229 stc sr, r9 230 or r8, r9 231 ldc r9, sr 232 ! 233 mov.l @r15+, r8 234 mov.l @r15+, r9 235 mov.l @r15+, r10 236 mov.l @r15+, r11 237 mov.l @r15+, r12 238 mov.l @r15+, r13 239 mov.l @r15+, r14 240 mov.l @r15+, k4 ! original stack pointer 241 ldc.l @r15+, spc 242 mov.l @r15+, k2 ! original PR 243 mov.l @r15+, k3 ! original SR 244 ldc.l @r15+, gbr 245 lds.l @r15+, mach 246 lds.l @r15+, macl 247 rts 248 add #4, r15 ! Skip syscall number 249 250restore_all: 251 mov.l 7f, r8 252 bsr restore_regs 253 nop 254 255 lds k2, pr ! restore pr 256 ! 257 ! Calculate new SR value 258 mov k3, k2 ! original SR value 259 mov #0xf0, k1 260 extu.b k1, k1 261 not k1, k1 262 and k1, k2 ! Mask original SR value 263 ! 264 mov k3, k0 ! Calculate IMASK-bits 265 shlr2 k0 266 and #0x3c, k0 267 cmp/eq #0x3c, k0 268 bt/s 6f 269 shll2 k0 270 mov g_imask, k0 271 ! 2726: or k0, k2 ! Set the IMASK-bits 273 ldc k2, ssr 274 ! 275#if defined(CONFIG_KGDB) 276 ! Clear in_nmi 277 mov.l 6f, k0 278 mov #0, k1 279 mov.b k1, @k0 280#endif 281 mov k4, r15 282 rte 283 nop 284 285 .align 2 2865: .long 0x00001000 ! DSP 287#ifdef CONFIG_KGDB 2886: .long in_nmi 289#endif 2907: .long 0x30000000 291 292! common exception handler 293#include "../../entry-common.S" 294 295! Exception Vector Base 296! 297! Should be aligned page boundary. 298! 299 .balign 4096,0,4096 300ENTRY(vbr_base) 301 .long 0 302! 303! 0x100: General exception vector 304! 305 .balign 256,0,256 306general_exception: 307#ifndef CONFIG_CPU_SUBTYPE_SHX3 308 bra handle_exception 309 sts pr, k3 ! save original pr value in k3 310#else 311 mov.l 1f, k4 312 mov.l @k4, k4 313 314 ! Is EXPEVT larger than 0x800? 315 mov #0x8, k0 316 shll8 k0 317 cmp/hs k0, k4 318 bf 0f 319 320 ! then add 0x580 (k2 is 0xd80 or 0xda0) 321 mov #0x58, k0 322 shll2 k0 323 shll2 k0 324 add k0, k4 3250: 326 ! Setup stack and save DSP context (k0 contains original r15 on return) 327 bsr prepare_stack 328 nop 329 330 ! Save registers / Switch to bank 0 331 mov k4, k2 ! keep vector in k2 332 mov.l 1f, k4 ! SR bits to clear in k4 333 bsr save_regs ! needs original pr value in k3 334 nop 335 336 bra handle_exception_special 337 nop 338 339 .align 2 3401: .long EXPEVT 341#endif 342 343! prepare_stack() 344! - roll back gRB 345! - switch to kernel stack 346! k0 returns original sp (after roll back) 347! k1 trashed 348! k2 trashed 349 350prepare_stack: 351#ifdef CONFIG_GUSA 352 ! Check for roll back gRB (User and Kernel) 353 mov r15, k0 354 shll k0 355 bf/s 1f 356 shll k0 357 bf/s 1f 358 stc spc, k1 359 stc r0_bank, k0 360 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) 361 bt/s 2f 362 stc r1_bank, k1 363 364 add #-2, k0 365 add r15, k0 366 ldc k0, spc ! PC = saved r0 + r15 - 2 3672: mov k1, r15 ! SP = r1 3681: 369#endif 370 ! Switch to kernel stack if needed 371 stc ssr, k0 ! Is it from kernel space? 372 shll k0 ! Check MD bit (bit30) by shifting it into... 373 shll k0 ! ...the T bit 374 bt/s 1f ! It's a kernel to kernel transition. 375 mov r15, k0 ! save original stack to k0 376 /* User space to kernel */ 377 mov #(THREAD_SIZE >> 10), k1 378 shll8 k1 ! k1 := THREAD_SIZE 379 shll2 k1 380 add current, k1 381 mov k1, r15 ! change to kernel stack 382 ! 3831: 384 rts 385 nop 386 387! 388! 0x400: Instruction and Data TLB miss exception vector 389! 390 .balign 1024,0,1024 391tlb_miss: 392 sts pr, k3 ! save original pr value in k3 393 394handle_exception: 395 mova exception_data, k0 396 397 ! Setup stack and save DSP context (k0 contains original r15 on return) 398 bsr prepare_stack 399 PREF(k0) 400 401 ! Save registers / Switch to bank 0 402 mov.l 5f, k2 ! vector register address 403 mov.l 1f, k4 ! SR bits to clear in k4 404 bsr save_regs ! needs original pr value in k3 405 mov.l @k2, k2 ! read out vector and keep in k2 406 407handle_exception_special: 408 ! Setup return address and jump to exception handler 409 mov.l 7f, r9 ! fetch return address 410 stc r2_bank, r0 ! k2 (vector) 411 mov.l 6f, r10 412 shlr2 r0 413 shlr r0 414 mov.l @(r0, r10), r10 415 jmp @r10 416 lds r9, pr ! put return address in pr 417 418 .align L1_CACHE_SHIFT 419 420! save_regs() 421! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack 422! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack 423! - switch bank 424! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 425! k0 contains original stack pointer* 426! k1 trashed 427! k3 passes original pr* 428! k4 passes SR bitmask 429! BL=1 on entry, on exit BL=0. 430 431ENTRY(save_regs) 432 mov #-1, r1 433 mov.l k1, @-r15 ! set TRA (default: -1) 434 sts.l macl, @-r15 435 sts.l mach, @-r15 436 stc.l gbr, @-r15 437 stc.l ssr, @-r15 438 mov.l k3, @-r15 ! original pr in k3 439 stc.l spc, @-r15 440 441 mov.l k0, @-r15 ! original stack pointer in k0 442 mov.l r14, @-r15 443 mov.l r13, @-r15 444 mov.l r12, @-r15 445 mov.l r11, @-r15 446 mov.l r10, @-r15 447 mov.l r9, @-r15 448 mov.l r8, @-r15 449 450 mov.l 0f, k3 ! SR bits to set in k3 451 452 ! fall-through 453 454! save_low_regs() 455! - modify SR for bank switch 456! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 457! k3 passes bits to set in SR 458! k4 passes bits to clear in SR 459 460ENTRY(save_low_regs) 461 stc sr, r8 462 or k3, r8 463 and k4, r8 464 ldc r8, sr 465 466 mov.l r7, @-r15 467 mov.l r6, @-r15 468 mov.l r5, @-r15 469 mov.l r4, @-r15 470 mov.l r3, @-r15 471 mov.l r2, @-r15 472 mov.l r1, @-r15 473 rts 474 mov.l r0, @-r15 475 476! 477! 0x600: Interrupt / NMI vector 478! 479 .balign 512,0,512 480ENTRY(handle_interrupt) 481#if defined(CONFIG_KGDB) 482 mov.l 2f, k2 483 ! Debounce (filter nested NMI) 484 mov.l @k2, k0 485 mov.l 9f, k1 486 cmp/eq k1, k0 487 bf 11f 488 mov.l 10f, k1 489 tas.b @k1 490 bt 11f 491 rte 492 nop 493 .align 2 4949: .long NMI_VEC 49510: .long in_nmi 49611: 497#endif /* defined(CONFIG_KGDB) */ 498 sts pr, k3 ! save original pr value in k3 499 mova exception_data, k0 500 501 ! Setup stack and save DSP context (k0 contains original r15 on return) 502 bsr prepare_stack 503 PREF(k0) 504 505 ! Save registers / Switch to bank 0 506 mov.l 1f, k4 ! SR bits to clear in k4 507 bsr save_regs ! needs original pr value in k3 508 mov #-1, k2 ! default vector kept in k2 509 510 ! Setup return address and jump to do_IRQ 511 mov.l 4f, r9 ! fetch return address 512 lds r9, pr ! put return address in pr 513 mov.l 2f, r4 514 mov.l 3f, r9 515 mov.l @r4, r4 ! pass INTEVT vector as arg0 516 jmp @r9 517 mov r15, r5 ! pass saved registers as arg1 518 519ENTRY(exception_none) 520 rts 521 nop 522 523 .align L1_CACHE_SHIFT 524exception_data: 5250: .long 0x000080f0 ! FD=1, IMASK=15 5261: .long 0xcfffffff ! RB=0, BL=0 5272: .long INTEVT 5283: .long do_IRQ 5294: .long ret_from_irq 5305: .long EXPEVT 5316: .long exception_handling_table 5327: .long ret_from_exception 533