diff -Naru linux-2.4.19/arch/alpha/config.in linux-2.4.19-hooks/arch/alpha/config.in
--- linux-2.4.19/arch/alpha/config.in	2002-08-03 09:39:42.000000000 +0900
+++ linux-2.4.19-hooks/arch/alpha/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -422,4 +422,8 @@
    define_tristate CONFIG_MATHEMU y
 fi
 
+tristate '  Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '    /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/arm/config.in linux-2.4.19-hooks/arch/arm/config.in
--- linux-2.4.19/arch/arm/config.in	2002-08-03 09:39:42.000000000 +0900
+++ linux-2.4.19-hooks/arch/arm/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -654,4 +654,8 @@
 dep_bool '  Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL
 dep_bool '    Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
 dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
+tristate '  Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '    /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/cris/config.in linux-2.4.19-hooks/arch/cris/config.in
--- linux-2.4.19/arch/cris/config.in	2002-02-26 04:37:52.000000000 +0900
+++ linux-2.4.19-hooks/arch/cris/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -253,4 +253,8 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/i386/config.in linux-2.4.19-hooks/arch/i386/config.in
--- linux-2.4.19/arch/i386/config.in	2002-08-03 09:39:42.000000000 +0900
+++ linux-2.4.19-hooks/arch/i386/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -425,4 +425,9 @@
    bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
 fi
 
+tristate '  Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      define_bool CONFIG_ASM_HOOK y
+      bool '    /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/ia64/config.in linux-2.4.19-hooks/arch/ia64/config.in
--- linux-2.4.19/arch/ia64/config.in	2002-08-03 09:39:42.000000000 +0900
+++ linux-2.4.19-hooks/arch/ia64/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -278,4 +278,9 @@
    bool '  Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
 fi
 
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      define_bool CONFIG_ASM_HOOK y
+      bool '    /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/m68k/config.in linux-2.4.19-hooks/arch/m68k/config.in
--- linux-2.4.19/arch/m68k/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/m68k/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -564,4 +564,8 @@
    bool '  Verbose BUG() reporting' CONFIG_DEBUG_BUGVERBOSE
 fi
 
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/mips/config.in linux-2.4.19-hooks/arch/mips/config.in
--- linux-2.4.19/arch/mips/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/mips/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -631,4 +631,8 @@
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/mips64/config.in linux-2.4.19-hooks/arch/mips64/config.in
--- linux-2.4.19/arch/mips64/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/mips64/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -335,4 +335,5 @@
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
+tristate 'Kernel Hook support' CONFIG_HOOK
 endmenu
diff -Naru linux-2.4.19/arch/parisc/config.in linux-2.4.19-hooks/arch/parisc/config.in
--- linux-2.4.19/arch/parisc/config.in	2001-04-18 09:19:25.000000000 +0900
+++ linux-2.4.19-hooks/arch/parisc/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -206,5 +206,9 @@
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
 
diff -Naru linux-2.4.19/arch/ppc/config.in linux-2.4.19-hooks/arch/ppc/config.in
--- linux-2.4.19/arch/ppc/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/ppc/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -401,4 +401,9 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+	define_bool CONFIG_ASM_HOOK y
+	bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/ppc64/config.in linux-2.4.19-hooks/arch/ppc64/config.in
--- linux-2.4.19/arch/ppc64/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/ppc64/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -238,4 +238,9 @@
 #  define_bool CONFIG_KALLSYMS y
 #fi
 bool 'Include PPCDBG realtime debugging' CONFIG_PPCDBG
+tristate	'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+	define_bool CONFIG_ASM_HOOK y
+	bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/s390/config.in linux-2.4.19-hooks/arch/s390/config.in
--- linux-2.4.19/arch/s390/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/s390/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -73,5 +73,10 @@
 #  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 #fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+	define_bool CONFIG_ASM_HOOK y
+	bool '    /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
 
diff -Naru linux-2.4.19/arch/s390x/config.in linux-2.4.19-hooks/arch/s390x/config.in
--- linux-2.4.19/arch/s390x/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/s390x/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -75,5 +75,10 @@
 #  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 #fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+	define_bool CONFIG_ASM_HOOK y
+	bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
 
diff -Naru linux-2.4.19/arch/sh/config.in linux-2.4.19-hooks/arch/sh/config.in
--- linux-2.4.19/arch/sh/config.in	2002-02-26 04:37:56.000000000 +0900
+++ linux-2.4.19-hooks/arch/sh/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -385,4 +385,8 @@
 if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
    bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
 fi
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/sparc/config.in linux-2.4.19-hooks/arch/sparc/config.in
--- linux-2.4.19/arch/sparc/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/sparc/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -270,4 +270,8 @@
 comment 'Kernel hacking'
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/arch/sparc64/config.in linux-2.4.19-hooks/arch/sparc64/config.in
--- linux-2.4.19/arch/sparc64/config.in	2002-08-03 09:39:43.000000000 +0900
+++ linux-2.4.19-hooks/arch/sparc64/config.in	2003-03-31 11:01:51.000000000 +0900
@@ -307,4 +307,8 @@
    define_bool CONFIG_MCOUNT y
 fi
 
+tristate 'Kernel Hook support' CONFIG_HOOK
+   if [ "$CONFIG_HOOK" != "n" ]; then
+      bool '  /proc interface for hooks' CONFIG_HOOK_PROCFS
+   fi
 endmenu
diff -Naru linux-2.4.19/Documentation/Configure.help linux-2.4.19-hooks/Documentation/Configure.help
--- linux-2.4.19/Documentation/Configure.help	2002-08-03 09:39:42.000000000 +0900
+++ linux-2.4.19-hooks/Documentation/Configure.help	2003-03-31 11:01:51.000000000 +0900
@@ -19613,6 +19613,16 @@
   keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
   unless you really know what this hack does.
 
+Kernel Hook Support
+CONFIG_HOOK
+  The Kernel Hooks Interface is a generalised facility for placing hooks in
+  arbitrary kernel locations. A hook is a location in the kernel that
+  calls out of the kernel to a kernel module routine - a hook exit routine.
+  Read Documentation/hook/HOWTO for more details.
+
+  This is required for enabling IBM Dynamic Probes. If you need Dynamic Probes
+  you have to say Y or M. If in doubt, say N.
+
 ISDN support
 CONFIG_ISDN
   ISDN ("Integrated Services Digital Networks", called RNIS in France)
diff -Naru linux-2.4.19/Documentation/hook/HOWTO linux-2.4.19-hooks/Documentation/hook/HOWTO
--- linux-2.4.19/Documentation/hook/HOWTO	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/Documentation/hook/HOWTO	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,427 @@
+How to use Kernel Hooks?
+
+Author: Richard J Moore, richardj_moore@uk.ibm.com, 
+	Vamsi Krishna S., vamsi_krishna@in.ibm.com
+	Linux Technology Centre, IBM Corp.
+
+Copyright 2000 IBM Corporation
+Copyright 2000 IBM UK Ltd
+
+
+Introduction:
+------------
+
+The Kernel Hooks Interface is a generalised facility for placing hooks in 
+arbitrary kernel locations. A hook is a location in the kernel
+that calls out of the kernel to a kernel module routine - a hook exit routine.
+It enables many kernel enhancements, which are otherwise self-contained, to
+become loadable kernel modules and retain a substantial degree of independence
+from the kernel source. This affords advantages for maintenance and
+co-existence with other kernel enhancements. 
+
+Hooks are implemented as fast and slim-line insertions to kernel space code.
+When not active that have practically no overhead to the kernel. They are in
+essence a conditional jmp to the exit dispatching code. 
+
+There are two hook optimizations employed in gkhi, one of which is optional - the
+exclusive hook; the other - the arch-hook - is dependent on the IA32 architecture
+and always used in that environment.
+
+The exclusive hook eliminates some of the generalised processing associated with
+dispatching multiple exits. This can be used where it is known that only one 
+exit would ever register to use a hook. Exclusive hooks are coded as 
+EXCLUSIVE_HOOK, EXCLUSIVE_HOOK_RET etc. You have to use the macro
+DECLARE_EXCLUSIVE_HOOK_HEAD to declare the exclusive hook.
+
+The arch-hook optimization uses architecturally dependent features. We have 
+provided an implementation for IA32, though could be ported to other 
+architectures without difficulty. The code for the IA32 implementation may 
+be found in include/asm-i386/hook.h. This optimization is always used under IA32. 
+It is implemented by:
+ 
+  1. moving the hook exit dispatching code to a separate section to minimise the
+     icache footprint of the hook code. (This should be applicable
+     to all architectures.)
+  2. changing the test for the conditional jmp to be dependent on a register variable
+     which set by moving a literal constant into the register.
+  3. modifying the literal value in the MOV instruction to activate and deactivate the
+     hook.
+ 
+These actions both minimise the cache hit and the number of instructions required to
+test for an inactive hook.
+
+There is another type of hooks: generic hooks. These are slower than the
+arch-optimized hooks, but they generate no symbols at hook locations and
+could be used to place hooks even in inline functions. Use the macros
+DECLARE_GENERIC_HOOK_HEAD and GENERIC_HOOK etc. to define generic hooks.
+
+The hook interface allows multiple kernel modules to register their exits for
+a given hook, in order to receive control at that given hook location. Multiple
+hooks may be defined within the kernel and a single kernel module may register
+exits to use multiple hooks.
+
+When hook exits register they may specify co-existence criteria, that is
+whether they can co-exist with other exist for the same hook and their
+dispatching priority.
+
+Hooks may be placed in kernel modules as well as the kernel itself.
+
+A hook exit receives control as if called from the code in which the hook is
+placed. Parameters may be passed to a hook exit and may be modified by an
+exit (subject to being declared for that purpose). The exit may return a
+non-zero result to stop other exits from being dispatched.
+
+There are two type of hook:
+
+	normal.
+	conditional return.
+
+With normal hooks, control returns to the hooked code after any exits are
+dispatched.
+
+With conditional return hooks, an exit may optionally specify that the routine
+in which the hook is coded must return when the exit returns.
+
+Exits are made callable in a two-stage process:
+
+1) Registration - this is used to make the exit known to the hook interface
+and to perform some validation. 
+
+2) Arming - this is used to make a set of exits callable. The arming operation
+is atomic as far as kernel processing is concerned.
+
+These operations may be reversed using disarming and de-registration functions.
+
+Hook interface is implemented in kernel/hook.c which can be compiled into the
+kernel or as a module based on the kernel compilation option specified in
+the "Kernel Hacking" section of the build configuration.
+
+Hooks are defined by coding a DECLARE_HOOK_HEAD macro to define a hook-head 
+structure and by calling hook_initialise() to inform Hook interface that the 
+hook exists and is usable. Modules defining hooks may load before or after 
+hook.o when it is compiled as a module, however they have to identify to the
+hook interface module the existence of a hook before an exit can be register 
+and arm itself.
+
+Hooks can be disabled from use by calling hook_terminate().
+
+Hooks are identified by name, which should avoid problems of uniqueness. The
+name specified is used to generate labels for the hook-head structure and the
+hook location.
+
+
+Installation:
+-------------
+
+Apply this patch to the kernel source and say 'Y' or 'M' to "Kernel Hooks 
+Interface" in the "Kernel Hacking" section of the build configuration. Build 
+the kernel and boot with it. If you build the hook interface as a module,
+build and install the module.
+
+-------------------------------------------------------------------------------
+If you want to see a working example then compile khook.c and kexit.c using 
+the following command:
+   
+gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -O2 -fomit-frame-pointer -DMODULE -DEXPORT_SYMTAB -DHOOK_DEBUG -c khook.c
+gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -O2 -fomit-frame-pointer -DMODULE -DEXPORT_SYMTAB -DHOOK_DEBUG -c kexit.c
+
+insmod khook.o
+insmod kexit.o
+
+khook.c shows how hooks are coded.
+kexit.c shows how hook exits register and arm themselves.
+
+There is a debug switch for  (-DHOOK_DEBUG) that can be specified at compile
+time. This will build in debugging printk calls.
+
+The procedure for defining and using hooks involves the following steps:
+	- add hooks to the kernel/kernel module source
+	- initialise hooks
+	- register hook exits
+	- arm hook exits
+and when we are done using the hooks, undo the above:
+	- disarm hook exits
+	- deregister hook exits
+	- terminate hooks
+
+-------------------------------------------------------------------------------
+
+Adding Hooks to the Kernel
+--------------------------
+
+Let's say we want to place a hook named hook_trap1_entry in the beginning of the
+trap1 handler then edit arch/i386/traps.c, locate routine do_debug. This is the
+trap1 exception handler. The code begins as follows:
+
+asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+{
+	unsigned int condition;
+	struct task_struct *tsk = current;
+
+	if (regs->eflags & VM_MASK)
+		goto debug_vm86;
+
+	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
+
+Suppose we want a hook before the if statement. We add to traps.c:
+
+#include <linux/hook.h>
+#define HOOK_TRAP1_ENTRY hook_trap1_entry /* just a convenient define */
+DECLARE_HOOK_HEAD(HOOK_TRAP1_ENTRY);
+
+then in do_debug we insert the hook definition:
+asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+{
+	unsigned int condition;
+	struct task_struct *tsk = current;
+
+	HOOK(HOOK_TRAP1_ENTRY);
+
+	if (regs->eflags & VM_MASK)
+		goto debug_vm86;
+
+	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
+
+Now recompile the kernel.
+
+For example to pass "condition" from do_debug to a hook exit:
+
+    HOOK(HOOK_TRAP1_ENTRY, condition);
+
+If you want to code a conditional-return hook the use for exmaple:
+
+    HOOK_RET(HOOK_TRAP1_ENTRY, condition);
+
+The kernel now has a dormant hook at the beginning of the trap1 exception
+handler.
+
+Adding Hooks to a Kernel Module
+-------------------------------
+Adding hooks to a kernel module is very similar to adding hooks to kernel.
+In the module that is to have a hook defined code the DECLARE_HOOK_HEAD macro 
+before the first routine is defined - in other words where external static 
+variables would be defined. For example suppose we wish to define my_hook,
+then code:
+
+#include <linux/hook.h>
+DECLARE_HOOK_HEAD(my_hook);
+
+Next you'll need to define the hook by coding a HOOK macro in the code path 
+where the hook is to be placed. In this example:
+
+	HOOK(my_hook);
+
+would be coded. This defines a public symbol for the hook location using the
+name my_hook.
+
+Initializing a Hook:
+-------------------
+Before any exit can register an exit for this hook you must identify it to
+the hook interface by calling hook_initialise. In this example you would code:
+	rc = hook_initialise(my_hook);
+0 will be return if successful.
+
+After this point exits may register and arm themselves for this hook.
+
+Before the module containing the hook terminates, it must be disabled 
+to stop any further registrations and optionally to force the hook to become
+inactive - that is to immediately stop any exits armed for this hook to become
+disarmed. To disale my_hook call hook_terminate as follows:
+
+	rc = hook_terminate(my_hook);
+
+The hook id you chose my be define by a symbol, for example:
+
+#define HOOK1 my_hook
+
+
+Using Hooks - registering and arming hook exits:
+------------------------------------------------
+
+To use this hook from your kernel module you need to perform 3 actions:
+
+1) If hook interface hook.o is built as a module, insert it using:
+	insmod hook.o
+you might need the -f switch if you've changed kernel  versions after
+compiling hook.o
+
+2) You need to register the entry point (the hook exit) in your kernel module
+that will receive control from hook.
+
+You do this by calling hook_exit_register passing a hook name (in this example
+HOOK_TRAP1_ENTRY) and a pointer to a hook record structure (defined in
+hook.h as hook_rec_t). You will need to include linux/hook.h into your module's 
+source. Refer to this file for the definition of hook_rec_t and the relavent
+flags.
+
+Allocate an instance of this structure for each hook exit you wish to
+register. The hook.o interface will use these structures for as long as your
+exits remain registered so allocate them from persistent memory e.g. the
+kernel heap or global memory in you module. Don't allocate them as local
+variables!
+
+You set up your hook record as follows:
+
+1) initialise the entire structure to NULLs.
+
+2) set hook_exit to the address of you hook routine.
+
+3) optionally set hook_flags to one of the following:
+
+#define HOOK_PRIORITY_FIRST	0x00000004
+#define HOOK_PRIORITY_LAST	0x00000008
+#define HOOK_QUEUE_LIFO		0x00000010
+
+HOOK_PRIORITY_FIRST inserts your exit at the head of the queue of exits to be 
+dispatched for the particular hook. If another exit has already registered with
+HOOK_PRIORITY_FIRST, then your registration fails.
+
+HOOK_PRIORITY_LAST inserts your exit at the tail of the dispatching
+queue. If another exit has already registered with this priority, then your 
+registration fails.
+
+Set HOOK_QUEUE_LIFO if you want to be inserted at the head of those exits that
+can happily co-exist, but after a HOOK_PRIORITY_FIRST exit if one exists. 
+
+If you leave hook_flag to NULL you'll be inserted at the tail, but above a 
+HOOK_PRIORITY_LAST exit if it exists.
+
+You now call hook_exit_register. If you get a NO_ERROR result then your exit has
+been successfully registered. Note: registration does not cause your exit to be
+called - that only happens after arming you exit. The reason for making this
+distinction is to allow a group of exits to be simultaneously armed, once
+successfully registered.
+
+On successful registration you hook record will have hook_index indicating the
+current position of this exit in the list of all exits registered for this 
+hook, i.e., its dispatching priority (1 being first). Note that it will be 
+updated as more exits register or deregister.
+
+To get a group of exits callable from the hook you need to arm them. They
+can be armed simultaneously, but note that arming is not necessarily atomic 
+under multiple processors. Arming is done by calling hook_exit_arm and 
+passing a pointer to the first of a group of hook records linked by hook_link. 
+The last in the list must have hook_link set to NULL, so if only one exit is 
+armed at a time then hook_link will be NULL.
+
+Once this is done your exits will be called whenever the kernel executes a
+HOOK statement - unless a higher priority exit set a non-zero return value.
+
+Hook Exit Parameters and Return Values.
+--------------------------------------
+A hook exit receives a variable length parameter list defined as follows:
+
+For normal (unconditional return) hooks:
+
+parm 0: pointer to the hook record structure. This is useful if you have the
+	same exit routine registered for multiple hooks, in which case this
+	can be used to determine which hook has caused the exit routine to be
+	called. 
+parm 1 to (n+1): parameters coded on the HOOK macros.
+
+For conditional-return hooks:
+
+parm 0: pointer to the hook record structure. This is useful if you have the
+	same exit routine registered for multiple hooks, in which case this
+	can be used to determine which hook has caused the exit routine to be
+	called. 
+parm 1: pointer to the return code (int *) to be set if a forced return of the
+	hooked routine is requested by the exit routine. 
+parm 2 to (n+2): parameters coded on the HOOK macros.
+
+If the exit function's prototype does not match the expected prototype, then
+the kernel could oops.
+
+A hook exit may itself return with the following return values:
+
+HOOK_CONTINUE - allows dispatching of other exits.
+HOOK_TERMINATE - stops further exit dispatching and returns to the hooked code.
+HOOK_RETURN - stops further exit dispatching and for conditional return hooks
+forces the hooked routine to return using parm2 as a return value.
+
+It is possible to write a hook exit function that takes variable number of
+arguments, see kexit.c for an example.
+
+Deregistering and disarming exits
+---------------------------------
+
+Exits may be disarmed and re-armed as often as like. Disarming may be done two
+ways:
+
+1) by calling hook_exit_disarm and passing a pointer to a hook record, which 
+may be linked optionally to a list of hook records, via hook_link, to be 
+disarmed simultaneously.
+
+2) by turning off HOOK_ARMED in hook_flags (&=~HOOK_ARMED) from the hook exit.
+
+Exits may be de-registered by calling hook_exit_deregister and passing a 
+pointer to a hook record, which may be linked optionally to a list of hook
+records, via hook_link, to be de-registered. De-registration will force 
+disarming.
+
+WARNING!!! A kernel module must deregister its exits from its module_cleanup
+routine if that have not already been deregistered. 
+
+/proc interface
+---------------
+When Generalized Kernel Hooks is initialized, a /proc/hooks directory is 
+created. Whenever a new hook is initialized, a /proc/hooks/<hook_id> 
+subdirectory is created. Whenever a new hook exit is registered, a 
+/proc/hooks/<hook_id>/<hook_exit_name> file is created. This file is writable 
+if hook_exit_register is called with the proc_writable set to 1, otherwise, 
+it is read-only. The file name is taken from hook_exit_name if set in the 
+hook_rec_t structure. If not set, the file name is the exit's memory location. 
+This file contains a boolean value of '1' or '0' to indicate whether the exit 
+is armed or not. It may be written to independently of GKHI to arm or disarm 
+a hook exit, provided that proc_writable flag is set on registration.
+
+Reporting Problems and Discussing GKHI
+--------------------------------------
+email: dprobes@oss.software.ibm.com
+vist: http://oss.software.ibm.com/developerworks/linux
+
+For further information read the USENIX 2000 Anual Linux Showcase paper, and
+the UKUUG Linux2001 Generalised Kernel Hooks paper which may be found at
+http://oss.software.ibm.com/developerworks/linux
+
+License
+-------
+Copyright (C) 2001 IBM Corporation
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA.
+
+Change History
+--------------
+0.6	8th November 2000	First public drop
+1.0	14th February 2001	SMP Enablement. Slim-line hooks implemented
+				Thanks to Andrea Arcangeli for suggestions for
+				improvement.
+1.1	12th April 2001		Hooks initialised dynamically.
+				Named hooks supported.
+				Conditonal return hooks supported.
+				Support for hooks in kernel modules added.
+1.2 	3rd July 2001		Bug fixes.
+				Rewrite to confirm to kernel coding style.
+				Make it part of the kernel build process.
+				Seperate out arch-dependent and indepedent
+				parts. Arch-independent hooks and convenient
+				provision to allow arch-specific optimized
+				implementation of hooks. Updated documentation
+				and simplify the sample modules.
+1.3	20th Sept. 2001		/proc interface
+				exclusive hooks
+1.4	4th Oct. 2001		HOOK macros now take variable number of args
+				Bug fix in is_asm_hook()
diff -Naru linux-2.4.19/Documentation/hook/kexit.c linux-2.4.19-hooks/Documentation/hook/kexit.c
--- linux-2.4.19/Documentation/hook/kexit.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/Documentation/hook/kexit.c	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,265 @@
+/*****************************************************************************/
+/* Kernel Hooks Interface.                                    		     */
+/* Version 1.4                                                               */
+/* Author: Richard J Moore richardj_moore@uk.ibm.com                         */
+/* 	   Vamsi Krishna S. r1vamsi@in.ibm.com 				     */
+/*                                                                           */
+/* A sample kernel module registering exits for hooks defined in khook.o.    */
+/*                                                                           */
+/* Refer to Documentation/hook/HOWTO for details.                            */
+/*****************************************************************************/
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/hook.h>
+
+#define TEST_HOOK1 test_hook1
+#define TEST_HOOK2 test_hook2
+#define TEST_HOOK3 test_hook3
+#define TEST_HOOK4 test_hook4
+#define TEST_HOOK5 test_hook5
+int exit1(hook_rec_t *, int *);	/* first exit for test_hook1 */
+int exit2(hook_rec_t *);		/* first exit for test_hook2 */
+int exit3(hook_rec_t *, int *);	/* second exit for test_hook1 */
+int exit4(hook_rec_t *);		/* second exit for test_hook2 */
+int exit_var0(hook_rec_t *);
+int exit_var1(hook_rec_t *, int);
+int exit_var2(hook_rec_t *, int, int);
+int exit_var2_mismatch(hook_rec_t *, int);
+
+int ex_exit_var0(hook_rec_t *);
+int ex_exit_var1(hook_rec_t *, int);
+int ex_exit_var2(hook_rec_t *, int, int);
+int exit_var_args(hook_rec_t * hookrec, ...);
+extern int testhook(void);
+
+hook_rec_t hook1;
+hook_rec_t hook2;
+hook_rec_t hook3;
+hook_rec_t hook4;
+hook_rec_t var0;
+hook_rec_t var1;
+hook_rec_t var2;
+hook_rec_t ex_var0;
+hook_rec_t ex_var1;
+hook_rec_t ex_var2;
+
+int init_module(void)
+{
+	int rc;
+
+	hook1.hook_exit = &exit1;
+	hook1.hook_exit_name = "exit1";
+	rc = hook_exit_register(TEST_HOOK1, &hook1);
+	DPRINTK("hook_exit_register exit1 for hook1 returned %u\n", rc);
+	if(rc) goto err;
+
+	hook2.hook_exit = &exit2;
+	hook2.hook_exit_name = "exit2";
+	rc = hook_exit_register(TEST_HOOK2, &hook2);
+	DPRINTK("hook_exit_register exit2 for hook2 returned %u\n", rc);
+	if(rc) goto err1;
+
+	hook3.hook_exit = &exit3;
+	hook3.hook_exit_name = "exit3";
+	rc = hook_exit_register(TEST_HOOK1, &hook3);
+	DPRINTK("hook_exit_register exit3 for hook1 returned %u\n", rc);
+	if(rc) goto err2;
+
+	hook4.hook_exit = &exit4;
+	hook4.hook_exit_name = "exit4";
+	rc = hook_exit_register(TEST_HOOK2, &hook4);
+	DPRINTK("hook_exit_register exit4 for hook2 returned %u\n", rc);
+	if(rc) goto err3;
+
+
+	var0.hook_exit = &exit_var0;
+	rc = hook_exit_register(TEST_HOOK3, &var0);
+	if(rc) goto err4;
+
+	var1.hook_exit = &exit_var1;
+	rc = hook_exit_register(TEST_HOOK4, &var1);
+	if(rc) goto err5;
+
+	var2.hook_exit = &exit_var2_mismatch;
+	rc = hook_exit_register(TEST_HOOK5, &var2);
+	if(rc) goto err6;
+
+	ex_var0.hook_exit = &ex_exit_var0;
+	rc = hook_exit_register(EX_TEST_HOOK3, &ex_var0);
+	if(rc) goto err7;
+
+	ex_var1.hook_exit = &ex_exit_var1;
+	rc = hook_exit_register(EX_TEST_HOOK4, &ex_var1);
+	if(rc) goto err8;
+
+//	ex_var2.hook_exit = &ex_exit_var2;
+	ex_var2.hook_exit = exit_var_args;
+	rc = hook_exit_register(EX_TEST_HOOK5, &ex_var2);
+	if(rc) goto err9;
+
+	/* now arm all exits in a single operation */
+	hook1.hook_link = &hook2;
+	hook2.hook_link = &hook3;
+	hook3.hook_link = &hook4;
+	hook4.hook_link = &var0;
+	var0.hook_link = &var1;
+	var1.hook_link = &var2;
+	var2.hook_link = &ex_var0;
+	ex_var0.hook_link = &ex_var1;
+	ex_var1.hook_link = &ex_var2;
+	ex_var2.hook_link = NULL;
+
+	printk("hook exits are registered, but not yet armed.\n");
+
+	testhook();
+
+	rc = hook_exit_arm(&hook1);
+	DPRINTK("hook_exit_arm returned %u\n", rc);
+	if(rc) goto err10;
+
+	printk("hook exit are now armed.\n");
+
+	testhook();
+
+	printk("disarming exit1 only\n");
+	hook1.hook_link = NULL;
+	rc = hook_exit_disarm(&hook1);
+	DPRINTK("hook_exit_disarm returned %u\n", rc);
+	if(rc) goto error;
+
+	testhook();
+
+	DPRINTK("disarming exit2 only\n");
+	hook2.hook_link = NULL;
+	rc = hook_exit_disarm(&hook2);
+	DPRINTK("hook_exit_disarm returned %u\n", rc);
+	if(rc) goto error;
+
+	testhook();
+	return 0;
+	
+error:
+err10:	hook_exit_deregister(&ex_var2);
+err9:	hook_exit_deregister(&ex_var1);
+err8:	hook_exit_deregister(&ex_var0);
+err7:	hook_exit_deregister(&var2);
+err6:	hook_exit_deregister(&var1);
+err5:	hook_exit_deregister(&var0);
+err4:	hook_exit_deregister(&hook4);
+err3:	hook_exit_deregister(&hook3);
+err2:	hook_exit_deregister(&hook2);
+err1:	hook_exit_deregister(&hook1);
+err: 	return rc;
+}
+
+void cleanup_module(void)
+{
+	/* link all hook_rec structs and deregister */
+	hook1.hook_link = &hook2;
+	hook2.hook_link = &hook3;
+
+	hook_exit_deregister(&hook1);
+
+	printk("deregistered all hook exits.\n");
+
+	testhook();
+
+	return;
+}
+
+/* exit1 exit to test_hook1 */
+int exit1(hook_rec_t * hookrec, int *rc)
+{
+	printk("exit1: hook exit1 entered, indicate for testhook to return immediately\n");
+	*rc = 0;
+	printk("exit1: hook exit1 exiting\n");
+	return HOOK_RETURN;
+}
+
+/* exit2 exit to test_hook2 */
+int exit2(hook_rec_t * hookrec)
+{
+	printk("exit2: hook exit2 entered\n");
+	printk("exit2: hook exit2 exiting\n");
+	return HOOK_CONTINUE;
+}
+
+/* exit3 exit to test_hook1 */
+int exit3(hook_rec_t * hookrec, int *rc)
+{
+	printk("exit3: hook exit3 entered, allow testhook to continue\n");
+	*rc = 0;
+	printk("exit3: hook exit3 exiting\n");
+	return HOOK_CONTINUE;
+}
+
+/* exit4 exit to test_hook2 */
+int exit4(hook_rec_t * hookrec)
+{
+	printk("exit4: hook exit4 entered\n");
+	printk("exit4: hook exit4 exiting\n");
+	return HOOK_CONTINUE;
+}
+
+int exit_var0(hook_rec_t *hr)
+{
+	printk("exit_var0: entered\n");
+	printk("exit_var0: exiting\n");
+	return HOOK_CONTINUE;
+}
+int exit_var1(hook_rec_t *hr, int i)
+{
+	printk("exit_var1: entered, %x\n", i);
+	printk("exit_var1: exiting\n");
+	return HOOK_CONTINUE;
+}
+int exit_var2(hook_rec_t *hr, int i, int j)
+{
+	printk("exit_var2: entered %x, %x\n", i, j);
+	printk("exit_var2: exiting\n");
+	return HOOK_CONTINUE;
+}
+
+int exit_var2_mismatch(hook_rec_t *hr, int i)
+{
+	printk("exit_var2: entered using only the first arg: %x\n", i);
+	printk("exit_var2: exiting\n");
+	return HOOK_CONTINUE;
+}
+
+int ex_exit_var0(hook_rec_t *hr)
+{
+	printk("ex_exit_var0: entered %s\n", hr->hook_head->hook_id);
+	printk("ex_exit_var0: exiting\n");
+	return HOOK_CONTINUE;
+}
+int ex_exit_var1(hook_rec_t *hr, int i)
+{
+	printk("ex_exit_var1: entered, %x\n", i);
+	printk("ex_exit_var1: exiting\n");
+	return HOOK_CONTINUE;
+}
+int ex_exit_var2(hook_rec_t *hr, int i, int j)
+{
+	printk("ex_exit_var2: entered %x, %x\n", i, j);
+	printk("ex_exit_var2: exiting\n");
+	return HOOK_CONTINUE;
+}
+
+int exit_var_args(hook_rec_t * hookrec, ...)
+{
+	va_list args;
+	char buf[80];
+	char *fmt;
+	printk("exit_var_args: entered\n");
+	va_start(args, hookrec);
+	fmt = va_arg(args, char *);
+	vsprintf(buf, fmt, args);
+	printk("vsprintf output=%s\n", buf);
+	va_end(args);
+	printk("exit_var_args: exiting\n");
+	return HOOK_CONTINUE;
+}
diff -Naru linux-2.4.19/Documentation/hook/khook.c linux-2.4.19-hooks/Documentation/hook/khook.c
--- linux-2.4.19/Documentation/hook/khook.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/Documentation/hook/khook.c	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,101 @@
+/*****************************************************************************/
+/* Kernel Hooks Interface.                                    		     */
+/* Version 1.4                                                               */
+/* Author: Richard J Moore richardj_moore@uk.ibm.com                         */
+/* 	   Vamsi Krishna S. r1vamsi@in.ibm.com 				     */
+/*                                                                           */
+/* A sample kernel module with hooks in it (in the testhook function).   */
+/*                                                                           */
+/* Refer to Documentation/hook/HOWTO for details.                            */
+/*****************************************************************************/
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/hook.h>
+
+#define TEST_HOOK1 test_hook1
+#define TEST_HOOK2 test_hook2
+#define TEST_HOOK3 test_hook3
+#define TEST_HOOK4 test_hook4
+#define TEST_HOOK5 test_hook5
+DECLARE_HOOK_HEAD(TEST_HOOK1);
+DECLARE_HOOK_HEAD(TEST_HOOK2);
+DECLARE_HOOK_HEAD(TEST_HOOK3);
+DECLARE_HOOK_HEAD(TEST_HOOK4);
+DECLARE_HOOK_HEAD(TEST_HOOK5);
+DECLARE_EXCLUSIVE_HOOK_HEAD(EX_TEST_HOOK3);
+DECLARE_EXCLUSIVE_HOOK_HEAD(EX_TEST_HOOK4);
+DECLARE_EXCLUSIVE_HOOK_HEAD(EX_TEST_HOOK5);
+
+int init_module(void)
+{
+	int rc;
+
+	rc = hook_initialise(TEST_HOOK1);
+	DPRINTK("hook_initialise returned %u\n", rc);
+	if(rc) 
+		return 1;
+
+	rc = hook_initialise(TEST_HOOK2);
+	DPRINTK("hook_initialise returned %u\n", rc);
+	if(rc) {
+		hook_terminate(TEST_HOOK1, 0);
+		return 1;
+	}
+	hook_initialise(TEST_HOOK3);
+	hook_initialise(TEST_HOOK4);
+	hook_initialise(TEST_HOOK5);
+	hook_initialise(EX_TEST_HOOK3);
+	hook_initialise(EX_TEST_HOOK4);
+	hook_initialise(EX_TEST_HOOK5);
+
+	DPRINTK("now load kexit.o to test the hook(s)\n");
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int rc;
+
+	rc = hook_terminate(TEST_HOOK1, 0);
+	DPRINTK("hook_terminate returned %u\n", rc);
+
+	rc = hook_terminate(TEST_HOOK2, 0);
+	DPRINTK("hook_terminate returned %u\n", rc);
+
+	hook_terminate(TEST_HOOK3, 0);
+	hook_terminate(TEST_HOOK4, 0);
+	hook_terminate(TEST_HOOK5, 0);
+	hook_terminate(EX_TEST_HOOK3, 0);
+	hook_terminate(EX_TEST_HOOK4, 0);
+	hook_terminate(EX_TEST_HOOK5, 0);
+
+	return;
+}
+
+/*
+ * this is an example of how the hooks would be coded in the kernel or a
+ * kernel module.
+ */
+int testhook(void)
+{
+	printk("testhook entered\n");
+	
+	HOOK_RET(TEST_HOOK1);
+	HOOK(TEST_HOOK2);
+
+	HOOK(TEST_HOOK3);
+	HOOK(TEST_HOOK4, 4);
+	HOOK(TEST_HOOK5, 5, 0);
+
+	EXCLUSIVE_HOOK(EX_TEST_HOOK3);
+	EXCLUSIVE_HOOK(EX_TEST_HOOK4, 4);
+	EXCLUSIVE_HOOK(EX_TEST_HOOK5, "%s, %d", "test_hook3", 1);
+
+	printk("testhook exited\n");
+	return 0;
+}
+
+EXPORT_SYMBOL_NOVERS(testhook);
diff -Naru linux-2.4.19/include/asm-i386/hook.h linux-2.4.19-hooks/include/asm-i386/hook.h
--- linux-2.4.19/include/asm-i386/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-i386/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,87 @@
+#ifndef __ASM_I386_HOOK_H
+#define __ASM_I386_HOOK_H
+/*
+ * Kernel Hooks optimized for ia32.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ */
+#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":movl $0, %0":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+/*
+ * Sanity check the hook location for valid instructions at hook location.
+ * At hook location, we should find these instructions:
+ *	b9 00 00 00 00       	mov    $0x0,%ecx
+ *	85 c9                	test   %ecx,%ecx
+ * We can check for mov and test instructions. As these instructions encode
+ * the register name in them and the register cannot be predicted, we mask out
+ * the bits corresponding to registers in the opcode before comparing.
+ * 
+ * mov imm to reg
+ * 	1011 wreg
+ *	1100 011w : 1100 0reg (or)
+ * test reg1 reg2
+ * 	1000 010w : 11xx xyyy (xxx = reg1, yyy = reg2)
+ * 	
+ * v1.4: 10/04/2001
+ * Unfortunately, we can't be certain that the test instruction follows right
+ * after the mov, as the compiler could move some other code in between these
+ * two instructions. So, is_asm_hook checks only for "mov $0, reg" at the given
+ * hook location.
+ */
+#define OPCODE_MOV1			0xb0
+#define OPCODE_MOV1_MASK		0xf0
+#define OPCODE_MOV2_1			0xc6 /* first byte */
+#define OPCODE_MOV2_2			0xc0 /* second byte */
+#define OPCODE_MOV2_1_MASK		0xfe
+#define OPCODE_MOV2_2_MASK		0xf8
+#define OPCODE_TEST_1			0x84 /* first byte */
+#define OPCODE_TEST_2			0xc0 /* second byte */
+#define OPCODE_TEST_1_MASK		0xfe	
+#define OPCODE_TEST_2_MASK		0xc0	
+		
+static inline int is_asm_hook(unsigned char *addr)
+{
+	if (!addr)
+		return 0;
+	if((addr[0] & OPCODE_MOV1_MASK) == OPCODE_MOV1) {
+		if (*((unsigned long *)(addr+1)) == 0)
+			return 1;
+	} else if (((addr[0] & OPCODE_MOV2_1_MASK) == OPCODE_MOV2_1) && 
+		    ((addr[1] & OPCODE_MOV2_2_MASK) == OPCODE_MOV2_2)) {
+		if (*((unsigned long *)(addr+2)) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+static inline void deactivate_asm_hook(hook_t *hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 0;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+/*
+ * we activate a hook by changing the bypass jump offset to 0 - this atomic
+ * under MP
+ */
+static inline void activate_asm_hook(hook_t *hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 1;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+#endif /* __ASM_I386_HOOK_H */
diff -Naru linux-2.4.19/include/asm-ia64/hook.h linux-2.4.19-hooks/include/asm-ia64/hook.h
--- linux-2.4.19/include/asm-ia64/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-ia64/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,102 @@
+/* $Id: kernelhooks-1.7-2419-2.patch,v 1.1 2003/03/31 05:50:32 hiramatu Exp $ */
+/* linux/include/asm-ia64/hook.h */
+
+/************************************************************
+ *
+ * COPYRIGHT (C) HITACHI,LTD. 2002 ALL RIGHTS RESERVED.
+ * WRITTEN BY HITACHI SYSTEMS DEVELOPMENT LABORATORY,
+ *            HITACHI CENTRAL RESEARCH LABORATORY.
+ *
+ * Created by Y.Matsuo <yo-matsu@kam.hitachi-sk.co.jp>
+ *
+ ************************************************************/
+
+#ifndef __ASM_IA64_HOOK_H
+#define __ASM_IA64_HOOK_H
+
+//#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":addl %0=0,r0":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+#define OPCODE_MAJOR_OP			0x24
+#define OPCODE_MAJOR_OP_MASK		0x3c
+#define OPCODE_TEMPLATE_0		0x00
+#define OPCODE_TEMPLATE_1		0x01
+#define OPCODE_TEMPLATE_2		0x02
+#define OPCODE_TEMPLATE_a		0x0a
+#define OPCODE_TEMPLATE_b		0x0b
+#define OPCODE_TEMPLATE_MASK		0x1f
+#define OPCODE_IMM			0x00
+#define OPCODE_IMM_MASK1		0xfc
+#define OPCODE_IMM_MASK2		0x01
+#define OPCODE_IMM_MASK3		0x7f
+
+#define AVAILABLE_TEMPLATE(template)			\
+		( (template == OPCODE_TEMPLATE_0) ||	\
+		  (template == OPCODE_TEMPLATE_1) ||	\
+		  (template == OPCODE_TEMPLATE_2) ||	\
+		  (template == OPCODE_TEMPLATE_a) ||	\
+		  (template == OPCODE_TEMPLATE_b) )
+		
+static inline int is_asm_hook(unsigned char * addr)
+{
+	unsigned char template;
+	unsigned char major_op;
+	unsigned char imm1, imm2, imm3;
+
+	if(addr == NULL) {
+		return 0;
+	}
+
+	template = addr[0] & OPCODE_TEMPLATE_MASK;
+	major_op = addr[5] & OPCODE_MAJOR_OP_MASK;
+	imm1     = addr[2] & OPCODE_IMM_MASK1;
+	imm2     = addr[3] & OPCODE_IMM_MASK2;
+	imm3     = addr[4] & OPCODE_IMM_MASK3;
+
+	if(AVAILABLE_TEMPLATE(template)) {
+		if(major_op == OPCODE_MAJOR_OP) {
+			if((imm1 == OPCODE_IMM) && (imm2 == OPCODE_IMM) &&
+						   (imm3 == OPCODE_IMM)) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static inline void deactivate_asm_hook(hook_t * hook)
+{
+//	extern void flush_icache_range (unsigned long, unsigned long);
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+
+	addr[4] = 0;
+//	flush_icache_range((unsigned long)phook + 4, (unsigned long)phook + 4);
+
+	return;
+}
+
+/*
+ *  we activate a hook by changing the bypass jump offset to 0 - this atomic
+ *  under MP
+ */
+static inline void activate_asm_hook(hook_t * hook)
+{
+//	extern void flush_icache_range (unsigned long, unsigned long);
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+
+	addr[4] = 2;
+//	flush_icache_range((unsigned long)phook + 4, (unsigned long)phook + 4);
+
+	return;
+}
+
+#endif /* __ASM_IA64_HOOK_H */
diff -Naru linux-2.4.19/include/asm-ppc/hook.h linux-2.4.19-hooks/include/asm-ppc/hook.h
--- linux-2.4.19/include/asm-ppc/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-ppc/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,78 @@
+#ifndef __ASM_PPC_HOOK_H
+#define __ASM_PPC_HOOK_H
+/*
+ * Kernel Hooks optimized for PPC.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ *	    Mike Grundy <grundym@us.ibm.com> PPC
+ */
+#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":li %0, 0x00":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+
+/*
+ * Sanity check the hook location for valid instructions at hook location.
+ * At hook location, we should find these instructions:
+ *	38 00 00 00       	li    	r0,0
+ *	2c 00 00 00            	cmpwi	r0,0
+ *	
+ * We can check for li and cmpwi instructions. As these instructions encode
+ * the register name in the second byte and the register cannot be predicted, 
+ * we mask out the bits corresponding to registers in the opcode before comparing.
+ * PPC opcodes are six bits, hence mask of 0xFC
+ * 	
+ * v1.4: 10/04/2001
+ * Unfortunately, we can't be certain that the test instruction follows right
+ * after the mov, as the compiler could move some other code in between these
+ * two instructions. So, is_asm_hook checks only for "mov 0x00, reg" at the given
+ * hook location.
+ */
+#define OPCODE_MOV1			0x38 /* LI (really an extended mnemonic for addi */   
+#define OPCODE_MOV1_MASK		0xFC
+/* Compiler generates 2c 00 00 00     cmpwi   r0,0 */
+#define OPCODE_TEST_1			0x2c /* first byte */
+#define OPCODE_TEST_1_MASK		0xfc	
+		
+static inline int is_asm_hook(unsigned char * addr)
+{
+	if (!addr)
+		return 0;
+	
+	if((addr[0] & OPCODE_MOV1_MASK) == OPCODE_MOV1) {
+		if (*((unsigned short *)(addr+1)) == 0)
+			return 1;
+	}
+	return 0;
+}
+static inline void deactivate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	
+	addr[2] = 0;
+	flush_icache_range((unsigned long)addr + 2, (unsigned long)addr + 2);
+	return;
+}
+
+/*
+ *  we activate a hook by changing the immediate data to 1 - this is atomic
+ *  under MP
+ */
+static inline void activate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	
+	addr[2] = 1;
+	flush_icache_range((unsigned long)addr + 2, (unsigned long)addr + 2);
+	return;
+}
+
+#endif /* __ASM_PPC_HOOK_H */
diff -Naru linux-2.4.19/include/asm-ppc64/hook.h linux-2.4.19-hooks/include/asm-ppc64/hook.h
--- linux-2.4.19/include/asm-ppc64/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-ppc64/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,78 @@
+#ifndef __ASM_PPC_HOOK_H
+#define __ASM_PPC_HOOK_H
+/*
+ * Kernel Hooks optimized for PPC64.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ *	    Mike Grundy <grundym@us.ibm.com> PPC64
+ */
+#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":li %0, 0x00":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+
+/*
+ * Sanity check the hook location for valid instructions at hook location.
+ * At hook location, we should find these instructions:
+ *	38 00 00 00       	li    	r0,0
+ *	2c 00 00 00            	cmpwi	r0,0
+ *	
+ * We can check for li and cmpwi instructions. As these instructions encode
+ * the register name in the second byte and the register cannot be predicted, 
+ * we mask out the bits corresponding to registers in the opcode before comparing.
+ * PPC opcodes are six bits, hence mask of 0xFC
+ * 	
+ * v1.4: 10/04/2001
+ * Unfortunately, we can't be certain that the test instruction follows right
+ * after the mov, as the compiler could move some other code in between these
+ * two instructions. So, is_asm_hook checks only for "mov 0x00, reg" at the given
+ * hook location.
+ */
+#define OPCODE_MOV1			0x38 /* LI (really an extended mnemonic for addi */   
+#define OPCODE_MOV1_MASK		0xFC
+/* Compiler generates 2c 00 00 00     cmpwi   r0,0 */
+#define OPCODE_TEST_1			0x2c /* first byte */
+#define OPCODE_TEST_1_MASK		0xfc	
+		
+static inline int is_asm_hook(unsigned char * addr)
+{
+	if (!addr)
+		return 0;
+	
+	if((addr[0] & OPCODE_MOV1_MASK) == OPCODE_MOV1) {
+		if (*((unsigned short *)(addr+1)) == 0)
+			return 1;
+	}
+	return 0;
+}
+static inline void deactivate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	
+	addr[2] = 0;
+	flush_icache_range((unsigned long)addr + 2, (unsigned long)addr + 2);
+	return;
+}
+
+/*
+ *  we activate a hook by changing the immediate data to 1 - this is atomic
+ *  under MP
+ */
+static inline void activate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	
+	addr[2] = 1;
+	flush_icache_range((unsigned long)addr + 2, (unsigned long)addr + 2);
+	return;
+}
+
+#endif /* __ASM_PPC_HOOK_H */
diff -Naru linux-2.4.19/include/asm-s390/hook.h linux-2.4.19-hooks/include/asm-s390/hook.h
--- linux-2.4.19/include/asm-s390/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-s390/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,75 @@
+#ifndef __ASM_S390_HOOK_H
+#define __ASM_S390_HOOK_H
+/*
+ * Kernel Hooks optimized for s390.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ *	    Mike Grundy <grundym@us.ibm.com> s390
+ */
+#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":lhi %0, 0x00":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+/*
+ * Sanity check the hook location for valid instructions at hook location.
+ * At hook location, we should find these instructions:
+ *  a7 18 00 00             lhi     %r1,0
+ *  12 11                   ltr     %r1,%r1
+ * We can check for the lhi and ltr instructions. As the lhi instruction encodes
+ * the register name in it, and we can't guarantee which register will be used,
+ * we'll mask out the bits corresponding to the target register.
+ */
+#define OPCODE_MOV2_1			0xa7 /* LHI first byte */
+#define OPCODE_MOV2_2			0x08 /* LHI second byte */
+#define OPCODE_MOV2_1_MASK		0xff
+#define OPCODE_MOV2_2_MASK		0x0f
+/* Compiler generates LTR opcode 12, but second op not tested */
+#define OPCODE_TEST_1			0x12 /* first byte */
+#define OPCODE_TEST_2			0x00 /* no second byte opcode, operands just get zero'd in test */
+#define OPCODE_TEST_1_MASK		0xff	
+#define OPCODE_TEST_2_MASK		0x00	
+		
+static inline int is_asm_hook(unsigned char * addr)
+{
+	if (!addr){
+		return 0;
+	}
+	if (((addr[0] & OPCODE_MOV2_1_MASK) == OPCODE_MOV2_1) && 
+		    ((addr[1] & OPCODE_MOV2_2_MASK) == OPCODE_MOV2_2)) {
+		/* was checking a 32bit val, need to check 16, cheated with 8+8 */
+		if (addr[2]== 0 && addr[3]== 0){
+			return 1;
+		}
+	}
+	return 0;
+}
+/* flush_icache_range evaluates to nothing on s/390, but I left it in for show */
+static inline void deactivate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 0;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+/*
+ *  we activate a hook by changing the bypass jump offset to 0 - this atomic
+ *  under MP
+ */
+static inline void activate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 1;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+#endif /* __ASM_S390_HOOK_H */
diff -Naru linux-2.4.19/include/asm-s390x/hook.h linux-2.4.19-hooks/include/asm-s390x/hook.h
--- linux-2.4.19/include/asm-s390x/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/asm-s390x/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,75 @@
+#ifndef __ASM_S390X_HOOK_H
+#define __ASM_S390X_HOOK_H
+/*
+ * Kernel Hooks optimized for s390x(64bit).
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ *	    Mike Grundy <grundym@us.ibm.com> s390x
+ */
+#include <asm/pgtable.h>
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+
+#define IF_HOOK_ENABLED(h, h1) \
+	register int tmp; \
+	__asm__ __volatile__ (".global "h"; "h":lhi %0, 0x00":"=r"(tmp)); \
+	if (unlikely(tmp))
+
+#endif /* CONFIG_HOOK || CONFIG_HOOK_MODULE */
+
+/*
+ * Sanity check the hook location for valid instructions at hook location.
+ * At hook location, we should find these instructions:
+ *  a7 18 00 00             lhi     %r1,0
+ *  12 11                   ltr     %r1,%r1
+ * We can check for the lhi and ltr instructions. As the lhi instruction encodes
+ * the register name in it, and we can't guarantee which register will be used,
+ * we'll mask out the bits corresponding to the target register.
+ */
+#define OPCODE_MOV2_1			0xa7 /* LHI first byte */
+#define OPCODE_MOV2_2			0x08 /* LHI second byte */
+#define OPCODE_MOV2_1_MASK		0xff
+#define OPCODE_MOV2_2_MASK		0x0f
+/* Compiler generates LTR opcode 12, but second op not tested */
+#define OPCODE_TEST_1			0x12 /* first byte */
+#define OPCODE_TEST_2			0x00 /* no second byte opcode, operands just get zero'd in test */
+#define OPCODE_TEST_1_MASK		0xff	
+#define OPCODE_TEST_2_MASK		0x00	
+		
+static inline int is_asm_hook(unsigned char * addr)
+{
+	if (!addr){
+		return 0;
+	}
+	if (((addr[0] & OPCODE_MOV2_1_MASK) == OPCODE_MOV2_1) && 
+		    ((addr[1] & OPCODE_MOV2_2_MASK) == OPCODE_MOV2_2)) {
+		/* was checking a 32bit val, need to check 16, cheated with 8+8 */
+		if (addr[2]== 0 && addr[3]== 0){
+			return 1;
+		}
+	}
+	return 0;
+}
+/* flush_icache_range evaluates to nothing on s/390, but I left it in for show */
+static inline void deactivate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 0;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+/*
+ *  we activate a hook by changing the bypass jump offset to 0 - this atomic
+ *  under MP
+ */
+static inline void activate_asm_hook(hook_head_t * hook)
+{
+	unsigned char *addr = (unsigned char *) (hook->hook_addr);
+	addr[2] = 1;
+	flush_icache_range(addr + 2, addr + 2);
+	return;
+}
+
+#endif /* __ASM_S390X_HOOK_H */
diff -Naru linux-2.4.19/include/linux/hook.h linux-2.4.19-hooks/include/linux/hook.h
--- linux-2.4.19/include/linux/hook.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/include/linux/hook.h	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,296 @@
+#ifndef __LINUX_HOOK_H
+#define __LINUX_HOOK_H
+/*
+ * Kernel Hooks Interface.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ */
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+/*
+ * Use the DECLARE_HOOK_HEAD macro to define the hookhead structure in global 
+ * memory of a kernel module that is implementing a hook.
+ */
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+#define DECLARE_HOOK_HEAD(x) _DECLARE_HOOK_HEAD(x)
+#define _DECLARE_HOOK_HEAD(hk) \
+extern void hk; \
+hook_t hk ## _head = { \
+	hook_head: &(hk##_head), \
+	hook_addr: &(hk), \
+	hook_id: #hk \
+}; \
+EXPORT_SYMBOL(hk ## _head); \
+extern hook_t hk ## _head
+
+#define DECLARE_EXCLUSIVE_HOOK_HEAD(x) _DECLARE_EXCLUSIVE_HOOK_HEAD(x)
+#define _DECLARE_EXCLUSIVE_HOOK_HEAD(hk) \
+extern void hk; \
+hook_t hk ## _head = { \
+	hook_head: &(hk##_head), \
+	hook_addr: &(hk), \
+	hook_id: #hk, \
+	hook_flags: HOOK_HEAD_EXCLUSIVE \
+}; \
+EXPORT_SYMBOL_NOVERS(hk ## _head); \
+extern hook_t hk ## _head
+
+#define USE_HOOK(x) _USE_HOOK(x)
+#define _USE_HOOK(hk) extern hook_t hk ## _head
+#else
+#define DECLARE_HOOK_HEAD(x)
+#define USE_HOOK(x)
+#endif
+
+/* define the user (kernel module) hook structure */
+struct hook_rec_s;
+struct hook_head_s;
+
+typedef struct hook_rec_s {
+	void * hook_exit;
+	char * hook_exit_name;
+	struct hook_rec_s * hook_next;
+	struct hook_rec_s * hook_prev;
+	unsigned int hook_flags;
+	struct hook_rec_s * hook_link;
+	struct hook_head_s * hook_head;
+	unsigned int hook_index;
+	struct proc_dir_entry *proc_entry;
+	int proc_writable;
+} hook_rec_t;
+
+typedef struct hook_head_s {
+	void * hook_exit;
+	char * hook_exit_name;
+	struct hook_rec_s * hook_next;
+	struct hook_rec_s * hook_prev;
+	unsigned int hook_flags;
+	struct hook_rec_s * hook_link;
+	struct hook_head_s * hook_head;
+	unsigned int hook_index;
+	struct proc_dir_entry *proc_entry;
+	struct hook_head_s * hook_head_next;
+	void * hook_addr;
+	char * hook_id;
+} hook_t;
+
+/* hook flags */
+#define HOOK_ARMED		0x00000001
+#define HOOK_REGISTERED		0x00000002
+#define HOOK_PRIORITY_FIRST	0x00000004
+#define HOOK_PRIORITY_LAST	0x00000008
+#define HOOK_PRIORITY_EXCLUSIVE	0x0000000c
+#define HOOK_QUEUE_LIFO		0x00000010
+
+/* the following are reserved for future enhancement */
+#define HOOK_OPTION_DISABLE_IRQS	0x00001000
+#define HOOK_OPTION_STOP_CPUS		0x00002000
+
+
+/* flag groupings */
+#define HOOK_STATUS		(HOOK_ARMED | HOOK_REGISTERED)
+#define HOOK_PRIORITY		(HOOK_PRIORITY_FIRST | HOOK_PRIORITY_LAST)
+#define HOOK_QUEUE		HOOK_QUEUE_LIFO
+#define HOOK_OPTIONS		(HOOK_OPTION_DISABLE_IRQS | HOOK_OPTION_STOP_CPUS)
+#define HOOK_VALID_USER_FLAGS	(HOOK_PRIORITY | HOOK_QUEUE | HOOK_OPTIONS)
+
+/* exported functions wrapped in a macro */
+int _hook_initialise(hook_t *);
+int _hook_terminate(hook_t *, int);
+int _hook_exit_register(char *, hook_rec_t *);
+
+/* exported functions error codes */
+#define NO_ERROR 				 0
+#define ERROR_HOOK_NOT_FOUND 			-1
+#define ERROR_HIGHER_PRIORITY_HOOK 		-2
+#define ERROR_INVALID_REGISTRATION_RECORD 	-3
+#define ERROR_LOWER_PRIORITY_HOOK 		-4
+#define ERROR_GKHI_UNAVAILABLE 			-5
+#define ERROR_INVALID_HOOK_LOCATION 		-6
+#define ERROR_HOOK_EXISTS 			-7
+#define ERROR_HOOK_IS_ACTIVE 			-8
+
+/* Return values from Hook Exit routines */
+#define HOOK_CONTINUE 	0
+#define HOOK_TERMINATE 	1
+#define HOOK_RETURN 	-1
+
+/* exported function prototypes */
+int hook_exit_deregister(hook_rec_t *);
+int hook_exit_arm(hook_rec_t *);
+int hook_exit_disarm(hook_rec_t *);
+
+/*
+ * public interfaces requiring a macro wrapper
+ *
+ * int hook_exit_register(hookid, hook_rec_t *);
+ * int hook_terminate(hookid, int force_flag);/
+ * int hook_initialise(hookid);
+ *
+ * where hookid is a typeless name
+ */
+#define hook_exit_register(x, y) dummy_hook_exit_register(x, y)
+#define dummy_hook_exit_register(x, y) _hook_exit_register(#x, y)
+#define hook_terminate(x, y) dummy_hook_terminate(x, y)
+#define dummy_hook_terminate(x, y) _hook_terminate(&(x ## _head), y)
+#define hook_initialise(x) dummy_hook_initialise(x)
+#define dummy_hook_initialise(x) _hook_initialise(&(x ## _head))
+
+/* define head record only flags */
+#define HOOK_HEAD_ACTIVE	0x80000000
+#define HOOK_HEAD_ASM_HOOK	0x40000000
+#define HOOK_HEAD_EXCLUSIVE	0x20000000
+#define HOOK_HEAD_VALID_FLAGS	(HOOK_VALID_USER_FLAGS | HOOK_STATUS | HOOK_HEAD_ACTIVE | HOOK_HEAD_ASM_HOOK | HOOK_HEAD_EXCLUSIVE)
+
+/* global status flags */
+#define HOOK_INIT	1
+
+#ifdef HOOK_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: "fmt, __FUNCTION__ , ##args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+typedef int (*hook_fn_t)(hook_rec_t *, ...);
+#ifdef CONFIG_ASM_HOOK
+#include <asm/hook.h>
+#else
+static inline int is_asm_hook(unsigned char *phookloc) {return 0;}
+static inline void activate_asm_hook(hook_t * phookhead) { }
+static inline void deactivate_asm_hook(hook_t * phookhead) { }
+#endif
+
+#ifndef IF_HOOK_ENABLED
+#define IF_HOOK_ENABLED(h, h1) \
+	__asm__ __volatile__ (".global "h"; "h":"); \
+	if (unlikely(h1##_head.hook_flags & HOOK_HEAD_ACTIVE))
+#endif
+
+#if defined(CONFIG_HOOK) || defined(CONFIG_HOOK_MODULE)
+#define HOOK(h, args...) _HOOK(h , ##args)
+#define _HOOK(h, args...) __HOOK(#h, h , ##args)
+#define __HOOK(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		register hook_rec_t *ptr; \
+		extern hook_t h1##_head; \
+		for (ptr = h1##_head.hook_next; \
+			!((ptr->hook_flags & HOOK_ARMED) && \
+			  ((*(hook_fn_t)(ptr->hook_exit))(ptr , ##args))); \
+			ptr = ptr->hook_next); \
+	} \
+}
+
+#define HOOK_RET(h, args...) _HOOK_RET(h , ##args)
+#define _HOOK_RET(h, args...) __HOOK_RET(#h, h , ##args)
+#define __HOOK_RET(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		typedef int (*f)(hook_rec_t *, int *, ...); \
+		register hook_rec_t *ptr; \
+		int rc; \
+		register int dsprc; \
+		extern hook_t h1##_head; \
+		for (ptr = h1##_head.hook_next; \
+			!((ptr->hook_flags & HOOK_ARMED) && \
+			  (dsprc=(*(hook_fn_t)(ptr->hook_exit))(ptr, &rc , ##args))); \
+			ptr=ptr->hook_next); \
+		if (dsprc == HOOK_RETURN) return rc; \
+	} \
+}
+
+#define HOOK_RET_NORC(h, args...) _HOOK_RET_NORC(h , ##args)
+#define _HOOK_RET_NORC(h, args...) __HOOK_RET_NORC(#h, h , ##args)
+#define __HOOK_RET_NORC(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		typedef int (*f)(hook_rec_t *, ...); \
+		register hook_rec_t *ptr; \
+		register int dsprc; \
+		extern hook_t h1##_head; \
+		for (ptr = h1##_head.hook_next; \
+			!((ptr->hook_flags & HOOK_ARMED) && \
+			  (dsprc=(*(hook_fn_t)(ptr->hook_exit))(ptr , ##args))); \
+			ptr = ptr->hook_next); \
+	 	if (dsprc == HOOK_RETURN) return; \
+	} \
+}
+
+#define EXCLUSIVE_HOOK(h, args...) _EXCLUSIVE_HOOK(h , ##args)
+#define _EXCLUSIVE_HOOK(h, args...) __EXCLUSIVE_HOOK(#h, h , ##args)
+#define __EXCLUSIVE_HOOK(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		typedef int (*f)(hook_rec_t *, ...); \
+		extern hook_t h1##_head; \
+		(*(hook_fn_t)(h1##_head.hook_exit))(h1##_head.hook_next , ##args); \
+	} \
+}
+
+#define EXCLUSIVE_HOOK_RET(h, args...) _EXCLUSIVE_HOOK_RET(h , ##args)
+#define _EXCLUSIVE_HOOK_RET(h, args...) __EXCLUSIVE_HOOK_RET(#h, h , ##args)
+#define __EXCLUSIVE_HOOK_RET(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		typedef int (*f)(int *); \
+		int rc; \
+		register int dsprc; \
+		extern hook_t h1##_head; \
+		dsprc = (*(hook_fn_t)(h1##_head.hook_exit))(h1##_head.hook_next, &rc , ##args); \
+		if (dsprc == HOOK_RETURN) return rc; \
+	} \
+}
+
+#define EXCLUSIVE_HOOK_RET_NORC(h, args...) _EXCLUSIVE_HOOK_RET_NORC(h , ##args)
+#define _EXCLUSIVE_HOOK_RET_NORC(h, args...) __EXCLUSIVE_HOOK_RET_NORC(#h, h , ##args)
+#define __EXCLUSIVE_HOOK_RET_NORC(h, h1, args...) \
+{ \
+	IF_HOOK_ENABLED(h, h1) { \
+		typedef int (*f)(void *); \
+		extern hook_t h1##_head; \
+		register int dsprc = (*(hook_fn_t)(h1##_head.hook_exit))(h1##_head.hook_next , ##args); \
+		if (dsprc == HOOK_RETURN) return; \
+	} \
+}
+
+/*
+ *  Generic hooks are the same in all architectures and may be used to
+ *  place hooks even in inline functions. They don't define a symbol at hook
+ *  location.
+ */ 
+#define DECLARE_GENERIC_HOOK_HEAD(x) _DECLARE_GENERIC_HOOK_HEAD(x)
+#define _DECLARE_GENERIC_HOOK_HEAD(hk) \
+hook_t hk ## _head = { \
+	hook_head: &(hk##_head), \
+	hook_addr: NULL, \
+	hook_id: #hk \
+}; \
+EXPORT_SYMBOL(hk ## _head); \
+extern hook_t hk ## _head
+
+#define GENERIC_HOOK(h, args...) _GENERIC_HOOK(h , ##args)
+#define _GENERIC_HOOK(h, args...) __GENERIC_HOOK(#h, h , ##args)
+#define __GENERIC_HOOK(h, h1, args...) { \
+	extern hook_t h1##_head; \
+	if (unlikely(h1##_head.hook_flags & HOOK_HEAD_ACTIVE)) { \
+		register hook_rec_t *ptr; \
+		for (ptr = h1##_head.hook_next; \
+			!((ptr->hook_flags & HOOK_ARMED) && \
+			  ((*(hook_fn_t)(ptr->hook_exit))(ptr , ##args))); \
+			ptr = ptr->hook_next); \
+	} \
+}
+#else
+/* dummy macros when hooks are not compiled in */
+#define HOOK(h, args...)
+#define HOOK_RET(h, args...)
+#define HOOK_RET_NORC(h, args...)
+#define EXCLUSIVE_HOOK(h, args...)
+#define EXCLUSIVE_HOOK_RET(h, args...)
+#define EXCLUSIVE_HOOK_RET_NORC(h, args...)
+#endif
+
+#endif /* __LINUX_HOOK_H */
diff -Naru linux-2.4.19/kernel/hook.c linux-2.4.19-hooks/kernel/hook.c
--- linux-2.4.19/kernel/hook.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.19-hooks/kernel/hook.c	2003-03-31 11:01:51.000000000 +0900
@@ -0,0 +1,567 @@
+/*
+ * Kernel Hooks Interface.
+ * 
+ * Authors: Richard J Moore <richardj_moore@uk.ibm.com>
+ *	    Vamsi Krishna S. <vamsi_krishna@in.ibm.com>
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/hook.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+static spinlock_t hook_lock = SPIN_LOCK_UNLOCKED;
+
+static int hook_global_status = 0;
+static hook_t *hook_list_head;
+
+#define for_each_hook(hook) \
+	for(hook = hook_list_head; hook; hook = (hook->hook_head_next))
+	
+#define for_each_hook_rec(hook, hook_rec) \
+	for(hook_rec = hook->hook_next; \
+	    hook_rec != (hook_rec_t *) hook; \
+	    hook_rec = hook_rec->hook_next)
+
+#ifndef FLASE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+
+static int hook_default_exit(hook_rec_t *hook_rec, ...)
+{
+	DPRINTK("hook_record: %p\n", hook_rec);
+	return HOOK_TERMINATE;
+}
+
+static void calculate_indicies(hook_t *hook)
+{
+	hook_rec_t *rec;
+	for_each_hook_rec(hook, rec) {
+		rec->hook_index = (rec->hook_prev->hook_index) + 1;
+	}
+	return;
+}
+
+static inline void deactivate_hook(hook_t *hook)
+{
+	hook->hook_flags &= ~HOOK_HEAD_ACTIVE;
+	if(hook->hook_flags & HOOK_HEAD_ASM_HOOK)
+		deactivate_asm_hook(hook);
+}
+
+static inline void activate_hook(hook_t *hook)
+{
+	hook->hook_flags |= HOOK_HEAD_ACTIVE;
+	if(hook->hook_flags & HOOK_HEAD_ASM_HOOK)
+		activate_asm_hook(hook);
+}
+
+/*
+ * Disarm this hook exit. If no other armed exits exit for this hook,
+ * deactivate the hook.
+ */
+static void disarm_one_hook_exit(hook_rec_t *hook_rec)
+{
+	hook_rec_t *rec;
+
+	hook_rec->hook_flags &= ~HOOK_ARMED;
+	for_each_hook_rec(hook_rec->hook_head, rec) {
+		if(rec->hook_flags & HOOK_ARMED) {
+			return;
+		}
+	}
+	deactivate_hook(rec->hook_head);
+	return;
+}
+
+/* 
+ * validate input hook registeration record 
+ */
+static int validate_input_hook_rec(hook_rec_t *hook_rec)
+{
+        if(hook_rec->hook_flags & ~HOOK_VALID_USER_FLAGS) {
+		DPRINTK("Invalid hook_flags %08x\n", hook_rec->hook_flags);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_exit)) {
+		DPRINTK("Invalid hook_exit %08x\n", hook_rec->hook_exit);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if((hook_rec->hook_next)) {
+		DPRINTK("Invalid hook_nextflags %08x\n", hook_rec->hook_next);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if((hook_rec->hook_prev)) {
+		DPRINTK("Invalid hook_prev %08x\n", hook_rec->hook_prev);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if((hook_rec->hook_index)) {
+		DPRINTK("Invalid hook_index %08x\n", hook_rec->hook_index);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if((hook_rec->hook_head)) {
+		DPRINTK("Invalid hHead %08x\n", hook_rec->hook_head);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	return 0;
+}
+
+/* validate a current hook registeration record*/
+static int validate_hook_rec(hook_rec_t *hook_rec)
+{
+	if(!(hook_rec->hook_flags & HOOK_REGISTERED)) {
+		DPRINTK("Invalid hook_flags %08x\n", hook_rec->hook_flags);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_exit)) {
+		DPRINTK("Invalid hook_hook_rec %08x\n", hook_rec->hook_exit);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_next)) {
+		DPRINTK("Invalid hook_next %08x\n", hook_rec->hook_next);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_prev)) {
+		DPRINTK("Invalid hook_prev %08x\n", hook_rec->hook_prev);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_index)) {
+		DPRINTK("Invalid hook_index %08x\n", hook_rec->hook_index);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	if(!(hook_rec->hook_head)) {
+		DPRINTK("Invalid hook_head %08x\n", hook_rec->hook_head);
+		return ERROR_INVALID_REGISTRATION_RECORD;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_HOOK_PROCFS
+static struct proc_dir_entry *proc_hooks_dir;
+#define PROC_HOOKS_ROOT "hooks"
+
+static int hook_read_proc(char *page, char **start, off_t off, int count, 
+		int *eof, void *data)
+{
+	int len;
+	hook_rec_t *hook_rec = (hook_rec_t *)data;
+	len = sprintf(page, "%d\n", (hook_rec->hook_flags & HOOK_ARMED));
+	return len;
+}
+
+static int hook_write_proc(struct file *file, const char *buffer, 
+		unsigned long count, void *data)
+{
+	hook_rec_t *hook_rec = (hook_rec_t *)data;
+	hook_rec_t *old_link = hook_rec->hook_link;
+	char input;
+	int armed;
+
+	if (copy_from_user(&input, buffer, 1)) {
+		return -EFAULT;
+	}
+	armed = input - '0';
+	if (armed && !(hook_rec->hook_flags & HOOK_ARMED)) {
+		hook_exit_arm(hook_rec);
+	} else if (!armed && (hook_rec->hook_flags & HOOK_ARMED)) {
+		hook_exit_disarm(hook_rec);
+	}
+	hook_rec->hook_link = old_link;
+	return count;
+}
+
+static void hook_create_proc(hook_rec_t *hook_rec)
+{
+	char *proc_entry_name;
+	hook_t *hook = (hook_t *) (hook_rec->hook_head);
+
+	if (hook->proc_entry) {
+		char tmp[32];
+		proc_entry_name = hook_rec->hook_exit_name;
+		if (!proc_entry_name) {
+			sprintf(tmp, "%p", hook_rec);
+			proc_entry_name = tmp;
+		}
+		if (!hook_rec->proc_writable) {
+			hook_rec->proc_entry = create_proc_read_entry(
+					proc_entry_name, 0444, 
+					hook->proc_entry, 
+					hook_read_proc,
+					hook_rec);
+		} else {
+			hook_rec->proc_entry = create_proc_entry(
+					proc_entry_name, 0644, 
+					hook->proc_entry);
+			if (hook_rec->proc_entry) {
+				hook_rec->proc_entry->data = hook_rec;
+				hook_rec->proc_entry->read_proc = hook_read_proc;
+				hook_rec->proc_entry->write_proc = hook_write_proc;
+			}
+		}
+	}
+}
+
+static inline void create_hook_exit_proc_entry(hook_rec_t *hook_rec)
+{
+	if(hook_global_status & HOOK_INIT) {
+		hook_create_proc(hook_rec);
+	}
+}
+
+static inline void remove_hook_exit_proc_entry(hook_rec_t *hook_rec)
+{
+	char tmp[32];
+	char *proc_entry_name;
+
+	if (hook_rec->proc_entry) {
+		proc_entry_name = hook_rec->hook_exit_name;
+		if (!proc_entry_name) {
+			sprintf(tmp, "%p", hook_rec);
+			proc_entry_name = tmp;
+		}
+		hook_rec->proc_entry->data = NULL;
+		remove_proc_entry(proc_entry_name, hook_rec->hook_head->proc_entry);
+	}
+}
+
+static inline void create_hook_proc_dir(hook_t *hook)
+{
+	if(hook_global_status & HOOK_INIT) {
+		hook->proc_entry = proc_mkdir(hook->hook_id, proc_hooks_dir);
+	}
+}
+
+static inline void remove_hook_proc_dir(hook_t *hook)
+{
+	if (hook->proc_entry) {
+		remove_proc_entry(hook->hook_id, proc_hooks_dir);
+	}
+}
+
+static void __init init_hook_procfs(void)
+{
+	hook_t *hook;
+	hook_rec_t *hook_rec;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&hook_lock, flags);
+	proc_hooks_dir = proc_mkdir(PROC_HOOKS_ROOT, NULL);
+	for_each_hook(hook) {
+		hook->proc_entry = proc_mkdir(hook->hook_id, proc_hooks_dir);
+		for_each_hook_rec(hook, hook_rec) {
+			hook_create_proc(hook_rec);
+		}
+	}
+	spin_unlock_irqrestore(&hook_lock, flags);
+}
+
+static void __exit cleanup_hook_procfs(void)
+{
+	remove_proc_entry(PROC_HOOKS_ROOT, NULL);
+}
+#else
+static inline void hook_create_proc(hook_rec_t *hook_rec) {}
+static inline void create_hook_exit_proc_entry(hook_rec_t *hook_rec) {}
+static inline void remove_hook_exit_proc_entry(hook_rec_t *hook_rec) {}
+static inline void create_hook_proc_dir(hook_t *hook) {}
+static inline void remove_hook_proc_dir(hook_t *hook) {}
+static inline void init_hook_procfs(void) {}
+static inline void cleanup_hook_procfs(void) {}
+#endif /* CONFIG_HOOK_PROCFS */
+
+int _hook_exit_register(char *hookid, hook_rec_t *hook_rec)
+{
+	hook_t *hook;
+	hook_rec_t *rec;
+	int retval;
+	unsigned long flags;
+
+        if ((retval = validate_input_hook_rec(hook_rec)))
+		return retval;
+
+	spin_lock_irqsave(&hook_lock, flags);
+
+	for_each_hook(hook) {
+		if(strcmp(hookid, hook->hook_id) == 0) {
+			break;
+		}
+	}
+	if(!hook) {
+		spin_unlock_irqrestore(&hook_lock, flags);
+		return ERROR_HOOK_NOT_FOUND;
+	}
+
+	/* 
+	 * check for priority special conditions and determine the insertion
+	 * point. Note if scheduling priority is not specified then exits are
+	 * dispatched in FIFO order unless the LIFO flag is set, in which
+	 * case the hook record is inseted at the head of the queue.
+	 */
+	rec = (hook_rec_t *)hook;
+
+	/*
+	 * If the hook head is defined as an exclusive hook, force
+	 * the hookrec flags to be exclusive.
+	 */
+	if(hook->hook_flags & HOOK_HEAD_EXCLUSIVE) {
+		hook_rec->hook_flags |= HOOK_PRIORITY_EXCLUSIVE;
+	}
+	
+	if((hook_rec->hook_flags) & HOOK_PRIORITY_FIRST) {
+		if(hook->hook_next != (hook_rec_t *) hook) {
+			if((hook->hook_next->hook_flags) & HOOK_PRIORITY_FIRST) {
+				spin_unlock_irqrestore(&hook_lock, flags);
+				return ERROR_HIGHER_PRIORITY_HOOK;
+			}
+		}
+	}
+
+	if((hook_rec->hook_flags) & HOOK_PRIORITY_LAST) {
+		if(hook->hook_next != (hook_rec_t *) hook) {
+			if((hook->hook_prev->hook_flags) & HOOK_PRIORITY_LAST) {
+				spin_unlock_irqrestore(&hook_lock, flags);
+				return ERROR_LOWER_PRIORITY_HOOK;
+			} else {
+				rec = hook->hook_prev;
+			}
+		}
+	}
+
+	if(!((hook_rec->hook_flags) & HOOK_PRIORITY)) {
+		if((hook_rec->hook_flags) & HOOK_QUEUE_LIFO) {
+			if((hook->hook_next->hook_flags) & HOOK_PRIORITY_FIRST)
+				rec = hook->hook_next;
+		} else if((hook->hook_prev->hook_flags) & HOOK_PRIORITY_LAST)
+			rec = hook->hook_prev->hook_prev;
+		else
+			rec = hook->hook_prev;
+	}
+
+	/* rec points to the hook record after which we make the insertion */
+	hook_rec->hook_next = rec->hook_next;
+	rec->hook_next = rec;
+	hook_rec->hook_prev = rec;
+	hook_rec->hook_next->hook_prev = hook_rec;
+	hook_rec->hook_head = hook;
+
+	calculate_indicies(hook_rec->hook_head);
+
+	create_hook_exit_proc_entry(hook_rec);
+
+	if (hook->hook_flags & HOOK_HEAD_EXCLUSIVE) {
+		hook->hook_exit = hook_rec->hook_exit;
+	}
+
+	hook_rec->hook_flags |= HOOK_REGISTERED;
+
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+int hook_exit_deregister(hook_rec_t *hook_rec)
+{
+	hook_rec_t *rec;
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hook_lock, flags);
+	for(rec = hook_rec; rec; rec = rec->hook_link) {
+		retval = validate_hook_rec(rec);
+		if (retval) {
+			spin_unlock_irqrestore(&hook_lock, flags);
+			return retval;
+		}
+
+		if(rec->hook_flags & HOOK_ARMED)
+			disarm_one_hook_exit(rec);
+
+		rec->hook_prev->hook_next = rec->hook_next;
+		rec->hook_next->hook_prev = rec->hook_prev;
+		remove_hook_exit_proc_entry(rec);
+		calculate_indicies(rec->hook_head);
+
+		if (rec->hook_head->hook_flags & HOOK_HEAD_EXCLUSIVE) {
+			rec->hook_head->hook_exit = &hook_default_exit;
+		}
+
+		rec->hook_flags &= ~HOOK_REGISTERED;
+	}
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+int hook_exit_arm(hook_rec_t *hook_rec)
+{
+	hook_rec_t *rec;
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hook_lock, flags);
+	for(rec = hook_rec; rec; rec = rec->hook_link) {
+		retval = validate_hook_rec(rec);
+		if (retval) {
+			spin_unlock_irqrestore(&hook_lock, flags);
+			return retval;
+		}
+		rec->hook_flags |= HOOK_ARMED;
+		if(!(rec->hook_head->hook_flags & HOOK_HEAD_ACTIVE)) {
+			activate_hook(rec->hook_head);
+		}
+	}
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+int hook_exit_disarm(hook_rec_t *hook_rec)
+{
+	hook_rec_t *rec;
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hook_lock, flags);
+	for(rec = hook_rec; rec; rec = rec->hook_link) {
+		retval = validate_hook_rec(rec);
+		if (retval) {
+			spin_unlock_irqrestore(&hook_lock, flags);
+			return retval;
+		}
+		if(!(rec->hook_flags & HOOK_ARMED)) {
+			spin_unlock_irqrestore(&hook_lock, flags);
+			DPRINTK("Invalid hook_flags %08x\n", hook_rec->hook_flags);
+			return ERROR_INVALID_REGISTRATION_RECORD;
+		}
+		disarm_one_hook_exit(rec);
+	}
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+int _hook_initialise(hook_t *hook)
+{
+	hook_t *h;
+	unsigned char *addr = (unsigned char *)(hook->hook_addr);
+	int retval;
+	unsigned long flags;
+
+	if(is_asm_hook(addr)) {
+		hook->hook_flags |= HOOK_HEAD_ASM_HOOK;
+	}
+
+	spin_lock_irqsave(&hook_lock, flags);
+
+	for_each_hook(h) {
+		if(strcmp(hook->hook_id, h->hook_id) == 0) {
+			break;
+		}
+	}
+	if(h) {
+		spin_unlock_irqrestore(&hook_lock, flags);
+		return ERROR_HOOK_EXISTS;
+	}
+
+	hook->hook_exit = &hook_default_exit;
+	hook->hook_next = (hook_rec_t *) hook;
+	hook->hook_prev = (hook_rec_t *) hook;
+	hook->hook_flags |= HOOK_ARMED;
+	hook->hook_link = NULL;
+	hook->hook_head = hook;
+	hook->hook_index = 0;
+	hook->hook_head_next = NULL;
+	hook->hook_addr = addr;
+
+	create_hook_proc_dir(hook);
+
+	hook->hook_head_next = hook_list_head;
+	hook_list_head = hook;
+
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+int _hook_terminate(hook_t *hook, int force)
+{
+	hook_t *h;
+	hook_t *prevhook = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hook_lock, flags);
+
+	for_each_hook(h) {
+		if(h == hook) {
+			break;
+		}
+		prevhook = h;
+	}
+	if(!h) {
+		spin_unlock_irqrestore(&hook_lock, flags);
+		return ERROR_HOOK_NOT_FOUND;
+	}
+
+	if(hook->hook_flags & HOOK_HEAD_ACTIVE) {
+		if(force) {
+			deactivate_hook(hook);
+		} else {
+			spin_unlock_irqrestore(&hook_lock, flags);
+			return ERROR_HOOK_IS_ACTIVE;
+		}
+	}
+
+	remove_hook_proc_dir(hook);
+
+	if(prevhook)
+		prevhook->hook_head_next = hook->hook_head_next;
+	if(hook == hook_list_head)
+		hook_list_head = hook->hook_head_next;
+
+	spin_unlock_irqrestore(&hook_lock, flags);
+	return NO_ERROR;
+}
+
+static int __init hook_init_module(void)
+{
+	hook_global_status |= HOOK_INIT;
+	init_hook_procfs();
+	printk(KERN_INFO "Generalised Kernel Hooks Interface 1.7\n");
+	DPRINTK("Debug version active\n");
+	return 0;
+}
+
+static void __exit hook_cleanup_module(void)
+{
+	hook_t *hook;
+	hook_rec_t *hook_rec;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hook_lock, flags);
+
+	for_each_hook(hook) {
+		for_each_hook_rec(hook, hook_rec) {
+        		hook_rec->hook_flags &= ~(HOOK_REGISTERED | HOOK_ARMED);
+		}
+		if(hook->hook_flags & HOOK_HEAD_ACTIVE) {
+			deactivate_hook(hook);
+		}
+	}
+	cleanup_hook_procfs();
+	spin_unlock_irqrestore(&hook_lock, flags);
+
+	printk(KERN_INFO "Generalised Kernel Hooks Interface 1.7 terminated\n");
+}
+
+module_init(hook_init_module);
+module_exit(hook_cleanup_module);
+
+EXPORT_SYMBOL(hook_exit_deregister);
+EXPORT_SYMBOL(hook_exit_arm);
+EXPORT_SYMBOL(hook_exit_disarm);
+EXPORT_SYMBOL(_hook_initialise);
+EXPORT_SYMBOL(_hook_terminate);
+EXPORT_SYMBOL(_hook_exit_register);
diff -Naru linux-2.4.19/kernel/Makefile linux-2.4.19-hooks/kernel/Makefile
--- linux-2.4.19/kernel/Makefile	2001-09-17 13:22:40.000000000 +0900
+++ linux-2.4.19-hooks/kernel/Makefile	2003-03-31 11:01:51.000000000 +0900
@@ -9,13 +9,14 @@
 
 O_TARGET := kernel.o
 
-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o
+export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o hook.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o context.o
 
+obj-$(CONFIG_HOOK) += hook.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_PM) += pm.o
