162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * arch/sh/kernel/cpu/sh2/entry.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * The SH-2 exception entry 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2005-2008 Yoshinori Sato 862306a36Sopenharmony_ci * Copyright (C) 2005 AXE,Inc. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/linkage.h> 1262306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1362306a36Sopenharmony_ci#include <asm/thread_info.h> 1462306a36Sopenharmony_ci#include <cpu/mmu_context.h> 1562306a36Sopenharmony_ci#include <asm/unistd.h> 1662306a36Sopenharmony_ci#include <asm/errno.h> 1762306a36Sopenharmony_ci#include <asm/page.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Offsets to the stack */ 2062306a36Sopenharmony_ciOFF_R0 = 0 /* Return value. New ABI also arg4 */ 2162306a36Sopenharmony_ciOFF_R1 = 4 /* New ABI: arg5 */ 2262306a36Sopenharmony_ciOFF_R2 = 8 /* New ABI: arg6 */ 2362306a36Sopenharmony_ciOFF_R3 = 12 /* New ABI: syscall_nr */ 2462306a36Sopenharmony_ciOFF_R4 = 16 /* New ABI: arg0 */ 2562306a36Sopenharmony_ciOFF_R5 = 20 /* New ABI: arg1 */ 2662306a36Sopenharmony_ciOFF_R6 = 24 /* New ABI: arg2 */ 2762306a36Sopenharmony_ciOFF_R7 = 28 /* New ABI: arg3 */ 2862306a36Sopenharmony_ciOFF_SP = (15*4) 2962306a36Sopenharmony_ciOFF_PC = (16*4) 3062306a36Sopenharmony_ciOFF_SR = (16*4+2*4) 3162306a36Sopenharmony_ciOFF_TRA = (16*4+6*4) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <asm/entry-macros.S> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciENTRY(exception_handler) 3662306a36Sopenharmony_ci ! stack 3762306a36Sopenharmony_ci ! r0 <- point sp 3862306a36Sopenharmony_ci ! r1 3962306a36Sopenharmony_ci ! pc 4062306a36Sopenharmony_ci ! sr 4162306a36Sopenharmony_ci ! r0 = temporary 4262306a36Sopenharmony_ci ! r1 = vector (pseudo EXPEVT / INTEVT / TRA) 4362306a36Sopenharmony_ci mov.l r2,@-sp 4462306a36Sopenharmony_ci mov.l r3,@-sp 4562306a36Sopenharmony_ci cli 4662306a36Sopenharmony_ci mov.l $cpu_mode,r2 4762306a36Sopenharmony_ci#ifdef CONFIG_SMP 4862306a36Sopenharmony_ci mov.l $cpuid,r3 4962306a36Sopenharmony_ci mov.l @r3,r3 5062306a36Sopenharmony_ci mov.l @r3,r3 5162306a36Sopenharmony_ci shll2 r3 5262306a36Sopenharmony_ci add r3,r2 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci mov.l @r2,r0 5562306a36Sopenharmony_ci mov.l @(5*4,r15),r3 ! previous SR 5662306a36Sopenharmony_ci or r0,r3 ! set MD 5762306a36Sopenharmony_ci tst r0,r0 5862306a36Sopenharmony_ci bf/s 1f ! previous mode check 5962306a36Sopenharmony_ci mov.l r3,@(5*4,r15) ! update SR 6062306a36Sopenharmony_ci ! switch to kernel mode 6162306a36Sopenharmony_ci mov.l __md_bit,r0 6262306a36Sopenharmony_ci mov.l r0,@r2 ! enter kernel mode 6362306a36Sopenharmony_ci mov.l $current_thread_info,r2 6462306a36Sopenharmony_ci#ifdef CONFIG_SMP 6562306a36Sopenharmony_ci mov.l $cpuid,r0 6662306a36Sopenharmony_ci mov.l @r0,r0 6762306a36Sopenharmony_ci mov.l @r0,r0 6862306a36Sopenharmony_ci shll2 r0 6962306a36Sopenharmony_ci add r0,r2 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci mov.l @r2,r2 7262306a36Sopenharmony_ci mov #(THREAD_SIZE >> 8),r0 7362306a36Sopenharmony_ci shll8 r0 7462306a36Sopenharmony_ci add r2,r0 7562306a36Sopenharmony_ci mov r15,r2 ! r2 = user stack top 7662306a36Sopenharmony_ci mov r0,r15 ! switch kernel stack 7762306a36Sopenharmony_ci mov.l r1,@-r15 ! TRA 7862306a36Sopenharmony_ci sts.l macl, @-r15 7962306a36Sopenharmony_ci sts.l mach, @-r15 8062306a36Sopenharmony_ci stc.l gbr, @-r15 8162306a36Sopenharmony_ci mov.l @(5*4,r2),r0 8262306a36Sopenharmony_ci mov.l r0,@-r15 ! original SR 8362306a36Sopenharmony_ci sts.l pr,@-r15 8462306a36Sopenharmony_ci mov.l @(4*4,r2),r0 8562306a36Sopenharmony_ci mov.l r0,@-r15 ! original PC 8662306a36Sopenharmony_ci mov r2,r3 8762306a36Sopenharmony_ci add #(4+2)*4,r3 ! rewind r0 - r3 + exception frame 8862306a36Sopenharmony_ci mov.l r3,@-r15 ! original SP 8962306a36Sopenharmony_ci mov.l r14,@-r15 9062306a36Sopenharmony_ci mov.l r13,@-r15 9162306a36Sopenharmony_ci mov.l r12,@-r15 9262306a36Sopenharmony_ci mov.l r11,@-r15 9362306a36Sopenharmony_ci mov.l r10,@-r15 9462306a36Sopenharmony_ci mov.l r9,@-r15 9562306a36Sopenharmony_ci mov.l r8,@-r15 9662306a36Sopenharmony_ci mov.l r7,@-r15 9762306a36Sopenharmony_ci mov.l r6,@-r15 9862306a36Sopenharmony_ci mov.l r5,@-r15 9962306a36Sopenharmony_ci mov.l r4,@-r15 10062306a36Sopenharmony_ci mov r1,r9 ! save TRA 10162306a36Sopenharmony_ci mov r2,r8 ! copy user -> kernel stack 10262306a36Sopenharmony_ci mov.l @(0,r8),r3 10362306a36Sopenharmony_ci mov.l r3,@-r15 10462306a36Sopenharmony_ci mov.l @(4,r8),r2 10562306a36Sopenharmony_ci mov.l r2,@-r15 10662306a36Sopenharmony_ci mov.l @(12,r8),r1 10762306a36Sopenharmony_ci mov.l r1,@-r15 10862306a36Sopenharmony_ci mov.l @(8,r8),r0 10962306a36Sopenharmony_ci bra 2f 11062306a36Sopenharmony_ci mov.l r0,@-r15 11162306a36Sopenharmony_ci1: 11262306a36Sopenharmony_ci ! in kernel exception 11362306a36Sopenharmony_ci mov #(22-4-4-1)*4+4,r0 11462306a36Sopenharmony_ci mov r15,r2 11562306a36Sopenharmony_ci sub r0,r15 11662306a36Sopenharmony_ci mov.l @r2+,r0 ! old R3 11762306a36Sopenharmony_ci mov.l r0,@-r15 11862306a36Sopenharmony_ci mov.l @r2+,r0 ! old R2 11962306a36Sopenharmony_ci mov.l r0,@-r15 12062306a36Sopenharmony_ci mov.l @(4,r2),r0 ! old R1 12162306a36Sopenharmony_ci mov.l r0,@-r15 12262306a36Sopenharmony_ci mov.l @r2,r0 ! old R0 12362306a36Sopenharmony_ci mov.l r0,@-r15 12462306a36Sopenharmony_ci add #8,r2 12562306a36Sopenharmony_ci mov.l @r2+,r3 ! old PC 12662306a36Sopenharmony_ci mov.l @r2+,r0 ! old SR 12762306a36Sopenharmony_ci add #-4,r2 ! exception frame stub (sr) 12862306a36Sopenharmony_ci mov.l r1,@-r2 ! TRA 12962306a36Sopenharmony_ci sts.l macl, @-r2 13062306a36Sopenharmony_ci sts.l mach, @-r2 13162306a36Sopenharmony_ci stc.l gbr, @-r2 13262306a36Sopenharmony_ci mov.l r0,@-r2 ! save old SR 13362306a36Sopenharmony_ci sts.l pr,@-r2 13462306a36Sopenharmony_ci mov.l r3,@-r2 ! save old PC 13562306a36Sopenharmony_ci mov r2,r0 13662306a36Sopenharmony_ci add #8*4,r0 13762306a36Sopenharmony_ci mov.l r0,@-r2 ! save old SP 13862306a36Sopenharmony_ci mov.l r14,@-r2 13962306a36Sopenharmony_ci mov.l r13,@-r2 14062306a36Sopenharmony_ci mov.l r12,@-r2 14162306a36Sopenharmony_ci mov.l r11,@-r2 14262306a36Sopenharmony_ci mov.l r10,@-r2 14362306a36Sopenharmony_ci mov.l r9,@-r2 14462306a36Sopenharmony_ci mov.l r8,@-r2 14562306a36Sopenharmony_ci mov.l r7,@-r2 14662306a36Sopenharmony_ci mov.l r6,@-r2 14762306a36Sopenharmony_ci mov.l r5,@-r2 14862306a36Sopenharmony_ci mov.l r4,@-r2 14962306a36Sopenharmony_ci mov r1,r9 15062306a36Sopenharmony_ci mov.l @(OFF_R0,r15),r0 15162306a36Sopenharmony_ci mov.l @(OFF_R1,r15),r1 15262306a36Sopenharmony_ci mov.l @(OFF_R2,r15),r2 15362306a36Sopenharmony_ci mov.l @(OFF_R3,r15),r3 15462306a36Sopenharmony_ci2: 15562306a36Sopenharmony_ci mov #64,r8 15662306a36Sopenharmony_ci cmp/hs r8,r9 15762306a36Sopenharmony_ci bt interrupt_entry ! vec >= 64 is interrupt 15862306a36Sopenharmony_ci mov #31,r8 15962306a36Sopenharmony_ci cmp/hs r8,r9 16062306a36Sopenharmony_ci bt trap_entry ! 64 > vec >= 31 is trap 16162306a36Sopenharmony_ci#ifdef CONFIG_CPU_J2 16262306a36Sopenharmony_ci mov #16,r8 16362306a36Sopenharmony_ci cmp/hs r8,r9 16462306a36Sopenharmony_ci bt interrupt_entry ! 31 > vec >= 16 is interrupt 16562306a36Sopenharmony_ci#endif 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mov.l 4f,r8 16862306a36Sopenharmony_ci mov r9,r4 16962306a36Sopenharmony_ci shll2 r9 17062306a36Sopenharmony_ci add r9,r8 17162306a36Sopenharmony_ci mov.l @r8,r8 ! exception handler address 17262306a36Sopenharmony_ci tst r8,r8 17362306a36Sopenharmony_ci bf 3f 17462306a36Sopenharmony_ci mov.l 8f,r8 ! unhandled exception 17562306a36Sopenharmony_ci3: 17662306a36Sopenharmony_ci mov.l 5f,r10 17762306a36Sopenharmony_ci jmp @r8 17862306a36Sopenharmony_ci lds r10,pr 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ciinterrupt_entry: 18162306a36Sopenharmony_ci mov r9,r4 18262306a36Sopenharmony_ci mov r15,r5 18362306a36Sopenharmony_ci mov.l 6f,r9 18462306a36Sopenharmony_ci mov.l 7f,r8 18562306a36Sopenharmony_ci jmp @r8 18662306a36Sopenharmony_ci lds r9,pr 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci .align 2 18962306a36Sopenharmony_ci4: .long exception_handling_table 19062306a36Sopenharmony_ci5: .long ret_from_exception 19162306a36Sopenharmony_ci6: .long ret_from_irq 19262306a36Sopenharmony_ci7: .long do_IRQ 19362306a36Sopenharmony_ci8: .long exception_error 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_citrap_entry: 19662306a36Sopenharmony_ci mov #0x30,r8 19762306a36Sopenharmony_ci cmp/ge r8,r9 ! vector 0x1f-0x2f is systemcall 19862306a36Sopenharmony_ci bt 1f 19962306a36Sopenharmony_ci mov #0x1f,r9 ! convert to unified SH2/3/4 trap number 20062306a36Sopenharmony_ci1: 20162306a36Sopenharmony_ci shll2 r9 ! TRA 20262306a36Sopenharmony_ci bra system_call ! jump common systemcall entry 20362306a36Sopenharmony_ci mov r9,r8 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#if defined(CONFIG_SH_STANDARD_BIOS) 20662306a36Sopenharmony_ci /* Unwind the stack and jmp to the debug entry */ 20762306a36Sopenharmony_ciENTRY(sh_bios_handler) 20862306a36Sopenharmony_ci mov r15,r0 20962306a36Sopenharmony_ci add #(22-4)*4-4,r0 21062306a36Sopenharmony_ci ldc.l @r0+,gbr 21162306a36Sopenharmony_ci lds.l @r0+,mach 21262306a36Sopenharmony_ci lds.l @r0+,macl 21362306a36Sopenharmony_ci mov r15,r0 21462306a36Sopenharmony_ci mov.l @(OFF_SP,r0),r1 21562306a36Sopenharmony_ci mov #OFF_SR,r2 21662306a36Sopenharmony_ci mov.l @(r0,r2),r3 21762306a36Sopenharmony_ci mov.l r3,@-r1 21862306a36Sopenharmony_ci mov #OFF_SP,r2 21962306a36Sopenharmony_ci mov.l @(r0,r2),r3 22062306a36Sopenharmony_ci mov.l r3,@-r1 22162306a36Sopenharmony_ci mov r15,r0 22262306a36Sopenharmony_ci add #(22-4)*4-8,r0 22362306a36Sopenharmony_ci mov.l 1f,r2 22462306a36Sopenharmony_ci mov.l @r2,r2 22562306a36Sopenharmony_ci stc sr,r3 22662306a36Sopenharmony_ci mov.l r2,@r0 22762306a36Sopenharmony_ci mov.l r3,@(4,r0) 22862306a36Sopenharmony_ci mov.l r1,@(8,r0) 22962306a36Sopenharmony_ci mov.l @r15+, r0 23062306a36Sopenharmony_ci mov.l @r15+, r1 23162306a36Sopenharmony_ci mov.l @r15+, r2 23262306a36Sopenharmony_ci mov.l @r15+, r3 23362306a36Sopenharmony_ci mov.l @r15+, r4 23462306a36Sopenharmony_ci mov.l @r15+, r5 23562306a36Sopenharmony_ci mov.l @r15+, r6 23662306a36Sopenharmony_ci mov.l @r15+, r7 23762306a36Sopenharmony_ci mov.l @r15+, r8 23862306a36Sopenharmony_ci mov.l @r15+, r9 23962306a36Sopenharmony_ci mov.l @r15+, r10 24062306a36Sopenharmony_ci mov.l @r15+, r11 24162306a36Sopenharmony_ci mov.l @r15+, r12 24262306a36Sopenharmony_ci mov.l @r15+, r13 24362306a36Sopenharmony_ci mov.l @r15+, r14 24462306a36Sopenharmony_ci add #8,r15 24562306a36Sopenharmony_ci lds.l @r15+, pr 24662306a36Sopenharmony_ci mov.l @r15+,r15 24762306a36Sopenharmony_ci rte 24862306a36Sopenharmony_ci nop 24962306a36Sopenharmony_ci .align 2 25062306a36Sopenharmony_ci1: .long gdb_vbr_vector 25162306a36Sopenharmony_ci#endif /* CONFIG_SH_STANDARD_BIOS */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciENTRY(address_error_trap_handler) 25462306a36Sopenharmony_ci mov r15,r4 ! regs 25562306a36Sopenharmony_ci mov #OFF_PC,r0 25662306a36Sopenharmony_ci mov.l @(r0,r15),r6 ! pc 25762306a36Sopenharmony_ci mov.l 1f,r0 25862306a36Sopenharmony_ci jmp @r0 25962306a36Sopenharmony_ci mov #0,r5 ! writeaccess is unknown 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci .align 2 26262306a36Sopenharmony_ci1: .long do_address_error 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cirestore_all: 26562306a36Sopenharmony_ci stc sr,r0 26662306a36Sopenharmony_ci or #0xf0,r0 26762306a36Sopenharmony_ci ldc r0,sr ! all interrupt block (same BL = 1) 26862306a36Sopenharmony_ci ! restore special register 26962306a36Sopenharmony_ci ! overlap exception frame 27062306a36Sopenharmony_ci mov r15,r0 27162306a36Sopenharmony_ci add #17*4,r0 27262306a36Sopenharmony_ci lds.l @r0+,pr 27362306a36Sopenharmony_ci add #4,r0 27462306a36Sopenharmony_ci ldc.l @r0+,gbr 27562306a36Sopenharmony_ci lds.l @r0+,mach 27662306a36Sopenharmony_ci lds.l @r0+,macl 27762306a36Sopenharmony_ci mov r15,r0 27862306a36Sopenharmony_ci mov.l $cpu_mode,r2 27962306a36Sopenharmony_ci#ifdef CONFIG_SMP 28062306a36Sopenharmony_ci mov.l $cpuid,r3 28162306a36Sopenharmony_ci mov.l @r3,r3 28262306a36Sopenharmony_ci mov.l @r3,r3 28362306a36Sopenharmony_ci shll2 r3 28462306a36Sopenharmony_ci add r3,r2 28562306a36Sopenharmony_ci#endif 28662306a36Sopenharmony_ci mov #OFF_SR,r3 28762306a36Sopenharmony_ci mov.l @(r0,r3),r1 28862306a36Sopenharmony_ci mov.l __md_bit,r3 28962306a36Sopenharmony_ci and r1,r3 ! copy MD bit 29062306a36Sopenharmony_ci mov.l r3,@r2 29162306a36Sopenharmony_ci shll2 r1 ! clear MD bit 29262306a36Sopenharmony_ci shlr2 r1 29362306a36Sopenharmony_ci mov.l @(OFF_SP,r0),r2 29462306a36Sopenharmony_ci add #-8,r2 29562306a36Sopenharmony_ci mov.l r2,@(OFF_SP,r0) ! point exception frame top 29662306a36Sopenharmony_ci mov.l r1,@(4,r2) ! set sr 29762306a36Sopenharmony_ci mov #OFF_PC,r3 29862306a36Sopenharmony_ci mov.l @(r0,r3),r1 29962306a36Sopenharmony_ci mov.l r1,@r2 ! set pc 30062306a36Sopenharmony_ci get_current_thread_info r0, r1 30162306a36Sopenharmony_ci mov.l $current_thread_info,r1 30262306a36Sopenharmony_ci#ifdef CONFIG_SMP 30362306a36Sopenharmony_ci mov.l $cpuid,r3 30462306a36Sopenharmony_ci mov.l @r3,r3 30562306a36Sopenharmony_ci mov.l @r3,r3 30662306a36Sopenharmony_ci shll2 r3 30762306a36Sopenharmony_ci add r3,r1 30862306a36Sopenharmony_ci#endif 30962306a36Sopenharmony_ci mov.l r0,@r1 31062306a36Sopenharmony_ci mov.l @r15+,r0 31162306a36Sopenharmony_ci mov.l @r15+,r1 31262306a36Sopenharmony_ci mov.l @r15+,r2 31362306a36Sopenharmony_ci mov.l @r15+,r3 31462306a36Sopenharmony_ci mov.l @r15+,r4 31562306a36Sopenharmony_ci mov.l @r15+,r5 31662306a36Sopenharmony_ci mov.l @r15+,r6 31762306a36Sopenharmony_ci mov.l @r15+,r7 31862306a36Sopenharmony_ci mov.l @r15+,r8 31962306a36Sopenharmony_ci mov.l @r15+,r9 32062306a36Sopenharmony_ci mov.l @r15+,r10 32162306a36Sopenharmony_ci mov.l @r15+,r11 32262306a36Sopenharmony_ci mov.l @r15+,r12 32362306a36Sopenharmony_ci mov.l @r15+,r13 32462306a36Sopenharmony_ci mov.l @r15+,r14 32562306a36Sopenharmony_ci mov.l @r15,r15 32662306a36Sopenharmony_ci rte 32762306a36Sopenharmony_ci nop 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci .align 2 33062306a36Sopenharmony_ci__md_bit: 33162306a36Sopenharmony_ci .long 0x40000000 33262306a36Sopenharmony_ci$current_thread_info: 33362306a36Sopenharmony_ci .long __current_thread_info 33462306a36Sopenharmony_ci$cpu_mode: 33562306a36Sopenharmony_ci .long __cpu_mode 33662306a36Sopenharmony_ci#ifdef CONFIG_SMP 33762306a36Sopenharmony_ci$cpuid: 33862306a36Sopenharmony_ci .long sh2_cpuid_addr 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci! common exception handler 34262306a36Sopenharmony_ci#include "../../entry-common.S" 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci#ifdef CONFIG_NR_CPUS 34562306a36Sopenharmony_ci#define NR_CPUS CONFIG_NR_CPUS 34662306a36Sopenharmony_ci#else 34762306a36Sopenharmony_ci#define NR_CPUS 1 34862306a36Sopenharmony_ci#endif 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci .data 35162306a36Sopenharmony_ci! cpu operation mode 35262306a36Sopenharmony_ci! bit30 = MD (compatible SH3/4) 35362306a36Sopenharmony_ci__cpu_mode: 35462306a36Sopenharmony_ci .rept NR_CPUS 35562306a36Sopenharmony_ci .long 0x40000000 35662306a36Sopenharmony_ci .endr 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci#ifdef CONFIG_SMP 35962306a36Sopenharmony_ci.global sh2_cpuid_addr 36062306a36Sopenharmony_cish2_cpuid_addr: 36162306a36Sopenharmony_ci .long dummy_cpuid 36262306a36Sopenharmony_cidummy_cpuid: 36362306a36Sopenharmony_ci .long 0 36462306a36Sopenharmony_ci#endif 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci .section .bss 36762306a36Sopenharmony_ci__current_thread_info: 36862306a36Sopenharmony_ci .rept NR_CPUS 36962306a36Sopenharmony_ci .long 0 37062306a36Sopenharmony_ci .endr 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciENTRY(exception_handling_table) 37362306a36Sopenharmony_ci .space 4*32 374