patch-2.3.43 linux/arch/ia64/kernel/entry.S
Next file: linux/arch/ia64/kernel/entry.h
Previous file: linux/arch/ia64/kernel/efi_stub.S
Back to the patch index
Back to the overall index
- Lines: 1262
- Date:
Sun Feb 6 18:42:40 2000
- Orig file:
v2.3.42/linux/arch/ia64/kernel/entry.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
@@ -0,0 +1,1261 @@
+/*
+ * ia64/kernel/entry.S
+ *
+ * Kernel entry points.
+ *
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
+ */
+/*
+ * Global (preserved) predicate usage on syscall entry/exit path:
+ *
+ *
+ * pEOI: See entry.h.
+ * pKern: See entry.h.
+ * pSys: See entry.h.
+ * pNonSys: !pSys
+ * p2: (Alias of pKern!) True if any signals are pending.
+ * p16/p17: Used by stubs calling ia64_do_signal to indicate if current task
+ * has PF_PTRACED flag bit set. p16 is true if so, p17 is the complement.
+ */
+
+#include <linux/config.h>
+
+#include <asm/errno.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+#include <asm/unistd.h>
+
+#include "entry.h"
+
+ .text
+ .psr abi64
+ .psr lsb
+ .lsb
+
+ /*
+ * execve() is special because in case of success, we need to
+ * setup a null register window frame.
+ */
+ .align 16
+ .proc ia64_execve
+ia64_execve:
+ alloc loc0=ar.pfs,3,2,4,0
+ mov loc1=rp
+ mov out0=in0 // filename
+ ;; // stop bit between alloc and call
+ mov out1=in1 // argv
+ mov out2=in2 // envp
+ add out3=16,sp // regs
+ br.call.sptk.few rp=sys_execve
+.ret0: cmp4.ge p6,p0=r8,r0
+ mov ar.pfs=loc0 // restore ar.pfs
+ ;;
+(p6) mov ar.pfs=r0 // clear ar.pfs in case of success
+ sxt4 r8=r8 // return 64-bit result
+ mov rp=loc1
+
+ br.ret.sptk.few rp
+ .endp ia64_execve
+
+ .align 16
+ .global sys_clone
+ .proc sys_clone
+sys_clone:
+ alloc r16=ar.pfs,2,2,3,0;;
+ movl r28=1f
+ mov loc1=rp
+ br.cond.sptk.many save_switch_stack
+1:
+ mov loc0=r16 // save ar.pfs across do_fork
+ adds out2=IA64_SWITCH_STACK_SIZE+16,sp
+ adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp
+ cmp.eq p8,p9=in1,r0 // usp == 0?
+ mov out0=in0 // out0 = clone_flags
+ ;;
+(p8) ld8 out1=[r2] // fetch usp from pt_regs.r12
+(p9) mov out1=in1
+ br.call.sptk.few rp=do_fork
+.ret1:
+ mov ar.pfs=loc0
+ adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
+ mov rp=loc1
+ ;;
+ br.ret.sptk.many rp
+ .endp sys_clone
+
+/*
+ * prev_task <- switch_to(struct task_struct *next)
+ */
+ .align 16
+ .global ia64_switch_to
+ .proc ia64_switch_to
+ia64_switch_to:
+ alloc r16=ar.pfs,1,0,0,0
+ movl r28=1f
+ br.cond.sptk.many save_switch_stack
+1:
+ // disable interrupts to ensure atomicity for next few instructions:
+ mov r17=psr // M-unit
+ ;;
+ rsm psr.i // M-unit
+ dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff
+ ;;
+ srlz.d
+ ;;
+ adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13
+ adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
+ ;;
+ st8 [r22]=sp // save kernel stack pointer of old task
+ ld8 sp=[r21] // load kernel stack pointer of new task
+ and r20=in0,r18 // physical address of "current"
+ ;;
+ mov r8=r13 // return pointer to previously running task
+ mov r13=in0 // set "current" pointer
+ mov ar.k6=r20 // copy "current" into ar.k6
+ ;;
+ // restore interrupts
+ mov psr.l=r17
+ ;;
+ srlz.d
+
+ movl r28=1f
+ br.cond.sptk.many load_switch_stack
+1:
+ br.ret.sptk.few rp
+ .endp ia64_switch_to
+
+ /*
+ * Like save_switch_stack, but also save the stack frame that is active
+ * at the time this function is called.
+ */
+ .align 16
+ .proc save_switch_stack_with_current_frame
+save_switch_stack_with_current_frame:
+1: {
+ alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack
+ mov r28=ip
+ }
+ ;;
+ adds r28=1f-1b,r28
+ br.cond.sptk.many save_switch_stack
+1: br.ret.sptk.few rp
+ .endp save_switch_stack_with_current_frame
+/*
+ * Note that interrupts are enabled during save_switch_stack and
+ * load_switch_stack. This means that we may get an interrupt with
+ * "sp" pointing to the new kernel stack while ar.bspstore is still
+ * pointing to the old kernel backing store area. Since ar.rsc,
+ * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts,
+ * this is not a problem.
+ */
+
+/*
+ * save_switch_stack:
+ * - r16 holds ar.pfs
+ * - r28 holds address to return to
+ * - rp (b0) holds return address to save
+ */
+ .align 16
+ .global save_switch_stack
+ .proc save_switch_stack
+save_switch_stack:
+ flushrs // flush dirty regs to backing store (must be first in insn group)
+ mov r17=ar.unat // preserve caller's
+ adds r2=-IA64_SWITCH_STACK_SIZE+16,sp // r2 = &sw->caller_unat
+ ;;
+ mov r18=ar.fpsr // preserve fpsr
+ mov ar.rsc=r0 // put RSE in mode: enforced lazy, little endian, pl 0
+ ;;
+ mov r19=ar.rnat
+ adds r3=-IA64_SWITCH_STACK_SIZE+24,sp // r3 = &sw->ar_fpsr
+
+ // Note: the instruction ordering is important here: we can't
+ // store anything to the switch stack before sp is updated
+ // as otherwise an interrupt might overwrite the memory!
+ adds sp=-IA64_SWITCH_STACK_SIZE,sp
+ ;;
+ st8 [r2]=r17,16
+ st8 [r3]=r18,24
+ ;;
+ stf.spill [r2]=f2,32
+ stf.spill [r3]=f3,32
+ mov r21=b0
+ ;;
+ stf.spill [r2]=f4,32
+ stf.spill [r3]=f5,32
+ ;;
+ stf.spill [r2]=f10,32
+ stf.spill [r3]=f11,32
+ mov r22=b1
+ ;;
+ stf.spill [r2]=f12,32
+ stf.spill [r3]=f13,32
+ mov r23=b2
+ ;;
+ stf.spill [r2]=f14,32
+ stf.spill [r3]=f15,32
+ mov r24=b3
+ ;;
+ stf.spill [r2]=f16,32
+ stf.spill [r3]=f17,32
+ mov r25=b4
+ ;;
+ stf.spill [r2]=f18,32
+ stf.spill [r3]=f19,32
+ mov r26=b5
+ ;;
+ stf.spill [r2]=f20,32
+ stf.spill [r3]=f21,32
+ mov r17=ar.lc // I-unit
+ ;;
+ stf.spill [r2]=f22,32
+ stf.spill [r3]=f23,32
+ ;;
+ stf.spill [r2]=f24,32
+ stf.spill [r3]=f25,32
+ ;;
+ stf.spill [r2]=f26,32
+ stf.spill [r3]=f27,32
+ ;;
+ stf.spill [r2]=f28,32
+ stf.spill [r3]=f29,32
+ ;;
+ stf.spill [r2]=f30,32
+ stf.spill [r3]=f31,24
+ ;;
+ st8.spill [r2]=r4,16
+ st8.spill [r3]=r5,16
+ ;;
+ st8.spill [r2]=r6,16
+ st8.spill [r3]=r7,16
+ ;;
+ st8 [r2]=r21,16 // save b0
+ st8 [r3]=r22,16 // save b1
+ /* since we're done with the spills, read and save ar.unat: */
+ mov r18=ar.unat // M-unit
+ mov r20=ar.bspstore // M-unit
+ ;;
+ st8 [r2]=r23,16 // save b2
+ st8 [r3]=r24,16 // save b3
+ ;;
+ st8 [r2]=r25,16 // save b4
+ st8 [r3]=r26,16 // save b5
+ ;;
+ st8 [r2]=r16,16 // save ar.pfs
+ st8 [r3]=r17,16 // save ar.lc
+ mov r21=pr
+ ;;
+ st8 [r2]=r18,16 // save ar.unat
+ st8 [r3]=r19,16 // save ar.rnat
+ mov b7=r28
+ ;;
+ st8 [r2]=r20 // save ar.bspstore
+ st8 [r3]=r21 // save predicate registers
+ mov ar.rsc=3 // put RSE back into eager mode, pl 0
+ br.cond.sptk.few b7
+ .endp save_switch_stack
+
+/*
+ * load_switch_stack:
+ * - r28 holds address to return to
+ */
+ .align 16
+ .proc load_switch_stack
+load_switch_stack:
+ invala // invalidate ALAT
+ adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp // get pointer to switch_stack.b0
+ mov ar.rsc=r0 // put RSE into enforced lazy mode
+ adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp // get pointer to switch_stack.b1
+ ;;
+ ld8 r21=[r2],16 // restore b0
+ ld8 r22=[r3],16 // restore b1
+ ;;
+ ld8 r23=[r2],16 // restore b2
+ ld8 r24=[r3],16 // restore b3
+ ;;
+ ld8 r25=[r2],16 // restore b4
+ ld8 r26=[r3],16 // restore b5
+ ;;
+ ld8 r16=[r2],16 // restore ar.pfs
+ ld8 r17=[r3],16 // restore ar.lc
+ ;;
+ ld8 r18=[r2],16 // restore ar.unat
+ ld8 r19=[r3],16 // restore ar.rnat
+ mov b0=r21
+ ;;
+ ld8 r20=[r2] // restore ar.bspstore
+ ld8 r21=[r3] // restore predicate registers
+ mov ar.pfs=r16
+ ;;
+ mov ar.bspstore=r20
+ ;;
+ loadrs // invalidate stacked regs outside current frame
+ adds r2=16-IA64_SWITCH_STACK_SIZE,r2 // get pointer to switch_stack.caller_unat
+ ;; // stop bit for rnat dependency
+ mov ar.rnat=r19
+ mov ar.unat=r18 // establish unat holding the NaT bits for r4-r7
+ adds r3=16-IA64_SWITCH_STACK_SIZE,r3 // get pointer to switch_stack.ar_fpsr
+ ;;
+ ld8 r18=[r2],16 // restore caller's unat
+ ld8 r19=[r3],24 // restore fpsr
+ mov ar.lc=r17
+ ;;
+ ldf.fill f2=[r2],32
+ ldf.fill f3=[r3],32
+ mov pr=r21,-1
+ ;;
+ ldf.fill f4=[r2],32
+ ldf.fill f5=[r3],32
+ ;;
+ ldf.fill f10=[r2],32
+ ldf.fill f11=[r3],32
+ mov b1=r22
+ ;;
+ ldf.fill f12=[r2],32
+ ldf.fill f13=[r3],32
+ mov b2=r23
+ ;;
+ ldf.fill f14=[r2],32
+ ldf.fill f15=[r3],32
+ mov b3=r24
+ ;;
+ ldf.fill f16=[r2],32
+ ldf.fill f17=[r3],32
+ mov b4=r25
+ ;;
+ ldf.fill f18=[r2],32
+ ldf.fill f19=[r3],32
+ mov b5=r26
+ ;;
+ ldf.fill f20=[r2],32
+ ldf.fill f21=[r3],32
+ ;;
+ ldf.fill f22=[r2],32
+ ldf.fill f23=[r3],32
+ ;;
+ ldf.fill f24=[r2],32
+ ldf.fill f25=[r3],32
+ ;;
+ ldf.fill f26=[r2],32
+ ldf.fill f27=[r3],32
+ ;;
+ ldf.fill f28=[r2],32
+ ldf.fill f29=[r3],32
+ ;;
+ ldf.fill f30=[r2],32
+ ldf.fill f31=[r3],24
+ ;;
+ ld8.fill r4=[r2],16
+ ld8.fill r5=[r3],16
+ mov b7=r28
+ ;;
+ ld8.fill r6=[r2],16
+ ld8.fill r7=[r3],16
+ mov ar.unat=r18 // restore caller's unat
+ mov ar.fpsr=r19 // restore fpsr
+ mov ar.rsc=3 // put RSE back into eager mode, pl 0
+ adds sp=IA64_SWITCH_STACK_SIZE,sp // pop switch_stack
+ br.cond.sptk.few b7
+ .endp load_switch_stack
+
+ .align 16
+ .global __ia64_syscall
+ .proc __ia64_syscall
+__ia64_syscall:
+ .regstk 6,0,0,0
+ mov r15=in5 // put syscall number in place
+ break __BREAK_SYSCALL
+ movl r2=errno
+ cmp.eq p6,p7=-1,r10
+ ;;
+(p6) st4 [r2]=r8
+(p6) mov r8=-1
+ br.ret.sptk.few rp
+ .endp __ia64_syscall
+
+ //
+ // We invoke syscall_trace through this intermediate function to
+ // ensure that the syscall input arguments are not clobbered. We
+ // also use it to preserve b6, which contains the syscall entry point.
+ //
+ .align 16
+ .global invoke_syscall_trace
+ .proc invoke_syscall_trace
+invoke_syscall_trace:
+ alloc loc0=ar.pfs,8,3,0,0
+ ;; // WAW on CFM at the br.call
+ mov loc1=rp
+ br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!!
+.ret2: mov loc2=b6
+ br.call.sptk.few rp=syscall_trace
+.ret3: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame
+ mov rp=loc1
+ mov ar.pfs=loc0
+ mov b6=loc2
+ ;;
+ br.ret.sptk.few rp
+ .endp invoke_syscall_trace
+
+ //
+ // Invoke a system call, but do some tracing before and after the call.
+ // We MUST preserve the current register frame throughout this routine
+ // because some system calls (such as ia64_execve) directly
+ // manipulate ar.pfs.
+ //
+ // Input:
+ // r15 = syscall number
+ // b6 = syscall entry point
+ //
+ .global ia64_trace_syscall
+ .global ia64_strace_leave_kernel
+ .global ia64_strace_clear_r8
+
+ .proc ia64_strace_clear_r8
+ia64_strace_clear_r8: // this is where we return after cloning when PF_TRACESYS is on
+# ifdef CONFIG_SMP
+ br.call.sptk.few rp=invoke_schedule_tail
+# endif
+ mov r8=0
+ br strace_check_retval
+ .endp ia64_strace_clear_r8
+
+ .proc ia64_trace_syscall
+ia64_trace_syscall:
+ br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args
+.ret4: br.call.sptk.few rp=b6 // do the syscall
+strace_check_retval:
+.ret5: cmp.lt p6,p0=r8,r0 // syscall failed?
+ ;;
+ adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8
+ adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10
+ mov r10=0
+(p6) br.cond.sptk.few strace_error // syscall failed ->
+ ;; // avoid RAW on r10
+strace_save_retval:
+ st8.spill [r2]=r8 // store return value in slot for r8
+ st8.spill [r3]=r10 // clear error indication in slot for r10
+ia64_strace_leave_kernel:
+ br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
+.ret6: br.cond.sptk.many ia64_leave_kernel
+
+strace_error:
+ ld8 r3=[r2] // load pt_regs.r8
+ sub r9=0,r8 // negate return value to get errno value
+ ;;
+ cmp.ne p6,p0=r3,r0 // is pt_regs.r8!=0?
+ adds r3=16,r2 // r3=&pt_regs.r10
+ ;;
+(p6) mov r10=-1
+(p6) mov r8=r9
+ br.cond.sptk.few strace_save_retval
+ .endp ia64_trace_syscall
+
+/*
+ * A couple of convenience macros to help implement/understand the state
+ * restoration that happens at the end of ia64_ret_from_syscall.
+ */
+#define rARPR r31
+#define rCRIFS r30
+#define rCRIPSR r29
+#define rCRIIP r28
+#define rARRSC r27
+#define rARPFS r26
+#define rARUNAT r25
+#define rARRNAT r24
+#define rARBSPSTORE r23
+#define rKRBS r22
+#define rB6 r21
+
+ .align 16
+ .global ia64_ret_from_syscall
+ .global ia64_ret_from_syscall_clear_r8
+ .global ia64_leave_kernel
+ .proc ia64_ret_from_syscall
+ia64_ret_from_syscall_clear_r8:
+#ifdef CONFIG_SMP
+ // In SMP mode, we need to call schedule_tail to complete the scheduling process.
+ // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the
+ // address of the previously executing task.
+ br.call.sptk.few rp=invoke_schedule_tail
+.ret7:
+#endif
+ mov r8=0
+ ;; // added stop bits to prevent r8 dependency
+ia64_ret_from_syscall:
+ cmp.ge p6,p7=r8,r0 // syscall executed successfully?
+ adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8
+ adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10
+ ;;
+(p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit
+(p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit
+(p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure
+
+ia64_leave_kernel:
+ // check & deliver software interrupts (bottom half handlers):
+
+ movl r2=bh_active // sheesh, why aren't these two in
+ movl r3=bh_mask // a struct??
+ ;;
+ ld8 r2=[r2]
+ ld8 r3=[r3]
+ ;;
+ and r2=r2,r3
+ ;;
+ cmp.ne p6,p7=r2,r0 // any soft interrupts ready for delivery?
+(p6) br.call.dpnt.few rp=invoke_do_bottom_half
+1:
+(pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery
+
+ // call schedule() until we find a task that doesn't have need_resched set:
+
+back_from_resched:
+ { .mii
+ adds r2=IA64_TASK_NEED_RESCHED_OFFSET,r13
+ mov r3=ip
+ adds r14=IA64_TASK_SIGPENDING_OFFSET,r13
+ }
+ ;;
+ ld8 r2=[r2]
+ ld4 r14=[r14]
+ mov rp=r3 // arrange for schedule() to return to back_from_resched
+ ;;
+ /*
+ * If pEOI is set, we need to write the cr.eoi now and then
+ * clear pEOI because both invoke_schedule() and
+ * handle_signal_delivery() may call the scheduler. Since
+ * we're returning to user-level, we get at most one nested
+ * interrupt of the same priority level, which doesn't tax the
+ * kernel stack too much.
+ */
+(pEOI) mov cr.eoi=r0
+ cmp.ne p6,p0=r2,r0
+ cmp.ne p2,p0=r14,r0 // NOTE: pKern is an alias for p2!!
+(pEOI) cmp.ne pEOI,p0=r0,r0 // clear pEOI before calling schedule()
+ srlz.d
+(p6) br.call.spnt.many b6=invoke_schedule // ignore return value
+2:
+ // check & deliver pending signals:
+(p2) br.call.spnt.few rp=handle_signal_delivery
+restore_all:
+
+ // start restoring the state saved on the kernel stack (struct pt_regs):
+
+ adds r2=IA64_PT_REGS_R8_OFFSET+16,r12
+ adds r3=IA64_PT_REGS_R8_OFFSET+24,r12
+ ;;
+ ld8.fill r8=[r2],16
+ ld8.fill r9=[r3],16
+ ;;
+ ld8.fill r10=[r2],16
+ ld8.fill r11=[r3],16
+ ;;
+ ld8.fill r16=[r2],16
+ ld8.fill r17=[r3],16
+ ;;
+ ld8.fill r18=[r2],16
+ ld8.fill r19=[r3],16
+ ;;
+ ld8.fill r20=[r2],16
+ ld8.fill r21=[r3],16
+ ;;
+ ld8.fill r22=[r2],16
+ ld8.fill r23=[r3],16
+ ;;
+ ld8.fill r24=[r2],16
+ ld8.fill r25=[r3],16
+ ;;
+ ld8.fill r26=[r2],16
+ ld8.fill r27=[r3],16
+ ;;
+ ld8.fill r28=[r2],16
+ ld8.fill r29=[r3],16
+ ;;
+ ld8.fill r30=[r2],16
+ ld8.fill r31=[r3],16
+ ;;
+ ld8 r1=[r2],16 // ar.ccv
+ ld8 r13=[r3],16 // ar.fpsr
+ ;;
+ ld8 r14=[r2],16 // b0
+ ld8 r15=[r3],16+8 // b7
+ ;;
+ ldf.fill f6=[r2],32
+ ldf.fill f7=[r3],32
+ ;;
+ ldf.fill f8=[r2],32
+ ldf.fill f9=[r3],32
+ ;;
+ mov ar.ccv=r1
+ mov ar.fpsr=r13
+ mov b0=r14
+ // turn off interrupts, interrupt collection, & data translation
+ rsm psr.i | psr.ic | psr.dt
+ ;;
+ srlz.i // EAS 2.5
+ mov b7=r15
+ ;;
+ invala // invalidate ALAT
+ dep r12=0,r12,61,3 // convert sp to physical address
+ bsw.0;; // switch back to bank 0 (must be last in insn group)
+ ;;
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+ nop.i 0x0
+ ;;
+ nop.i 0x0
+ ;;
+ nop.i 0x0
+ ;;
+#endif
+ adds r16=16,r12
+ adds r17=24,r12
+ ;;
+ ld8 rCRIPSR=[r16],16 // load cr.ipsr
+ ld8 rCRIIP=[r17],16 // load cr.iip
+ ;;
+ ld8 rCRIFS=[r16],16 // load cr.ifs
+ ld8 rARUNAT=[r17],16 // load ar.unat
+ ;;
+ ld8 rARPFS=[r16],16 // load ar.pfs
+ ld8 rARRSC=[r17],16 // load ar.rsc
+ ;;
+ ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage)
+ ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage)
+ ;;
+ ld8 rARPR=[r16],16 // load predicates
+ ld8 rB6=[r17],16 // load b6
+ ;;
+ ld8 r18=[r16],16 // load ar.rsc value for "loadrs"
+ ld8.fill r1=[r17],16 // load r1
+ ;;
+ ld8.fill r2=[r16],16
+ ld8.fill r3=[r17],16
+ ;;
+ ld8.fill r12=[r16],16
+ ld8.fill r13=[r17],16
+ extr.u r19=rCRIPSR,32,2 // extract ps.cpl
+ ;;
+ ld8.fill r14=[r16],16
+ ld8.fill r15=[r17],16
+ cmp.eq p6,p7=r0,r19 // are we returning to kernel mode? (psr.cpl==0)
+ ;;
+ mov b6=rB6
+ mov ar.pfs=rARPFS
+(p6) br.cond.dpnt.few skip_rbs_switch
+
+ /*
+ * Restore user backing store.
+ *
+ * NOTE: alloc, loadrs, and cover can't be predicated.
+ *
+ * XXX This needs some scheduling/tuning once we believe it
+ * really does work as intended.
+ */
+ mov r16=ar.bsp // get existing backing store pointer
+(pNonSys) br.cond.dpnt.few dont_preserve_current_frame
+ cover // add current frame into dirty partition
+ ;;
+ mov rCRIFS=cr.ifs // fetch the cr.ifs value that "cover" produced
+ mov r17=ar.bsp // get new backing store pointer
+ ;;
+ sub r16=r17,r16 // calculate number of bytes that were added to rbs
+ ;;
+ shl r16=r16,16 // shift additional frame size into position for loadrs
+ ;;
+ add r18=r16,r18 // adjust the loadrs value
+ ;;
+#ifdef CONFIG_IA64_SOFTSDV_HACKS
+ // Reset ITM if we've missed a timer tick. Workaround for SoftSDV bug
+ mov r16 = r2
+ mov r2 = ar.itc
+ mov r17 = cr.itm
+ ;;
+ cmp.gt p6,p7 = r2, r17
+(p6) addl r17 = 100, r2
+ ;;
+ mov cr.itm = r17
+ mov r2 = r16
+#endif
+dont_preserve_current_frame:
+ alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls)
+ ;;
+ mov ar.rsc=r18 // load ar.rsc to be used for "loadrs"
+#ifdef CONFIG_IA32_SUPPORT
+ tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT
+ ;;
+(p6) mov ar.rsc=r0 // returning to IA32 mode
+#endif
+ ;;
+ loadrs
+ ;;
+ mov ar.bspstore=rARBSPSTORE
+ ;;
+ mov ar.rnat=rARRNAT // must happen with RSE in lazy mode
+
+skip_rbs_switch:
+ mov ar.rsc=rARRSC
+ mov ar.unat=rARUNAT
+ mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall
+(pEOI) mov cr.eoi=r0
+ mov pr=rARPR,-1
+ mov cr.iip=rCRIIP
+ mov cr.ipsr=rCRIPSR
+ ;;
+ rfi;; // must be last instruction in an insn group
+
+handle_syscall_error:
+ /*
+ * Some system calls (e.g., ptrace, mmap) can return arbitrary
+ * values which could lead us to mistake a negative return
+ * value as a failed syscall. Those syscall must deposit
+ * a non-zero value in pt_regs.r8 to indicate an error.
+ * If pt_regs.r8 is zero, we assume that the call completed
+ * successfully.
+ */
+ ld8 r3=[r2] // load pt_regs.r8
+ sub r9=0,r8 // negate return value to get errno
+ ;;
+ mov r10=-1 // return -1 in pt_regs.r10 to indicate error
+ cmp.eq p6,p7=r3,r0 // is pt_regs.r8==0?
+ adds r3=16,r2 // r3=&pt_regs.r10
+ ;;
+(p6) mov r9=r8
+(p6) mov r10=0
+ ;;
+ st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit
+ st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit
+ br.cond.sptk.many ia64_leave_kernel
+ .endp __ret_from_syscall
+
+#ifdef CONFIG_SMP
+ /*
+ * Invoke schedule_tail(task) while preserving in0-in7, which may be needed
+ * in case a system call gets restarted.
+ */
+ .proc invoke_schedule_tail
+invoke_schedule_tail:
+ alloc loc0=ar.pfs,8,2,1,0
+ mov loc1=rp
+ mov out0=r8 // Address of previous task
+ ;;
+ br.call.sptk.few rp=schedule_tail
+.ret8:
+ mov ar.pfs=loc0
+ mov rp=loc1
+ br.ret.sptk.many rp
+ .endp invoke_schedule_tail
+#endif /* CONFIG_SMP */
+
+ /*
+ * Invoke do_bottom_half() while preserving in0-in7, which may be needed
+ * in case a system call gets restarted.
+ */
+ .proc invoke_do_bottom_half
+invoke_do_bottom_half:
+ alloc loc0=ar.pfs,8,2,0,0
+ mov loc1=rp
+ ;;
+ br.call.sptk.few rp=do_bottom_half
+.ret9:
+ mov ar.pfs=loc0
+ mov rp=loc1
+ br.ret.sptk.many rp
+ .endp invoke_do_bottom_half
+
+ /*
+ * Invoke schedule() while preserving in0-in7, which may be needed
+ * in case a system call gets restarted.
+ */
+ .proc invoke_schedule
+invoke_schedule:
+ alloc loc0=ar.pfs,8,2,0,0
+ mov loc1=rp
+ ;;
+ br.call.sptk.few rp=schedule
+.ret10:
+ mov ar.pfs=loc0
+ mov rp=loc1
+ br.ret.sptk.many rp
+ .endp invoke_schedule
+
+ //
+ // Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to
+ // be set up by the caller. We declare 8 input registers so the system call
+ // args get preserved, in case we need to restart a system call.
+ //
+ .align 16
+ .proc handle_signal_delivery
+handle_signal_delivery:
+ alloc loc0=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
+ mov r9=ar.unat
+
+ // If the process is being ptraced, the signal may not actually be delivered to
+ // the process. Instead, SIGCHLD will be sent to the parent. We need to
+ // setup a switch_stack so ptrace can inspect the processes state if necessary.
+ adds r2=IA64_TASK_FLAGS_OFFSET,r13
+ ;;
+ ld8 r2=[r2]
+ mov out0=0 // there is no "oldset"
+ adds out1=16,sp // out1=&pt_regs
+ ;;
+(pSys) mov out2=1 // out2==1 => we're in a syscall
+ tbit.nz p16,p17=r2,PF_PTRACED_BIT
+(p16) br.cond.spnt.many setup_switch_stack
+ ;;
+back_from_setup_switch_stack:
+(pNonSys) mov out2=0 // out2==0 => not a syscall
+ adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack
+ ;;
+(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat
+ mov loc1=rp // save return address
+ br.call.sptk.few rp=ia64_do_signal
+.ret11:
+ adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+ ;;
+ ld8 r9=[r3] // load new unat from sw->caller_unat
+ mov rp=loc1
+ ;;
+(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack
+(p17) mov ar.unat=r9
+(p17) mov ar.pfs=loc0
+(p17) br.ret.sptk.many rp
+
+ // restore the switch stack (ptrace may have modified it):
+ movl r28=1f
+ br.cond.sptk.many load_switch_stack
+1: br.ret.sptk.many rp
+ // NOT REACHED
+
+setup_switch_stack:
+ movl r28=back_from_setup_switch_stack
+ mov r16=loc0
+ br.cond.sptk.many save_switch_stack
+ // NOT REACHED
+
+ .endp handle_signal_delivery
+
+ .align 16
+ .proc sys_rt_sigsuspend
+ .global sys_rt_sigsuspend
+sys_rt_sigsuspend:
+ alloc loc0=ar.pfs,2,2,3,0
+ mov r9=ar.unat
+
+ // If the process is being ptraced, the signal may not actually be delivered to
+ // the process. Instead, SIGCHLD will be sent to the parent. We need to
+ // setup a switch_stack so ptrace can inspect the processes state if necessary.
+ adds r2=IA64_TASK_FLAGS_OFFSET,r13
+ ;;
+ ld8 r2=[r2]
+ mov out0=in0 // mask
+ mov out1=in1 // sigsetsize
+ ;;
+ adds out2=16,sp // out1=&pt_regs
+ tbit.nz p16,p17=r2,PF_PTRACED_BIT
+(p16) br.cond.spnt.many sigsuspend_setup_switch_stack
+ ;;
+back_from_sigsuspend_setup_switch_stack:
+ adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack
+ ;;
+(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat
+ mov loc1=rp // save return address
+ br.call.sptk.many rp=ia64_rt_sigsuspend
+.ret12:
+ adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+ ;;
+ ld8 r9=[r3] // load new unat from sw->caller_unat
+ mov rp=loc1
+ ;;
+(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack
+(p17) mov ar.unat=r9
+(p17) mov ar.pfs=loc0
+(p17) br.ret.sptk.many rp
+
+ // restore the switch stack (ptrace may have modified it):
+ movl r28=1f
+ br.cond.sptk.many load_switch_stack
+1: br.ret.sptk.many rp
+ // NOT REACHED
+
+sigsuspend_setup_switch_stack:
+ movl r28=back_from_sigsuspend_setup_switch_stack
+ mov r16=loc0
+ br.cond.sptk.many save_switch_stack
+ // NOT REACHED
+
+ .endp sys_rt_sigsuspend
+
+ .align 16
+ .proc sys_rt_sigreturn
+sys_rt_sigreturn:
+ alloc loc0=ar.pfs,8,1,1,0 // preserve all eight input regs in case of syscall restart!
+ adds out0=16,sp // out0 = &pt_regs
+ ;;
+ adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for unat and padding
+ br.call.sptk.few rp=ia64_rt_sigreturn
+.ret13:
+ adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+ ;;
+ ld8 r9=[r3] // load new ar.unat
+ mov rp=r8
+ ;;
+ adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame
+ mov ar.unat=r9
+ mov ar.pfs=loc0
+ br.ret.sptk.many rp
+ .endp sys_rt_sigreturn
+
+ .align 16
+ .global ia64_prepare_handle_unaligned
+ .proc ia64_prepare_handle_unaligned
+ia64_prepare_handle_unaligned:
+ movl r28=1f
+ //
+ // r16 = fake ar.pfs, we simply need to make sure
+ // privilege is still 0
+ //
+ mov r16=r0
+ br.cond.sptk.few save_switch_stack
+1: br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt
+.ret14:
+ movl r28=2f
+ br.cond.sptk.many load_switch_stack
+2: br.cond.sptk.many rp // goes to ia64_leave_kernel
+ .endp ia64_prepare_handle_unaligned
+
+#ifdef CONFIG_KDB
+ //
+ // This gets called from ivt.S with:
+ // SAVE MIN with cover done
+ // SAVE REST done
+ // no parameters
+ // r15 has return value = ia64_leave_kernel
+ //
+ .align 16
+ .global ia64_invoke_kdb
+ .proc ia64_invoke_kdb
+ia64_invoke_kdb:
+ alloc r16=ar.pfs,0,0,4,0
+ movl r28=1f // save_switch_stack protocol
+ ;; // avoid WAW on CFM
+ br.cond.sptk.many save_switch_stack // to flushrs
+1: mov out0=4 // kdb entry reason
+ mov out1=0 // err number
+ adds out2=IA64_SWITCH_STACK_SIZE+16,sp // pt_regs
+ add out3=16,sp // switch_stack
+ br.call.sptk.few rp=kdb
+.ret15:
+ movl r28=1f // load_switch_stack proto
+ br.cond.sptk.many load_switch_stack
+1: br.ret.sptk.many rp
+ .endp ia64_invoke_kdb
+
+ //
+ // When KDB is compiled in, we intercept each fault and give
+ // kdb a chance to run before calling the normal fault handler.
+ //
+ .align 16
+ .global ia64_invoke_kdb_fault_handler
+ .proc ia64_invoke_kdb_fault_handler
+ia64_invoke_kdb_fault_handler:
+ alloc r16=ar.pfs,5,1,5,0
+ movl r28=1f
+ mov loc0=rp // save this
+ br.cond.sptk.many save_switch_stack // to flushrs
+ ;; // avoid WAW on CFM
+1: mov out0=in0 // vector number
+ mov out1=in1 // cr.isr
+ mov out2=in2 // cr.ifa
+ mov out3=in3 // cr.iim
+ mov out4=in4 // cr.itir
+ br.call.sptk.few rp=ia64_kdb_fault_handler
+.ret16:
+
+ movl r28=1f
+ br.cond.sptk.many load_switch_stack
+1: cmp.ne p6,p0=r8,r0 // did ia64_kdb_fault_handler return 0?
+ mov rp=loc0
+(p6) br.ret.spnt.many rp // no, we're done
+ ;; // avoid WAW on rp
+ mov out0=in0 // vector number
+ mov out1=in1 // cr.isr
+ mov out2=in2 // cr.ifa
+ mov out3=in3 // cr.iim
+ mov out4=in4 // cr.itir
+ mov in0=ar.pfs // preserve ar.pfs returned by load_switch_stack
+ br.call.sptk.few rp=ia64_fault // yup -> we need to invoke normal fault handler now
+.ret17:
+ mov ar.pfs=in0
+ mov rp=loc0
+ br.ret.sptk.many rp
+
+ .endp ia64_invoke_kdb_fault_handler
+
+#endif /* CONFIG_KDB */
+
+ .rodata
+ .align 8
+ .globl sys_call_table
+sys_call_table:
+ data8 sys_ni_syscall // This must be sys_ni_syscall! See ivt.S.
+ data8 sys_exit // 1025
+ data8 sys_read
+ data8 sys_write
+ data8 sys_open
+ data8 sys_close
+ data8 sys_creat // 1030
+ data8 sys_link
+ data8 sys_unlink
+ data8 ia64_execve
+ data8 sys_chdir
+ data8 sys_fchdir // 1035
+ data8 sys_utimes
+ data8 sys_mknod
+ data8 sys_chmod
+ data8 sys_chown
+ data8 sys_lseek // 1040
+ data8 sys_getpid
+ data8 sys_getppid
+ data8 sys_mount
+ data8 sys_umount
+ data8 sys_setuid // 1045
+ data8 sys_getuid
+ data8 sys_geteuid
+ data8 sys_ptrace
+ data8 sys_access
+ data8 sys_sync // 1050
+ data8 sys_fsync
+ data8 sys_fdatasync
+ data8 sys_kill
+ data8 sys_rename
+ data8 sys_mkdir // 1055
+ data8 sys_rmdir
+ data8 sys_dup
+ data8 sys_pipe
+ data8 sys_times
+ data8 ia64_brk // 1060
+ data8 sys_setgid
+ data8 sys_getgid
+ data8 sys_getegid
+ data8 sys_acct
+ data8 sys_ioctl // 1065
+ data8 sys_fcntl
+ data8 sys_umask
+ data8 sys_chroot
+ data8 sys_ustat
+ data8 sys_dup2 // 1070
+ data8 sys_setreuid
+ data8 sys_setregid
+ data8 sys_getresuid
+ data8 sys_setresuid
+ data8 sys_getresgid // 1075
+ data8 sys_setresgid
+ data8 sys_getgroups
+ data8 sys_setgroups
+ data8 sys_getpgid
+ data8 sys_setpgid // 1080
+ data8 sys_setsid
+ data8 sys_getsid
+ data8 sys_sethostname
+ data8 sys_setrlimit
+ data8 sys_getrlimit // 1085
+ data8 sys_getrusage
+ data8 sys_gettimeofday
+ data8 sys_settimeofday
+ data8 sys_select
+ data8 sys_poll // 1090
+ data8 sys_symlink
+ data8 sys_readlink
+ data8 sys_uselib
+ data8 sys_swapon
+ data8 sys_swapoff // 1095
+ data8 sys_reboot
+ data8 sys_truncate
+ data8 sys_ftruncate
+ data8 sys_fchmod
+ data8 sys_fchown // 1100
+ data8 ia64_getpriority
+ data8 sys_setpriority
+ data8 sys_statfs
+ data8 sys_fstatfs
+ data8 sys_ioperm // 1105
+ data8 sys_semget
+ data8 sys_semop
+ data8 sys_semctl
+ data8 sys_msgget
+ data8 sys_msgsnd // 1110
+ data8 sys_msgrcv
+ data8 sys_msgctl
+ data8 sys_shmget
+ data8 ia64_shmat
+ data8 sys_shmdt // 1115
+ data8 sys_shmctl
+ data8 sys_syslog
+ data8 sys_setitimer
+ data8 sys_getitimer
+ data8 sys_newstat // 1120
+ data8 sys_newlstat
+ data8 sys_newfstat
+ data8 sys_vhangup
+ data8 sys_lchown
+ data8 sys_vm86 // 1125
+ data8 sys_wait4
+ data8 sys_sysinfo
+ data8 sys_clone
+ data8 sys_setdomainname
+ data8 sys_newuname // 1130
+ data8 sys_adjtimex
+ data8 sys_create_module
+ data8 sys_init_module
+ data8 sys_delete_module
+ data8 sys_get_kernel_syms // 1135
+ data8 sys_query_module
+ data8 sys_quotactl
+ data8 sys_bdflush
+ data8 sys_sysfs
+ data8 sys_personality // 1140
+ data8 ia64_ni_syscall // sys_afs_syscall
+ data8 sys_setfsuid
+ data8 sys_setfsgid
+ data8 sys_getdents
+ data8 sys_flock // 1145
+ data8 sys_readv
+ data8 sys_writev
+ data8 sys_pread
+ data8 sys_pwrite
+ data8 sys_sysctl // 1150
+ data8 sys_mmap
+ data8 sys_munmap
+ data8 sys_mlock
+ data8 sys_mlockall
+ data8 sys_mprotect // 1155
+ data8 sys_mremap
+ data8 sys_msync
+ data8 sys_munlock
+ data8 sys_munlockall
+ data8 sys_sched_getparam // 1160
+ data8 sys_sched_setparam
+ data8 sys_sched_getscheduler
+ data8 sys_sched_setscheduler
+ data8 sys_sched_yield
+ data8 sys_sched_get_priority_max // 1165
+ data8 sys_sched_get_priority_min
+ data8 sys_sched_rr_get_interval
+ data8 sys_nanosleep
+ data8 sys_nfsservctl
+ data8 sys_prctl // 1170
+ data8 sys_getpagesize
+ data8 sys_mmap2
+ data8 sys_pciconfig_read
+ data8 sys_pciconfig_write
+ data8 sys_perfmonctl // 1175
+ data8 sys_sigaltstack
+ data8 sys_rt_sigaction
+ data8 sys_rt_sigpending
+ data8 sys_rt_sigprocmask
+ data8 sys_rt_sigqueueinfo // 1180
+ data8 sys_rt_sigreturn
+ data8 sys_rt_sigsuspend
+ data8 sys_rt_sigtimedwait
+ data8 sys_getcwd
+ data8 sys_capget // 1185
+ data8 sys_capset
+ data8 sys_sendfile
+ data8 sys_ni_syscall // sys_getpmsg (STREAMS)
+ data8 sys_ni_syscall // sys_putpmsg (STREAMS)
+ data8 sys_socket // 1190
+ data8 sys_bind
+ data8 sys_connect
+ data8 sys_listen
+ data8 sys_accept
+ data8 sys_getsockname // 1195
+ data8 sys_getpeername
+ data8 sys_socketpair
+ data8 sys_send
+ data8 sys_sendto
+ data8 sys_recv // 1200
+ data8 sys_recvfrom
+ data8 sys_shutdown
+ data8 sys_setsockopt
+ data8 sys_getsockopt
+ data8 sys_sendmsg // 1205
+ data8 sys_recvmsg
+ data8 sys_pivot_root
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1210
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1215
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1220
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1225
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1230
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1235
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1240
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1245
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1250
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1255
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1260
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1265
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1270
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall // 1275
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+ data8 ia64_ni_syscall
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)