#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/asm-macros.h>
#include <asm/thread_info.h>
#include <asm/errno.h>
#include <asm/setup.h>
#include <asm/entry.h>
#include <asm/unistd.h>
#include <asm/processor.h>
.macro GET_THREAD_INFO reg
.if THREAD_SIZE & 0xffff0000
andhi \reg, sp, %hi(~(THREAD_SIZE-1))
.else
addi \reg, r0, %lo(~(THREAD_SIZE-1))
and \reg, \reg, sp
.endif
.endm
.macro kuser_cmpxchg_check
movui et, (KUSER_BASE + 4 + (cmpxchg_stw - __kuser_helper_start))
bgtu ea, et, 1f
subi et, et, (cmpxchg_stw - cmpxchg_ldw)
bltu ea, et, 1f
stw et, PT_EA(sp)
mov ea, et
1:
.endm
.section .rodata
.align 4
exception_table:
.word unhandled_exception
.word unhandled_exception
.word external_interrupt
.word handle_trap
.word instruction_trap
.word handle_illegal
.word handle_unaligned
.word handle_unaligned
.word handle_diverror
.word protection_exception_ba
.word protection_exception_instr
.word protection_exception_ba
.word unhandled_exception
.word protection_exception_pte
.word protection_exception_pte
.word protection_exception_pte
.word unhandled_exception
trap_table:
.word handle_system_call
.word handle_trap_1
.word handle_trap_2
.word handle_trap_3
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
.word handle_trap_reserved
#ifdef CONFIG_KGDB
.word handle_kgdb_breakpoint
#else
.word instruction_trap
#endif
.word handle_breakpoint
.text
.set noat
.set nobreak
ENTRY(inthandler)
SAVE_ALL
kuser_cmpxchg_check
rdctl r24, status
movi r9, %lo(~STATUS_EH)
and r24, r24, r9
wrctl status, r24
mov r4, sp
rdctl r5, exception
movia r9, exception_table
add r24, r9, r5
ldw r24, 0(r24)
jmp r24
ENTRY(handle_trap)
ldwio r24, -4(ea)
srli r24, r24, 4
andi r24, r24, 0x7c
movia r9,trap_table
add r24, r24, r9
ldw r24, 0(r24)
jmp r24
ENTRY(handle_system_call)
rdctl r10, status
ori r10, r10, STATUS_PIE
wrctl status, r10
ldw r4, PT_R4(sp)
ldw r5, PT_R5(sp)
local_restart:
stw r2, PT_ORIG_R2(sp)
movui r1, __NR_syscalls
bgeu r2, r1, ret_invsyscall
slli r1, r2, 2
movhi r11, %hiadj(sys_call_table)
add r1, r1, r11
ldw r1, %lo(sys_call_table)(r1)
GET_THREAD_INFO r11
ldw r11,TI_FLAGS(r11)
BTBNZ r11,r11,TIF_SYSCALL_TRACE,traced_system_call
callr r1
translate_rc_and_ret:
movi r1, 0
bge r2, zero, 3f
ldw r1, PT_ORIG_R2(sp)
addi r1, r1, 1
beq r1, zero, 3f
sub r2, zero, r2
movi r1, 1
3:
stw r2, PT_R2(sp)
stw r1, PT_R7(sp)
end_translate_rc_and_ret:
ret_from_exception:
ldw r1, PT_ESTATUS(sp)
TSTBNZ r1, r1, ESTATUS_EU, Luser_return
restore_all:
rdctl r10, status
andi r10, r10, %lo(~STATUS_PIE)
wrctl status, r10
RESTORE_ALL
eret
ret_invsyscall:
movi r2, -ENOSYS
br translate_rc_and_ret
traced_system_call:
SAVE_SWITCH_STACK
call do_syscall_trace_enter
RESTORE_SWITCH_STACK
ldw r2, PT_R2(sp)
ldw r4, PT_R4(sp)
ldw r5, PT_R5(sp)
ldw r6, PT_R6(sp)
ldw r7, PT_R7(sp)
movui r1, __NR_syscalls
bgeu r2, r1, traced_invsyscall
slli r1, r2, 2
movhi r11,%hiadj(sys_call_table)
add r1, r1, r11
ldw r1, %lo(sys_call_table)(r1)
callr r1
translate_rc_and_ret2:
movi r1, 0
bge r2, zero, 4f
ldw r1, PT_ORIG_R2(sp)
addi r1, r1, 1
beq r1, zero, 4f
sub r2, zero, r2
movi r1, 1
4:
stw r2, PT_R2(sp)
stw r1, PT_R7(sp)
end_translate_rc_and_ret2:
SAVE_SWITCH_STACK
call do_syscall_trace_exit
RESTORE_SWITCH_STACK
br ret_from_exception
traced_invsyscall:
movi r2, -ENOSYS
br translate_rc_and_ret2
Luser_return:
GET_THREAD_INFO r11
ldw r10, TI_FLAGS(r11)
ANDI32 r11, r10, _TIF_WORK_MASK
beq r11, r0, restore_all
BTBZ r1, r10, TIF_NEED_RESCHED, Lsignal_return
call schedule
br ret_from_exception
Lsignal_return:
ANDI32 r1, r10, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beq r1, r0, restore_all
mov r4, sp
SAVE_SWITCH_STACK
call do_notify_resume
beq r2, r0, no_work_pending
RESTORE_SWITCH_STACK
ldw r2, PT_R2(sp)
ldw r4, PT_R4(sp)
ldw r5, PT_R5(sp)
ldw r6, PT_R6(sp)
ldw r7, PT_R7(sp)
ldw r8, PT_R8(sp)
ldw r9, PT_R9(sp)
br local_restart
no_work_pending:
RESTORE_SWITCH_STACK
br ret_from_exception
external_interrupt:
rdctl r12, ipending
rdctl r9, ienable
and r12, r12, r9
beq r12, r0, ret_from_interrupt
addi ea, ea, -4
stw ea, PT_EA(sp)
2: movi r4, %lo(-1)
1: andi r10, r12, 1
srli r12, r12, 1
addi r4, r4, 1
beq r10, r0, 1b
mov r5, sp
call do_IRQ
rdctl r12, ipending
rdctl r9, ienable
and r12, r12, r9
bne r12, r0, 2b
ENTRY(ret_from_interrupt)
ldw r1, PT_ESTATUS(sp)
TSTBNZ r1, r1, ESTATUS_EU, Luser_return
#ifdef CONFIG_PREEMPTION
GET_THREAD_INFO r1
ldw r4, TI_PREEMPT_COUNT(r1)
bne r4, r0, restore_all
ldw r4, TI_FLAGS(r1)
BTBZ r10, r4, TIF_NEED_RESCHED, restore_all
ldw r4, PT_ESTATUS(sp)
andi r10, r4, ESTATUS_EPIE
beq r10, r0, restore_all
call preempt_schedule_irq
#endif
br restore_all
ENTRY(sys_clone)
SAVE_SWITCH_STACK
subi sp, sp, 4
stw r8, 0(sp)
call nios2_clone
addi sp, sp, 4
RESTORE_SWITCH_STACK
ret
ENTRY(__sys_clone3)
SAVE_SWITCH_STACK
call sys_clone3
RESTORE_SWITCH_STACK
ret
ENTRY(sys_rt_sigreturn)
SAVE_SWITCH_STACK
mov r4, sp
call do_rt_sigreturn
RESTORE_SWITCH_STACK
addi ra, ra, (end_translate_rc_and_ret - translate_rc_and_ret)
ret
protection_exception_pte:
rdctl r6, pteaddr
slli r6, r6, 10
call do_page_fault
br ret_from_exception
protection_exception_ba:
rdctl r6, badaddr
call do_page_fault
br ret_from_exception
protection_exception_instr:
call handle_supervisor_instr
br ret_from_exception
handle_breakpoint:
call breakpoint_c
br ret_from_exception
#ifdef CONFIG_NIOS2_ALIGNMENT_TRAP
handle_unaligned:
SAVE_SWITCH_STACK
call handle_unaligned_c
RESTORE_SWITCH_STACK
br ret_from_exception
#else
handle_unaligned:
call handle_unaligned_c
br ret_from_exception
#endif
handle_illegal:
call handle_illegal_c
br ret_from_exception
handle_diverror:
call handle_diverror_c
br ret_from_exception
#ifdef CONFIG_KGDB
handle_kgdb_breakpoint:
call kgdb_breakpoint_c
br ret_from_exception
#endif
handle_trap_1:
call handle_trap_1_c
br ret_from_exception
handle_trap_2:
call handle_trap_2_c
br ret_from_exception
handle_trap_3:
handle_trap_reserved:
call handle_trap_3_c
br ret_from_exception
ENTRY(resume)
rdctl r7, status
stw r7, TASK_THREAD + THREAD_KPSR(r4)
andi r7, r7, %lo(~STATUS_PIE)
wrctl status, r7
SAVE_SWITCH_STACK
stw sp, TASK_THREAD + THREAD_KSP(r4)
ldw sp, TASK_THREAD + THREAD_KSP(r5)
movia r24, _current_thread
GET_THREAD_INFO r1
stw r1, 0(r24)
RESTORE_SWITCH_STACK
ldw r7, TASK_THREAD + THREAD_KPSR(r5)
wrctl status, r7
ret
ENTRY(ret_from_fork)
call schedule_tail
br ret_from_exception
ENTRY(ret_from_kernel_thread)
call schedule_tail
mov r4,r17
callr r16
br ret_from_exception
.macro kuser_pad sym size
.if ((. - \sym) & 3)
.rept (4 - (. - \sym) & 3)
.byte 0
.endr
.endif
.rept ((\size - (. - \sym)) / 4)
.word 0xdeadbeef
.endr
.endm
.align 6
.globl __kuser_helper_start
__kuser_helper_start:
__kuser_helper_version:
.word ((__kuser_helper_end - __kuser_helper_start) >> 6)
__kuser_cmpxchg:
cmpxchg_ldw:
ldw r2, 0(r4)
sub r2, r2, r5
bne r2, zero, cmpxchg_ret
cmpxchg_stw:
stw r6, 0(r4)
cmpxchg_ret:
ret
kuser_pad __kuser_cmpxchg, 64
.globl __kuser_sigtramp
__kuser_sigtramp:
movi r2, __NR_rt_sigreturn
trap
kuser_pad __kuser_sigtramp, 64
.globl __kuser_helper_end
__kuser_helper_end: