blob: 3bc19ea6c6d157cd6dcd789130a1bae57c6aa0ee [file] [log] [blame]
/**
* @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)