Historically SH-2 Linux (and originally uClinux) used a syscall calling convention incompatible with the established SH-3/4 Linux ABI. This choice was made because the trap range used by the existing ABI, 0x10-0x17, overlaps with the hardware exception/interrupt trap range reserved by SH-2, and in particular, with the SH-2A divide-by-zero and division-overflow exceptions. Despite the documented syscall convention using the low bits of the trap number to signal the number of arguments the kernel should expect, no version of the kernel has ever used this information, nor is it useful; all of the registers need to be saved anyway. Therefore, it is possible to pick a new trap number, 0x1f, that is both supported by all existing SH-3/4 kernels and unassigned as a hardware trap in the SH-2 range. This makes it possible to produce SH-2 application binaries that are forwards-compatible with running on SH-3/4 kernels and to treat SH as a unified platform with varying ISA support levels rather than multiple gratuitously-incompatible platforms. This patch adjusts the range checking SH-2 and SH-2A kernels make for the syscall trap to accept the range 0x1f-0x2f rather than just 0x20-0x2f. As a result, trap 0x1f now acts as a syscall for all SH models. Signed-off-by: Rich Felker <dalias@libc.org>
322 lines
6.0 KiB
ArmAsm
322 lines
6.0 KiB
ArmAsm
/*
|
|
* arch/sh/kernel/cpu/sh2/entry.S
|
|
*
|
|
* The SH-2 exception entry
|
|
*
|
|
* Copyright (C) 2005-2008 Yoshinori Sato
|
|
* Copyright (C) 2005 AXE,Inc.
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/linkage.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/thread_info.h>
|
|
#include <cpu/mmu_context.h>
|
|
#include <asm/unistd.h>
|
|
#include <asm/errno.h>
|
|
#include <asm/page.h>
|
|
|
|
/* Offsets to the stack */
|
|
OFF_R0 = 0 /* Return value. New ABI also arg4 */
|
|
OFF_R1 = 4 /* New ABI: arg5 */
|
|
OFF_R2 = 8 /* New ABI: arg6 */
|
|
OFF_R3 = 12 /* New ABI: syscall_nr */
|
|
OFF_R4 = 16 /* New ABI: arg0 */
|
|
OFF_R5 = 20 /* New ABI: arg1 */
|
|
OFF_R6 = 24 /* New ABI: arg2 */
|
|
OFF_R7 = 28 /* New ABI: arg3 */
|
|
OFF_SP = (15*4)
|
|
OFF_PC = (16*4)
|
|
OFF_SR = (16*4+2*4)
|
|
OFF_TRA = (16*4+6*4)
|
|
|
|
#include <asm/entry-macros.S>
|
|
|
|
ENTRY(exception_handler)
|
|
! stack
|
|
! r0 <- point sp
|
|
! r1
|
|
! pc
|
|
! sr
|
|
! r0 = temporary
|
|
! r1 = vector (pseudo EXPEVT / INTEVT / TRA)
|
|
mov.l r2,@-sp
|
|
mov.l r3,@-sp
|
|
cli
|
|
mov.l $cpu_mode,r2
|
|
mov.l @r2,r0
|
|
mov.l @(5*4,r15),r3 ! previous SR
|
|
or r0,r3 ! set MD
|
|
tst r0,r0
|
|
bf/s 1f ! previous mode check
|
|
mov.l r3,@(5*4,r15) ! update SR
|
|
! switch to kernel mode
|
|
mov.l __md_bit,r0
|
|
mov.l r0,@r2 ! enter kernel mode
|
|
mov.l $current_thread_info,r2
|
|
mov.l @r2,r2
|
|
mov #(THREAD_SIZE >> 8),r0
|
|
shll8 r0
|
|
add r2,r0
|
|
mov r15,r2 ! r2 = user stack top
|
|
mov r0,r15 ! switch kernel stack
|
|
mov.l r1,@-r15 ! TRA
|
|
sts.l macl, @-r15
|
|
sts.l mach, @-r15
|
|
stc.l gbr, @-r15
|
|
mov.l @(5*4,r2),r0
|
|
mov.l r0,@-r15 ! original SR
|
|
sts.l pr,@-r15
|
|
mov.l @(4*4,r2),r0
|
|
mov.l r0,@-r15 ! original PC
|
|
mov r2,r3
|
|
add #(4+2)*4,r3 ! rewind r0 - r3 + exception frame
|
|
mov.l r3,@-r15 ! original SP
|
|
mov.l r14,@-r15
|
|
mov.l r13,@-r15
|
|
mov.l r12,@-r15
|
|
mov.l r11,@-r15
|
|
mov.l r10,@-r15
|
|
mov.l r9,@-r15
|
|
mov.l r8,@-r15
|
|
mov.l r7,@-r15
|
|
mov.l r6,@-r15
|
|
mov.l r5,@-r15
|
|
mov.l r4,@-r15
|
|
mov r1,r9 ! save TRA
|
|
mov r2,r8 ! copy user -> kernel stack
|
|
mov.l @(0,r8),r3
|
|
mov.l r3,@-r15
|
|
mov.l @(4,r8),r2
|
|
mov.l r2,@-r15
|
|
mov.l @(12,r8),r1
|
|
mov.l r1,@-r15
|
|
mov.l @(8,r8),r0
|
|
bra 2f
|
|
mov.l r0,@-r15
|
|
1:
|
|
! in kernel exception
|
|
mov #(22-4-4-1)*4+4,r0
|
|
mov r15,r2
|
|
sub r0,r15
|
|
mov.l @r2+,r0 ! old R3
|
|
mov.l r0,@-r15
|
|
mov.l @r2+,r0 ! old R2
|
|
mov.l r0,@-r15
|
|
mov.l @(4,r2),r0 ! old R1
|
|
mov.l r0,@-r15
|
|
mov.l @r2,r0 ! old R0
|
|
mov.l r0,@-r15
|
|
add #8,r2
|
|
mov.l @r2+,r3 ! old PC
|
|
mov.l @r2+,r0 ! old SR
|
|
add #-4,r2 ! exception frame stub (sr)
|
|
mov.l r1,@-r2 ! TRA
|
|
sts.l macl, @-r2
|
|
sts.l mach, @-r2
|
|
stc.l gbr, @-r2
|
|
mov.l r0,@-r2 ! save old SR
|
|
sts.l pr,@-r2
|
|
mov.l r3,@-r2 ! save old PC
|
|
mov r2,r0
|
|
add #8*4,r0
|
|
mov.l r0,@-r2 ! save old SP
|
|
mov.l r14,@-r2
|
|
mov.l r13,@-r2
|
|
mov.l r12,@-r2
|
|
mov.l r11,@-r2
|
|
mov.l r10,@-r2
|
|
mov.l r9,@-r2
|
|
mov.l r8,@-r2
|
|
mov.l r7,@-r2
|
|
mov.l r6,@-r2
|
|
mov.l r5,@-r2
|
|
mov.l r4,@-r2
|
|
mov r1,r9
|
|
mov.l @(OFF_R0,r15),r0
|
|
mov.l @(OFF_R1,r15),r1
|
|
mov.l @(OFF_R2,r15),r2
|
|
mov.l @(OFF_R3,r15),r3
|
|
2:
|
|
mov #64,r8
|
|
cmp/hs r8,r9
|
|
bt interrupt_entry ! vec >= 64 is interrupt
|
|
mov #31,r8
|
|
cmp/hs r8,r9
|
|
bt trap_entry ! 64 > vec >= 31 is trap
|
|
|
|
mov.l 4f,r8
|
|
mov r9,r4
|
|
shll2 r9
|
|
add r9,r8
|
|
mov.l @r8,r8 ! exception handler address
|
|
tst r8,r8
|
|
bf 3f
|
|
mov.l 8f,r8 ! unhandled exception
|
|
3:
|
|
mov.l 5f,r10
|
|
jmp @r8
|
|
lds r10,pr
|
|
|
|
interrupt_entry:
|
|
mov r9,r4
|
|
mov r15,r5
|
|
mov.l 6f,r9
|
|
mov.l 7f,r8
|
|
jmp @r8
|
|
lds r9,pr
|
|
|
|
.align 2
|
|
4: .long exception_handling_table
|
|
5: .long ret_from_exception
|
|
6: .long ret_from_irq
|
|
7: .long do_IRQ
|
|
8: .long exception_error
|
|
|
|
trap_entry:
|
|
mov #0x30,r8
|
|
cmp/ge r8,r9 ! vector 0x1f-0x2f is systemcall
|
|
bt 1f
|
|
mov #0x1f,r9 ! convert to unified SH2/3/4 trap number
|
|
1:
|
|
shll2 r9 ! TRA
|
|
bra system_call ! jump common systemcall entry
|
|
mov r9,r8
|
|
|
|
#if defined(CONFIG_SH_STANDARD_BIOS)
|
|
/* Unwind the stack and jmp to the debug entry */
|
|
ENTRY(sh_bios_handler)
|
|
mov r15,r0
|
|
add #(22-4)*4-4,r0
|
|
ldc.l @r0+,gbr
|
|
lds.l @r0+,mach
|
|
lds.l @r0+,macl
|
|
mov r15,r0
|
|
mov.l @(OFF_SP,r0),r1
|
|
mov #OFF_SR,r2
|
|
mov.l @(r0,r2),r3
|
|
mov.l r3,@-r1
|
|
mov #OFF_SP,r2
|
|
mov.l @(r0,r2),r3
|
|
mov.l r3,@-r1
|
|
mov r15,r0
|
|
add #(22-4)*4-8,r0
|
|
mov.l 1f,r2
|
|
mov.l @r2,r2
|
|
stc sr,r3
|
|
mov.l r2,@r0
|
|
mov.l r3,@(4,r0)
|
|
mov.l r1,@(8,r0)
|
|
mov.l @r15+, r0
|
|
mov.l @r15+, r1
|
|
mov.l @r15+, r2
|
|
mov.l @r15+, r3
|
|
mov.l @r15+, r4
|
|
mov.l @r15+, r5
|
|
mov.l @r15+, r6
|
|
mov.l @r15+, r7
|
|
mov.l @r15+, r8
|
|
mov.l @r15+, r9
|
|
mov.l @r15+, r10
|
|
mov.l @r15+, r11
|
|
mov.l @r15+, r12
|
|
mov.l @r15+, r13
|
|
mov.l @r15+, r14
|
|
add #8,r15
|
|
lds.l @r15+, pr
|
|
mov.l @r15+,r15
|
|
rte
|
|
nop
|
|
.align 2
|
|
1: .long gdb_vbr_vector
|
|
#endif /* CONFIG_SH_STANDARD_BIOS */
|
|
|
|
ENTRY(address_error_trap_handler)
|
|
mov r15,r4 ! regs
|
|
mov #OFF_PC,r0
|
|
mov.l @(r0,r15),r6 ! pc
|
|
mov.l 1f,r0
|
|
jmp @r0
|
|
mov #0,r5 ! writeaccess is unknown
|
|
|
|
.align 2
|
|
1: .long do_address_error
|
|
|
|
restore_all:
|
|
stc sr,r0
|
|
or #0xf0,r0
|
|
ldc r0,sr ! all interrupt block (same BL = 1)
|
|
! restore special register
|
|
! overlap exception frame
|
|
mov r15,r0
|
|
add #17*4,r0
|
|
lds.l @r0+,pr
|
|
add #4,r0
|
|
ldc.l @r0+,gbr
|
|
lds.l @r0+,mach
|
|
lds.l @r0+,macl
|
|
mov r15,r0
|
|
mov.l $cpu_mode,r2
|
|
mov #OFF_SR,r3
|
|
mov.l @(r0,r3),r1
|
|
mov.l __md_bit,r3
|
|
and r1,r3 ! copy MD bit
|
|
mov.l r3,@r2
|
|
shll2 r1 ! clear MD bit
|
|
shlr2 r1
|
|
mov.l @(OFF_SP,r0),r2
|
|
add #-8,r2
|
|
mov.l r2,@(OFF_SP,r0) ! point exception frame top
|
|
mov.l r1,@(4,r2) ! set sr
|
|
mov #OFF_PC,r3
|
|
mov.l @(r0,r3),r1
|
|
mov.l r1,@r2 ! set pc
|
|
get_current_thread_info r0, r1
|
|
mov.l $current_thread_info,r1
|
|
mov.l r0,@r1
|
|
mov.l @r15+,r0
|
|
mov.l @r15+,r1
|
|
mov.l @r15+,r2
|
|
mov.l @r15+,r3
|
|
mov.l @r15+,r4
|
|
mov.l @r15+,r5
|
|
mov.l @r15+,r6
|
|
mov.l @r15+,r7
|
|
mov.l @r15+,r8
|
|
mov.l @r15+,r9
|
|
mov.l @r15+,r10
|
|
mov.l @r15+,r11
|
|
mov.l @r15+,r12
|
|
mov.l @r15+,r13
|
|
mov.l @r15+,r14
|
|
mov.l @r15,r15
|
|
rte
|
|
nop
|
|
|
|
.align 2
|
|
__md_bit:
|
|
.long 0x40000000
|
|
$current_thread_info:
|
|
.long __current_thread_info
|
|
$cpu_mode:
|
|
.long __cpu_mode
|
|
|
|
! common exception handler
|
|
#include "../../entry-common.S"
|
|
|
|
.data
|
|
! cpu operation mode
|
|
! bit30 = MD (compatible SH3/4)
|
|
__cpu_mode:
|
|
.long 0x40000000
|
|
|
|
.section .bss
|
|
__current_thread_info:
|
|
.long 0
|
|
|
|
ENTRY(exception_handling_table)
|
|
.space 4*32
|