[prev in list] [next in list] [prev in thread] [next in thread] 

List:       fault-injection-developer
Subject:    [Fault-injection-developer] FITH ALL-IN-ONE patch
From:       Louis Zhuang <louis.zhuang () linux ! co ! intel ! com>
Date:       2003-01-14 5:55:31
[Download RAW message or body]

Pls take a look ;-)
-- 
Yours truly,
Louis Zhuang
---------------
Fault Injection Test Harness Project
BK tree: http://fault-injection.bkbits.net/linux-2.5
Home Page: http://sf.net/projects/fault-injection

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or
higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1017  -> 1.1018 
#	arch/i386/mm/fault.c	1.20.1.3 -> 1.27   
#	   arch/i386/Kconfig	1.12.2.19 -> 1.36   
#	arch/i386/kernel/traps.c	1.36.1.6 -> 1.46   
#	arch/i386/kernel/Makefile	1.29.2.1 -> 1.39   
#	     kernel/Makefile	1.22.1.3 -> 1.31   
#	arch/i386/kernel/entry.S	1.41.1.11 -> 1.48   
#	      REPORTING-BUGS	1.2     -> 1.3    
#	     kernel/module.c	1.32.1.17 -> 1.43   
#	include/linux/module.h	1.37.1.2 -> 1.40   
#	    drivers/Makefile	1.29    -> 1.30   
#	      lib/vsprintf.c	1.12.1.1 -> 1.14   
#	drivers/char/Makefile	1.50.1.2 -> 1.58   
#	arch/i386/kernel/i386_ksyms.c	1.40.1.2 -> 1.44   
#	               (new)	        -> 1.1     kernel/kprobes.c
#	               (new)	        -> 1.3    
drivers/fi/interceptors/dbp/Makefile
#	               (new)	        -> 1.7    
drivers/fi/codesegments/fi_sample_cs.c
#	               (new)	        -> 1.10   
drivers/fi/interceptors/fi_irq.c
#	               (new)	        -> 1.1     arch/i386/kernel/kprobes.c
#	               (new)	        -> 1.24   
drivers/fi/interceptors/pf/pf.c
#	               (new)	        -> 1.3     drivers/fi/README
#	               (new)	        -> 1.13    drivers/fi/Makefile
#	               (new)	        -> 1.3     include/linux/kmmio.h
#	               (new)	        -> 1.1     drivers/fi/testing/Makefile
#	               (new)	        -> 1.41    drivers/fi/fi_core.c
#	               (new)	        -> 1.7    
drivers/fi/interceptors/pf/Makefile
#	               (new)	        -> 1.1    
drivers/fi/interceptors/Makefile
#	               (new)	        -> 1.8    
drivers/fi/interceptors/pf/pf_in.c
#	               (new)	        -> 1.7     arch/i386/kernel/kmmio.c
#	               (new)	        -> 1.1     include/asm-i386/kprobes.h
#	               (new)	        -> 1.13   
drivers/fi/interceptors/dbp/fi_dbp.c
#	               (new)	        -> 1.1     include/linux/kprobes.h
#	               (new)	        -> 1.7     kernel/kmmio.c 
#	               (new)	        -> 1.14    include/linux/fi.h
#	               (new)	        -> 1.15    drivers/fi/testing/fi_test.c
#	               (new)	        -> 1.8    
drivers/fi/interceptors/pf/pf_utils.c
#	               (new)	        -> 1.7     arch/i386/kernel/kirq.c
#	               (new)	        -> 1.6    
drivers/fi/testing/fi_mock_cs.c
#	               (new)	        -> 1.12   
drivers/fi/testing/fi_mock_interceptor.c
#	               (new)	        -> 1.5     include/asm-i386/kirq.h
#	               (new)	        -> 1.1    
drivers/fi/codesegments/Makefile
#	               (new)	        -> 1.3     include/asm-i386/kmmio.h
#	               (new)	        -> 1.8    
drivers/fi/interceptors/pf/fi_pf.h
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/01/14	stanley@manticore.sh.intel.com	1.1018
# Merge from vanilla kernel tree by hand.
# --------------------------------------------
#
diff -Nru a/REPORTING-BUGS b/REPORTING-BUGS
--- a/REPORTING-BUGS	Tue Jan 14 13:43:34 2003
+++ b/REPORTING-BUGS	Tue Jan 14 13:43:34 2003
@@ -1,5 +1,7 @@
 [Some of this is taken from Frohwalt Egerer's original linux-kernel
FAQ]
 
+
+
      What follows is a suggested procedure for reporting Linux bugs.
You
 aren't obliged to use the bug reporting format, it is provided as a
guide
 to the kind of information that can be useful to developers - no more.
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig	Tue Jan 14 13:43:34 2003
+++ b/arch/i386/Kconfig	Tue Jan 14 13:43:34 2003
@@ -1543,6 +1543,169 @@
 	  Say Y here if you are developing drivers or trying to debug and
 	  identify kernel problems.
 
+config KPROBES
+	bool "Kprobes"
+	depends on DEBUG_KERNEL
+	help
+	  Kprobes allows you to trap at almost any kernel address, using
+	  register_kprobe(), and providing a callback function.  This is
useful
+	  for kernel debugging, non-intrusive instrumentation and testing.  If
+	  in doubt, say "N".
+config KMMIO
+	bool "KMMIO (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on KPROBES 
+	help
+	  KMMIO is a Kprobes add-ons for placing a probe on MMIO access, using
+	  register_kmmio(), and providing a callback function. This is useful
+	  for monitoring driver access specific MMIO address.
+
+config KIRQ
+	bool "Kernel Irq interceptor for X86(experimental)"
+	depends on DEBUG_KERNEL && EXPERIMENTAL
+	help
+	  This option enable an IRQ interceptor. You can get the control
+	  before any specified ISR is executing and decide whether it
+	  should be executing through "register_kirq/unregister_kirq".
+
+config FI
+	bool "Fault Injection (EXPERIMENTAL)"
+	depends on DEBUG_KERNEL && EXPERIMENTAL
+	help
+          Enabling Fault Injection will add hooks to the kernel to
allow
+          user space tools to insert specific faults into the kernel
for
+          the purpose of testing the kernels ability to handle
exceptional
+          conditions.
+
+          Fault injection would not normally be enabled on a production
+          system, but would normally be used in a test environment to
+          validate the suitablity of a kernel level code for an
environment
+          that requires extreme high availability.
+
+          This code is currently _very_ experimental and by definition
allows
+          some very nasty things to happen happen to your system.  Only
+          enable this if you are ok with the possibility of destroying
+          your operating system.
+
+config FI_DEBUG
+	bool "Fault Injection Debugging"
+	depends on FI
+	help
+          Enabling this option will result in more verbose fault
injection 
+          debugging information in the system log.
+
+config FI_SAMPLE_CODESEGMENT
+	tristate "Fault Injection Sample Code Segment (EXPERIMENTAL)"
+	depends on FI
+	help
+	  Enabling this option will cause the sample fault injection
+          code segment to be built.
+
+	  If in doubt say N.
+
+config FI_PF
+	tristate "Fault Injection Pagefault Interceptor (EXPERIMENTAL)"
+	depends on KMMIO
+	depends on FI
+	help
+          This component adds the ability for Fault Injection to
intercept
+          normal pagefault operations.  When combined with the core
+          fault injection infrastructure and a user space tool chain,
it 
+          will be possible to create test cases that manipulate data
read 
+          during a pagefault.
+
+          This driver is also available as a module ( = code which can
be
+          inserted in and removed from the running kernel whenever you
want).
+          The module will be called fi_pf.o.  If you want to compile it
as
+          a module, say M here and read
<file:Documentation/modules.txt>.
+
+          If in doubt, say N.
+
+config FI_DBP
+	tristate "Fault Injection DBP Interceptor (EXPERIMENTAL)"
+	depends on FI
+	help
+	  This component adds the ability for Fault Injection to intercept
+	  int3's handler. When combined with the core fault injection 
+	  infrastructure and a user space tool chain, it will be possible
+	  to create test cases that inject fault into normal PIO access.
+
+          This driver is also available as a module ( = code which can
be
+          inserted in and removed from the running kernel whenever you
want).
+          The module will be called fi_dbp.o.  If you want to compile
it as
+          a module, say M here and read
<file:Documentation/modules.txt>.
+
+          If in doubt, say N.
+
+config FI_IRQ
+	tristate "Fault Injection IRQ Interceptor (EXPERIMENTAL)"
+	depends on KIRQ
+	depends on FI
+	help
+          This component adds the ability for Fault Injection to
intercept
+          specified irq's handler.  When combined with the core fault 
+	  injection infrastructure and a user space tool chain, it 
+          will be possible to create test cases that inject fault into 
+	  driver's isr.
+
+          This driver is also available as a module ( = code which can
be
+          inserted in and removed from the running kernel whenever you
want).
+          The module will be called fi_irq.o.  If you want to compile
it as
+          a module, say M here and read
<file:Documentation/modules.txt>.
+
+          If in doubt, say N.
+
+
+config FI_INTERNEL_TESTING
+	bool "Fault Injection Internel Test Components (EXPERIMENTAL)"
+	depends on FI
+	help
+	  Enabling this option will build additional components that are
+          useful when hacking fault injection components, not creating
+          a fault injection test case.
+
+	  If in doubt say N
+
+config FI_MOCK_INTERCEPTOR
+	tristate "Fault Injection Mock Interceptor (EXPERIMENTAL)"
+	depends on FI_INTERNEL_TESTING
+	help
+	  Enabling this option will build a mock fault injection interceptor 
+          created for the sole purpose of exercising the fault
injection 
+          core code. The only reason a person would want to build this 
+          component is to hack the fault injection interceptor
interfaces.
+
+	  If in doubt say N
+
+config FI_MOCK_CODESEGMENT
+	tristate "Fault Injection Mock Codesegment (EXPERIMENTAL)"
+	depends on FI_INTERNEL_TESTING
+	help
+	  Enabling this option will build a mock fault injection codesegment 
+          created for the sole purpose of exercising the fault
injection 
+          core code. The only reason a person would want to build this 
+          component is to hack the fault injection codesegment
interfaces.
+
+	  If in doubt say N
+
+config FI_TEST
+	tristate "Fault Injection Test Driver (EXPERIMENTAL)"
+	depends on FI_INTERNEL_TESTING
+	help
+	  This component is test driver for demonstrating how the fault
+          injection kernel hooks, associated interceptor modules, and
the
+          ficl user space utility (available from
fault-injection.sf.net)
+          can be coordinated to implement "fault set" for use in
creating
+          test case scenarios.
+
+          This driver is also available as a module ( = code which can
be
+          inserted in and removed from the running kernel whenever you
want).
+          The module will be called fi_test.o.  If you want to compile
it as
+          a module, say M here and read
<file:Documentation/modules.txt>.
+
+	  Unless you are intending to experiment with fault injection testing,
+          just say N.
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Tue Jan 14 13:43:34 2003
+++ b/arch/i386/kernel/Makefile	Tue Jan 14 13:43:34 2003
@@ -4,7 +4,7 @@
 
 EXTRA_TARGETS := head.o init_task.o
 
-export-objs     := mca.o i386_ksyms.o time.o
+export-objs     := mca.o i386_ksyms.o time.o kirq.o kmmio.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
@@ -30,6 +30,9 @@
 obj-$(CONFIG_PROFILING)		+= profile.o
 obj-$(CONFIG_EDD)             	+= edd.o
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_KMMIO)		+= kmmio.o
+obj-$(CONFIG_KIRQ)		+= kirq.o
 obj-y				+= sysenter.o
 
 EXTRA_AFLAGS   := -traditional
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Tue Jan 14 13:43:34 2003
+++ b/arch/i386/kernel/entry.S	Tue Jan 14 13:43:34 2003
@@ -471,9 +471,16 @@
 	jmp ret_from_exception
 
 ENTRY(debug)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
 	pushl $0
-	pushl $do_debug
-	jmp error_code
+	pushl %edx
+	call do_debug
+	addl $8,%esp
+	testl %eax,%eax 
+	jnz restore_all
+	jmp ret_from_exception
 
 ENTRY(nmi)
 	pushl %eax
@@ -486,9 +493,16 @@
 	RESTORE_ALL
 
 ENTRY(int3)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
 	pushl $0
-	pushl $do_int3
-	jmp error_code
+	pushl %edx
+	call do_int3
+	addl $8,%esp
+	testl %eax,%eax 
+	jnz restore_all
+	jmp ret_from_exception
 
 ENTRY(overflow)
 	pushl $0
diff -Nru a/arch/i386/kernel/kirq.c b/arch/i386/kernel/kirq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/kirq.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,123 @@
+/* Support for kernel irq interceptor.
+   (C) 2002 Stanley Wang <stanley.wang@intel.com>.
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/kirq.h>
+
+struct kirq kirq_list[NR_IRQS] =
+	{ [0 ... NR_IRQS-1] = { NULL, NULL, NULL}};
+
+void kirq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int	i;
+	struct kirq *p = kirq_list + irq;
+	if (p->handler != NULL){
+		i = (*(p->handler))(p, irq, dev_id, regs);
+		if ( i == 0 )
+			(*(p->isr))(irq, dev_id, regs);
+	}else{
+		printk(KERN_ERR "%s: Dropping unexpected interrupt #%i\n",
+				__FUNCTION__, irq);
+	}
+	return;
+}
+
+int register_kirq(int irq, char *devname, kirq_handler_t handler)
+{
+	struct irqaction *action;
+	irq_desc_t *desc = irq_desc + irq;
+	struct kirq *p = kirq_list + irq;
+	unsigned long flags;
+	
+	if (handler == NULL) {
+		printk(KERN_ERR "%s: Missing handler!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	if (p->handler) {
+		printk(KERN_ERR "%s: KIRQ was regitsered already!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+	
+	spin_lock_irqsave(&desc->lock,flags);
+	
+	action = desc->action;
+	while (action) {
+		if (strcmp(action->name,devname)) {
+			action = action->next;
+		}else{
+			break;
+		}
+	}
+
+	if (!action) {
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return -1; 
+	}
+
+	p->isr = action->handler;
+	p->handler = handler;
+	p->dev_id = action->dev_id;
+		
+	action->handler = kirq_handler;
+		
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	return 0;
+}
+
+int unregister_kirq(int irq)
+{
+	struct irqaction *action;
+	irq_desc_t *desc = irq_desc + irq;
+	struct kirq *p = kirq_list + irq;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&desc->lock,flags);
+	
+	action = desc->action;
+	while ( action && action->dev_id != p->dev_id) {
+		action = action->next;
+	}
+
+	if (!action) {
+		printk(KERN_ERR "%s: Unregister KIRQ failed!\n", __FUNCTION__);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return -1;
+	}
+
+	action->handler = p->isr;
+	
+	p->isr = NULL;
+	p->handler = NULL;
+	p->dev_id = NULL;
+		
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	return 0;
+}
+
+void dispatch_kirq(int irq, struct pt_regs *regs)
+{
+	struct kirq *p = kirq_list + irq;
+	if (p->isr != NULL){
+		(*(p->isr))(irq, p->dev_id, regs);
+	}else{
+		printk(KERN_ERR "%s: Dropping wrong interrupt #%i\n",
+				__FUNCTION__, irq);
+	}
+	return;
+}
+
+EXPORT_SYMBOL_GPL(register_kirq);
+EXPORT_SYMBOL_GPL(unregister_kirq);
+EXPORT_SYMBOL_GPL(dispatch_kirq);
+
diff -Nru a/arch/i386/kernel/kmmio.c b/arch/i386/kernel/kmmio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/kmmio.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,156 @@
+/* 
+ * KMMIO
+ * Benfit many code from kprobes
+ * (C) 2002 Louis Zhuang <louis.zhuang@intel.com>.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/kmmio.h>
+#include <linux/ptrace.h>
+#include <linux/preempt.h>
+#include <asm/io.h>
+#include <asm/highmem.h>
+
+static int cpu=-1;
+static struct kmmio_fault_page *cur_page = NULL;
+static struct kmmio_probe *cur_probe = NULL;
+static unsigned long kmmio_saved_eflags;
+/*
+ * Interrupts are disabled on entry as trap3 is an interrupt gate and
they
+ * remain disabled thorough out this function.
+ */
+int kmmio_handler(struct pt_regs *regs, unsigned long addr)
+{
+	/* We're in an interrupt, but this is clear and BUG()-safe. */
+	preempt_disable();
+
+	lock_kmmio();
+
+	cur_page = get_kmmio_fault_page((void *)addr);
+	if (!cur_page) {
+		/* this page fault is not caused by kmmio */
+		/* XXX some pending fault on other cpu may cause problem! */ 
+		unlock_kmmio();
+		goto no_kmmio;
+	}
+	cpu = smp_processor_id();
+	
+	cur_probe = get_kmmio_probe((void *)addr); 
+	kmmio_saved_eflags = (regs->eflags & (TF_MASK|IF_MASK));
+	
+	if (cur_probe && cur_probe->pre_handler) {
+		cur_probe->pre_handler(cur_probe, regs, addr);
+	}
+	
+	regs->eflags |= TF_MASK;
+	regs->eflags &= ~IF_MASK;
+
+	/* We hold lock, now we set present bit in PTE and single step. */
+	disarm_kmmio_fault_page(cur_page->page);
+	
+
+	return 1;
+
+no_kmmio:
+	preempt_enable_no_resched();
+	return 0;
+}
+
+/*
+ * Interrupts are disabled on entry as trap1 is an interrupt gate and
they
+ * remain disabled thorough out this function.  And we hold kmmio lock.
+ */
+int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
+{
+	if (!is_kmmio_active())
+		return 0;
+	if (smp_processor_id() != cpu)
+		return 0;
+
+	if (cur_probe && cur_probe->post_handler) {
+		cur_probe->post_handler(cur_probe, condition, regs);
+	}
+
+	arm_kmmio_fault_page(cur_page->page);
+	__flush_tlb_one(cur_page->page);
+	
+	regs->eflags &= ~TF_MASK;
+	regs->eflags |= kmmio_saved_eflags;
+
+	cpu = -1;
+	
+	unlock_kmmio();
+	preempt_enable_no_resched();
+	
+        /*
+	 * if somebody else is singlestepping across a probe point, eflags
+	 * will have TF set, in which case, continue the remaining processing
+	 * of do_debug, as if this is not a probe hit.
+	 */
+	if (regs->eflags & TF_MASK)
+		return 0;
+
+	return 1;
+}
+
+static inline pte_t *get_pte(unsigned long address) 
+{
+        pgd_t *pgd = pgd_offset_k(address);
+	pmd_t *pmd = pmd_offset(pgd, address);
+	if (pmd_large(*pmd))
+		return (pte_t *)pmd;
+	return pte_offset_kernel(pmd, address);
+};
+
+/**
+ * Set/Clear pte bits
+ */
+static inline void clr_pte_bits(unsigned long addr, unsigned long
bitmask) 
+{
+	pte_t *pte;
+	pte = get_pte(addr);
+	set_pte( pte, __pte( pte_val(*pte) & ~bitmask) );	
+};
+
+static inline void set_pte_bits(unsigned long addr, unsigned long
bitmask) 
+{
+	pte_t *pte;
+	pte = get_pte(addr);
+	set_pte( pte, __pte( pte_val(*pte) | bitmask) );	
+};	
+
+void arm_kmmio_fault_page(kmmio_addr_t page)
+{	
+	(unsigned long)page &= PAGE_MASK;
+	clr_pte_bits((unsigned long)page, _PAGE_PRESENT);
+}
+
+void disarm_kmmio_fault_page(kmmio_addr_t page)
+{
+	(unsigned long)page &= PAGE_MASK;
+	set_pte_bits((unsigned long)page, _PAGE_PRESENT);
+}
+
+/* the function is only used to make virt map to bus */
+void *kmmio_invert_map(void *virt_addr, unsigned long bus_addr)
+{
+	int offset;
+	pte_t *pte;
+
+	if((unsigned long)virt_addr & ~PAGE_MASK)
+		BUG();
+	
+	offset = bus_addr & ~PAGE_MASK;
+	bus_addr &= PAGE_MASK;
+	pte = get_pte((unsigned long)virt_addr);
+	
+	set_pte( pte, __pte( (pte_val(*pte) & ~PAGE_MASK) | bus_addr) );
+	return virt_addr+offset;								
+}
+
+EXPORT_SYMBOL_GPL(kmmio_invert_map);
diff -Nru a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/kprobes.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,160 @@
+/* 
+ * Support for kernel probes.
+ * (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
+ */
+
+#include <linux/config.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/spinlock.h>
+#include <linux/preempt.h>
+
+/* kprobe_status settings */
+#define KPROBE_HIT_ACTIVE	0x00000001
+#define KPROBE_HIT_SS		0x00000002
+
+static struct kprobe *current_kprobe;
+static unsigned long kprobe_status, kprobe_old_eflags,
kprobe_saved_eflags;
+
+/*
+ * returns non-zero if opcode modifies the interrupt flag.
+ */
+static inline int is_IF_modifier(u8 opcode)
+{
+	switch(opcode) {
+		case 0xfa: 	/* cli */
+		case 0xfb:	/* sti */
+		case 0xcf:	/* iret/iretd */
+		case 0x9d:	/* popf/popfd */
+			return 1;
+	}
+	return 0;
+}
+
+static inline void disarm_kprobe(struct kprobe *p, struct pt_regs
*regs)
+{
+	*p->addr = p->opcode;
+	regs->eip = (unsigned long)p->addr;
+}
+
+/*
+ * Interrupts are disabled on entry as trap3 is an interrupt gate and
they
+ * remain disabled thorough out this function.
+ */
+int kprobe_handler(struct pt_regs *regs)
+{
+	struct kprobe *p;
+	int ret = 0;
+	u8 *addr = (u8 *)(regs->eip-1);
+
+	/* We're in an interrupt, but this is clear and BUG()-safe. */
+	preempt_disable();
+
+	/* Check we're not actually recursing */
+	if (kprobe_running()) {
+		/* We *are* holding lock here, so this is safe.
+                   Disarm the probe we just hit, and ignore it. */
+		p = get_kprobe(addr);
+		if (p) {
+			disarm_kprobe(p, regs);
+			ret = 1;
+		}
+		/* If it's not ours, can't be delete race, (we hold lock). */
+		goto no_kprobe;
+	}
+
+	lock_kprobes();
+	p = get_kprobe(addr); 
+	if (!p) {
+		unlock_kprobes();
+		/* Unregistered (on another cpu) after this hit?  Ignore */
+		if (*addr != BREAKPOINT_INSTRUCTION)
+			ret = 1;
+		/* Not one of ours: let kernel handle it */
+		goto no_kprobe;
+	}
+
+	kprobe_status = KPROBE_HIT_ACTIVE;
+	current_kprobe = p;
+	kprobe_saved_eflags = kprobe_old_eflags 
+		= (regs->eflags & (TF_MASK|IF_MASK));
+	if (is_IF_modifier(p->opcode))
+		kprobe_saved_eflags &= ~IF_MASK;
+
+	p->pre_handler(p, regs);
+
+	regs->eflags |= TF_MASK;
+	regs->eflags &= ~IF_MASK;
+
+	/* We hold lock, now we remove breakpoint and single step. */
+	disarm_kprobe(p, regs);
+	kprobe_status = KPROBE_HIT_SS;
+	return 1;
+
+no_kprobe:
+	preempt_enable_no_resched();
+	return ret;
+}
+
+static void rearm_kprobe(struct kprobe *p, struct pt_regs *regs)
+{
+	regs->eflags &= ~TF_MASK;
+	*p->addr = BREAKPOINT_INSTRUCTION;
+}
+	
+/*
+ * Interrupts are disabled on entry as trap1 is an interrupt gate and
they
+ * remain disabled thorough out this function.  And we hold kprobe
lock.
+ */
+int post_kprobe_handler(struct pt_regs *regs)
+{
+	if (!kprobe_running())
+		return 0;
+
+	if (current_kprobe->post_handler)
+		current_kprobe->post_handler(current_kprobe, regs, 0);
+
+	/*
+	 * We singlestepped with interrupts disabled. So, the result on
+	 * the stack would be incorrect for "pushfl" instruction.
+	 * Note that regs->esp is actually the top of the stack when the
+	 * trap occurs in kernel space.
+	 */
+	if (current_kprobe->opcode == 0x9c) { /* pushfl */
+		regs->esp &= ~(TF_MASK | IF_MASK);
+		regs->esp |= kprobe_old_eflags;
+	}
+
+	rearm_kprobe(current_kprobe, regs);
+	regs->eflags |= kprobe_saved_eflags;
+
+	unlock_kprobes();
+	preempt_enable_no_resched();
+
+        /*
+	 * if somebody else is singlestepping across a probe point, eflags
+	 * will have TF set, in which case, continue the remaining processing
+	 * of do_debug, as if this is not a probe hit.
+	 */
+	if (regs->eflags & TF_MASK)
+		return 0;
+
+	return 1;
+}
+
+/* Interrupts disabled, kprobe_lock held. */
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+	if (current_kprobe->fault_handler
+	    && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+		return 1;
+
+	if (kprobe_status & KPROBE_HIT_SS) {
+		rearm_kprobe(current_kprobe, regs);
+        	regs->eflags |= kprobe_old_eflags;
+
+		unlock_kprobes();
+		preempt_enable_no_resched();
+	}
+	return 0;
+}
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Tue Jan 14 13:43:34 2003
+++ b/arch/i386/kernel/traps.c	Tue Jan 14 13:43:34 2003
@@ -24,6 +24,8 @@
 #include <linux/interrupt.h>
 #include <linux/highmem.h>
 #include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/kmmio.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -344,7 +346,6 @@
 }
 
 DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error,
FPE_INTDIV, regs->eip)
-DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
 DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN,
regs->eip)
@@ -360,6 +361,9 @@
 {
 	if (regs->eflags & VM_MASK)
 		goto gp_in_vm86;
+	
+	if (kprobe_running() && kprobe_fault_handler(regs, 13))
+		return;
 
 	if (!(regs->xcs & 3))
 		goto gp_in_kernel;
@@ -484,6 +488,17 @@
 	nmi_callback = dummy_nmi_callback;
 }
 
+asmlinkage int do_int3(struct pt_regs *regs, long error_code)
+{
+	if (kprobe_handler(regs))
+		return 1;
+	/* This is an interrupt gate, because kprobes wants interrupts
+           disabled.  Normal trap handlers don't. */
+	restore_interrupts(regs);
+	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+	return 0;
+}
+
 /*
  * Our handling of the processor debug registers is non-trivial.
  * We do not clear them on entry and exit from the kernel. Therefore
@@ -506,7 +521,7 @@
  * find every occurrence of the TF bit that could be saved away even
  * by user code)
  */
-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+asmlinkage int do_debug(struct pt_regs * regs, long error_code)
 {
 	unsigned int condition;
 	struct task_struct *tsk = current;
@@ -514,6 +529,15 @@
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
+	if (post_kprobe_handler(regs))
+		return 1;
+
+	if (post_kmmio_handler(condition, regs))
+		return 1;	
+
+	/* Interrupts not disabled for normal trap handling. */
+	restore_interrupts(regs);
+
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7])
@@ -564,17 +588,17 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
-	return;
+	return 0;
 
 debug_vm86:
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-	return;
+	return 0;
 
 clear_TF_reenable:
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 clear_TF:
 	regs->eflags &= ~TF_MASK;
-	return;
+	return 0;
 }
 
 /*
@@ -738,6 +762,8 @@
 	struct task_struct *tsk = current;
 	clts();		/* Allow maths ops (or we recurse) */
 
+	if (kprobe_running() && kprobe_fault_handler(&regs, 7))
+		return;
 	if (!tsk->used_math)
 		init_fpu(tsk);
 	restore_fpu(tsk);
@@ -831,9 +857,9 @@
 #endif
 
 	set_trap_gate(0,&divide_error);
-	set_trap_gate(1,&debug);
+	_set_gate(idt_table+1,14,3,&debug); /* debug trap for kprobes */
 	set_intr_gate(2,&nmi);
-	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+	_set_gate(idt_table+3,14,3,&int3); /* int3-5 can be called from all */
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Tue Jan 14 13:43:34 2003
+++ b/arch/i386/mm/fault.c	Tue Jan 14 13:43:34 2003
@@ -20,6 +20,8 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/kmmio.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -161,6 +163,12 @@
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
+	if (kprobe_running() && kprobe_fault_handler(regs, 14))
+		return;
+	
+	if (is_kmmio_active() && kmmio_handler(regs, address))
+		return;
+	
 	/* It's safe to allow irq's after cr2 has been saved */
 	if (regs->eflags & X86_EFLAGS_IF)
 		local_irq_enable();
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Tue Jan 14 13:43:34 2003
+++ b/drivers/Makefile	Tue Jan 14 13:43:34 2003
@@ -44,3 +44,5 @@
 obj-$(CONFIG_HOTPLUG_PCI)	+= hotplug/
 obj-$(CONFIG_ISDN_BOOL)		+= isdn/
 obj-$(CONFIG_MCA)		+= mca/
+obj-$(CONFIG_FI)                += fi/
+
diff -Nru a/drivers/fi/Makefile b/drivers/fi/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,11 @@
+#
+# Kernel Fault Injection Features
+#
+
+EXTRA_AFLAGS	:= -traditional
+export-objs	:= fi_core.o
+
+obj-$(CONFIG_FI_INTERNEL_TESTING)	+= testing/
+obj-y					+= interceptors/
+obj-y					+= codesegments/
+obj-$(CONFIG_FI)			+= fi_core.o
diff -Nru a/drivers/fi/README b/drivers/fi/README
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/README	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,182 @@
+This is the root directory for fault injection.  Fault injection
contains the
+following:
+
+fi_core.c : Core fault injection code.
+EXPORT_SYMBOL_GPL(fi_register_interceptor);
+EXPORT_SYMBOL_GPL(fi_unregister_interceptor);
+EXPORT_SYMBOL_GPL(fi_register_code_segment);
+EXPORT_SYMBOL_GPL(fi_unregister_code_segment);
+EXPORT_SYMBOL_GPL(fi_execute_trigger);
+EXPORT_SYMBOL_GPL(fi_debug);
+
+testing/ : Proper place to add any code created for the purpose 
+	   of testing the fault injection core code (not to
+           to actually implement 'fault injection testing')
+	* Current test code includes
+		- mock interceptor : a simple interceptor implementation
+                                     that can be configured to
represent
+                                     any interceptor type, and adds a
'trip'
+                                     file to the specific trigger's
sysfs
+                                     directory to enable the trigger to
be
+                                     tripped via command line.
+		- mock code segment : a simple code segment implementation
+				      that ???
+
+interceptors/ : Proper place to add any interceptor implementations.
+        * Current interceptors are
+		- pf : 'page fault' interceptor for intercepting MMIO
+		- dbp : ???
+
+codesegments/ : Proper place to add any code segment implementations
+	* Current code segments are
+		- sample : ???
+
+
+What is an 'interceptor'?
+-------------------------
+
+An interceptor is a component that knows how to intercept some specific
+type of kernel level event or action to enable the fault injection
+core to 'hook' into event or action and take some action.  
+
+An interceptor is one level higher then a normal kernel hook.  For
example
+an interceptor could be written to utilize kprobes, where the kprobe 
+is tripped every time a specific address is executed, but the
interceptor
+might contain some additional logic to decide if the specific event or
action
+was happening.
+
+
+    Life cycle of an interceptor
+    ----------------------------
+
+   ( Startup )
+     ----------------
+    | Initialization | ----------------------------
+     ----------------                             ||
+            ||    |                               \/
+            ||    |         ------------------------------------------
+            ||    |        | initialize a 'interceptor' kernel object |
+            ||     ------- | with function pointers for the fault     |
+            ||             | injection core to interface with this    |
+            ||             | interceptor                              |
+            ||              ------------------------------------------
+            ||
+            ||
+            ||
+            \/
+     -----------------------------------------------
+    | (call into fi_core) fi_register_interceptor() |
+     -----------------------------------------------
+
+    (User starts using the interceptor)
+     --------------------------------
+    | Fault injection core creates   |
+    | a trigger that references this |
+    | interceptor                    |
+     --------------------------------
+            ||
+            \/
+     --------------
+    | arm(trigger) |  ------------
+     --------------              ||
+          |                      ||
+          |                      \/
+          |     ---------------------------------------
+          |___ | take what ever action is required     |
+               | to hook into the low level event.     |
+               | This could be with kprobes, or kmmio, |
+               | or whatever                           |
+                ---------------------------------------
+
+    (Event happens)
+     -----------------------------
+    | Low level hook is triggered |
+     -----------------------------
+               ||
+               \/    
+     ----------------------------------------
+    | (call into fi_core) fi_execute_trigger |
+     ----------------------------------------
+
+    (User stops using the interceptor)
+     -----------------------------------------------
+    | Fault injection core removes the trigger that |
+    | references this interceptor                   |
+     -----------------------------------------------
+               ||
+               \/
+     -----------------
+    | disarm(trigger) |  ---------
+     -----------------           ||
+          |                      ||
+          |                      \/
+          |     ---------------------------------------
+          |___ | take what ever action is required     |
+               | to remove the level hooks we added    |
+               | when we first armed the interceptor   |
+                ---------------------------------------
+    
+
+What is a 'code segment'?
+-------------------------
+A code segment is a component that knows how to handle a specific 
+type of trigger event.  In the absence of an attached code segment,
+the fault injection core will only be able to take some very simple
+actions when an interceptor executes a trigger.  Developers can 
+extend these basic cababilities by creating a code segment for a very
+specific type of event, loading the code segment, and then attaching
+the code segment to the appropriate triggers.
+
+    Life cycle of a code segment
+    ----------------------------
+
+   ( Startup )
+
+     ----------------
+    | Initialization |
+     ---------------- 
+            ||
+            ||
+            ||
+            \/
+     ------------------------------------------------
+    | (call into fi_core) fi_register_code_segment() |
+     ------------------------------------------------
+
+    (User starts using the code segment)
+    
+    Completely outside the view of the code segment, the user
+    via sysfs interfaces provided by the fault injection core
+    is able to:
+        1. create a trigger
+        2. 'attach' this code segment to the new trigger
+
+
+    (Event happens)
+
+     ------------------------------------------
+    | The previously created trigger is        |
+    | executed as described in the trigger     |
+    | life cycle above.  Durring the execution |
+    | of fi_core::fi_execute_trigger the core  |
+    | notices the attached code segment.       |
+     ------------------------------------------
+               ||
+               \/   
+     ----------------------------------------------
+    | (using function pointer from cs registration)| 
+    | execute_trigger()                            |
+     ----------------------------------------------
+
+
+    (User stops using the code segment)
+	
+    Completely outside the view of the code segment, the user
+    via sysfs interfaces provided by the fault injection core
+    either:
+        * removes the associated trigger
+        - or -
+        * removes the association between the trigger and the code
segment
+
+
+
diff -Nru a/drivers/fi/codesegments/Makefile
b/drivers/fi/codesegments/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/codesegments/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,7 @@
+#
+# Kernel Fault Injection Codesegments
+#
+
+EXTRA_AFLAGS	:= -traditional
+
+obj-$(CONFIG_FI_SAMPLE_CODESEGMENT)	+= fi_sample_cs.o
diff -Nru a/drivers/fi/codesegments/fi_sample_cs.c
b/drivers/fi/codesegments/fi_sample_cs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/codesegments/fi_sample_cs.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,72 @@
+/* Copyright (C) 2002 Louis Zhuang <louis.zhuang@intel.com> */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kobject.h>
+#include <linux/fi.h>
+
+#include <asm/io.h>
+#include <asm/kmmio.h>
+
+#define DRIVER_AUTHOR   "Louis Zhuang <louis.zhuang@intel.com>"
+#define DRIVER_DESC     "Fault Injection Sample Code Segment"
+
+static unsigned long bus_addr=0;
+static void *iopage;
+
+static void sample_execute(struct trigger *t, struct interceptor *i, 
+		__u32 val, int len, int type, void *data)
+{
+	void *virt_ptr;
+	info("tri=%s, intcpt=%s, val=%i, len=%i, type=%i, data=%p",
+			t->kobj.name, i->kobj.name, val, len, type,
+			data);
+	virt_ptr = kmmio_invert_map(iopage, bus_addr);
+	info("virt_ptr=%p", virt_ptr);
+}
+
+static struct code_segment sample_code_segment = {
+	.execute_trigger = sample_execute,
+	.kobj = {.name="sample"} 
+};
+
+static ssize_t sample_addr_show (struct code_segment *cs, char *page)
+{
+	return sprintf(page, "%#lx", bus_addr);
+}
+
+static ssize_t sample_addr_store (struct code_segment *cs, const char
*page, size_t count)
+{
+	sscanf(page, "%ld", &bus_addr);
+	return count;
+}
+
+static struct code_segment_attribute sample_attr_trigger = {
+	.attr = { .name = "bus_addr", .mode = 0644 },
+	.show = sample_addr_show,
+	.store= sample_addr_store
+};
+
+	
+static int __init sample_init(void)
+{
+	iopage = ioremap(0xe0000000, 4096);
+	if (fi_register_code_segment(&sample_code_segment)) {
+		err("Failed to register Mock Code Segment\n");
+		return -EINVAL;
+	}
+	sysfs_create_file(&sample_code_segment.kobj,
&sample_attr_trigger.attr);
+	return 0;
+}
+
+static void __exit sample_exit(void)
+{
+	sysfs_remove_file(&sample_code_segment.kobj,
&sample_attr_trigger.attr);
+	fi_unregister_code_segment(&sample_code_segment);
+	iounmap(iopage);
+}
+module_init(sample_init);
+module_exit(sample_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff -Nru a/drivers/fi/fi_core.c b/drivers/fi/fi_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/fi_core.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,949 @@
+/******************************************************************************
+ *  Fault Injection Core Functionality
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ * 
+ * interceptor<-------->trigger<-------->code segment
+ *            1        *       1        *
+ * 
+ * There are one-multi relationship between interceptor and trigger,
also 
+ * between trigger and code segment.
+ * 	--lz
+
******************************************************************************
+ * This is a rewrite of code originally submitted by 
+ * Louis Zhuang <louis.zhuang@intel.com>.  I have moved the code from
+ * a ioctl based control using proc to expose information about
+ * fault injection data that was contained in fixed sized tables,
+ * to an extendable kobject based implementation that uses sysfs
+ * for all user space access.
+ *    --rustyl
+ *
+ * Contributors:
+ * Louis Zhuang <louis.zhuang@intel.com>
+ * Stanley Wang <stanley.wang@intel.com>
+ * Rusty Lynch <rusty@linux.intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kprobes.h>
+#include <linux/slab.h>
+#include <linux/kobject.h>
+#include <linux/random.h>
+
+#include <linux/fi.h>
+
+static DECLARE_MUTEX(fi_sem);
+
+static struct subsystem fi_subsys;
+static struct subsystem trigger_subsys;
+static struct subsystem interceptor_subsys;
+
+static int is_initialized = 0;
+int fi_debug = 1;
+
+
+/*
+ * ===========================================================
+ *       <>-- Misc functions --<>
+ * -----------------------------------------------------------
+ */
+static inline struct trigger *find_trigger_by_name(const char *name)
+{
+	struct kobject *kobj;
+	kobj = kset_find_obj(&trigger_subsys.kset, name);
+	if (kobj) 
+		return container_of(kobj, struct trigger, kobj);
+
+	return NULL;
+}
+
+static inline struct interceptor *find_interceptor_by_name(const char
*name)
+{
+	struct kobject *kobj;
+	kobj = kset_find_obj(&interceptor_subsys.kset, name);
+	if (kobj)
+		return container_of(kobj, struct interceptor, kobj);
+
+	return NULL;
+}
+
+/*
+ * ===========================================================
+ *       <>-- Code segment functions --<>
+ * -----------------------------------------------------------
+ */
+static struct code_segment_attribute code_segment_attr_ctl;
+
+static inline void create_code_segment_files(struct code_segment *cs)
+{
+	sysfs_create_file(&cs->kobj, &code_segment_attr_ctl.attr);
+}
+
+static inline void remove_code_segment_files(struct code_segment *cs)
+{
+	sysfs_remove_file(&cs->kobj, &code_segment_attr_ctl.attr);
+}
+
+static inline void add_code_segment(struct code_segment *cs, struct
trigger *t) 
+{
+	kobject_get(&t->kobj);
+	kobject_get(&cs->kobj);
+	list_add(&cs->list, &t->cs_list);
+	cs->tri = t;
+}
+
+static inline void del_code_segment(struct code_segment *cs)
+{
+	struct trigger *t = cs->tri;
+	
+	list_del(&cs->list);
+	cs->tri = NULL;
+	kobject_put(&cs->kobj);
+	kobject_put(&t->kobj);
+}
+
+static inline void del_cs_list(struct list_head *head) {
+	struct list_head *pos;
+	struct list_head *tmp;
+	list_for_each_safe (pos, tmp, head) {
+		del_code_segment(list_entry(pos, struct code_segment, list));
+	}
+}	
+
+/*
+ * ===========================================================
+ *       <>-- Trigger functions --<>
+ * -----------------------------------------------------------
+ */
+static struct trigger_attribute trigger_attr_wp;
+static struct trigger_attribute trigger_attr_bitmask;
+static struct trigger_attribute trigger_attr_min;
+static struct trigger_attribute trigger_attr_max;
+static struct trigger_attribute trigger_attr_skip;
+static struct trigger_attribute trigger_attr_stop;
+static struct trigger_attribute trigger_attr_protection;
+static struct trigger_attribute trigger_attr_hertz;
+static struct trigger_attribute trigger_attr_registered;
+static struct trigger_attribute trigger_attr_opcode;
+static struct trigger_attribute trigger_attr_operand;
+static struct trigger_attribute trigger_attr_count;
+static struct trigger_attribute trigger_attr_intcpt;
+
+static inline void create_trigger_files(struct trigger *t)
+{
+	sysfs_create_file(&t->kobj, &trigger_attr_wp.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_bitmask.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_min.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_max.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_skip.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_stop.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_protection.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_hertz.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_registered.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_opcode.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_operand.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_count.attr);
+	sysfs_create_file(&t->kobj, &trigger_attr_intcpt.attr);
+}
+
+static inline void remove_trigger_files(struct trigger *t)
+{
+	sysfs_remove_file(&t->kobj, &trigger_attr_wp.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_bitmask.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_min.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_max.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_skip.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_stop.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_protection.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_hertz.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_registered.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_opcode.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_operand.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_count.attr);
+	sysfs_remove_file(&t->kobj, &trigger_attr_intcpt.attr);
+}
+
+static inline void unarm_trigger(struct trigger *t)
+{
+	(t->intcpt->disarm)(t);
+	list_del(&t->list);
+}
+
+static inline int arm_trigger(struct trigger *t, const char
*intcpt_name)
+{
+	int rv;
+	struct interceptor * i;
+	i = find_interceptor_by_name(intcpt_name);
+	if (!i) return -1;
+	t->intcpt = i;
+	list_add(&t->list, &i->tri_list);
+	rv = (i->arm)(t);
+	if (rv) {
+		list_del(&t->list);
+	}
+	return rv;
+}
+
+static inline ssize_t add_trigger(struct trigger *t, const char
*intcpt_name)
+{
+	struct trigger *n;
+
+	n = kmalloc(sizeof(struct trigger),GFP_KERNEL);
+	
+	if (!n)	return -ENOMEM;
+	
+	memset(n,0,sizeof(struct trigger));
+	INIT_LIST_HEAD(&n->cs_list);
+	INIT_LIST_HEAD(&n->list);
+	
+	strncpy(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN);
+	n->kobj.kset = &trigger_subsys.kset;
+	n->wp.addr    = t->wp.addr;
+	n->wp.type    = t->wp.type;
+	n->bitmask    = t->bitmask;
+	n->min        = t->min;
+	n->max        = t->max;
+	n->skip       = t->skip;
+	n->stop       = t->stop;
+	n->protection = t->protection;
+	n->hertz      = t->hertz;
+	n->registered = t->registered;
+	n->opcode     = t->opcode;
+	n->operand    = t->operand;
+	atomic_set(&n->count, 0);
+
+	if (kobject_register(&n->kobj)) {
+		err("Unable to register kobject");
+		return -EINVAL;
+	}
+
+	if (arm_trigger(n, intcpt_name)) {
+		err("Unable to arm the trigger, unregister %s", 
+		    n->kobj.name);
+		kobject_unregister(&n->kobj);
+		kfree(n);
+		return -EINVAL;
+	}
+	
+	create_trigger_files(n);
+	return 0;
+}
+
+static inline void del_trigger(struct trigger *t)
+{	
+	unarm_trigger(t);
+	remove_trigger_files(t);
+	del_cs_list(&t->cs_list);
+	kobject_unregister(&t->kobj);
+}
+
+static inline ssize_t del_trigger_by_name(const char *tri_name)
+{
+	struct trigger * t;
+
+	t = find_trigger_by_name(tri_name);
+	if (!t)	{
+		err("trigger %s does not exist", tri_name);
+		return -EINVAL;
+	}
+	
+	del_trigger(t);
+	return 0;
+
+}
+
+static inline void del_triggers(struct list_head *head)
+{
+	struct list_head *pos;
+	struct list_head *tmp;
+	
+	list_for_each_safe (pos, tmp, head) {
+		del_trigger(list_entry(pos, struct trigger, list));
+	}
+}
+
+/*
+ * ===========================================================
+ *     <>-- Toplevel Containing Subsystem (fi_subsys) --<>
+ * -----------------------------------------------------------
+ */
+
+static ssize_t fi_debug_show(struct subsystem *s, char *page)
+{
+	return sprintf(page,"%i\n",fi_debug);
+}
+
+static ssize_t fi_debug_store(struct subsystem *s, const char *page,
+			      size_t count)
+{
+	int tmp;
+	int num;
+	int ret = 0;
+
+	num = sscanf(page,"%i",&tmp);
+	if (!num) {
+		ret = -EINVAL;
+		goto Done;
+	}
+	
+	if (tmp) {
+		fi_debug = 1;
+	} else {
+		fi_debug = 0;
+	}
+
+Done:
+	return ret ? ret : count;
+}
+
+static decl_subsys(fi, NULL);
+
+static struct subsys_attribute fi_subsys_attr_debug = {
+	.attr	= { .name = "debug", .mode = 0644 },
+	.show	= fi_debug_show,
+	.store	= fi_debug_store,
+};
+
+/*
+ * ===============================================================
+ * <>-- Interceptor Containing Subsystem (interceptor_subsys) --<>
+ * ---------------------------------------------------------------
+ */
+
+static ssize_t interceptor_attr_show(struct kobject * kobj, 
+				     struct attribute * attr,
+				     char * page)
+{
+	struct interceptor * i = container_of(kobj,struct interceptor,kobj);
+	struct interceptor_attribute * a = 
+		container_of(attr,struct interceptor_attribute,attr);
+
+	dbg("about to call show function for %s", a->attr.name);
+	return a->show ? a->show(i,page) : 0;
+}
+
+static ssize_t interceptor_attr_store(struct kobject * kobj, 
+				      struct attribute * attr,
+				      const char * page,
+				      size_t count)
+{
+	struct interceptor * i = container_of(kobj,struct interceptor,kobj);
+	struct interceptor_attribute * a = 
+		container_of(attr,struct interceptor_attribute,attr);
+
+	dbg("about to call store function for %s", a->attr.name);
+	return a->store ? a->store(i,page,count) : 0;
+};
+
+static struct sysfs_ops interceptor_sysfs_ops = {
+	.show	= interceptor_attr_show,
+	.store  = interceptor_attr_store,
+};
+
+static struct kobj_type interceptor_ktype = {
+	.sysfs_ops = &interceptor_sysfs_ops
+};
+
+static decl_subsys(interceptor, &interceptor_ktype);
+
+/*
+ * ===========================================================
+ *       <>-- Trigger Subsystem (trigger_subsys) --<>
+ * -----------------------------------------------------------
+ */
+
+static ssize_t trigger_attr_show(struct kobject * kobj, 
+				 struct attribute * attr,
+				 char * page)
+{
+	struct trigger * n = container_of(kobj,struct trigger,kobj);
+	struct trigger_attribute * trigger_attr = 
+		container_of(attr,struct trigger_attribute,attr);
+
+	dbg("about to call show function for %s", trigger_attr->attr.name);
+	return trigger_attr->show ? trigger_attr->show(n,page) : 0;
+}
+
+static ssize_t trigger_attr_store(struct kobject * kobj, 
+				  struct attribute * attr,
+				  const char * page,
+				  size_t count)
+{
+	struct trigger * n = container_of(kobj,struct trigger,kobj);
+	struct trigger_attribute * trigger_attr = 
+		container_of(attr,struct trigger_attribute,attr);
+
+	dbg("about to call store function for %s", trigger_attr->attr.name);
+	return trigger_attr->store ? trigger_attr->store(n,page,count) : 0;
+}
+
+static struct sysfs_ops trigger_sysfs_ops = {
+	.show	= trigger_attr_show,
+	.store  = trigger_attr_store,
+};
+
+static struct kobj_type trigger_ktype = {
+	.sysfs_ops = &trigger_sysfs_ops
+};
+
+static decl_subsys(trigger, &trigger_ktype);
+
+static ssize_t trigger_wp_read(struct trigger * p, char * page)
+{
+	dbg("wp.addr = %#lx, wp.type = %#x", p->wp.addr, p->wp.type);
+	return sprintf(page,"%#lx %#x\n",
+		       p->wp.addr,p->wp.type);
+}
+static struct trigger_attribute trigger_attr_wp = {
+	.attr	= { .name = "wp", .mode = S_IRUGO },
+	.show	= trigger_wp_read,	
+};
+
+static ssize_t trigger_bitmask_read(struct trigger * p, char * page)
+{
+	dbg("bitmask = %#x", p->bitmask);
+	return sprintf(page,"%#x\n",p->bitmask);
+}
+static struct trigger_attribute trigger_attr_bitmask = {
+	.attr	= { .name = "bitmask", .mode = S_IRUGO },
+	.show	= trigger_bitmask_read,	
+};
+
+static ssize_t trigger_min_read(struct trigger * p, char * page)
+{
+	dbg("min = %i", p->min);
+	return sprintf(page,"%i\n",p->min);
+}
+static struct trigger_attribute trigger_attr_min = {
+	.attr	= { .name = "min", .mode = S_IRUGO },
+	.show	= trigger_min_read,	
+};
+
+static ssize_t trigger_max_read(struct trigger * p, char * page)
+{
+	dbg("max = %i", p->max);
+	return sprintf(page,"%i\n",p->max);
+}
+static struct trigger_attribute trigger_attr_max = {
+	.attr	= { .name = "max", .mode = S_IRUGO },
+	.show	= trigger_max_read,	
+};
+
+static ssize_t trigger_skip_read(struct trigger * p, char * page)
+{
+	dbg("skip = %i", p->skip);
+	return sprintf(page,"%i\n",p->skip);
+}
+static struct trigger_attribute trigger_attr_skip = {
+	.attr	= { .name = "skip", .mode = S_IRUGO },
+	.show	= trigger_skip_read,	
+};
+
+static ssize_t trigger_stop_read(struct trigger * p, char * page)
+{
+	dbg("stop = %i", p->stop);
+	return sprintf(page,"%i\n",p->stop);
+}
+static struct trigger_attribute trigger_attr_stop = {
+	.attr	= { .name = "stop", .mode = S_IRUGO },
+	.show	= trigger_stop_read,	
+};
+
+static ssize_t trigger_protection_read(struct trigger * p, char * page)
+{
+	dbg("protection = %i", p->protection);
+	return sprintf(page,"%i\n",p->protection);
+}
+
+static struct trigger_attribute trigger_attr_protection = {
+	.attr	= { .name = "protection", .mode = S_IRUGO },
+	.show	= trigger_protection_read,	
+};
+
+static ssize_t trigger_hertz_read(struct trigger * p, char * page)
+{
+	dbg("hertz = %i", p->hertz);
+	return sprintf(page,"%i\n",p->hertz);
+}
+
+static struct trigger_attribute trigger_attr_hertz = {
+	.attr	= { .name = "hertz", .mode = S_IRUGO },
+	.show	= trigger_hertz_read,	
+};
+
+static ssize_t trigger_registered_read(struct trigger * p, char * page)
+{
+	dbg("registered = %i", p->registered);
+	return sprintf(page,"%i\n",p->registered);
+}
+
+static struct trigger_attribute trigger_attr_registered = {
+	.attr	= { .name = "registered", .mode = S_IRUGO },
+	.show	= trigger_registered_read,	
+};
+
+static ssize_t trigger_count_read(struct trigger * p, char * page)
+{
+	dbg("count = %i", atomic_read(&p->count));
+	return sprintf(page,"%i\n",atomic_read(&p->count));
+}
+
+static struct trigger_attribute trigger_attr_count = {
+	.attr	= { .name = "count", .mode = S_IRUGO },
+	.show	= trigger_count_read,	
+};
+
+static ssize_t trigger_intcpt_read(struct trigger * p, char * page)
+{
+	return sprintf(page,"%s\n",p->intcpt->kobj.name);
+}
+
+static struct trigger_attribute trigger_attr_intcpt = {
+	.attr	= { .name = "interceptor", .mode = S_IRUGO },
+	.show	= trigger_intcpt_read,	
+};
+
+static inline ssize_t print_cs_list(struct list_head *head, 
+				    char *page) 
+{
+	int i = 0;
+	struct code_segment *pos;
+	list_for_each_entry (pos, head, list) {
+		i += sprintf(page+i, "code segment name: %s\n", 
+			     pos->kobj.name);
+	}
+	return 0;
+}
+
+static ssize_t trigger_opcode_read(struct trigger * p, char * page)
+{
+	dbg("opcode = %i", p->opcode);
+	if (list_empty(&p->cs_list)) {
+		return sprintf(page,"op code: %i\n",p->opcode);
+	} else {
+		int i;
+		i =  print_cs_list(&p->cs_list, page);
+		return i;
+	}
+}
+
+static struct trigger_attribute trigger_attr_opcode = {
+	.attr	= { .name = "opcode", .mode = S_IRUGO },
+	.show	= trigger_opcode_read,	
+};
+
+static ssize_t trigger_operand_read(struct trigger * p, char * page)
+{
+	dbg("operand = %i", p->operand);
+	if (list_empty(&p->cs_list)) {
+		return sprintf(page,"%i\n",p->operand);
+	} else {
+		return sprintf(page,"(no used)\n");
+	}
+}
+
+static struct trigger_attribute trigger_attr_operand = {
+	.attr	= { .name = "operand", .mode = S_IRUGO },
+	.show	= trigger_operand_read,	
+};
+
+static ssize_t trigger_ctl_show(struct subsystem *s, char *page)
+{
+	return 0;
+}
+
+static ssize_t trigger_ctl_store(struct subsystem *s, const char *page,
+				 size_t count)
+{
+	char ctl[KOBJ_NAME_LEN];
+	char intcpt[KOBJ_NAME_LEN];
+	int num;
+	int ret = 0;
+	struct trigger tmp;
+
+	/*                      3  4  5   6  7  8  9 10 11 12 13 14 15 16 17
*/
+	/*                    ctl nm ic  wa wb bm mn mx sk st pt hz rg oc oa
*/
+	num = sscanf( page, "%15s %s %s %lx %x %x %i %i %i %i %i %i %i %i %i",
+		      ctl,                /* 3  */
+		      tmp.kobj.name,      /* 4  */
+		      intcpt,             /* 5  */
+		      &tmp.wp.addr,       /* 6  */
+		      &tmp.wp.type,       /* 7  */
+		      &tmp.bitmask,       /* 8  */
+		      &tmp.min,           /* 9  */
+		      &tmp.max,           /* 10 */
+		      &tmp.skip,          /* 11 */
+		      &tmp.stop,          /* 12 */
+		      &tmp.protection,    /* 13 */
+		      &tmp.hertz,         /* 14 */
+		      &tmp.registered,    /* 15 */
+		      (int *)&tmp.opcode, /* 16 */
+		      &tmp.operand);      /* 17 */
+	if (!num) {
+		err("Invalid command format, translated no commands");
+		ret = -EINVAL;
+		goto Done;
+	}
+	
+	if (!strcmp(ctl,"add") && num == 15) {
+		dbg("intcpt = '%s'", intcpt);
+		ret = add_trigger(&tmp, intcpt);
+	} else if (!strcmp(ctl,"del") && num == 2) {
+		ret = del_trigger_by_name(tmp.kobj.name);
+	} else {
+		err("Invalid command format: %s, %i tokens found",ctl,num);
+		ret = -EINVAL;
+	}
+
+Done:
+	return ret ? ret : count;
+}
+
+static struct subsys_attribute trigger_subsys_attr_ctl = {
+	.attr	= { .name = "ctl", .mode = 0644 },
+	.show	= trigger_ctl_show,
+	.store	= trigger_ctl_store,
+};
+
+
+/*
+ * ===============================================================
+ * <>-- Code Segment Containing Subsystem (code_segment_subsys) --<>
+ * ---------------------------------------------------------------
+ */
+static ssize_t code_segment_attr_show(struct kobject * kobj, 
+				     struct attribute * attr,
+				     char * page)
+{
+	struct code_segment * cs = container_of(kobj,struct
code_segment,kobj);
+	struct code_segment_attribute * a = 
+		container_of(attr,struct code_segment_attribute,attr);
+
+	dbg("about to call show function for %s", a->attr.name);
+	return a->show ? a->show(cs,page) : 0;
+}
+
+static ssize_t code_segment_attr_store(struct kobject * kobj, 
+				      struct attribute * attr,
+				      const char * page,
+				      size_t count)
+{
+	struct code_segment * cs = container_of(kobj,struct
code_segment,kobj);
+	struct code_segment_attribute * a = 
+		container_of(attr,struct code_segment_attribute,attr);
+
+	dbg("about to call store function for %s", a->attr.name);
+	return a->store ? a->store(cs,page,count) : 0;
+}
+
+static struct sysfs_ops code_segment_sysfs_ops = {
+	.show	= code_segment_attr_show,
+	.store  = code_segment_attr_store,
+};
+
+static struct kobj_type code_segment_ktype = {
+	.sysfs_ops = &code_segment_sysfs_ops
+};
+
+static decl_subsys(code_segment, &code_segment_ktype);
+
+static ssize_t code_segment_ctl_show(struct code_segment *cs,
+				     char * page)
+{
+	if (cs->tri) {
+		return sprintf(page, "%s\n", cs->tri->kobj.name);
+	} else {
+		return sprintf(page, "%s\n",
+				"Usage: attach|detach [trigger_name]");
+	}
+}
+
+static ssize_t code_segment_ctl_store(struct code_segment *cs,
+				      const char *page, 
+				      size_t count)
+{
+	char ctl[KOBJ_NAME_LEN];
+	char tri_name[KOBJ_NAME_LEN];
+	int num;
+	int ret = 0;
+	struct trigger *t;
+
+	num = sscanf(page, "%15s %15s", ctl, tri_name);
+	if (!num) {
+		err("Invalid command format, translated no commands");
+		ret = -EINVAL;
+		goto Done;
+	}
+	
+	if (!strcmp(ctl, "attach") && num==2) {
+		if (cs->tri) {
+			err("Unable to attach more trigger");
+			ret = -EINVAL;
+			goto Done;
+		}
+		dbg("trigger = '%s'", tri_name);
+		t = find_trigger_by_name(tri_name);
+		if (t) {
+			add_code_segment(cs, t);
+		} else {
+			err("Unable to find trigger %s", tri_name);
+		}
+	} else if (!strcmp(ctl, "detach") && num==1) {
+		if (!cs->tri) {
+			err("No trigger is attached");
+			ret = -EINVAL;
+			goto Done;
+		}
+		del_code_segment(cs);
+	} else {
+		err("Invalid command format: %s, %i tokens found",ctl,num);
+		ret = -EINVAL;
+	}
+Done:
+	return ret ? ret : count;
+}
+
+static struct code_segment_attribute code_segment_attr_ctl = {
+	.attr = { .name = "ctl", .mode = 0644 },
+	.show = code_segment_ctl_show,
+	.store= code_segment_ctl_store
+};
+
+/*
+ * ===============================================================
+ * <>-- Others ;) --<>
+ * ---------------------------------------------------------------
+ */
+
+static inline int is_in_random(int hertz) 
+{
+	int tmp;
+	if (hertz==0 || hertz==1) return 1;
+	get_random_bytes(&tmp, sizeof(tmp));
+	return (tmp < 0xFFFFFFFF/hertz); 
+}
+
+static inline int is_in_range(int data, int min, int max, int bitmask)
+{
+	int tmp;
+	if (min==0 && max==0) return 1;
+	tmp = data & (~bitmask);
+	if ( min<=tmp && tmp<max) return 1;
+	return 0;
+}
+		
+static inline int is_ready(struct trigger *t, unsigned int val) 
+{	
+    	if ( is_in_random(t->hertz) 
+		&& is_in_range(val, t->min, t->max, t->bitmask)) {
+		return 1;
+	}
+	return 0;
+}
+
+static inline int is_in_count(int count, int skip, int stop) 
+{
+	if (skip >= count) return 0;
+	if (stop!=0 && (stop+skip) <count) return 0;
+	return 1;
+}
+
+static inline int protect_bits(int new, int orig, int bitmask) 
+{
+	return (new&(~bitmask)) | (orig&bitmask);
+}
+
+void fi_execute_trigger(struct trigger *t, struct interceptor *i,
+			__u32 val, int len, int type, void *data)
+{
+	int tmp = 0;
+
+	if (!t) {
+		err("Unable to execute null trigger");
+		return;
+	}
+
+	if(!is_ready(t,val)) return;
+
+	/* increase count only when all conditions have passed */
+	atomic_inc(&t->count);
+
+	if(!is_in_count(atomic_read(&t->count), t->skip, t->stop)) return;
+
+	dbg("count=%d, skip=%d, min=%d, max=%d, val=%d",
+	    atomic_read(&t->count), t->skip, t->min, t->max, val);
+	
+	if (!list_empty(&t->cs_list)) {
+		struct code_segment *pos;
+		list_for_each_entry (pos, &t->cs_list, list) {
+			pos->execute_trigger(t, i, val, len, type, data);
+		}
+		return;
+	}
+	
+	//legacy trigger logic code
+	tmp = val;
+	switch (t->opcode) {
+	case TRIGGER_OPCODE_NOTHING:
+		goto exit_for;
+	case TRIGGER_OPCODE_SET:
+		tmp = t->operand;
+		break;
+	case TRIGGER_OPCODE_AND:
+		tmp &= t->operand;
+		break;
+	case TRIGGER_OPCODE_OR:
+		tmp |= t->operand;
+		break;
+	case TRIGGER_OPCODE_NOT:
+		tmp = ~tmp;
+		break;
+	case TRIGGER_OPCODE_XOR:
+		tmp ^= t->operand;
+		break;
+	case TRIGGER_OPCODE_NAND:
+		tmp = ~(tmp & t->operand);
+		break;
+	case TRIGGER_OPCODE_NOR:
+		tmp = ~(tmp | t->operand);
+		break;
+	case TRIGGER_OPCODE_ADD:
+		tmp = tmp + t->operand;
+		break;
+	case TRIGGER_OPCODE_SUB:
+		tmp = tmp - t->operand;
+		break;
+	default:
+		err("Not recognized opcode%d", t->opcode);
+		break;
+	}
+
+ exit_for:
+	val = protect_bits(tmp, val, t->protection);
+
+	i->corrupt(val, data);
+	return;	
+}
+
+static int __init fi_init(void);
+int fi_register_interceptor(struct interceptor *i)
+{
+	int rv ;
+	
+	/*
+	 * If an interceptor is able to initialize
+	 * before we are then do our own initialization
+	 * before going on
+	 */
+	if (!is_initialized)
+		fi_init();
+
+	dbg("registering interceptor %s", i->kobj.name);
+	i->kobj.kset = &interceptor_subsys.kset;
+	INIT_LIST_HEAD(&i->tri_list); 
+	rv = kobject_register(&i->kobj);
+	if (rv) {
+		err("Unable to register kobject");
+	}
+	return rv;
+}
+
+void fi_unregister_interceptor(struct interceptor *i)
+{
+	del_triggers(&i->tri_list);
+	kobject_unregister(&i->kobj);
+}
+
+int fi_register_code_segment(struct code_segment *cs)
+{
+	int rv;
+	
+	if (!is_initialized)
+		fi_init();
+
+	dbg("registering code segment %s", cs->kobj.name);
+	cs->kobj.kset = &code_segment_subsys.kset;
+	rv = kobject_register(&cs->kobj);
+	if (rv) {
+		err("Unable to register kobject");
+	}
+	create_code_segment_files(cs);
+	return 0;
+}
+
+void fi_unregister_code_segment(struct code_segment *cs)
+{
+	if (cs->tri) del_code_segment(cs);
+	remove_code_segment_files(cs);
+	kobject_unregister(&cs->kobj);
+}
+
+static int __init fi_init(void)
+{
+	down(&fi_sem);
+	if (is_initialized) {
+		dbg("alreading initialized... exiting");
+		goto Done;
+	}
+
+	dbg("initializing fault injection core");
+	
+	
+	interceptor_subsys.kset.subsys = &fi_subsys;
+	code_segment_subsys.kset.subsys = &fi_subsys;
+	trigger_subsys.kset.subsys = &fi_subsys;
+	
+	subsystem_register(&fi_subsys);
+	subsys_create_file(&fi_subsys,&fi_subsys_attr_debug);
+	subsystem_register(&code_segment_subsys);
+	subsystem_register(&interceptor_subsys);
+	subsystem_register(&trigger_subsys);
+	subsys_create_file(&trigger_subsys,&trigger_subsys_attr_ctl);
+	is_initialized++;
+Done:
+	up(&fi_sem);
+	return 0;
+}
+
+static void __exit fi_exit(void)
+{
+	dbg("exit fault injection core");
+	subsys_remove_file(&trigger_subsys,&trigger_subsys_attr_ctl);
+	subsystem_unregister(&trigger_subsys);
+	subsystem_unregister(&interceptor_subsys);
+	subsystem_unregister(&code_segment_subsys);
+	subsys_remove_file(&fi_subsys,&fi_subsys_attr_debug);
+	subsystem_unregister(&fi_subsys);
+}
+
+/* Is there a better way to get my init code to execute on startup? */
+module_init(fi_init);
+module_exit(fi_exit);
+
+EXPORT_SYMBOL_GPL(fi_register_interceptor);
+EXPORT_SYMBOL_GPL(fi_unregister_interceptor);
+EXPORT_SYMBOL_GPL(fi_register_code_segment);
+EXPORT_SYMBOL_GPL(fi_unregister_code_segment);
+EXPORT_SYMBOL_GPL(fi_execute_trigger);
+EXPORT_SYMBOL_GPL(fi_debug);
+
+MODULE_PARM(fi_debug, "i");
+MODULE_PARM_DESC(fi_debug, "Debugging mode enabled or not");
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/fi/interceptors/Makefile
b/drivers/fi/interceptors/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,9 @@
+#
+# Kernel Fault Injection Interceptors
+#
+
+EXTRA_AFLAGS	:= -traditional
+
+obj-$(CONFIG_FI_IRQ)	+= fi_irq.o
+obj-$(CONFIG_FI_DBP)	+= dbp/
+obj-$(CONFIG_FI_PF)	+= pf/
diff -Nru a/drivers/fi/interceptors/dbp/Makefile
b/drivers/fi/interceptors/dbp/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/dbp/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux kernel.
+#
+export-objs = fi_dbp.o
+
+obj-$(CONFIG_FI_DBP) += fi_dbp.o
+
+
+EXTRA_AFLAGS   := -traditional
diff -Nru a/drivers/fi/interceptors/dbp/fi_dbp.c
b/drivers/fi/interceptors/dbp/fi_dbp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/dbp/fi_dbp.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,563 @@
+/******************************************************************************
+ *  Fault Injection Test harness (FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ */
+
+/*  $Id: fi_dbp.c,v 1.9 2002/11/19 08:03:04 brlock Exp $ 
+ *  Copyright by Intel Crop., 2002 
+ *  Stanley Wang (stanley.wang@intel.com)
+ *
+ */
+
+/**
+ * @file dbp.c
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/debugreg.h>
+#include <asm/uaccess.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+#include <linux/list.h>
+#include <linux/kprobes.h>
+
+#include <linux/fi.h>
+
+#define MAX_WP 32
+
+/*define reason of entering do_debug*/
+#define REASON_NOTME	0
+#define REASON_READ	1
+#define REASON_WRITE	2
+
+#define PREFIX_16	0x66
+
+struct opcode {
+	unsigned int 	port;
+	unsigned int 	write;
+	unsigned int 	len; /*0:byte    1:word    2:double word*/
+	unsigned int 	inst_len;
+};
+
+struct corrupt {
+	unsigned long	*preg;
+	unsigned long 	mask;
+};
+
+struct inst_rec {
+	struct list_head	list;	
+	struct kprobe		kprobe;
+};
+
+struct {
+	struct watchpoint 	wp;
+	struct trigger		*trigger;
+	spinlock_t 		lock;
+}wp_tb[MAX_WP] = { [0 ... MAX_WP-1] = {{0,0}, NULL,
SPIN_LOCK_UNLOCKED}};
+
+struct {
+	int 			reason;
+	int			wp_tab_id;
+	unsigned long		value;
+	unsigned char		cancel_opcode;
+	struct inst_rec		*inst;
+	struct opcode		op;
+}which_inst[NR_CPUS] = {[0 ... NR_CPUS-1] = {-1, -1, 0, 0, NULL, {0, 0,
0, 0}}};
+
+static DECLARE_MUTEX(dbp_sem);
+static LIST_HEAD(inst_rec_head);
+static struct interceptor dbp_interceptor;
+
+static int dbp_arm(struct trigger *t);
+void dbp_disarm(struct trigger *t);
+void dbp_corrupt(__u32 dirty, void *data);
+int get_IO_opcode(struct opcode *op, struct pt_regs *regs);
+
+int add_ins(const char *page);
+void clear_ins(void);
+
+void post_probe_handler(struct kprobe *, struct pt_regs *, unsigned
long);
+void pre_probe_handler(struct kprobe *, struct pt_regs *);
+void rmmod_exit(struct module *);
+
+	
+static inline int find_wp(unsigned long addr){
+    int i=0;
+
+    for (i=0; i<MAX_WP; i++) {
+	if (addr == wp_tb[i].wp.addr) {
+	    break;
+	}
+    }
+    return i;
+};
+
+static int dbp_arm(struct trigger *t)
+{
+	unsigned long flags; 
+	int i=0;
+
+	if ( t->wp.type& (~FI_WPTYPE_ALL_MASK) ) {
+		err("Reason: %s\n", "/* There are reserved bits in use*/");
+		return -EINVAL;
+	}
+	if (!is_IO(t->wp.type)) {
+    		err("Reason: %s\n", "/* Isn't I/O access*/");
+    		return -EINVAL;
+	}
+	if ( (unsigned int)t->wp.addr>0xffff ) {
+    		err("Reason: %s\n", "/* beyond 64k IO space*/");
+    		return -EINVAL;
+	}
+
+
+	/* Make sure there are no the same wp or id */
+	for (i=0; i<MAX_WP; i++){
+    		if (t->wp.addr==wp_tb[i].wp.addr) {
+        		err("Reason: %s\n", "/*there are same wp*/");
+        		return -EINVAL;
+    		}
+	}
+
+find_empty_wp:
+	/* find empty item in wp_tb */
+	for (i=0; i<MAX_WP; i++){
+    		if (wp_tb[i].wp.addr==0){
+        	break;
+    		}
+	}
+	if (i>=MAX_WP) return -EINVAL;
+
+	/*LOCK! NOTICE!!!*/
+	spin_lock_irqsave(&wp_tb[i].lock, flags);
+	if (wp_tb[i].wp.addr!=0) {
+		//if there is some one who changed the wp before we lock it
+		spin_unlock_irqrestore(&wp_tb[i].lock, flags);
+		goto find_empty_wp;
+	}
+
+	/* register this wp into wp_tb*/
+	wp_tb[i].wp.addr = t->wp.addr;
+	wp_tb[i].wp.type = t->wp.type;
+	wp_tb[i].trigger = t;
+
+	/* UNLOCK! NOTICE!!! */
+	spin_unlock_irqrestore(&wp_tb[i].lock, flags);
+	return 0;
+}
+
+void dbp_disarm(struct trigger *t)
+{
+	unsigned long flags;
+	int i = 0;
+    
+find_wp_by_addr:
+	for (i=0; i<MAX_WP; i++) {
+		if (wp_tb[i].wp.addr == t->wp.addr) {
+			break;
+		}
+    	}
+    	if (i>=MAX_WP) return ;
+
+	/* LOCK */
+    	spin_lock_irqsave(&wp_tb[i].lock, flags);
+    	if (wp_tb[i].wp.addr!=t->wp.addr) {
+		spin_unlock_irqrestore(&wp_tb[i].lock, flags);
+		goto find_wp_by_addr;
+    	}
+
+	wp_tb[i].wp.addr = 0;
+    	wp_tb[i].wp.type = 0;
+	wp_tb[i].trigger = NULL;
+    	/* UNLOCK */
+    	spin_unlock_irqrestore(&wp_tb[i].lock, flags);
+	return; 
+}
+
+void dbp_corrupt(__u32 dirty, void *data)
+{
+	unsigned long mask = ((struct corrupt*)data)->mask;
+	*(((struct corrupt*)data)->preg) &= ~mask;
+	*(((struct corrupt*)data)->preg) |= (dirty&mask);
+	dbg("corrupt data to:%#lX\n", dirty&mask);
+	return;
+}
+
+int get_IO_opcode(struct opcode *op, struct pt_regs *regs)
+{
+	unsigned char *p;
+	int flag_16=0;
+	
+	p = (unsigned char*)(regs->eip);
+	if (*p == PREFIX_16) {
+		flag_16 = 1; /*word*/
+		p++;
+	}
+	switch(*p) {
+		case 0xec:
+			op->port = regs->edx;
+			op->write = 0;
+			op->len = 1; /*byte*/ 
+			op->inst_len = 1;
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xed:
+			op->port = regs->edx;
+			op->write = 0; 
+			if (flag_16) {
+				op->len = 2; /*word*/ 
+				op->inst_len = 2;
+			} else {
+				op->len = 4; /*double word*/
+				op->inst_len = 1;
+			}
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xee:
+			op->port = regs->edx;
+			op->write = 1;
+			op->len = 1; /*byte*/ 
+			op->inst_len = 1;
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xef:
+			op->port = regs->edx;
+			op->write = 1;
+			if (flag_16) {
+				op->len = 2; /*word*/ 
+				op->inst_len = 2;
+			} else {
+				op->len = 4; /*double word*/
+				op->inst_len = 1;
+			}
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xe4:
+			op->port = *(++p);
+			op->write = 0;
+			op->len = 1; /*byte*/ 
+			op->inst_len = 2;
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xe5:
+			op->port = *(++p);
+			op->write = 0;
+			if (flag_16) {
+				op->len = 2; /*word*/ 
+				op->inst_len = 3;
+			} else {
+				op->len = 4; /*double word*/
+				op->inst_len = 2;
+			}
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xe6:
+			op->port = *(++p);
+			op->write = 1;
+			op->len = 1; /*byte*/ 
+			op->inst_len = 2;
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		case 0xe7:
+			op->port = *(++p);
+			op->write = 1;
+			if (flag_16) {
+				op->len = 2; /*word*/ 
+				op->inst_len = 3;
+			} else {
+				op->len = 4; /*double word*/
+				op->inst_len = 2;
+			}
+			dbg("OPCODE: %lX\n",*(unsigned long*)p);
+			return 0;
+		default:
+			err("Can't analyze IO opcode! @%s\n", __FILE__);
+			return -EINVAL;
+	}
+
+	dbg("OPCODE: %lX\n",*(unsigned long*)p);
+	return 0;
+}
+
+void pre_probe_handler(struct kprobe *kprobe, struct pt_regs * regs)
+{
+	struct opcode op;
+	struct corrupt crpt;
+	int i;
+	unsigned long origin;
+	int cpu = smp_processor_id();
+	
+	dbg("Enter pre_probe_handler, Instruction @ %lX\n",(unsigned
long)(regs->eip - 1));
+	
+	*kprobe->addr = kprobe->opcode; /*restore the original opcode*/
+	regs->eip = (unsigned long)kprobe->addr; /*back step*/
+	
+	i = get_IO_opcode(&op, regs);
+	if ( i < 0 ) {
+		err("Can't analyze opcode! @%s\n", __FILE__);
+		goto exit;
+	}
+	
+	regs->eip += 1;
+	
+	which_inst[cpu].op.port = op.port;
+	which_inst[cpu].op.write = op.write;
+	which_inst[cpu].op.inst_len = op.inst_len;
+	which_inst[cpu].value = regs->eax;
+
+	i=0;
+	
+find_wp_by_addr:
+    	i=find_wp((unsigned long)(op.port));/*XXX*/
+    	if (i>=MAX_WP) {
+		/*not watched by me*/
+		which_inst[cpu].reason = REASON_NOTME;
+		goto exit;
+	}
+    	/*LOCK!*/
+    	spin_lock(&wp_tb[i].lock);
+    	if (wp_tb[i].wp.addr!=(unsigned long)(op.port)) {
+		//there are others who modify this wp
+		spin_unlock(&wp_tb[i].lock);
+		goto find_wp_by_addr;
+    	}
+    	if (op.write){
+		if (!is_write(wp_tb[i].wp.type)) {
+			spin_unlock(&wp_tb[i].lock);
+			which_inst[cpu].reason = REASON_NOTME;
+			goto exit;
+		}
+	}else if (!is_read(wp_tb[i].wp.type)) {
+		spin_unlock(&wp_tb[i].lock);
+		which_inst[cpu].reason = REASON_NOTME;
+		goto exit;
+	}
+	
+	which_inst[cpu].op.len = access_len(wp_tb[i].wp.type);
+	which_inst[cpu].wp_tab_id = i;
+	
+	if (op.write) {
+		/*inject write fault*/
+		crpt.preg = &(regs->eax);
+		switch (which_inst[cpu].op.len) {
+			case 1:
+				crpt.mask =0xFF;
+				break;
+			case 2:
+				crpt.mask =0xFFFF;
+				break;
+			case 4:
+				crpt.mask =0xFFFFFFFF;
+				break;
+			default:
+				err("Wrong length!@%s\n", __FILE__);
+				break;
+		}
+		origin = (regs->eax)&crpt.mask;
+		fi_execute_trigger(wp_tb[i].trigger, &dbp_interceptor, origin, \
+					      op.len, op.write, &crpt); 
+    		/*UNLOCK*/
+    		spin_unlock(&wp_tb[i].lock);
+		which_inst[cpu].reason = REASON_WRITE;
+	}else {
+		/*inject read fault*/
+		which_inst[cpu].reason = REASON_READ;
+	}
+
+exit:
+    	return;
+}
+
+void post_probe_handler(struct kprobe *kprobe, struct pt_regs *regs,
unsigned long flags)
+{
+    	unsigned long origin;
+	struct corrupt crpt;
+    	int cpu;
+
+	cpu = smp_processor_id();
+	
+	dbg("Enter post_probe_handler @CPU%d\n", smp_processor_id());
+
+	switch (which_inst[cpu].reason) {
+		case REASON_WRITE:
+			regs->eax = which_inst[cpu].value;	
+		case REASON_NOTME:
+			which_inst[cpu].reason = -1;
+			break;
+		case REASON_READ:
+			which_inst[cpu].reason = -1;
+
+			crpt.preg = &(regs->eax);
+			if(which_inst[cpu].op.len == 1) {
+				crpt.mask =0xFF;
+			}
+			if(which_inst[cpu].op.len == 2) {
+				crpt.mask =0xFFFF;
+			}
+			if(which_inst[cpu].op.len == 4)	{
+				crpt.mask =0xFFFFFFFF;
+			}
+			if(which_inst[cpu].op.len > 4 || which_inst[cpu].op.len < 1) {
+				err("Wrong length!@%s\n", __FILE__);
+			}
+			origin = (regs->eax)&crpt.mask;
+			fi_execute_trigger(wp_tb[which_inst[cpu].wp_tab_id].trigger, \
+				 &dbp_interceptor,origin, which_inst[cpu].op.len, \
+				 which_inst[cpu].op.write, &crpt); 
+    			/*UNLOCK*/
+    			spin_unlock(&wp_tb[which_inst[cpu].wp_tab_id].lock);
+			break;
+		default:
+			return;
+	}
+    	return ;
+}
+
+int add_ins(const char *page)
+{
+	struct inst_rec	*inst;
+	char tmp[16];
+	int num=0;
+	unsigned long addr=0;
+	
+	num = sscanf(page, "%15s %lu", tmp, &addr);
+	if (num != 2) {
+		err("Invalid command format, translated no commands\n");
+		return -EINVAL;
+	}
+
+	inst=(struct inst_rec *)kmalloc(sizeof(struct inst_rec), GFP_KERNEL);
+	if (!inst) {
+		err("Allocate memory failed.\n");
+		return -ENOMEM;
+	}
+		
+	inst->kprobe.addr = (kprobe_opcode_t *)addr;
+	inst->kprobe.pre_handler = pre_probe_handler;
+	inst->kprobe.post_handler = post_probe_handler;
+	inst->kprobe.fault_handler = NULL;
+	if ( register_kprobe(&(inst->kprobe)) < 0 )	
+	{
+		kfree(inst);
+		err("register_kprobe failed @ %s\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	list_add(&inst->list, &inst_rec_head);
+	return 0;
+}
+
+void clear_ins(void)
+{
+	struct inst_rec *inst;
+
+	while (!list_empty(&inst_rec_head)) {
+		inst=list_entry(inst_rec_head.next, struct inst_rec, list);
+		list_del(&inst->list);
+		unregister_kprobe(&inst->kprobe);
+		kfree(inst);
+	}
+}
+static ssize_t ctl_show(struct interceptor * p, char * page)
+{
+	return 0;
+}
+
+static ssize_t ctl_store(struct interceptor * p, const char * page, 
+			 size_t count)
+{
+	char ctl[16];
+	int num;
+	int error=0;
+	
+	num = sscanf(page, "%15s", ctl);
+	if (!num) {
+		err("Invalid command format, translated no commands\n");
+		error = -EINVAL;
+		goto done;
+	}
+		
+	down(&dbp_sem);
+	if (!strncmp(ctl, "add", 3)) {
+		error = add_ins(page);
+	} else if (!strncmp(ctl, "clear", 5)) {
+		clear_ins();
+	} else {
+		err("Unknow command %s\n", page);
+		error = -EINVAL;
+	}
+	up(&dbp_sem);
+
+done:
+	return error ? error : count;
+}
+
+static struct interceptor_attribute attr_ctl = {
+	.attr  = { .name = "ctl", .mode = 0644 },
+	.show  = ctl_show,
+	.store = ctl_store,
+};
+
+static struct interceptor dbp_interceptor = {
+	.kobj    = {.name = "dbp_interceptor"},
+	.arm     = dbp_arm,
+	.disarm  = dbp_disarm,
+	.corrupt = dbp_corrupt
+};
+
+static int __init dbp_start(void)
+{
+	if (fi_register_interceptor(&dbp_interceptor)) {
+		dbg("Failed to register DBP Interceptor");
+		return -EINVAL;
+	}
+	
+	sysfs_create_file(&dbp_interceptor.kobj, &attr_ctl.attr);
+
+	EXPORT_NO_SYMBOLS;
+	return 0;
+}
+
+static void __exit dbp_stop(void)
+{
+	clear_ins();
+	sysfs_remove_file(&dbp_interceptor.kobj, &attr_ctl.attr);
+	fi_unregister_interceptor(&dbp_interceptor);
+	return;
+}
+
+module_init(dbp_start);
+module_exit(dbp_stop);
+
+MODULE_AUTHOR("Stanley Wang");
+MODULE_DESCRIPTION("DBP component for FI.");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/fi/interceptors/fi_irq.c
b/drivers/fi/interceptors/fi_irq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/fi_irq.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *  Fault Injection Test harness Irq Interceptor(FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ * Contributors:
+ * Louis Zhuang <louis.zhuang@intel.com>
+ * Stanley Wang <stanley.wang@intel.com>
+ * Rusty Lynch	<rusty.lynch@intel.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <linux/fi.h>
+#include <asm/kirq.h>
+
+struct fi_irq_faultset{
+	int irq_spurious_hertz;//0 means never do this
+	int irq_delay_hertz;
+	int irq_delay_time;//0 means lost
+	int num;
+	char devname[80];
+};
+
+static DECLARE_MUTEX(irq_sem);
+static int in_used=0;
+static struct fi_irq_faultset irq_fs[1];
+
+static int irq_spurious_count=0;
+static int irq_delay_count=0;
+static int irq_delay_time_count=0;
+static atomic_t irq_delay_num=ATOMIC_INIT(0);
+int fi_irq_handler(struct kirq *k, int num, void *id, struct pt_regs
*regs)
+{    
+	if (num == 0) { //it is timer interrupt
+		dispatch_kirq(num, regs);//dispatch timer first
+	
+		if (irq_fs->irq_spurious_hertz){
+			irq_spurious_count++;
+			if (irq_spurious_count>=irq_fs->irq_spurious_hertz){
+				irq_spurious_count=0;
+				dispatch_kirq(irq_fs->num, regs);
+				info("dispatch a spurious %s interrupt, num# %d\n",
irq_fs->devname, irq_fs->num);
+			}
+		}
+
+		if (atomic_read(&irq_delay_num)) {
+			irq_delay_time_count++;
+			if (irq_delay_time_count>=irq_fs->irq_delay_time) {
+				irq_delay_time_count=0;
+				atomic_dec(&irq_delay_num);
+				dispatch_kirq(irq_fs->num, regs);
+				info("dispatch a delayed %s interrupt, num# %d\n", irq_fs->devname,
irq_fs->num);
+			}
+		}
+	}else if (num == irq_fs->num) { //it is fake_irq
+		if (irq_fs->irq_delay_hertz) {
+			irq_delay_count++;
+			if (irq_delay_count>=irq_fs->irq_delay_hertz) {
+				if (irq_fs->irq_delay_time){
+					//FIXME:add spin lock
+					atomic_inc(&irq_delay_num);
+					info("announce a delayed %s interrupt, num# %d, jiffies: %ld\n", 
+					      irq_fs->devname, num, jiffies);
+				}else{
+					info("announce a lost %s interrupt, num# %d\n", irq_fs->devname,
num);
+				}
+				irq_delay_count=0;
+		
+			} else {
+				dispatch_kirq(num, regs);//dispatch timer first
+			}
+		} else {
+			dispatch_kirq(num, regs);//dispatch timer first
+		}
+	}else{
+		err("error interrupt! num# %d\n", num);
+	}
+	return 1;
+}
+
+
+static int set_irq_faultset(struct fi_irq_faultset *f) {
+	int rv=0;
+    
+	strncpy(irq_fs->devname, f->devname, 80);
+	irq_fs->num = f->num;
+	irq_fs->irq_spurious_hertz = f->irq_spurious_hertz;
+	irq_fs->irq_delay_hertz = f->irq_delay_hertz;
+	irq_fs->irq_delay_time = f->irq_delay_time;
+	
+	if ( register_kirq(irq_fs->num, irq_fs->devname, fi_irq_handler) != 0)
{
+		dbg("set irq faultset fail@%s, irq=%d, devname=%s, handler=%p\n", 
+				__FUNCTION__, irq_fs->num, irq_fs->devname, fi_irq_handler);
+		rv = -EINVAL;
+		goto exit;
+	}
+	if ( register_kirq(0, "timer", fi_irq_handler) != 0) {
+		dbg("set irq faultset fail@%s, irq=0, devname=timer, handler=%p\n", 
+				__FUNCTION__, fi_irq_handler);
+		rv = -EINVAL;
+	}
+
+exit:	
+	return rv;
+};
+static void clear_irq_faultset(void) 
+{
+	unregister_kirq(0);
+	unregister_kirq(irq_fs->num);
+
+     	irq_fs->num =0;
+	irq_fs->irq_spurious_hertz =0;
+	irq_fs->irq_delay_hertz =0;
+	irq_fs->irq_delay_time =0;	
+	
+	/* clear vars used by fi_irq_handler  */
+	irq_spurious_count=0;
+	irq_delay_count=0;
+	irq_delay_time_count=0;
+	atomic_set(&irq_delay_num, 0);
+};
+
+static ssize_t ctl_show(struct interceptor * p, char * page)
+{
+	return sprintf( page,
+			"IRQ Faultset:\n"
+			"Device Name = %s\n"	
+			"IRQ number = %d\n"
+			"Spurious Hertz = %d\n"
+			"Delay Hertz = %d\n"
+			"Delay Time = %d\n\n", 
+			irq_fs->num ? irq_fs->devname : "(NULL)",	
+			irq_fs->num, irq_fs->irq_spurious_hertz,
+			irq_fs->irq_delay_hertz,
+			irq_fs->irq_delay_time);
+}
+
+static ssize_t ctl_store(struct interceptor * p, const char * page,
size_t count)
+{
+	char ctl[16];
+	int num;
+	int error = 0;
+	struct fi_irq_faultset tmp;
+
+	/*                    3  4  5  6  7  8   */
+	/*                  ctl irq dn sh dh dt  */
+	num = sscanf(page,"%15s %i %s %i %i %i",
+			ctl,           			/* 3  */
+		     	&tmp.num,      			/* 4  */
+			tmp.devname,			/* 5  */
+			&tmp.irq_spurious_hertz,	/* 6  */
+			&tmp.irq_delay_hertz, 		/* 7  */
+			&tmp.irq_delay_time);		/* 8  */
+	if (!num) {
+		err("Invalid command format, translated no commands");
+		error = -EINVAL;
+		goto Done;
+	}
+	
+	down(&irq_sem);
+	if (!strcmp(ctl,"add") && num == 6){
+		if (tmp.num == 0) {
+			err("Intercept Timer IRQ is not permitted!\n");
+			error = -EACCES;
+		} else if ((in_used == 0) && ((error = set_irq_faultset(&tmp)) == 0))
{
+			in_used++;
+		} else {
+			err("Wrong IRQ faultset OR IRQ_INTERCEPTOR is in used!\n");
+			error = -EINVAL;
+		}
+	} else if (!strcmp(ctl,"del") && num == 1) {
+		if (in_used == 1) {
+			clear_irq_faultset();
+			in_used--;
+		} else {
+			err("IRQ_INTERCEPTOR is not in used!\nNO irq faultset to
remove.\n");
+			error = -EINVAL;
+		}
+	} else {
+		err("Invalid command format: %s, %i tokens found",ctl,num);
+		error = -EINVAL;
+	}
+	up(&irq_sem);
+
+Done:
+	return error ? error : count;
+}
+
+static struct interceptor_attribute attr_ctl = {
+	.attr  = { .name = "ctl", .mode = 0644 },
+	.show  = ctl_show,
+	.store = ctl_store
+};
+
+static struct interceptor irq_interceptor = {
+	.kobj    = {.name = "irq_interceptor"},
+	.arm     = NULL,
+	.disarm  = NULL,
+	.corrupt = NULL
+};
+
+static int __init fi_irq_init(void)
+{
+	if (fi_register_interceptor(&irq_interceptor)) {
+		dbg("Failed to register irq Interceptor");
+		return -EINVAL;
+	}
+	
+	sysfs_create_file(&irq_interceptor.kobj, &attr_ctl.attr);
+	return 0;
+}
+
+static void __exit fi_irq_exit (void)
+{
+	sysfs_remove_file(&irq_interceptor.kobj, &attr_ctl.attr);
+	fi_unregister_interceptor(&irq_interceptor);
+}
+
+module_init(fi_irq_init);
+module_exit(fi_irq_exit);
+
+
+MODULE_DESCRIPTION("Implementation for inject fault into IRQ");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/fi/interceptors/pf/Makefile
b/drivers/fi/interceptors/pf/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/pf/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+export-objs = fi_pf.o
+
+obj-$(CONFIG_FI_PF) += fi_pf.o
+fi_pf-objs := pf.o pf_in.o pf_utils.o
+
+
+EXTRA_AFLAGS   := -traditional
diff -Nru a/drivers/fi/interceptors/pf/fi_pf.h
b/drivers/fi/interceptors/pf/fi_pf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/pf/fi_pf.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *  Fault Injection Test harness (FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ */
+
+#ifndef __PF_H_
+#define __PF_H_
+
+/* 
+ * Delcare typedefs
+ */
+enum reason_type{
+	REG_READ	= 0,	/* read from addr to reg */ 
+	REG_WRITE	= 1,	/* write from reg to addr */
+	IMM_WRITE	= 2,	/* write from imm to addr */
+	OTHERS	= 3	/* Other instructions can not intercept */
+};
+
+/*
+ * Declare functions in pf_in.c
+ */
+enum reason_type get_ins_type(unsigned long ins_addr);
+unsigned int get_ins_width(unsigned long ins_addr);
+unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs
*regs);
+void set_ins_reg_val(unsigned long addr, struct pt_regs *regs, unsigned
long val);
+unsigned long get_ins_imm_val(unsigned long ins_addr);
+void set_ins_imm_val(unsigned long ins_addr, unsigned long val);
+
+/*
+ * Declare functions in pf_utils.c
+ */
+unsigned long fi_phy_to_virt(unsigned long phy_addr);
+
+#endif//__PF_H_
diff -Nru a/drivers/fi/interceptors/pf/pf.c
b/drivers/fi/interceptors/pf/pf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/pf/pf.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,284 @@
+/******************************************************************************
+ *  Fault Injection Test harness (FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ */
+
+/*  $Id: pf.c,v 1.2 2002/11/14 06:19:49 yzhuang Exp $ 
+ *  Copyright by Intel Crop., 2002 
+ *  Louis Zhuang (louis.zhuang@intel.com)
+ */
+
+/**
+ * @file pf.c
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/kmmio.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/highmem.h>
+
+#include <linux/fi.h>
+
+#include "fi_pf.h"
+
+static struct interceptor pf_interceptor;
+
+/* Wrapping trigger within the structure */
+struct pf_trigger {
+	struct kmmio_probe probe;
+	struct trigger	*trigger;
+	unsigned long eip;
+	enum reason_type type;
+	unsigned long val;
+};
+
+/**
+ * This is a KEY data structure. When interceptor triggers DM
+ * and then DM call iAction method. iAction remembers this corrupted
data.  
+ * Then DM returns to Interceptor and Interceptor returns corrupted
data 
+ * to intercepted access.
+ */
+struct pf_corrupt{
+	__u32 corrupted_data;
+};
+
+static unsigned long crpt_mask[] = { 0x000000FF, 0x0000FFFF,
0x00FFFFFF, 0xFFFFFFFF};
+
+extern void fi_execute_trigger(struct trigger *,struct interceptor *,
+			       __u32,int,int,void *);
+void pf_page_fault(struct kmmio_probe *p, struct pt_regs *regs,
unsigned long address) 
+{
+	struct pf_trigger *pft;
+	struct pf_corrupt crpt;
+	int ins_len, crpt_len;
+	
+	pft = container_of(p, struct pf_trigger, probe);;
+	
+	if (pft->probe.addr != (void*)address)
+		BUG();
+	
+	pft->eip = regs->eip; 
+	pft->type = get_ins_type(pft->eip);
+    
+	dbg("watching %p, type=%d\n", pft->probe.addr, pft->type);
+	
+	switch (pft->type) {
+	case OTHERS:
+		dbg("Hmm? Can not analyze the instruction, *eip=0x%08lx\n", 
+		       *(unsigned long *)pft->eip);
+		break;
+	case REG_WRITE:
+		dbg("reg_write instruction eip=0x%08lx\n", 
+		       pft->eip);
+		if (is_write(pft->trigger->wp.type)) {
+		    
+			ins_len = get_ins_width(pft->eip);
+			pft->val = get_ins_reg_val(pft->eip, regs);
+		
+			crpt_len = (WP_LEN(pft->trigger->wp)<ins_len)?
+				WP_LEN(pft->trigger->wp):ins_len;
+			crpt.corrupted_data = 
+				pft->val & crpt_mask[crpt_len-1];
+			fi_execute_trigger(pft->trigger,
+					   &pf_interceptor,
+					   crpt.corrupted_data,
+					   crpt_len, 1, &crpt);		
+			set_ins_reg_val(pft->eip, regs, 
+					(crpt.corrupted_data&crpt_mask[crpt_len-1]) 
+					| (pft->val&(~crpt_mask[crpt_len-1])));
+		}
+		break;
+	case IMM_WRITE:
+		dbg("imm_write instruction eip=0x%08lx\n", 
+		       pft->eip);
+		if (is_write(pft->trigger->wp.type)) {
+		    
+			ins_len = get_ins_width(pft->eip);
+			pft->val = get_ins_imm_val(pft->eip);
+		
+			crpt_len = (WP_LEN(pft->trigger->wp)<ins_len)?
+				WP_LEN(pft->trigger->wp):ins_len;
+			crpt.corrupted_data = pft->val & crpt_mask[crpt_len-1];		
+			fi_execute_trigger(pft->trigger, 
+					   &pf_interceptor,
+					   crpt.corrupted_data,
+					   crpt_len, 1, &crpt);		
+
+			set_ins_imm_val(pft->eip, 
+					(crpt.corrupted_data&crpt_mask[crpt_len-1]) 
+					| (pft->val&(~crpt_mask[crpt_len-1])));
+		}
+		break;
+	case REG_READ:
+		dbg("reg_read instruction eip=0x%08lx\n", 
+		       pft->eip);
+		/* we should trigger it in do_debug*/
+		break;
+	default:
+		err("error when getting instruction eip=0x%08lx\n", 
+		       pft->eip);
+		break;
+	}
+}
+
+void pf_post_page_fault(struct kmmio_probe *p, unsigned long condition,
struct pt_regs * regs)  
+{
+	struct pf_trigger *pft;
+	struct pf_corrupt crpt;
+	int ins_len, crpt_len;
+
+	pft = container_of(p, struct pf_trigger, probe);
+	switch (pft->type) {
+	case OTHERS:
+		dbg("can not analyze the instruction cond=0x%08lx\n", condition);
+		break;
+	case REG_WRITE:
+		dbg( "restore regval after reg_write corrupting, val=0x%08lx\n",
+			pft->val);
+		if (is_write(pft->trigger->wp.type)) {
+			set_ins_reg_val(pft->eip, regs, pft->val);
+		}
+		break;
+	case IMM_WRITE:
+		dbg("restore immval after imm_write corrputing, val=0x%08lx\n", 
+		       pft->val);
+		if (is_write(pft->trigger->wp.type)) {
+			set_ins_imm_val(pft->eip, pft->val);
+		}
+		break;
+	case REG_READ:
+		dbg("corrupt reg after reg_read! cond=0x%08lx\n", condition);
+		    
+		if (is_read(pft->trigger->wp.type)) {
+		    
+			ins_len = get_ins_width(pft->eip);
+			pft->val = get_ins_reg_val(pft->eip, regs);
+		
+			crpt_len = (WP_LEN(pft->trigger->wp)<ins_len)?
+				WP_LEN(pft->trigger->wp):ins_len;
+			crpt.corrupted_data = pft->val & crpt_mask[crpt_len-1];
+			fi_execute_trigger(pft->trigger, 
+					   &pf_interceptor,
+					   crpt.corrupted_data,
+					   crpt_len, 0, &crpt);		
+		
+			set_ins_reg_val(pft->eip, regs, 
+					(crpt.corrupted_data&crpt_mask[crpt_len-1]) 
+					| (pft->val&(~crpt_mask[crpt_len-1])));
+		}
+		break;
+	default:
+		err("should never reach here! cond=0x%08lx\n", condition);
+		break;
+	}
+};
+
+static int pf_arm(struct trigger *t)
+{
+	unsigned long addr;
+	struct pf_trigger *pft;
+    
+	/* Make sure that wp is vaild */
+	if ( t==NULL ) { 
+		err("Reason: %s\n", "/* There are no trigger */");
+		return -1;
+	}   
+	if ( t->wp.type& (~FI_WPTYPE_ALL_MASK) ) {
+		err("Reason: %s\n", "/* There are reserved bits in use*/");
+		return -1;
+	}
+	
+	addr = fi_phy_to_virt(t->wp.addr);
+	
+	if ( !(is_MMIO(t->wp.type) && addr) ) {
+		err("Reason: %s\n", "Address is not present.");
+		return -1;
+	}
+    
+	pft = kmalloc(sizeof(*pft), GFP_KERNEL);
+	
+	/* date trigger points to pft, so we can find it in unregister */
+	t->data = pft;
+	
+	/* register this trigger */
+	pft->probe.addr = (void *)addr;
+	pft->probe.pre_handler = pf_page_fault;
+	pft->probe.post_handler = pf_post_page_fault;
+	pft->trigger = t;
+
+	return register_kmmio_probe(&pft->probe);
+};
+
+
+static void pf_disarm(struct trigger *t) 
+{
+	struct pf_trigger *pft;
+	
+	pft = t->data;
+	unregister_kmmio_probe(&pft->probe);
+	kfree(pft);
+};
+
+static void corrupt(__u32 dirty, void *data)
+{
+	((struct pf_corrupt *)data)->corrupted_data = dirty;
+};
+
+static struct interceptor pf_interceptor = {
+	.kobj    = {.name = "pf"},
+	.arm     = &pf_arm,
+	.disarm  = &pf_disarm,
+	.corrupt = &corrupt
+};
+
+static int __init pf_init(void) 
+{
+	return fi_register_interceptor(&pf_interceptor);
+}
+
+static void __exit pf_exit(void)
+{
+	fi_unregister_interceptor(&pf_interceptor);
+}
+
+module_init(pf_init);
+module_exit(pf_exit);
+
+MODULE_DESCRIPTION("Pagefault interceptor component for FI");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/fi/interceptors/pf/pf_in.c
b/drivers/fi/interceptors/pf/pf_in.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/pf/pf_in.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,453 @@
+/******************************************************************************
+ *  Fault Injection Test harness (FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ */
+
+/*  $Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp $ 
+ *  Copyright by Intel Crop., 2002 
+ *  Louis Zhuang (louis.zhuang@intel.com)
+ */
+
+/**
+ * @file pf_hooks.c
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#include <linux/fi.h>
+
+#include "fi_pf.h"
+
+#define NR_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))
+
+/* IA32 Manual 3, 2-1 */
+static unsigned char prefix_codes[] = {
+	0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
+	0x65, 0x2E, 0x3E, 0x66, 0x67
+};
+
+int skip_prefix(unsigned char *addr, int *shorted) 
+{
+	int i=0;
+	unsigned char *p=addr;
+	*shorted=0;
+    
+ restart:
+	for (i=0; i<NR_ELEMENTS(prefix_codes); i++) {
+		if (*p == prefix_codes[i]){
+			if (*p == 0x66) *shorted = 1;
+			p++;
+			goto restart;
+		}
+	}
+	return p-addr;
+};
+
+int get_opcode(unsigned char *addr, unsigned int *opcode) 
+{
+	int rv;
+	if (*addr == 0x0F){/*0x0F is extension instruction*/
+		*opcode = *(unsigned short*)addr;
+		rv=2;
+	}else{
+		*opcode = *addr;
+		rv=1;
+	}
+	return rv;
+};
+
+/* IA32 Manual 3, 3-432*/
+static unsigned int reg_rop[] = {0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F,
0xBF0F};
+static unsigned int reg_wop[] = {0x88, 0x89};
+static unsigned int imm_wop[] = {0xC6, 0xC7};
+
+enum reason_type get_ins_type(unsigned long ins_addr) 
+{
+	unsigned int opcode;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+	enum reason_type rv=OTHERS;
+   
+	p = (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+    
+	for (i=0; i<NR_ELEMENTS(reg_rop); i++) {
+		if (reg_rop[i]==opcode) {
+			rv = REG_READ;
+			goto exit;
+		}
+	}
+
+	for (i=0; i<NR_ELEMENTS(reg_wop); i++) {
+		if (reg_wop[i]==opcode) {
+			rv = REG_WRITE;
+			goto exit;
+		}
+	}
+
+	for (i=0; i<NR_ELEMENTS(imm_wop); i++) {
+		if (imm_wop[i]==opcode) {
+			rv = IMM_WRITE;
+			goto exit;
+		}
+	}
+
+ exit:
+	return rv;
+};
+
+/* IA32 Manual 3, 3-432*/
+static unsigned int w8[] = {0x88, 0x8A, 0xC6};
+static unsigned int w32[]= {0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F,
0xBF0F}; 
+unsigned int get_ins_width(unsigned long ins_addr) 
+{
+	unsigned int opcode;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+
+	p = (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+    
+	for (i=0; i<NR_ELEMENTS(w8); i++) {
+		if (w8[i]==opcode) {
+			return 1;
+		}
+	}
+	for (i=0; i<NR_ELEMENTS(w32); i++) {
+		if (w32[i]==opcode) {
+			if (shorted) {
+				return 2;
+			} else {
+				return 4;
+			}
+		}
+	}
+
+	err("Unknow opcode=0x%02x\n", opcode);
+	return 0;
+};
+
+/* define register ident in mod/rm byte after undefine it in ptrace*/
+#undef  EAX 
+#define EAX 0
+#define ECX 1
+#define EDX 2
+#undef  EBX
+#define EBX 3
+#define ESP 4
+#define EBP 5
+#undef  ESI
+#define ESI 6
+#undef  EDI
+#define EDI 7
+
+#define AL 0
+#define CL 1
+#define DL 2
+#define BL 3
+#define AH 4
+#define CH 5
+#define DH 6
+#define BH 7
+
+unsigned char *get_reg_w8(int no, struct pt_regs *regs)
+{
+	unsigned char *rv=NULL;
+    
+	switch (no) {
+	case AL:
+		rv = (unsigned char *)&regs->eax;
+		break;
+	case BL:
+		rv = (unsigned char *)&regs->ebx;
+		break;
+	case CL:
+		rv = (unsigned char *)&regs->ecx;
+		break;
+	case DL:
+		rv = (unsigned char *)&regs->edx;
+		break;
+	case AH:
+		rv = 1+(unsigned char *)&regs->eax;
+		break;
+	case BH:
+		rv = 1+(unsigned char *)&regs->ebx;
+		break;
+	case CH:
+		rv = 1+(unsigned char *)&regs->ecx;
+		break;
+	case DH:
+		rv = 1+(unsigned char *)&regs->edx;
+		break;
+	default:
+		err("Error reg no# %d\n", no);
+		break;
+	}
+	return rv;
+};
+
+unsigned long *get_reg_w32(int no, struct pt_regs *regs)
+{
+	unsigned long *rv=NULL;
+
+	switch (no) {
+	case EAX:
+		rv = &regs->eax;
+		break;
+	case EBX:
+		rv = &regs->ebx;
+		break;
+	case ECX:
+		rv = &regs->ecx;
+		break;
+	case EDX:
+		rv = &regs->edx;
+		break;
+	case ESP:
+		rv = &regs->esp;
+		break;
+	case EBP:
+		rv = &regs->ebp;
+		break;
+	case ESI:
+		rv = &regs->esi;
+		break;
+	case EDI:
+		rv = &regs->edi;
+		break;
+	default:
+		err("Error reg no# %d\n", no);
+	}
+	return rv;
+};
+    
+unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs
*regs) 
+{    
+	unsigned int opcode;
+	unsigned char mod_rm;
+	int reg;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+	unsigned long rv;
+
+	p = (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+	for (i=0; i<NR_ELEMENTS(reg_rop); i++) {
+		if (reg_rop[i]==opcode) {
+			rv = REG_READ;
+			goto do_work;
+		}
+	}
+
+	for (i=0; i<NR_ELEMENTS(reg_wop); i++) {
+		if (reg_wop[i]==opcode) {
+			rv = REG_WRITE;
+			goto do_work;
+		}
+	}
+	err("Not a register instruction, opcode=0x%02x\n", opcode);
+	goto err;
+ do_work:
+	mod_rm = *p;
+	reg = (mod_rm>>3)&0x7;
+	if (get_ins_width(ins_addr)==1) {
+		return *get_reg_w8(reg, regs);
+	}else if (get_ins_width(ins_addr)==2) {
+		return *(unsigned short*)get_reg_w32(reg, regs);
+	}else if (get_ins_width(ins_addr)==4) {
+		return *get_reg_w32(reg, regs);
+	}else{
+		err("Error width# %d\n", reg);
+		goto err;
+	}
+ err:
+	return 0;
+};
+
+
+void set_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs,
unsigned long val) 
+{
+	unsigned int opcode;
+	unsigned char mod_rm;
+	int reg;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+	unsigned long rv;
+
+	p= (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+	for (i=0; i<NR_ELEMENTS(reg_rop); i++) {
+		if (reg_rop[i]==opcode) {
+			rv = REG_READ;
+			goto do_work;
+		}
+	}
+
+	for (i=0; i<NR_ELEMENTS(reg_wop); i++) {
+		if (reg_wop[i]==opcode) {
+			rv = REG_WRITE;
+			goto do_work;
+		}
+	}
+	err("Not a register instruction, opcode=0x%02x\n", opcode);
+	goto err;
+ do_work:
+	mod_rm = *p;
+	reg = (mod_rm>>3)&0x7;
+	if (get_ins_width(ins_addr)==1) {
+		*get_reg_w8(reg, regs) = val;
+	}else if (get_ins_width(ins_addr)==2) {
+		*(unsigned short*)get_reg_w32(reg, regs) = val;
+	}else if (get_ins_width(ins_addr)==4) {
+		*get_reg_w32(reg, regs) = val;
+	}else{
+		err("Error width, reg=%d\n", reg);
+		goto err;
+	}
+ err:
+	return;
+    
+};
+
+unsigned long get_ins_imm_val(unsigned long ins_addr) 
+{
+	unsigned int opcode;
+	unsigned char mod_rm;
+	unsigned char mod;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+	unsigned long rv;
+
+	p= (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+	for (i=0; i<NR_ELEMENTS(imm_wop); i++) {
+		if (imm_wop[i]==opcode) {
+			rv = IMM_WRITE;
+			goto do_work;
+		}
+	}
+	err("Not a imm instruction, opcode=0x%02x\n", opcode);
+	goto err;
+ do_work:
+	mod_rm = *p;
+	mod = mod_rm>>6;
+	p++;
+	switch (mod) {
+	case 0:
+		break;
+	case 1:
+		p += 1;
+		break;
+	case 2:
+		p += 4;
+	case 3:
+	default:
+		err("it is not a memory access instruction, rm_mod=0x%02x\n",
mod_rm);
+	}
+	if (get_ins_width(ins_addr)==1) {
+		return *(unsigned char *)p;
+	}else if (get_ins_width(ins_addr)==2) {
+		return *(unsigned short*)p;
+	}else if (get_ins_width(ins_addr)==4) {
+		return *(unsigned long*)p;
+	}else{
+		err("Error width%s\n", ".");
+		goto err;
+	}
+ err:
+	return 0;
+};
+
+void set_ins_imm_val(unsigned long ins_addr, unsigned long val) 
+{
+	unsigned int opcode;
+	unsigned char mod_rm;
+	unsigned char mod;
+	unsigned char *p;
+	int shorted=0;
+	int i=0;
+	unsigned long rv;
+
+	p= (unsigned char *)ins_addr;
+	p += skip_prefix(p, &shorted);
+	p += get_opcode(p, &opcode);
+	for (i=0; i<NR_ELEMENTS(imm_wop); i++) {
+		if (imm_wop[i]==opcode) {
+			rv = IMM_WRITE;
+			goto do_work;
+		}
+	}
+	err("Not a imm instruction, opcode=0x%02x\n", opcode);
+	goto err;
+ do_work:
+	mod_rm = *p;
+	mod = mod_rm>>6;
+	p++;
+	switch (mod) {
+	case 0:
+		break;
+	case 1:
+		p += 1;
+		break;
+	case 2:
+		p += 4;
+		break;
+	case 3:
+	default:
+		err("it is not a memory access instruction, rm_mod=0x%02x\n",
mod_rm);
+	}
+	if (get_ins_width(ins_addr)==1) {
+		*(unsigned char *)p = val;
+	}else if (get_ins_width(ins_addr)==2) {
+		*(unsigned short*)p = val;
+	}else if (get_ins_width(ins_addr)==4) {
+		*(unsigned long*)p = val;
+	}else{
+		err("Error width%s\n", ".");
+		goto err;
+	}
+ err:
+	return;
+};
diff -Nru a/drivers/fi/interceptors/pf/pf_utils.c
b/drivers/fi/interceptors/pf/pf_utils.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/interceptors/pf/pf_utils.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *  Fault Injection Test harness (FI)
+ *  Copyright (C) Intel Crop.
+ *
+ *  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.
+ *
+
******************************************************************************
+ */
+
+/*  $Id: pf_utils.c,v 1.3 2002/11/14 07:11:40 brlock Exp $ 
+ *  Copyright by Intel Crop., 2002 
+ *  Stanley Wang (stanley.wang@intel.com)
+ */
+
+/**
+ * @file pf_utils.c
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
+
+
+#include <linux/fi.h>
+
+#include "fi_pf.h"
+
+unsigned long fi_phy_to_virt(unsigned long phy_addr) 
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long virt_addr;
+	
+	for (virt_addr=VMALLOC_START; virt_addr<VMALLOC_END;
+	     virt_addr+=PAGE_SIZE ) {
+		pgd = pgd_offset_k(virt_addr);
+		if ( !(pgd_val(*pgd)&_PAGE_PRESENT) ) {
+			continue;
+		};
+		pmd = pmd_offset(pgd, virt_addr);
+		if (pmd_large(*pmd)) {
+			pte = (pte_t *)pmd;
+		} else {
+			pte = pte_offset_kernel(pmd, virt_addr);
+		}
+		if ( (pte_val(*pte)&PAGE_MASK) == (phy_addr&PAGE_MASK) ) {
+			return virt_addr + (phy_addr&(~PAGE_MASK));
+		};
+	}
+	return 0;
+};
diff -Nru a/drivers/fi/testing/Makefile b/drivers/fi/testing/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/testing/Makefile	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,9 @@
+#
+# Kernel Fault Injection Interceptors
+#
+
+EXTRA_AFLAGS	:= -traditional
+
+obj-$(CONFIG_FI_MOCK_INTERCEPTOR)	+= fi_mock_interceptor.o
+obj-$(CONFIG_FI_MOCK_CODESEGMENT)	+= fi_mock_cs.o
+obj-$(CONFIG_FI_TEST)			+= fi_test.o
diff -Nru a/drivers/fi/testing/fi_mock_cs.c
b/drivers/fi/testing/fi_mock_cs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/testing/fi_mock_cs.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Louis Zhuang <louis.zhuang@intel.com> */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kobject.h>
+#include <linux/fi.h>
+
+#define DRIVER_AUTHOR   "Louis Zhuang <louis.zhuang@intel.com>"
+#define DRIVER_DESC     "Fault Injection Mock Code Segment"
+
+void mock_execute(struct trigger *t, struct interceptor *i, 
+		__u32 val, int len, int type, void *data)
+{
+	info("tri=%s, intcpt=%s, val=%i, len=%i, type=%i, data=%p",
+			t->kobj.name, i->kobj.name, val, len, type,
+			data);
+}
+
+static struct code_segment mock_code_segment = {
+	.execute_trigger = mock_execute,
+	.kobj = {.name="mock"} 
+};
+
+static int __init mock_init(void)
+{
+	if (fi_register_code_segment(&mock_code_segment)) {
+		err("Failed to register Mock Code Segment\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void __exit mock_exit(void)
+{
+	fi_unregister_code_segment(&mock_code_segment);
+}
+module_init(mock_init);
+module_exit(mock_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff -Nru a/drivers/fi/testing/fi_mock_interceptor.c
b/drivers/fi/testing/fi_mock_interceptor.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/testing/fi_mock_interceptor.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,120 @@
+/*
+ * Fault Injection Mock Interceptor Driver
+ * ---------------------------------------
+ * 
+ * This is a fault injection interceptor interceptor created
+ * for the sole purpose of testing the core fault injection code. 
+ * By loading this driver a new interceptor named 'mock_interceptor' 
+ * will appear in the list of available interceptors.
+ * 
+ * When a trigger is loaded that utilizes this interceptor:
+ * - you should be able to trace of the interceptor <==> core
+ *   by looking at dmesg
+ * - a new file called 'trip' will created in the trigger directory
+ *   that when written to will trip the trigger
+ *
+ * In addition to this, the type of intercepor (interceptor_type_t)
+ * that this moc implementation claims to be when it registers
+ * with the fault injection core can be controled with the
+ * 'mock_type' parameter.
+ * 
+ * For example, to pretend to be a a INTERCEPTOR_TYPE_PIO 
+ * interceptor (which is really just the number '2' as defined
+ * in the fi.h enum declaration), you would load:
+ * $ insmod fi_mock_interceptor mod_type=2
+ *
+ * You can find out what the current type is by reading the
+ * 'type' file in the mock_interceptor directory.
+ * (i.e. 'cat fault_injection/interceptors/mock_interceptor/type')
+ *
+ * Copyright (C) 2002 Rusty Lynch <rusty@linux.intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kobject.h>
+#include <linux/fi.h>
+
+#define DRIVER_AUTHOR	"Rusty Lynch <rusty@linux.intel.com>"
+#define DRIVER_DESC	"Fault Injection Mock Interceptor"
+
+static struct interceptor mock_interceptor;
+
+static ssize_t trip_store(struct trigger * p, const char * page, 
+			     size_t count)
+{
+	trace("%s, %p, %i", p ? p->kobj.name:"NULL",page,count);
+	fi_execute_trigger(p, &mock_interceptor, 0, 0, 0, 0);
+	return count;
+}
+static struct trigger_attribute attr_trip = {
+	.attr	= { .name = "trip", .mode = 0644 },
+	.store  = &trip_store,
+};
+
+static int arm(struct trigger *t)
+{
+	trace("%s", t ? t->kobj.name : "NULL");
+	if (!t) {
+		dbg("Null trigger passed into arming function!");
+		return -EINVAL;
+	}
+
+	sysfs_create_file(&t->kobj, &attr_trip.attr);
+	return 0;
+};
+
+static void disarm(struct trigger *t) 
+{
+	trace("%s", t ? t->kobj.name : "NULL");
+	if (!t) {
+		dbg("Null trigger passed into disarming function!");
+		return;
+	}
+
+	sysfs_remove_file(&t->kobj, &attr_trip.attr);	
+	return;
+};
+
+static void corrupt(__u32 dirty, void *data)
+{
+	trace("%ul, %p", dirty, data);
+	return;
+};
+
+static struct interceptor mock_interceptor = {
+	.kobj    = {.name = "mock"},
+	.arm     = &arm,
+	.disarm  = &disarm,
+	.corrupt = &corrupt
+};
+
+static int __init mock_init(void)
+{
+	trace();
+
+	if (fi_register_interceptor(&mock_interceptor)) {
+		dbg("Failed to register Mock Interceptor");
+
+		/* FIXME!! For some reason kobject_register */
+		/* is returning an error when none occured */
+		/*return -EINVAL;*/
+	}
+	return 0;
+}
+
+static void __exit mock_exit (void)
+{
+	trace();
+	fi_unregister_interceptor(&mock_interceptor);
+}
+
+module_init(mock_init);
+module_exit(mock_exit);
+
+MODULE_PARM_DESC(mock_type, "(interceptor_type_t) Type of
interceptor");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff -Nru a/drivers/fi/testing/fi_test.c b/drivers/fi/testing/fi_test.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/fi/testing/fi_test.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,304 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/vmalloc.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+
+#define LOG_TIME printk(KERN_INFO "FI_TEST: %ld jiffies = %ld
\n",global_counter++,jiffies)
+
+#if !defined(CONFIG_FI_TEST_MODULE)
+#define MY_NAME	"fi_test"
+#else
+#define MY_NAME	THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while(0)
+
+
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME
, ## arg)
+#define info(format, arg...) printk(KERN_INFO "#%ld %s : " format "\n",
global_counter++, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n",
MY_NAME , ## arg)
+
+
+#define PP_BASE 0x378
+#define MM_BASE 0x00001000
+
+static int debug;
+
+void *mmio_address;
+volatile unsigned long global_counter = 0;
+ssize_t io_show(struct subsystem *s, char *page);
+ssize_t io_store(struct subsystem *s, const char *page, size_t count);
+
+ssize_t mmio_show(struct subsystem *s, char *page);
+ssize_t mmio_store(struct subsystem *s, const char *page, size_t
count);
+
+struct subsys_attribute io =
+{
+	.attr = { .name = "io", .mode = 0644 },
+	.show = io_show,
+	.store = io_store,
+};
+
+struct subsys_attribute mmio =
+{
+	.attr = { .name = "mmio", .mode = 0644 },
+	.show = mmio_show,
+	.store = mmio_store,
+};
+
+ssize_t fith_test_show(struct kobject *k, struct attribute *attr, 
+		       char *page)
+{
+	return 0;
+}
+
+ssize_t fith_test_store(struct kobject *kobj, struct attribute *attr, 
+			const char *page, size_t count)
+{
+	return count; 
+}
+
+struct sysfs_ops fith_test_ops =
+{
+	.show = fith_test_show,
+	.store = fith_test_store,
+};
+
+struct kobj_type ktype_fith_test = {
+	.sysfs_ops = &fith_test_ops
+};
+
+decl_subsys(fith_test, &ktype_fith_test);
+
+int print_global_counter(char *page, char **start, off_t off, int
count, 
+			 int *eof, void *data)
+{
+	sprintf(page,"%ld\n",global_counter);
+	return strlen(page);
+}
+
+void do_io_access(int write, int type)
+{
+	unsigned char value=0;
+	if (write) 
+		info("Write 0X5A* to parellel port register!\n");
+	else
+		info("Expect read 0X5A* from parellel port register!\n");
+
+	switch (type){
+	case 0:
+		outb(0x5a, PP_BASE);
+		value = inb(PP_BASE);
+		break;
+	case 1:
+		outw(0x5a, PP_BASE);
+		value = inw(PP_BASE);
+		break;
+	case 2:
+		outl(0x5a, PP_BASE);
+		value = inl(PP_BASE);
+		break;
+	case 4:
+		outw_p(0x5a, PP_BASE);
+		value = inw_p(PP_BASE);
+		break;
+	case 5:
+		outl_p(0x5a, PP_BASE);
+		value = inl_p(PP_BASE);
+		break;
+	default:
+		break;
+	}
+	if (write) 
+		info("%#X was write to parellel port register!\n",value);
+	else
+		info("%#X was read from parellel port register!\n",value);
+}
+
+void do_mm_io_access(int write, int type)
+{
+	unsigned long value=0;
+	if (write) 
+		info("Write 0X5A* to MMI/O address");
+	else
+		info("Expect read 0X5A* from MMI/O address");
+
+	switch(type){
+	case 0:
+		writeb(0x5a,mmio_address);
+		value = readb(mmio_address);
+		break;
+	case 1:
+		writew(0x5a5a,mmio_address);
+		value = readw(mmio_address);
+		break;
+	case 2:
+		writel(0x5a5a5a5a,mmio_address);
+		value = readl(mmio_address);
+		break;
+	default:
+		break;
+	}
+	if (write) 
+		info("%#lX was write to MMI/O address", value);
+	else
+		info("%#lX was read from MMI/O address", value);
+
+}
+
+ssize_t io_show(struct subsystem *s, char *page)
+{
+	return 0;
+}
+
+ssize_t io_store(struct subsystem *s, const char *page, size_t count)
+{
+	char cmd[16];
+	char len[16];	
+	int num = 0;
+	int error = 0;
+
+	num = sscanf(page, "%15s %15s", cmd, len);
+
+	if (num < 0) {
+		err("Unknow command format!");
+		error = -EINVAL;
+		goto done;
+	}
+	
+	LOG_TIME;
+	if (!strncmp(cmd, "read", 4)) {
+		if (!strncmp(len, "byte", 4)) {
+			info("COMMAND_IO_READ");
+			do_io_access(0,0);
+		} else if (!strncmp(len, "word", 4)) {
+			info("COMMAND_IO_READW");
+			do_io_access(0,1);
+		} else if (!strncmp(len, "long", 4)) {
+			info("COMMAND_IO_READL");
+			do_io_access(0,2);
+		} else {
+			err("Invalid length!");
+			error = -EINVAL;
+		}
+	} else if (!strncmp(cmd, "write", 5)) {
+		if (!strncmp(len, "byte", 4)) {
+			info("COMMAND_IO_WRITE");
+			do_io_access(1,0);
+		} else if (!strncmp(len, "word", 4)) {
+			info("COMMAND_IO_WRITEW");
+			do_io_access(1,1);
+		} else if (!strncmp(len, "long", 4)) {
+			info("COMMAND_IO_WRITEL");
+			do_io_access(1,2);
+		} else {
+			err("Invalid length!");
+			error = -EINVAL;
+		}
+	} else {
+		err("Unknow command!");
+		error = -EINVAL;
+	}
+done:
+	return error ? error : count;
+}
+
+ssize_t mmio_show(struct subsystem *s, char *page)
+{
+	return 0;
+}
+
+ssize_t mmio_store(struct subsystem *s, const char *page,
+		   size_t count)
+{
+	char cmd[16];
+	char len[16];	
+	int num = 0;
+	int error = 0;
+
+	num = sscanf(page, "%15s %15s", cmd, len);
+
+	if (num < 0) {
+		err("Unknow command format!");
+		error = -EINVAL;
+		goto done;
+	}
+	
+	LOG_TIME;
+	if (!strncmp(cmd, "read", 4)) {
+		if (!strncmp(len, "byte", 4)) {
+			info("COMMAND_MMIO_READ");
+			do_mm_io_access(0,0);
+		} else if (!strncmp(len, "word", 4)) {
+			info("COMMAND_MMIO_READW");
+			do_mm_io_access(0,1);
+		} else if (!strncmp(len, "long", 4)) {
+			info("COMMAND_MMIO_READL");
+			do_mm_io_access(0,2);
+		} else {
+			err("Invalid length!");
+			error = -EINVAL;
+		}		
+	} else if (!strncmp(cmd, "write", 5)) {
+		if (!strncmp(len, "byte", 4)) {
+			info("COMMAND_MMIO_WRITE");
+			do_mm_io_access(1,0);
+		} else if (!strncmp(len, "word", 4)) {
+			info("COMMAND_MMIO_WRITEW");
+			do_mm_io_access(1,1);
+		} else if (!strncmp(len, "long", 4)) {
+			info("COMMAND_MMIO_WRITEL");
+			do_mm_io_access(1,2);
+		} else {
+			err("Invalid length!");
+			error = -EINVAL;
+		}
+	} else {
+		err("Unknow command!");
+		error = -EINVAL;
+	}
+done:
+	return error ? error : count;
+}
+
+static int __init fi_test_init(void)
+{
+	dbg("Initialize fith_test.");
+	subsystem_register(&fith_test_subsys);
+	subsys_create_file(&fith_test_subsys, &mmio);
+	subsys_create_file(&fith_test_subsys, &io);
+	
+	mmio_address = ioremap(MM_BASE, 0x8);
+	info("mmio_address = %p", mmio_address);
+	*(unsigned long *)mmio_address = 0xf0f0;	
+	mb();
+	
+	return 0;
+}
+
+static void __exit fi_test_exit (void)
+{
+	dbg("Cleanup fith_test.");
+	subsys_remove_file(&fith_test_subsys, &io);
+	subsys_remove_file(&fith_test_subsys, &mmio);
+	subsystem_unregister(&fith_test_subsys);
+	iounmap(mmio_address);
+}
+
+module_init(fi_test_init);
+module_exit(fi_test_exit);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_AUTHOR("Stanley Wang");
+MODULE_DESCRIPTION("Fault Injection test driver.");
+MODULE_LICENSE("GPL");
diff -Nru a/include/asm-i386/kirq.h b/include/asm-i386/kirq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/kirq.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,27 @@
+#ifndef _ASM_KIRQ_H
+#define _ASM_KIRQ_H
+
+#include <linux/errno.h>
+
+/* Define return value for kirq handler. */
+#define KIRQ_CONTINUE	0
+#define KIRQ_SKIP	1
+
+struct kirq;
+typedef int (*kirq_handler_t)(struct kirq *, int, void *, struct
pt_regs *);
+struct kirq {
+	void *dev_id;
+	void (*isr)(int, void *, struct pt_regs *);
+	kirq_handler_t	handler;
+};
+
+#ifdef CONFIG_KIRQ
+extern int register_kirq(int irq, char *devname, kirq_handler_t
handler);
+extern int unregister_kirq(int irq);
+extern void dispatch_kirq(int irq, struct pt_regs* regs);
+#else
+int register_kirq(int irq, char *devname, kirq_handler_t handler) {
return -ENOSYS; }
+int unregister_kirq(int irq) { return -ENOSYS; }
+void dispatch_kirq(int irq, struct pt_regs* regs) {}
+#endif /*CONFIG_KIRQ*/
+#endif /*_ASM_KIRQ_H*/
diff -Nru a/include/asm-i386/kmmio.h b/include/asm-i386/kmmio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/kmmio.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,25 @@
+/*
+ * Benfit many code from kprobes
+ * (C) 2002 Louis Zhuang <louis.zhuang@intel.com>.
+ */
+
+#ifndef _ASM_KMMIO_H
+#define _ASM_KMMIO_H
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+struct pt_regs;
+
+typedef void* kmmio_addr_t;
+
+#ifdef CONFIG_KMMIO
+extern void arm_kmmio_fault_page(kmmio_addr_t page);
+extern void disarm_kmmio_fault_page(kmmio_addr_t page);
+extern int post_kmmio_handler(unsigned long condition, struct pt_regs
*regs);
+extern int kmmio_handler(struct pt_regs *regs, unsigned long addr);
+extern void *kmmio_invert_map(void *virt_addr, unsigned long bus_addr);
+#else /* !CONFIG_KMMIO */
+static inline int post_kmmio_handler(unsigned long condition, struct
pt_regs *regs) { return 0; }
+static inline int kmmio_handler(struct pt_regs *regs, unsigned long
addr) { return 0; }
+#endif
+#endif /* _ASM_KMMIO_H */
diff -Nru a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/kprobes.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,34 @@
+#ifndef _ASM_KPROBES_H
+#define _ASM_KPROBES_H
+/*
+ *  Dynamic Probes (kprobes) support
+ *  	Vamsi Krishna S <vamsi_krishna@in.ibm.com>, July, 2002
+ *	Mailing list: dprobes@www-124.ibm.com
+ */
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+struct pt_regs;
+
+typedef u8 kprobe_opcode_t;
+#define BREAKPOINT_INSTRUCTION	0xcc
+
+/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
+ * if necessary, before executing the original int3/1 (trap) handler.
+ */
+static inline void restore_interrupts(struct pt_regs *regs)
+{
+	if (regs->eflags & IF_MASK)
+		__asm__ __volatile__ ("sti");
+}
+
+#ifdef CONFIG_KPROBES
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
+extern int post_kprobe_handler(struct pt_regs *regs);
+extern int kprobe_handler(struct pt_regs *regs);
+#else /* !CONFIG_KPROBES */
+static inline int kprobe_fault_handler(struct pt_regs *regs, int
trapnr) { return 0; }
+static inline int post_kprobe_handler(struct pt_regs *regs) { return 0;
}
+static inline int kprobe_handler(struct pt_regs *regs) { return 0; }
+#endif
+#endif /* _ASM_KPROBES_H */
diff -Nru a/include/linux/fi.h b/include/linux/fi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/fi.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,155 @@
+#ifndef _FAULT_INJECTION_H
+#define _FAULT_INJECTION_H
+#if	defined(__KERNEL__)
+
+#include <linux/kobject.h>
+
+/**
+ * define uniform watchpoint structure.
+ */
+#define FI_WPTYPE_MMIO 4
+#define FI_WPTYPE_READ 8
+#define FI_WPTYPE_WRITE 16
+#define FI_WPTYPE_EXEC 32
+
+#define FI_WPTYPE_LEN_MASK 3
+#define FI_WPTYPE_ALL_MASK 	( FI_WPTYPE_MMIO \
+				| FI_WPTYPE_READ \
+				| FI_WPTYPE_WRITE \
+				| FI_WPTYPE_EXEC \
+				| FI_WPTYPE_LEN_MASK \
+				)
+
+struct watchpoint{
+	/*address intercepted.*/
+	unsigned long addr;
+	/**
+	 * intercepted type. 
+	 * 	bit 0-1	2^N bytes leng.
+	 * 	bit 2	IO-space IO/MMIO
+	 * 	bit 3	Read
+	 * 	bit 4	Write
+	 * 	bit 5	Execute(not implementation yet) 
+	 * XXX: you can not register the same address with IO and MMIO, 
+	 * but MMIO seldom uses low 64k space, so it is not a problem in
fact.*/
+	unsigned int type;
+};
+
+#define WP_LEN(wp) (1<<((unsigned long)(wp.type)&3))
+typedef enum
+{
+        TRIGGER_OPCODE_NOTHING=0, 
+	TRIGGER_OPCODE_SET=1, 
+	TRIGGER_OPCODE_AND=2, 
+	TRIGGER_OPCODE_OR=3, 
+	TRIGGER_OPCODE_NOT=4, 
+	TRIGGER_OPCODE_XOR=5, 
+	TRIGGER_OPCODE_NAND=6, 
+	TRIGGER_OPCODE_NOR=7, 
+	TRIGGER_OPCODE_ADD=8, 
+	TRIGGER_OPCODE_SUB=9,
+} trigger_opcode_t;
+
+struct trigger;
+struct interceptor;
+struct code_segment {
+	struct list_head list;
+	void (*execute_trigger) (struct trigger *t, 
+				 struct interceptor *i, 
+				 __u32 val, 
+				 int len, 
+				 int type, 
+				 void *data); 
+	struct trigger *tri;
+	struct kobject kobj;
+};
+
+struct trigger {
+	struct list_head list;
+	struct watchpoint wp;
+	__u32 bitmask;
+	int min;
+	int max;
+	int skip;
+	int stop;
+	int protection;
+	int hertz;
+	int registered;
+	struct list_head cs_list;
+	struct interceptor *intcpt;
+	atomic_t count;
+	/* opaque data struct for register */
+	void *data;
+	struct kobject kobj;
+
+	/* these two fields is legacy */
+	trigger_opcode_t opcode;
+	int operand;
+};
+
+struct interceptor {
+	int (*arm) (struct trigger *);
+	void (*disarm) (struct trigger *);
+	void (*corrupt)(__u32, void *);
+	struct list_head tri_list;
+	struct kobject kobj;
+};
+
+struct code_segment_attribute {
+	struct attribute attr;
+	ssize_t (*show) (struct code_segment *,char *);
+	ssize_t (*store) (struct code_segment *,const char *, size_t);
+};
+
+struct trigger_attribute {
+	struct attribute attr;
+	ssize_t (*show) (struct trigger *,char *);
+	ssize_t (*store)(struct trigger *,const char *, size_t);
+};
+
+struct interceptor_attribute {
+	struct attribute attr;
+	ssize_t (*show) (struct interceptor *,char *);
+	ssize_t (*store)(struct interceptor *,const char *, size_t);
+};
+
+
+extern int fi_register_interceptor(struct interceptor *);
+extern void fi_unregister_interceptor(struct interceptor *i);
+extern int fi_register_code_segment(struct code_segment *);
+extern void fi_unregister_code_segment(struct code_segment *);
+extern void fi_execute_trigger(struct trigger *t, struct interceptor
*i,
+				__u32 val, int len, int type, void *data);
+
+#endif	/* __KERNEL__ */
+
+#ifdef CONFIG_FI_DEBUG
+extern int fi_debug;
+#define dbg(format, arg...)					\
+	do {							\
+		if(fi_debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				__FUNCTION__, ## arg); 		\
+	} while(0)
+#else
+#define dbg(format, arg...)
+#endif /* CONFIG_FI_DEBUG */
+
+#define err(format, arg...) \
+                printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##
arg)
+#define info(format, arg...) \
+                printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##
arg)
+#define warn(format, arg...) \
+                printk(KERN_WARNING "%s: " format "\n", __FUNCTION__ ,
## arg)
+#define trace(format, arg...) \
+                printk(KERN_INFO "%s(" format ")\n", __FUNCTION__ , ##
arg)
+
+/*define macros for WP type*/
+inline static int is_MMIO(int type)	{ return (type&0x04)?1:0; };
+inline static int is_IO(int type)	{ return (type&0x04)?0:1; };
+inline static int is_read(int type)	{ return (type&0x08)?1:0; };
+inline static int is_write(int type)	{ return (type&0x10)?1:0; };
+inline static int is_execute(int type)	{ return (type&0x20)?1:0; };
+inline static int access_len(int type)	{ return 1UL<<(type&0x03);};
+
+#endif	/* _FAULT_INJECTION_H */
diff -Nru a/include/linux/kmmio.h b/include/linux/kmmio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/kmmio.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,62 @@
+#ifndef _LINUX_KMMIO_H
+#define _LINUX_KMMIO_H
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <asm/kmmio.h>
+
+struct kmmio_probe;
+struct kmmio_fault_page;
+struct pt_regs;
+
+typedef void (*kmmio_pre_handler_t)(struct kmmio_probe *, struct
pt_regs *, unsigned long addr);
+typedef void (*kmmio_post_handler_t)(struct kmmio_probe *, unsigned
long condition, struct pt_regs *);
+struct kmmio_probe {
+	struct list_head list;
+
+	/* location of the probe point */
+	kmmio_addr_t addr;
+
+	 /* Called before addr is executed. */
+	kmmio_pre_handler_t pre_handler;
+
+	/* Called after addr is executed, unless... */
+	kmmio_post_handler_t post_handler;
+};
+
+struct kmmio_fault_page {
+	struct list_head list;
+
+	/* location of the fault page */
+	kmmio_addr_t page;
+
+	int count;
+};
+
+#ifdef CONFIG_KMMIO
+/* Locks kmmio: irq must be disabled */
+void lock_kmmio(void);
+void unlock_kmmio(void);
+
+/* kmmio is active by some kmmio_probes? */
+static inline int is_kmmio_active(void)
+{
+	extern unsigned int kmmio_count;
+	return kmmio_count;
+}
+
+/* Get the kmmio at this addr (if any).  Must have called lock_kmmio */
+struct kmmio_probe *get_kmmio_probe(kmmio_addr_t addr);
+struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page);
+int add_kmmio_fault_page(kmmio_addr_t page);
+void release_kmmio_fault_page(kmmio_addr_t page);
+
+int register_kmmio_probe(struct kmmio_probe *p);
+void unregister_kmmio_probe(struct kmmio_probe *p);
+#else
+static inline int is_kmmio_active(void) { return 0; }
+static inline int register_kmmio_probe(struct kmmio_probe *p) { return
-ENOSYS; }
+static inline void unregister_kmmio_probe(struct kmmio_probe *p) { }
+#endif
+#endif /* _LINUX_KMMIO_H */
diff -Nru a/include/linux/kprobes.h b/include/linux/kprobes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/kprobes.h	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,60 @@
+#ifndef _LINUX_KPROBES_H
+#define _LINUX_KPROBES_H
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <asm/kprobes.h>
+
+struct kprobe;
+struct pt_regs;
+
+typedef void (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs
*);
+typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs
*,
+				      unsigned long flags);
+typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs
*,
+				      int trapnr);
+
+struct kprobe {
+	struct list_head list;
+
+	/* location of the probe point */
+	kprobe_opcode_t *addr;
+
+	 /* Called before addr is executed. */
+	kprobe_pre_handler_t pre_handler;
+
+	/* Called after addr is executed, unless... */
+	kprobe_post_handler_t post_handler;
+
+	 /* ... called if executing addr causes a fault (eg. page fault).
+	  * Return 1 if it handled fault, otherwise kernel will see it. */
+	kprobe_fault_handler_t fault_handler;
+
+	/* Saved opcode (which has been replaced with breakpoint) */
+	kprobe_opcode_t opcode;
+};
+
+#ifdef CONFIG_KPROBES
+/* Locks kprobe: irq must be disabled */
+void lock_kprobes(void);
+void unlock_kprobes(void);
+
+/* kprobe running now on this CPU? */
+static inline int kprobe_running(void)
+{
+	extern unsigned int kprobe_cpu;
+	return kprobe_cpu == smp_processor_id();
+}
+
+/* Get the kprobe at this addr (if any).  Must have called lock_kprobes
*/
+struct kprobe *get_kprobe(void *addr);
+
+int register_kprobe(struct kprobe *p);
+void unregister_kprobe(struct kprobe *p);
+#else
+static inline int kprobe_running(void) { return 0; }
+static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; }
+static inline void unregister_kprobe(struct kprobe *p) { }
+#endif
+#endif /* _LINUX_KPROBES_H */
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Tue Jan 14 13:43:34 2003
+++ b/kernel/Makefile	Tue Jan 14 13:43:34 2003
@@ -1,10 +1,10 @@
-#
+#}{
 # Makefile for the linux kernel.
 #
 
 export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o
exec_domain.o \
 		printk.o suspend.o dma.o module.o cpufreq.o \
-		profile.o rcupdate.o intermodule.o params.o
+		profile.o rcupdate.o intermodule.o params.o kprobes.o kmmio.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
 	    exit.o itimer.o time.o softirq.o resource.o \
@@ -22,6 +22,8 @@
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
 obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_KMMIO)   += kmmio.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the
-fno-omit-frame-pointer is
diff -Nru a/kernel/kmmio.c b/kernel/kmmio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/kmmio.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,147 @@
+/* Support for MMIO probes.
+ * Benfit many code from kprobes
+ * (C) 2002 Louis Zhuang <louis.zhuang@intel.com>.
+*/
+
+#include <linux/kmmio.h>
+#include <linux/spinlock.h>
+#include <linux/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/errno.h>
+#include <asm/highmem.h>
+
+#define KMMIO_HASH_BITS 6
+#define KMMIO_TABLE_SIZE (1 << KMMIO_HASH_BITS)
+
+static struct list_head kmmio_table[KMMIO_TABLE_SIZE];
+
+#define KMMIO_PAGE_HASH_BITS 4
+#define KMMIO_PAGE_TABLE_SIZE (1 << KMMIO_PAGE_HASH_BITS)
+static struct list_head kmmio_page_table[KMMIO_PAGE_TABLE_SIZE];
+
+unsigned int kmmio_count = 0;
+static spinlock_t kmmio_lock = SPIN_LOCK_UNLOCKED;
+
+/* Locks kmmio: irqs must be disabled */
+void lock_kmmio(void)
+{
+	spin_lock(&kmmio_lock);
+}
+
+void unlock_kmmio(void)
+{
+	spin_unlock(&kmmio_lock);
+}
+
+/* You have to be holding the kmmio_lock */
+struct kmmio_probe *get_kmmio_probe(void *addr)
+{
+	struct list_head *head, *tmp;
+
+	head = &kmmio_table[hash_ptr(addr, KMMIO_HASH_BITS)];
+	list_for_each(tmp, head) {
+		struct kmmio_probe *p = list_entry(tmp, struct kmmio_probe, list);
+		if (p->addr == addr)
+			return p;
+	}
+	return NULL;
+}
+
+int register_kmmio_probe(struct kmmio_probe *p)
+{
+	int ret = 0;
+	
+	spin_lock_irq(&kmmio_lock);
+	kmmio_count++;
+	if (get_kmmio_probe(p->addr)) {
+		ret = -EEXIST;
+		goto out;
+	}
+	list_add(&p->list, &kmmio_table[hash_ptr(p->addr, KMMIO_HASH_BITS)]);
+
+	if (add_kmmio_fault_page(p->addr)) {
+		printk(KERN_ERR "Unable to set page fault\n");
+	}
+	
+ out:
+	spin_unlock_irq(&kmmio_lock);
+	flush_tlb_all();
+	return ret;
+}
+
+void unregister_kmmio_probe(struct kmmio_probe *p)
+{
+	spin_lock_irq(&kmmio_lock);
+	release_kmmio_fault_page(p->addr);
+	list_del(&p->list);
+	kmmio_count--;
+	spin_unlock_irq(&kmmio_lock);
+}
+
+struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page)
+{
+	struct list_head *head, *tmp;
+
+	(unsigned long)page &= PAGE_MASK;
+	head = &kmmio_page_table[hash_ptr(page, KMMIO_PAGE_HASH_BITS)];
+	list_for_each(tmp, head) {
+		struct kmmio_fault_page *p = list_entry(tmp, struct kmmio_fault_page,
list);
+		if (p->page == page)
+			return p;
+	}
+	return NULL;
+}
+
+int add_kmmio_fault_page(kmmio_addr_t page)
+{
+	struct kmmio_fault_page *f;
+	
+	(unsigned long)page &= PAGE_MASK;
+	f = get_kmmio_fault_page(page);
+	if (f) {
+		f->count++;
+		return 0;
+	}
+	f = (struct kmmio_fault_page *)kmalloc(sizeof(*f), GFP_ATOMIC);
+	if (!f) return -1;
+	f->count = 1;
+	f->page = page;
+	list_add(&f->list, &kmmio_page_table[hash_ptr(f->page,
KMMIO_PAGE_HASH_BITS)]);
+
+	arm_kmmio_fault_page(f->page);
+	return 0;
+}
+
+void release_kmmio_fault_page(kmmio_addr_t page)
+{
+	struct kmmio_fault_page *f;
+
+	(unsigned long)page &= PAGE_MASK;
+	f = get_kmmio_fault_page(page);
+	if (!f)	return;
+	f->count--;
+	if(!f->count) {
+		disarm_kmmio_fault_page(f->page);
+		list_del(&f->list);
+	}
+}
+
+static int __init init_kmmio(void)
+{
+	int i;
+
+	/* FIXME allocate the probe table, currently defined statically */
+	/* initialize all list heads */
+	for (i = 0; i < KMMIO_TABLE_SIZE; i++)
+		INIT_LIST_HEAD(&kmmio_table[i]);
+	for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++) 
+		INIT_LIST_HEAD(&kmmio_page_table[i]);
+	return 0;
+}
+__initcall(init_kmmio);
+
+EXPORT_SYMBOL_GPL(register_kmmio_probe);
+EXPORT_SYMBOL_GPL(unregister_kmmio_probe);
diff -Nru a/kernel/kprobes.c b/kernel/kprobes.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/kprobes.c	Tue Jan 14 13:43:34 2003
@@ -0,0 +1,89 @@
+/* Support for kernel probes.
+   (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
+*/
+#include <linux/kprobes.h>
+#include <linux/spinlock.h>
+#include <linux/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/errno.h>
+
+#define KPROBE_HASH_BITS 6
+#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
+
+static struct list_head kprobe_table[KPROBE_TABLE_SIZE];
+
+unsigned int kprobe_cpu = NR_CPUS;
+static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
+
+/* Locks kprobe: irqs must be disabled */
+void lock_kprobes(void)
+{
+	spin_lock(&kprobe_lock);
+	kprobe_cpu = smp_processor_id();
+}
+
+void unlock_kprobes(void)
+{
+	kprobe_cpu = NR_CPUS;
+	spin_unlock(&kprobe_lock);
+}
+
+/* You have to be holding the kprobe_lock */
+struct kprobe *get_kprobe(void *addr)
+{
+	struct list_head *head, *tmp;
+
+	head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
+	list_for_each(tmp, head) {
+		struct kprobe *p = list_entry(tmp, struct kprobe, list);
+		if (p->addr == addr)
+			return p;
+	}
+	return NULL;
+}
+
+int register_kprobe(struct kprobe *p)
+{
+	int ret = 0;
+
+	spin_lock_irq(&kprobe_lock);
+	if (get_kprobe(p->addr)) {
+		ret = -EEXIST;
+		goto out;
+	}
+	list_add(&p->list, &kprobe_table[hash_ptr(p->addr,
KPROBE_HASH_BITS)]);
+
+	p->opcode = *p->addr;
+	*p->addr = BREAKPOINT_INSTRUCTION;
+	flush_icache_range(p->addr, p->addr + sizeof(kprobe_opcode_t));
+ out:
+	spin_unlock_irq(&kprobe_lock);
+	return ret;
+}
+
+void unregister_kprobe(struct kprobe *p)
+{
+	spin_lock_irq(&kprobe_lock);
+	*p->addr = p->opcode;
+	list_del(&p->list);
+	flush_icache_range(p->addr, p->addr + sizeof(kprobe_opcode_t));
+	spin_unlock_irq(&kprobe_lock);
+}
+
+static int __init init_kprobes(void)
+{
+	int i;
+
+	/* FIXME allocate the probe table, currently defined statically */
+	/* initialize all list heads */
+	for (i = 0; i < KPROBE_TABLE_SIZE; i++)
+		INIT_LIST_HEAD(&kprobe_table[i]);
+
+	return 0;
+}
+__initcall(init_kprobes);
+
+EXPORT_SYMBOL_GPL(register_kprobe);
+EXPORT_SYMBOL_GPL(unregister_kprobe);




-------------------------------------------------------
This SF.NET email is sponsored by: FREE  SSL Guide from Thawte
are you planning your Web Server Security? Click here to get a FREE
Thawte SSL guide and find the answers to all your  SSL security issues.
http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en
_______________________________________________
Fault-injection-developer mailing list
Fault-injection-developer@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/fault-injection-developer
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic