/** * @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)