/*
* linux/arch/cris/entry.S
*
* Copyright (C) 2000, 2001, 2002 Axis Communications AB
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*/
/*
* entry.S contains the system-call and fault low-level handling routines.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
* Stack layout in 'ret_from_system_call':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
* ptrace.c and ptrace.h
*
*/
#include <linux/linkage.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <arch/sv_addr_ag.h>
#include <asm/errno.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/pgtable.h>
;; functions exported from this file
.globl system_call
.globl ret_from_intr
.globl ret_from_fork
.globl resume
.globl multiple_interrupt
.globl hwbreakpoint
.globl IRQ1_interrupt
.globl spurious_interrupt
.globl hw_bp_trigs
.globl mmu_bus_fault
.globl do_sigtrap
.globl gdb_handle_breakpoint
.globl sys_call_table
;; below are various parts of system_call which are not in the fast-path
#ifdef CONFIG_PREEMPT
; Check if preemptive kernel scheduling should be done
_resume_kernel:
di
; Load current task struct
movs.w -8192, $r0 ; THREAD_SIZE = 8192
and.d $sp, $r0
move.d [$r0+TI_preempt_count], $r10 ; Preemption disabled?
bne _Rexit
nop
_need_resched:
move.d [$r0+TI_flags], $r10
btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set
bpl _Rexit
nop
; Ok, lets's do some preemptive kernel scheduling
jsr preempt_schedule_irq
; Load new task struct
movs.w -8192, $r0 ; THREAD_SIZE = 8192
and.d $sp, $r0
; One more time (with new task)
ba _need_resched
nop
#else
#define _resume_kernel _Rexit
#endif
; Called at exit from fork. schedule_tail must be called to drop
; spinlock if CONFIG_PREEMPT
ret_from_fork:
jsr schedule_tail
ba ret_from_sys_call
nop
ret_from_intr:
;; check for resched if preemptive kernel or if we're going back to user-mode
;; this test matches the user_regs(regs) macro
;; we cannot simply test $dccr, because that does not necessarily
;; reflect what mode we'll return into.
move.d [$sp + PT_dccr], $r0; regs->dccr
btstq 8, $r0 ; U-flag
bpl _resume_kernel
; Note that di below is in delay slot
_resume_userspace:
di ; so need_resched and sigpending don't change
movs.w -8192, $r0 ; THREAD_SIZE == 8192
and.d $sp, $r0
move.d [$r0+TI_flags], $r10 ; current->work
and.d _TIF_WORK_MASK, $r10 ; is there any work to be done on return
bne _work_pending
nop
ba _Rexit
nop
;; The system_call is called by a BREAK instruction, which works like
;; an interrupt call but it stores the return PC in BRP instead of IRP.
;; Since we dont really want to have two epilogues (one for system calls
;; and one for interrupts) we push the contents of BRP instead of IRP in the
;; system call prologue, to make it look like an ordinary interrupt on the
;; stackframe.
;;
;; Since we can't have system calls inside interrupts, it should not matter
;; that we don't stack IRP.
;;
;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
;;
;; This function looks on the _surface_ like spaghetti programming, but it's
;; really designed so that the fast-path does not force cache-loading of non-used
;; instructions. Only the non-common cases cause the outlined code to run..
system_call:
;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call
move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
push $srp
push $dccr
push $mof
subq 14*4, $sp ; make room for r0-r13
movem $r13, [$sp] ; push r0-r13
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe
movs.w -ENOSYS, $r0
move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame
;; check if this process is syscall-traced
movs.w -8192, $r0 ; THREAD_SIZE == 8192
and.d $sp, $r0
move.d [$r0+TI_flags], $r0
btstq TIF_SYSCALL_TRACE, $r0
bmi _syscall_trace_entry
nop
_syscall_traced:
;; check for sanity i