/**
 * @file oprofile_stubs.S
 * Assembly language system call interceptor stubs 
 *
 * @remark Copyright 2001-2002 Hewlett-Packard Company
 * @remark Read the file COPYING
 *
 * @author Bob Montgomery <bob_montgomery@hp.com>
 */

/*
 * This interceptor for execve was stolen from ia64/kernel/entry.S
 *
 * Kernel entry points.
 *
 * Copyright (C) 1998-2001 Hewlett-Packard Co
 *	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>
 */
/*
 * ia64_switch_to now places correct virtual mapping in in TR2 for
 * kernel stack. This allows us to handle interrupts without changing
 * to physical mode.
 *
 * Jonathan Nicklin	<nicklin@missioncriticallinux.com>
 * Patrick O'Rourke	<orourke@missioncriticallinux.com>
 * 11/07/2000
 */
/*
 * Global (preserved) predicate usage on syscall entry/exit path:
 *
 *	pKern:		See entry.h.
 *	pUser:		See entry.h.
 *	pSys:		See entry.h.
 *	pNonSys:	!pSys
 */

#include <linux/config.h>

#include <asm/cache.h>
#include <asm/errno.h>
#include <asm/kregs.h>
#include <asm/offsets.h>
#include <asm/processor.h>
#include <asm/unistd.h>
#include <asm/asmmacro.h>
#include <asm/pgtable.h>

#include "IA64minstate.h"

	/*
	 * execve() is special because in case of success, we need to
	 * setup a null register window frame.
	 */
GLOBAL_ENTRY(my_ia64_execve)
	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)
	alloc loc1=ar.pfs, 3, 3, 4, 0
	mov loc0=rp
	mov loc2=gp
	.body
	mov out0=in0			// filename
	;;				// stop bit between alloc and call
	mov out1=in1			// argv
	mov out2=in2			// envp
	add out3=16, sp			// regs
	/* 
	 * We are here with the kernel's gp register value but we need
	 * to find the module's gp value before we can call our own
	 * routine.  That's why we can't just use:
	 *	br.call.sptk.many rp=my_sys_execve
	 * Use ip-relative addressing to get to the fptr since I can't
	 * use gp-relative anything without the module's gp.
	 */
.L1_execve:
	mov r3 = ip
	;;
	addl r14 = .fptr_execve - .L1_execve, r3
	;;
	ld8 r14=[r14]
	;;
	ld8 r15=[r14], 8
	;;
	ld8 gp=[r14]
	;;
	mov b6=r15
	br.call.sptk.many b0=b6
	;;
.ret0:	cmp4.ge p6, p7=r8, r0
	mov ar.pfs=loc1			// restore ar.pfs
	sxt4 r8=r8			// return 64-bit result
	;;
	stf.spill [sp]=f0
(p6)	cmp.ne pKern, pUser=r0, r0	// a successful execve() lands us in user-mode...
	mov gp=loc2
	mov rp=loc0
(p6)	mov ar.pfs=r0			// clear ar.pfs on success
(p7)	br.ret.sptk.many rp

	/*
	 * In theory, we'd have to zap this state only to prevent leaking of
	 * security sensitive state (e.g., if current->mm->dumpable is zero).  However,
	 * this executes in less than 20 cycles even on Itanium, so it's not worth
	 * optimizing for...).
	 */
	mov r4=0;		mov f2=f0;		mov b1=r0
	mov r5=0;		mov f3=f0;		mov b2=r0
	mov r6=0;		mov f4=f0;		mov b3=r0
	mov r7=0;		mov f5=f0;		mov b4=r0
	mov ar.unat=0;		mov f10=f0;		mov b5=r0
	ldf.fill f11=[sp];	ldf.fill f12=[sp];	mov f13=f0
	ldf.fill f14=[sp];	ldf.fill f15=[sp];	mov f16=f0
	ldf.fill f17=[sp];	ldf.fill f18=[sp];	mov f19=f0
	ldf.fill f20=[sp];	ldf.fill f21=[sp];	mov f22=f0
	ldf.fill f23=[sp];	ldf.fill f24=[sp];	mov f25=f0
	ldf.fill f26=[sp];	ldf.fill f27=[sp];	mov f28=f0
	ldf.fill f29=[sp];	ldf.fill f30=[sp];	mov f31=f0
	mov ar.lc=0
	br.ret.sptk.many rp
	.align 16
.fptr_execve:
	data8 @fptr(my_sys_execve)
END(my_ia64_execve)

/* These interceptors are from IA64syscallstub.h macros */
#include "IA64syscallstub.h"

SYSCALLSTUB_POST(clone)

SYSCALLSTUB_POST(clone2)

SYSCALLSTUB_POST(mmap)

SYSCALLSTUB_POST(mmap2)

SYSCALLSTUB_POST(init_module)

SYSCALLSTUB_PRE(exit)