fault-injection-developer Mailing List for Fault Injection Test Harness (Page 5)
Status: Alpha
Brought to you by:
rustyl
You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
(13) |
Sep
(2) |
Oct
(49) |
Nov
(69) |
Dec
(70) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(64) |
Feb
(41) |
Mar
(25) |
Apr
(18) |
May
(5) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(3) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(1) |
Nov
|
Dec
|
2009 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
2016 |
Jan
(2) |
Feb
(5) |
Mar
(2) |
Apr
(1) |
May
(1) |
Jun
(1) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(4) |
Nov
|
Dec
|
From: Rusty L. <ru...@li...> - 2003-01-29 18:16:11
|
As I previously noted in an earlier message at http://marc.theaimsgroup.com/?l=linux-kernel&m=104386132315914&w=2, while kicking around ideas in the fault injection project, the need for some additional non-fi specific features has surfaced. One of these needs is the ability to hook (in same way that kprobes can add a hook) to a specific memory mapped IO region before the user of the region gets access. A fault injection test case may need to just note when a given region is being read/written, take some action before the caller returns from the read or write operation, or change the value that is being read or written. The following is a patch for a 2.5.59 kernel with the kprobes patch (posted at http://marc.theaimsgroup.com/?l=linux-kernel&m=104254476428330&w=2 ) already applied that provides this feature for the i368 architecture. The patch does not call the kprobes functions, but depends on the same tweaks to traps.c and fault.c that kprobes provides. We also followed the same usage that kprobes provides, with a register_kmmio_probe() function for adding the hook/probe, and a unregister_kmmio_probe() function for removing the hook/probe. As with the kirq patch, this patch is an early request for comments with the goal of an acceptable patch for the 2.7 kernel. --rustyl # 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.957 -> 1.958 # arch/i386/mm/fault.c 1.24 -> 1.25 # arch/i386/Kconfig 1.35 -> 1.36 # arch/i386/kernel/traps.c 1.43 -> 1.44 # arch/i386/kernel/Makefile 1.33 -> 1.34 # kernel/Makefile 1.26 -> 1.27 # (new) -> 1.1 include/linux/kmmio.h # (new) -> 1.1 kernel/kmmio.c # (new) -> 1.1 arch/i386/kernel/kmmio.c # (new) -> 1.1 include/asm-i386/kmmio.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/01/23 rusty@vmhack.(none) 1.958 # Adding kmmio # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Thu Jan 23 11:37:54 2003 +++ b/arch/i386/Kconfig Thu Jan 23 11:37:54 2003 @@ -1554,6 +1554,15 @@ 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 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 Thu Jan 23 11:37:54 2003 +++ b/arch/i386/kernel/Makefile Thu Jan 23 11:37:54 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 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,7 @@ obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KMMIO) += kmmio.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o 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 Thu Jan 23 11:37:54 2003 @@ -0,0 +1,159 @@ +/* + * KMMIO + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ +#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/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Thu Jan 23 11:37:54 2003 +++ b/arch/i386/kernel/traps.c Thu Jan 23 11:37:54 2003 @@ -25,6 +25,7 @@ #include <linux/highmem.h> #include <linux/kallsyms.h> #include <linux/kprobes.h> +#include <linux/kmmio.h> #ifdef CONFIG_EISA #include <linux/ioport.h> @@ -529,6 +530,9 @@ __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. */ diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c Thu Jan 23 11:37:54 2003 +++ b/arch/i386/mm/fault.c Thu Jan 23 11:37:54 2003 @@ -21,6 +21,7 @@ #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> @@ -163,6 +164,9 @@ __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 */ 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 Thu Jan 23 11:37:54 2003 @@ -0,0 +1,33 @@ +/* + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ + +#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/linux/kmmio.h b/include/linux/kmmio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/kmmio.h Thu Jan 23 11:37:54 2003 @@ -0,0 +1,67 @@ +#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; +} +#endif +#endif /* _LINUX_KMMIO_H */ diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Thu Jan 23 11:37:54 2003 +++ b/kernel/Makefile Thu Jan 23 11:37:54 2003 @@ -4,7 +4,7 @@ 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 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 \ @@ -23,6 +23,7 @@ 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 <al...@li...>, 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 Thu Jan 23 11:37:54 2003 @@ -0,0 +1,149 @@ +/* Support for MMIO probes. + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. +*/ + +#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); |
From: Rusty L. <ru...@li...> - 2003-01-29 17:25:14
|
As part of the work from the fault injection project at http://fault-injection.sf.net/, the need for a few features has come up that are not specific to fault injection. One of these needed features is the ability to hook into an arbitrary interrupt handler, and have the opportunity to bypass that handler. For a fault injection test case we may need to simply note when a given interrupt has fired, take some action before the driver has a chance to respond to the interrupt, or maybe just drop the interrupt without the driver knowing. The following patch applies to a 2.5.59 kernel to provide such a feature for the i386 architecture. There really isn't much to this, we just add global functions for adding the hook (which we call kirq but I suspect that's probably a bad choice) and then removing the hook. Given the development kernel is currently in a feature freeze, and I can't really justify this as a driver, then this email is really an early request for comments. --rustyl # 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.956 -> 1.957 # arch/i386/Kconfig 1.34 -> 1.35 # arch/i386/kernel/Makefile 1.32 -> 1.33 # (new) -> 1.1 include/asm-i386/kirq.h # (new) -> 1.1 arch/i386/kernel/kirq.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/01/20 rusty@vmhack.(none) 1.957 # Adds KIRQ implementation which enables arbitrary interrupt callbacks # to be hooked into. # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Mon Jan 20 08:44:57 2003 +++ b/arch/i386/Kconfig Mon Jan 20 08:44:57 2003 @@ -1545,6 +1545,14 @@ Say Y here if you are developing drivers or trying to debug and identify kernel problems. +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 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 Mon Jan 20 08:44:57 2003 +++ b/arch/i386/kernel/Makefile Mon Jan 20 08:44:57 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 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,7 @@ obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_KIRQ) += kirq.o obj-y += sysenter.o EXTRA_AFLAGS := -traditional 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 Mon Jan 20 08:44:57 2003 @@ -0,0 +1,123 @@ +/* Support for kernel irq interceptor. + (C) 2002 Stanley Wang <sta...@in...>. +*/ + +#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/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 Mon Jan 20 08:44:57 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 +void dispatch_kirq(int irq, struct pt_regs* regs) {} +#endif /*CONFIG_KIRQ*/ +#endif /*_ASM_KIRQ_H*/ |
From: Gao, K. <kev...@in...> - 2003-01-29 01:07:30
|
The FITH utility has done, we still use tools "ficl" You can use parameters as follow: --attach, -a <modname,file_path> attach a module into dbp. --detach, -d detach all modules that attached to dbp. --insert, -i <file.fsml> insert a faultset written in file.fsml into FITH. --remove, -r {file.fsml|all} remove the faultset written in file.fsml or all faultset. --help, -h help information. You can download the code in bk://fau...@fa.../fith-tool |
From: Louis Z. <lou...@li...> - 2003-01-17 05:07:39
|
Dear Rusty, Following is KMMIO patch. It needs kprobes firstly. -- 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 You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== ChangeSet@1.951, 2003-01-17 11:30:25+08:00, lo...@ha... Add KMMIO 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. ChangeSet@1.950, 2003-01-17 11:05:19+08:00, lo...@ha... Merge arch/i386/Kconfig | 9 ++ arch/i386/kernel/Makefile | 1 arch/i386/kernel/kmmio.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/traps.c | 4 + arch/i386/mm/fault.c | 4 + include/asm-i386/kmmio.h | 33 +++++++++ include/linux/kmmio.h | 67 +++++++++++++++++++ kernel/Makefile | 1 kernel/kmmio.c | 149 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 427 insertions(+) diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Fri Jan 17 13:03:11 2003 +++ b/arch/i386/Kconfig Fri Jan 17 13:03:11 2003 @@ -1552,6 +1552,15 @@ 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 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 Fri Jan 17 13:03:11 2003 +++ b/arch/i386/kernel/Makefile Fri Jan 17 13:03:11 2003 @@ -32,6 +32,7 @@ obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KMMIO) += kmmio.o EXTRA_AFLAGS := -traditional 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 Fri Jan 17 13:03:11 2003 @@ -0,0 +1,159 @@ +/* + * KMMIO + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ +#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/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Fri Jan 17 13:03:11 2003 +++ b/arch/i386/kernel/traps.c Fri Jan 17 13:03:11 2003 @@ -25,6 +25,7 @@ #include <linux/highmem.h> #include <linux/kallsyms.h> #include <linux/kprobes.h> +#include <linux/kmmio.h> #ifdef CONFIG_EISA #include <linux/ioport.h> @@ -530,6 +531,9 @@ 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); diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c Fri Jan 17 13:03:11 2003 +++ b/arch/i386/mm/fault.c Fri Jan 17 13:03:11 2003 @@ -21,6 +21,7 @@ #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> @@ -165,6 +166,9 @@ 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/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 Fri Jan 17 13:03:11 2003 @@ -0,0 +1,33 @@ +/* + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ + +#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/linux/kmmio.h b/include/linux/kmmio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/kmmio.h Fri Jan 17 13:03:11 2003 @@ -0,0 +1,67 @@ +#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; +} +#endif +#endif /* _LINUX_KMMIO_H */ diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Fri Jan 17 13:03:11 2003 +++ b/kernel/Makefile Fri Jan 17 13:03:11 2003 @@ -23,6 +23,7 @@ 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 <al...@li...>, 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 Fri Jan 17 13:03:11 2003 @@ -0,0 +1,149 @@ +/* Support for MMIO probes. + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. +*/ + +#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); =================================================================== This BitKeeper patch contains the following changesets: 1.950,1.951 ## Wrapped with gzip_uu ## begin 664 bkpatch1305 M'XL(`(^.)SX``^U<ZW+;.++^+3X%9K*5(SFRS+LD:YR-XU$R+E_BLIVSWMU, ML2@2M+BB2!V22L:S\C[[Z09(B5?KDGAWIRI.RA8)H-'H_M#=:`!Z03Y&-#QL M>,'<C807Y)<@B@\;8_/+I!.-.ZX?4Z]C!5,HN0X"*#D8!U-ZP&H?R!UM?S*= MNH$`Q5=F;(W)9QI&APVIHRS?Q`\S>MBX'K[_>'Y\+0A'1^1D;/KW](;&Y.A( MB(/PL^G9T1LS'GN!WXE#TX^F-#:QU\6RZD(611G^:5)7$35](>FBVEU8DBU) MIBI16Y35GJX*C*\W)>[S=!11DKJBK*B:NM!TH";\3*1.7Q.)J!R(TH'4)9)T M*&J'4O^5V#L415)#EKR2R+XHO"7?=A`G@D4N:'A/!9>$\RA^>!,!P3BPS"BF M82>*77_R8)EQ!7%)EB115S49B*NJWA?.B*;)8E^X^&I*5RN]"?M;_@B":(K" MZS5R,D-K?.`J/?U@0D.?>@=0/(LZ5D9L*C"V4!6YJRT<4:)]LR>IMD+EGJ[7 M*>E)LAP*H`RQMU``$**P#82@G=1?<`%S"$DY""GBH:RM@U#_N2!T;-OD[.+B M]`.!!Y)\="-BDK-9&(PH?++M_<"/B!.$9.:9ENO?0RDK)(%/6`/3LF@4M<D\ M@E)&**3W+L+'8%._V6H3T[>QU6?7YA0LT_-&IC4ASMRW8A=&0V['T#/\GT?4 MF7N,#O8Z#7P71H[-[-`%XY'T1Z(9M5S'M1(F;#N$MQV`L]*79?7?"L;I],`Q MYUY<!**X@$FB2XN^W)6TOJ)V>Z.^*IO.!D#,DTS`)/=5;2&J6K\+S-71<'W+ MF]M@@%U__ML!TT!GG">B`U^Z)"^4O@1_^Z:IZHHTLD=?0[.[$/N:]A1CR=SB MK:TB1[JB]>"W;.MJCXYDK=?73:KN1*R[D.2>UENKP(3&A3FACNO1[,3I*_V% MJG<5:3&RM+YN]VW5I(HCV70=1UEJ6;5IHM27@:7?W=F,>F^8)/>G>F_2"<+[ MOZ>,_IJ!P)D5^(Y[SVTMT!+!JDF]A:SJO=X"U*=(/=$<]26MJXO6!I#*T,LR M)LM=7?DOMKR,2554>NKV3%:HEG.I*CJH1!I1VW%$3;%L4[3LS;FL4S),=EU] M8@J4"%7B5ULHNM@5%Z8M]M2N9-N*V+-MLQYZFY'5`8.*]A1[Z30WH^D^)U<U MT[6%)/;%[D*U-"J9(U76`7^VNMYZ/$U67X@]3=)8_%<W(`P'+^D7@K(_K*TE M_"]1Z[WTU^F`>?%\&"CW#]6U/EQ\#A]ND;=N?$;I#+PBBH14AMX'M7("7XF# M!%]96^6:E"1P1\3?>K*T@U=]3IU(V^L$?/+S1%;OB(1A-9MM'\A^^(7]!PD\ M(>CMI7DJ$AB!<+!'!++'@S?\\):"E8_)U/0?B!6`PW)"&.R$!W18H7G2(C@2 M<HZ"(7\;SV%\Y"<FIL[O[.G-4DJO.]#D0'B1S&&HQD(`[DHZX]>E$CZLJI)I M8,\]6E42S5S?"ZQ)9:MI90O/'.'[3^7^N6TI-YF!5JW*[F<AI=-9G"\"8W50 M)(3OQN[]>$JGO/,H-F.(0$%:Q)K-C_:E0?H*5E%S*R:,&X-%<L;,O*=DSYJ' M_-,1N?QX?E[=@`?8O"[[6*@\]R/WWJ?HL4!UO$UD?J:V01W/O(\&@`I4]2FH M,0SGLQ@B^9`2VXW,D0?-('2G?AP^$#,BZ'$5%O7[.!!>G]R;,66XPL@]'M,' M".JGINNO:,3C(`SF]V,2S&-X``++6)Y!!H7".8/Y8WLT;"9#G,4&+!`BLH>_ MVX6Q8!S?$OXI-`#6?Z'_`TQ#GUG.VF24]@?_+8^:(>/Q[<?WS=9^9#JT@[TW M$J4:";_-U@#TU4"4I:L2]B*CCGL:&T5]-9N?`]<F>RW&UT!HN`YI_I`V:A%@ M%#EE[#`RK"ERY@>`"1,6,S89/7!!,+ZP^MW='8G`4I,9]=F"B+<"K00@ZA"Q M!//W@;=GJRV/3G^`Y@3:S_W\(!J-^R`.H#_^"EX\PK"`PA&)IC/$#RZ7@M!P M;58]&7,"J]6@V9O">*&_,KB@51-5M_\Z>7Y)FK?OC(OCF[/%*?_;XAVAL%:= MO7Q)E@_[KT$_*3"X&*O+5NW;A.,EU<0C]I#C8W%$$CX&A9*71^1?IVG1IP1< M9!QXB#IKT@;I?2%?*(DHP!/6D3`YR`B,*&#OZG;(\(6+6_"PL*R=<8`AL,)I M&3$I.&`8"!$4Q"=D)YZ'/I&P^U15ARN44A]!:D`)]&Z-*5=5TD@<"(_0;+LI M+7W;*4U8RV-H^241'(<T,]O+^3X+HA1.J?[RTQO\ANTBP3:IL@9LYK,IYD8) M'1/Z_PS3MP406<F#52K#F_QPA),G7_?3&B`BS[5(S!1FH9@9!^.;X1$ZVA`1 MAN%X\VALQ-[("/Q*S)0!7(-M0'V5`_B4&@%T2D"N9#:>AIY`DA]`70,T#Q)$ MBS4*[`="/;!*``X^)7!&S%A6QPJ#*%JFAV8!(*)-.#^,QA?7\\@8N(1IBE.M MC?/KR]BUQF#I(B[5&#PR170FX$3"B8XQNX1D`H?8@6'3T?R^C6@'UE)W@$8W M[7_LQAVL?\#57[!8B3!+2%G-T\>L?X=``4844R,F>V@RX6.S[+B`R18!"*>R MF]W;V`#^@![P(7"<"`UN,ZV->ICR2E-6:9I6:D+]-LG4PT%@L6>&@"FLGYT3 MS82Y%KQ?60Y\F?;)XC*DD*7Z.&"&A5D6B'`/3I@_A69H_B(VK_,R8.[!\D*4 M@(%U*L301C>%CBI;`'6G9C1A\FDDS,*?`7M('!%*-37O4?*,S+2)L?QL0*3> MQ)8MT.*_EE1;@P8?3`6[":G_-+L+4N`6'0-CL-)J).8/Z$/?S"P(_X1YG!]` MBP4=8!VNCM\/4_.04T]%?>"/5;^Z'MX,+V];'.N,DSJG5L7,1KSD9+\Q+RRD MHDOO@U,[\+T'PL(I"':FY@1TZX:XS)GAB]$\0JSRX(4SZ_J?:1@;4"&):;"^ MP15>T/4\,I9Q)[HQ/F4&><4S-U(<PI(F@G$Y;IR7+!YEEI=3`\RD_>3J0I75 M^[SL\DBKZYEW4HF_9FF^K%A$.*;C)IE@8TGW52*%1O+#%#.\N_IP?6O<_/7B M[8=SX_W5>;,H;""%&9RZG$\^@U-7Z^D,SM>EJ?Z(&9Q:.9T1-DCAJEZ4UZ0D M@6?(X'P#G>R0P5&4YTS@L'1D(7]3*^:=\C>*DD3USY*TP>2(X]O4(<;QS87! M,D3&+\(+>(.^,?^RD!/!/?GHZ30*^MIL"(\F$IMAAVAQ]TC6:PPX.UAX\N'R MW>E[WK5`?X/UB4^V\8.#7*/-7=:RW;9+%8P/>$17N6C)T=TQY9$?T^XN;""\ M8.$Y>-`?LG(N1W*["*%1+P0(E$AFQ4K`793[VU$X%;1?8.;$2?[@:+-HQL%F MG5`N,UCM@7)5-G,_.VRPUO@>_8_@>_(2.B-LA!F+F"^_)J6Q/Z/7V54599>S M5A5Z]SE=#MM"KW$Y>0'OY&_T[LHEG)]>?KPK.X7"ZXWS_IX;Q57O84GN.BX- M*[/XTUDYP;Y,X"_]2R8_.1!J$NN#-<Z(-/=2,LO<HA&WFE5I]XRM*YJH3%&E M$:_N,I-$VJ!/LH,);@TJA(7)K.0M:L<84]-FG](<J!=8)EM?!0Y;;V42-RQO MDG.A^(<U1&M[8GJ8,!Q1)P@I*\(U&OV-6O.8VIU,ZYR\2>8I92(A93HQGNTI M4$)WX.&YGDZ.9DZ@)/LX2+,`U=LOVTJ$)^;YSDU1(!QVG_B2T0KF?IQT7A7F M`.WSP)I$G"7P.^'_D>D\BD&$J_QKNH+-9.KP&93+7N=2>$D!6ROS5"SF>UFR M%#<<V/9"!@O1GZLC@&*>E9'%=7`2CBRQN'+?R5!3?YQ[F2S>W].8B8\S9B;) M9*;<)KAKB');'4(N</PL'VAQ#*R&QYDM3Y/B=D4)H<6)D-UZJ]S@J0H3<:SP M9K/*3#4A]:@9T<U:?&(=Y`_))>.I&O-LI?^MVK!`<%.5;Q1BY7Q#&F0]=4)C MFW,9NQP/^R/&4Z4S&&QHX.=+)R]*HWV&"&IGJ>\0.DGJLYZWX(?^"L'3-SEE MH;)3%C?SV2P(8W8JE2VIN&'M/,OZ/5F^;WBVX:D#%&,3M%#QWO7=RH#MB6,: MR:&+?+QFF=:8LNVL<AD-0W_=&8HT\DS,RO'-+\;;T]L;HA=*;H_?G@^-F]._ M#4E3(C_]5&S06B7_2RZ>V[L8O>S?B]1^'9288%G2%2=J57$-._FFK34<H4/( ML54@S7BK<\'D"/>LT@X2!!AI%7R`&C=7IY?&^8>3,^/C)?X9_IS$#,5H)-H\ M','P`/MC?31?KOK+[B24@Y5E,UY4T1#8^FLPYR$!)O7Y3C-N`2Z#"3ZN#:,# MGC19IO9+2MC#WVVR%T]G+)!C+X_(RRQ<</H8LSAL\K1+$72@H08C"%;!H#`5 MFD"L39`2WTRN],[0"6O$=NQYBW*]-JO#3GBPO;_]URR`PN.1;$2-Y>;?C!^' M2)[X2:''[<.,=/LCI`FV&AD]&X"1@LH:&3"^>I5L419UD+#=XM+@I/>'P[O3 MF]OEV95@'O,1,*%`]>9+:(8/[1IE)%0K]-%:;OA71G!Y=F8AC'?2/!M>7QK# MZVORXT>V&8[@8T=!EB=Z/OD_IF=.D-O#')*K1+/:WX?0-GN8(Z1Q;I9LJ9\G M]5$;A::C3L%J4V\IXH(B]_<'ZP;W^,0":],@>Z/YN,'^8G[*9NSI"BILE['2 M.F\W>;.CG+&U^)I9O&I0GLK\S-E1(HS-IO*&2Y*,:,N,.VQ6;R!8I^Y$7'I" M!0?B<#$Y^Z]71B![2N>1TVG6LM.:3&%^!%8S<G^G@=/<<UIM\O[=E7%\^^'B M]&1YX@XZ2LBRXRQIAT`[>4S.\/$U><:..*D=`<:>0DE"H@XHW*I4[C,XJT,[ M^?-:VRX,U^EMLPFQD=Y`G@FS&6&RF>\Z4)B\X,JMVU_)C#MC5)R547G,'Z&) MB6%@S$GP5S$N8.O2-`GS[O3N8D@8+O#(VBHSQ736QL-;(<PY[X'PL,PFO!-H M\<#2-$`#.W%-#U"%A-CT8_.:'1-H8`C?=)F3(R[YJ11APMM7KW!:GEZ>WL*R M]^;6^&5X_',SYXS<7YFAKR15B.,X/5)+,(-(3C6+)"XV'%US)3H&R/)N?)4W M@:KEBM6.)]F\K[WOLOXZ[E=>P=G\AD#Y"HZLJ&IO(2N:I+`5JB+O<"7@^U7+ M;:Y:\OM.ZZXXI*K:9?6MJ+"V#T;_V/]3,YM/;9'LSZOD"&0GJ(9O<JEL!_1N M=<M-6'N!^DGZR7UJ^+60-$U+0-PK7CD7>_^1[!:"^.;DY(9,\=ZY+;@K^ICF MVD:0DBSCO6CXO5!4K:L"+1N6?/]X@YD3`.&$/N"ER,Y\LHZ.(HFJS';W$CI< M`_C;"L(9LM(QYY6W*ROO&XHP=K&K=1<J*$+^%O0D7=,5X$\11?$K9(:T^F#A M-!EH::`1H#6ZIV$4O[%=VX_MN55_D;3Z:J4BZ6"!Y84*\NOB53!VN?WBVY)= M9QJ2QL]ZE^S)R_QLCO6W=Q3J=T>QC:/@]W>?#PVG,JBN/E]ZJD$PH*2)@8I3 M+\7S_)F3U=*`%+S*ZF[^-AYEVR\)V`#@55\2P*,@799U_HT3LO(=W,\-;OQ" MAEILKY2T$ZZ5)W$MZ5W`-4-UZ<8,WG/)HWQU@0I/_Z\PCCF!S%;>YM'^3M^@ ML&XOJBZRAYFA2QS3VO?(_IDQS;^NHGHS[6OB>5!=73Q?&\4G7UR!<'RF;\_8 MP-:6OCTC,;1*%X(QMB&Z`RB_?[//=LM-]E4EM98V4=$NL(0%ETKZ0@*TY"Y] M\C,*`H_\R$78'-Y=#:]/+X:7M\?GK1^%ADWQ#B]>3R'9HES!V=7UA[?#&X+9 K:F\F-+Z1/AK?1AV-W;3Q:?6-;M:86I-H/CVR%+#[HFX+_P_:DR5D,TX````` ` end |
From: <sta...@li...> - 2003-01-17 01:59:06
|
FYI -Stan # 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.952 -> 1.953 # arch/i386/Kconfig 1.14.1.20 -> 1.20 # arch/i386/kernel/Makefile 1.31.1.1 -> 1.33 # (new) -> 1.7 arch/i386/kernel/kirq.c # (new) -> 1.5 include/asm-i386/kirq.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/01/17 st...@ma... 1.953 # Merge manticore.sh.intel.com:/home/stanley/linux-2.5 # into manticore.sh.intel.com:/home/stanley/work/2.5-kirq # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Fri Jan 17 09:52:42 2003 +++ b/arch/i386/Kconfig Fri Jan 17 09:52:42 2003 @@ -1591,6 +1591,14 @@ best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +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 DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Fri Jan 17 09:52:42 2003 +++ b/arch/i386/kernel/Makefile Fri Jan 17 09:52:42 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 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,7 @@ obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_KIRQ) += kirq.o obj-y += sysenter.o EXTRA_AFLAGS := -traditional 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 Fri Jan 17 09:52:42 2003 @@ -0,0 +1,123 @@ +/* Support for kernel irq interceptor. + (C) 2002 Stanley Wang <sta...@in...>. +*/ + +#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/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 Fri Jan 17 09:52:42 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*/ -- Opinions expressed are those of the author and do not represent Intel Corporation |
From: Louis Z. <lou...@li...> - 2003-01-16 02:46:03
|
FYI -----Forwarded Message----- > From: Andrew J. Hutton <aj...@li...> > To: Louis Zhuang <lou...@li...> > Subject: Re: FW: OSL Paper Proposal - Fault Injection Test Harness Project > Date: 15 Jan 2003 21:40:29 -0500 > > Now we wait while the review committee goes over the 100 submissions so > far and tries to pick out the 40 we'll be accepting. > > On Wed, 2003-01-15 at 21:26, Louis Zhuang wrote: > > Dear Andrew, > > Greatly thanks for your help. It is my first time to submit such > > stuffs... What should I do the next? Many thanks! > > > > Yours truly, > > - Louis > > On Thu, 2003-01-16 at 10:21, Zhuang, Louis wrote: > > > -----Original Message----- > > > From: Andrew J. Hutton [mailto:aj...@li...] > > > Sent: Thursday, January 16, 2003 9:55 AM > > > To: Zhuang, Louis > > > Subject: Re: OSL Paper Proposal - Fault Injection Test Harness Project > > > > > > This message uses a character set that is not supported by the Internet > > > Service. To view the original message content, open the attached message. > > > If the text doesn't display correctly, save the attachment to disk, and then > > > open it using a viewer that can display the original character set. > > > <<message.txt>> > -- > Andrew J. Hutton <aj...@li...> > Linux Symposium Inc. -- 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 |
From: Gao, K. <kev...@in...> - 2003-01-16 01:13:13
|
FITH Utility Usage Model draft: 1. I think useing old fsml (xml file format) file for user to build a trigger (IRQ trigger used different model, ".xml", it is xml file format yet.) is still a good choise. User only needs one=20 template (using our test cases), and then changing some parameters is enough. =20 The draft fsml: <?xml encoding=3D"UTF-8" ?> <fsml:fsml xmlns:fsml=3D"http://fault-injection.sourceforge.net/FSML"> <fsml:trigger <!-- Required, but not used in current release --> id=3D"string" <!-- trigger name, it should be exclusive --> name=3D"string" <!-- Required, intercptor name, e.g. pf, dbp... --> interceptor=3D"string" <!-- Required, 'm' means capture MMIO while default is IO. 'seq_io' means capture specific IO sequence. 'pci_config' means capture PCI=20 configuration access. You could select one or none from the previous three types. 'r' and 'w' stand for capturing read or write access. You must select at least one of them. --> type=3D"[m|seq_io|pci_config]|{r|w}" =20 <!-- Required, corrupted address length --> len=3D"1|2|4" addr=3D"0xXXXXXXXX" <!-- The following two attributes are only used for type =A1=B0seq_io=A1=B1 --> index_addr=3D"0xXXXXXXXX" data_addr=3D"0xXXXXXXXX" <!-- The following four attributes are only=20 used for type =A1=B0pci_config=A1=B1 --> bus=3D"unsigned integer" slot=3D"unsigned integer" func=3D"unsigned integer" reg_no=3D"unsigned integer" <!-- bitmask/min/max are optional.=20 bitmask/min/max allow you to specify a condition logic. The trigger starts to work only if it meets "min <=3D captured data & ~bitmask < max" condition. By default, the condition is always met. --> bitmask=3D"0xXXXXXXXX" min=3D"unsigned integer" max=3D"unsigned integer" <!-- Optional. Default to 0. trigger starts to work after the specified access type happens=20 'skip' times. --> skip=3D"unsigned integer" <!-- Optional. Default to 0, never stops. Trigger will stop to work after the specified access type happens 'stop' times --> stop=3D"unsigned integer" <!-- Optional. Default to 0, no protection! bit set to 1 in this mask will never be=20 corrupted or modified. This only applies to write fault injectionFI. --> protection_mask=3D"0xXXXXXXXX" <!-- Optional. Default to be 1 and not allow being negative. Trigger is activated once every 'hz' times with considerations of 'skip' and 'stop'. --> HZ=3D"unsigned integer" > =09 <!-- Execute the specified Code-Segment=A1=AFs name. You must NOT use Code-Segment and the other actions simultaneously. --> <fsml:action codesegment=3D"string" /> <!-- Captured data is replaced with this 'val' --> <fsml:set val=3D"0xXXXXXXXX" /> <!-- Captured data & 'val' --> <fsml:and val=3D"0xXXXXXXXX" /> <!-- Captured data | val' --> <fsml:or val=3D"0xXXXXXXXX" /> <!-- !Captured data --> <fsml:not /> <!-- Captured data ^ 'val' --> <fsml:xor val=3D"0xXXXXXXXX" /> <!-- !(Captured data & 'val') --> <fsml:nand val=3D"0xXXXXXXXX" /> <!-- !(Captured data | 'val') --> <fsml:nor val=3D"0xXXXXXXXX" /> <!-- Captured data + 'val' --> <fsml:add val=3D"0xXXXXXXXXX" /> <!-- Captured data - 'val' --> <fsml:sub val=3D"0xXXXXXXXX" /> </fsml:trigger> </fsml:fsml> IRQ trigger will not be changed: <?xml version=3D"1.0" encoding=3D"UTF-8" ?> <fake_irq=20 <!-- the intercepted IRQ number. --> irq=3D"unsigned integer" =20 <!-- The IRQ device name. You can get it=20 by =A1=AEcat /proc/interrupt=A1=AF. FITH use the name to distinguish IRQ handlers in the=20 same IRQ name. --> devname=3D"dummy" <!-- Optional. The IRQ will isbe spurious every X timer ticker. X is the value of=20 the attribute. Vaild range [0, 0x7FFFFFFF] --> spurious_hertz=3D"unsigned integer" <!-- Optional. The IRQ will isbe delayed every Y times. Y is the value of the attribute. Vaild range [0, 0x7FFFFFFF] --> delay_hertz=3D"unsigned integer" <!-- Optional. The default value =A1=AE0=A1=AF means =A1=AEdelay unlimited time=A1=AF. FITH will delays the delayed IRQ Z timer ticker. Z is the value of the attribute. Vaild range [0, 0x7FFFFFFF] --> delay_time=3D"unsigned integer" /> 2. The execution file of FITH utility is still "ficl", and most of the functionality will be not changed. So old user will change little about their test cases.=20 =20 The usage model of "ficl" command: --insert, -i <file.fsml> insert a faultset written in file.fsml into FITH,=20 enable the faultset and return the SN of the faultset. --remove, -r <SN>|all remove the faultset specified by SN. Also you can use '-r all' to remove all faultset.=20 --disable, -d <SN>|all --enable, -e <SN>|all disable/enable the faultset specified by SN. Also you can use '-d all'/'-e all' to disable/enable all faultset.=20 --setirq, -s <file.xml> --clrirq, -c=20 set/clear irq IRQ faultset. Notice, irq IRQ faultset is different and does not use fsml format. Please also read examples in fith/test/src/fault_set/fun_test/irq*.xml. --verbose, -v verbose mode=20 --version, -V print version information=20 --help, -h print help information There is a still issue, do we need to use ficl command to insert and register the codesegment instead of user register it.If so,=20 we will add new command parameter to do that thing. Any comment/idea? =20 -Kevin |
From: Rusty L. <ru...@li...> - 2003-01-15 17:28:34
|
Kevin, it looks like your email client added newlines, making your email pretty hard to read. Could you resend without the extra newlines? -rustyl On Tue, 2003-01-14 at 18:11, Gao, Kevin wrote: > FITH Utility Usage Model draft: >=20 > 1. I think useing old fsml (xml file format) file for user to build a > trigger (IRQ trigger used > different model, ".xml", it is xml file format yet.) is still a g= ood > choise. User only needs one=20 > template (using our test cases), and then changing some parameters i= s > enough. > =20 > The draft fsml: >=20 > <?xml encoding=3D"UTF-8" ?> > <fsml:fsml xmlns:fsml=3D"http://fault-injection.sourceforge.net/FSML"> > <fsml:trigger > id=3D"string" <!-- Required, but > not used in current release --> > name=3D"string" <!-- trigger name, > it should be exclusive --> > interceptor=3D"string" <!-- Required, > intercptor name, e.g. pf, dbp... --> > type=3D"[m|seq_io|pci_config]|{r|w}" <!-- Required, 'm' > means capture MMIO while=20 > =09 > default is IO. 'seq_io' means capture specific =20 > IO sequence. > 'pci_config' means capture PCI =20 > configuration > access. You could select one or =20 > none from the > previous three types. 'r' and=20 > 'w' stand for > capturing read or write access.=20 > =09 > You must select at least one of them. --> > len=3D"1|2|4" <!-- Required, > corrupted address length --> > addr=3D"0xXXXXXXXX" >=20 > <!-- The following two attributes are only used for type > =E2=80=9Cseq_io=E2=80=9D--> > index_addr=3D"0xXXXXXXXX" > data_addr=3D"0xXXXXXXXX" >=20 > <!-- The following four attributes are only used for > type =E2=80=9Cpci_config=E2=80=9D--> > bus=3D"unsigned integer" > slot=3D"unsigned integer" > func=3D"unsigned integer" > reg_no=3D"unsigned integer" >=20 > <!-- NOTICE! YOU SHOULDMUST NOT SET THESE ATTRIBUTES AS > NEGATIVE!!! > bitmask/min/max are optional. bitmask/min/max allow you >=20 > to specify a condition logic. The trigger starts to > work only=20 > if it meets "min <=3D captured data & ~bitmask < max" > condition.=20 > By default, the condition is always met. > --> =09 > bitmask=3D"0xXXXXXXXX" > min=3D"unsigned integer" > max=3D"unsigned integer" >=20 > <!-- Optional. Default to 0. trigger starts to work after > the=20 > specified access type happens 'skip' times. --> > skip=3D"unsigned integer" >=20 > <!-- Optional. Default to 0, never stops. Trigger will > stop=20 > to work after the specified access type happens 'stop' > times --> > stop=3D"unsigned integer" >=20 > <!-- Optional. Default to 0, no protection! bit set to > 1 in=20 > this mask will never be corrupted or modified. This > only=20 > applies to write fault injectionFI. --> > protection_mask=3D"0xXXXXXXXX" > <!-- Optional. Default to be 1 and not allow being > negative.=20 > Trigger is activated once every 'hz' times with > considerations=20 > of 'skip' and 'stop'. --> > HZ=3D"unsigned integer" > > > <fsml:action codesegment=3D"string" /> <!-- Execute > the specified Code-Segment=E2=80=99s=20 > =09 > name. You must NOT use Code-Segment and > the > other actions simultaneously. --> =20 > <fsml:set val=3D"0xXXXXXXXX" /> <!-- > Captured data is replaced with this 'val' --> > <fsml:and val=3D"0xXXXXXXXX" /> <!-- > Captured data & 'val' --> > <fsml:or val=3D"0xXXXXXXXX" /> <!-- > Captured data | val' --> > <fsml:not /> <!-- > !Captured data --> > <fsml:xor val=3D"0xXXXXXXXX" /> <!-- > Captured data ^ 'val' --> > <fsml:nand val=3D"0xXXXXXXXX" /> <!-- > !(Captured data & 'val') --> > <fsml:nor val=3D"0xXXXXXXXX" /> <!-- > !(Captured data | 'val') --> > <fsml:add val=3D"0xXXXXXXXXX" /> <!-- > Captured data + 'val' --> > <fsml:sub val=3D"0xXXXXXXXX" /> <!-- > Captured data - 'val' --> > </fsml:trigger> > </fsml:fsml> >=20 > IRQ trigger will not be changed: >=20 > <?xml version=3D"1.0" encoding=3D"UTF-8" ?> > <fake_irq=20 > <!-- NOTICE! YOU SHOULDMUST NOT SET THESE ATTRIBUTES AS > NEGATIVE!!! =C3=A0 > <!-- the intercepted IRQ number. --> > irq=3D"unsigned integer" > =20 > <!-- The IRQ device name. You can get it by =E2=80=98cat > /proc/interrupt=E2=80=99. FITH use the > name to distinguish IRQ handlers in the same IRQ name. --> > devname=3D"dummy" >=20 > <!-- Optional. The IRQ will isbe spurious every X timer ticker.= X > is the value of the=20 > attribute. Vaild range [0, 0x7FFFFFFF] --> > spurious_hertz=3D"unsigned integer" >=20 > <!-- Optional. The IRQ will isbe delayed every Y times. Y is th= e > value of the > attribute. Vaild range [0, 0x7FFFFFFF] --> > delay_hertz=3D"unsigned integer" >=20 > <!-- Optional. The default value =E2=80=980=E2=80=99 means =E2= =80=98delay unlimited > time=E2=80=99. FITH will > delays the delayed IRQ Z timer ticker. Z is the value of the > attribute. > Vaild range [0, 0x7FFFFFFF] --> > delay_time=3D"unsigned integer" > /> >=20 > 2. The execution file of FITH utility is still "ficl", and most of the > functionality will be not changed. > So old user will change little about their test cases.=20 > =20 > The usage model of "ficl" command: >=20 > --insert, -i <file.fsml> > insert a faultset written in file.fsml into FITH, enable the > faultset and return the SN of the faultset. >=20 > --remove, -r <SN>|all > remove the faultset specified by SN. Also you can use '-r all' to > remove all faultset.=20 >=20 > --disable, -d <SN>|all > --enable, -e <SN>|all > disable/enable the faultset specified by SN. Also you can use '-d > all'/'-e all' to disable/enable all faultset.=20 >=20 > --setirq, -s <file.xml> > --clrirq, -c=20 > set/clear irq IRQ faultset. Notice, irq IRQ faultset is different > and does not use fsml format. Please also read examples in > fith/test/src/fault_set/fun_test/irq*.xml.=20 >=20 > --verbose, -v > verbose mode=20 >=20 > --version, -V > print version information=20 >=20 > --help, -h > print help information >=20 > There is a still issue, do we need to use ficl command to insert and > register the codesegment instead of user register it. > If so we will add new command parameter to do that thing. >=20 > Any comment/idea? > =20 > -Kevin >=20 >=20 > ------------------------------------------------------- > This SF.NET email is sponsored by: Take your first step towards giving=20 > your online business a competitive advantage. Test-drive a Thawte SSL=20 > certificate - our easy online guide will show you how. Click here to get=20 > started: http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0027en > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Gao, K. <kev...@in...> - 2003-01-15 02:14:05
|
FITH Utility Usage Model draft: 1. I think useing old fsml (xml file format) file for user to build a trigger (IRQ trigger used different model, ".xml", it is xml file format yet.) is still a = good choise. User only needs one=20 template (using our test cases), and then changing some parameters = is enough. =20 The draft fsml: <?xml encoding=3D"UTF-8" ?> <fsml:fsml xmlns:fsml=3D"http://fault-injection.sourceforge.net/FSML"> <fsml:trigger id=3D"string" <!-- Required, but not used in current release --> name=3D"string" <!-- trigger name, it should be exclusive --> interceptor=3D"string" <!-- Required, intercptor name, e.g. pf, dbp... --> type=3D"[m|seq_io|pci_config]|{r|w}" <!-- Required, 'm' means capture MMIO while=20 =09 default is IO. 'seq_io' means capture specific =20 IO sequence. 'pci_config' means capture PCI =20 configuration access. You could select one or =20 none from the previous three types. 'r' and=20 'w' stand for capturing read or write access.=20 =09 You must select at least one of them. --> len=3D"1|2|4" <!-- Required, corrupted address length --> addr=3D"0xXXXXXXXX" <!-- The following two attributes are only used for type =A1=B0seq_io=A1=B1--> index_addr=3D"0xXXXXXXXX" data_addr=3D"0xXXXXXXXX" <!-- The following four attributes are only used for type =A1=B0pci_config=A1=B1--> bus=3D"unsigned integer" slot=3D"unsigned integer" func=3D"unsigned integer" reg_no=3D"unsigned integer" <!-- NOTICE! YOU SHOULDMUST NOT SET THESE ATTRIBUTES AS NEGATIVE!!! bitmask/min/max are optional. bitmask/min/max allow you to specify a condition logic. The trigger starts to work only=20 if it meets "min <=3D captured data & ~bitmask < max" condition.=20 By default, the condition is always met. --> =09 bitmask=3D"0xXXXXXXXX" min=3D"unsigned integer" max=3D"unsigned integer" <!-- Optional. Default to 0. trigger starts to work after the=20 specified access type happens 'skip' times. --> skip=3D"unsigned integer" <!-- Optional. Default to 0, never stops. Trigger will stop=20 to work after the specified access type happens 'stop' times --> stop=3D"unsigned integer" <!-- Optional. Default to 0, no protection! bit set to 1 in=20 this mask will never be corrupted or modified. This only=20 applies to write fault injectionFI. --> protection_mask=3D"0xXXXXXXXX" <!-- Optional. Default to be 1 and not allow being negative.=20 Trigger is activated once every 'hz' times with considerations=20 of 'skip' and 'stop'. --> HZ=3D"unsigned integer" > <fsml:action codesegment=3D"string" /> <!-- Execute the specified Code-Segment=A1=AFs=20 =09 name. You must NOT use Code-Segment and the other actions simultaneously. --> =20 <fsml:set val=3D"0xXXXXXXXX" /> <!-- Captured data is replaced with this 'val' --> <fsml:and val=3D"0xXXXXXXXX" /> <!-- Captured data & 'val' --> <fsml:or val=3D"0xXXXXXXXX" /> <!-- Captured data | val' --> <fsml:not /> <!-- !Captured data --> <fsml:xor val=3D"0xXXXXXXXX" /> <!-- Captured data ^ 'val' --> <fsml:nand val=3D"0xXXXXXXXX" /> <!-- !(Captured data & 'val') --> <fsml:nor val=3D"0xXXXXXXXX" /> <!-- !(Captured data | 'val') --> <fsml:add val=3D"0xXXXXXXXXX" /> <!-- Captured data + 'val' --> <fsml:sub val=3D"0xXXXXXXXX" /> <!-- Captured data - 'val' --> </fsml:trigger> </fsml:fsml> IRQ trigger will not be changed: <?xml version=3D"1.0" encoding=3D"UTF-8" ?> <fake_irq=20 <!-- NOTICE! YOU SHOULDMUST NOT SET THESE ATTRIBUTES AS NEGATIVE!!! =A8=A4 <!-- the intercepted IRQ number. --> irq=3D"unsigned integer" =20 <!-- The IRQ device name. You can get it by =A1=AEcat /proc/interrupt=A1=AF. FITH use the name to distinguish IRQ handlers in the same IRQ name. --> devname=3D"dummy" <!-- Optional. The IRQ will isbe spurious every X timer = ticker. X is the value of the=20 attribute. Vaild range [0, 0x7FFFFFFF] --> spurious_hertz=3D"unsigned integer" <!-- Optional. The IRQ will isbe delayed every Y times. Y is = the value of the attribute. Vaild range [0, 0x7FFFFFFF] --> delay_hertz=3D"unsigned integer" <!-- Optional. The default value =A1=AE0=A1=AF means = =A1=AEdelay unlimited time=A1=AF. FITH will delays the delayed IRQ Z timer ticker. Z is the value of the attribute. Vaild range [0, 0x7FFFFFFF] --> delay_time=3D"unsigned integer" /> 2. The execution file of FITH utility is still "ficl", and most of the functionality will be not changed. So old user will change little about their test cases.=20 =20 The usage model of "ficl" command: --insert, -i <file.fsml> insert a faultset written in file.fsml into FITH, enable the faultset and return the SN of the faultset. --remove, -r <SN>|all remove the faultset specified by SN. Also you can use '-r all' to remove all faultset.=20 --disable, -d <SN>|all --enable, -e <SN>|all disable/enable the faultset specified by SN. Also you can use '-d all'/'-e all' to disable/enable all faultset.=20 --setirq, -s <file.xml> --clrirq, -c=20 set/clear irq IRQ faultset. Notice, irq IRQ faultset is different and does not use fsml format. Please also read examples in fith/test/src/fault_set/fun_test/irq*.xml.=20 --verbose, -v verbose mode=20 --version, -V print version information=20 --help, -h print help information There is a still issue, do we need to use ficl command to insert and register the codesegment instead of user register it. If so we will add new command parameter to do that thing. Any comment/idea? =20 -Kevin |
From: Louis Z. <lou...@li...> - 2003-01-15 01:35:57
|
Because of Linus' and my :-p long vacation, the patch against 2.5.58 is here. Please take a look at it and use it. -- 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 REPORTING-BUGS | 2 arch/i386/Kconfig | 163 +++++ arch/i386/kernel/Makefile | 5 arch/i386/kernel/entry.S | 22 arch/i386/kernel/kirq.c | 123 ++++ arch/i386/kernel/kmmio.c | 159 +++++ arch/i386/kernel/kprobes.c | 160 +++++ arch/i386/kernel/traps.c | 40 + arch/i386/mm/fault.c | 8 drivers/Makefile | 2 drivers/fi/Makefile | 11 drivers/fi/README | 181 +++++ drivers/fi/codesegments/Makefile | 7 drivers/fi/codesegments/fi_sample_cs.c | 76 ++ drivers/fi/fi_core.c | 941 +++++++++++++++++++++++++++++++ drivers/fi/interceptors/Makefile | 9 drivers/fi/interceptors/dbp/Makefile | 9 drivers/fi/interceptors/dbp/fi_dbp.c | 556 ++++++++++++++++++ drivers/fi/interceptors/fi_irq.c | 239 +++++++ drivers/fi/interceptors/pf/Makefile | 10 drivers/fi/interceptors/pf/fi_pf.h | 43 + drivers/fi/interceptors/pf/pf.c | 269 ++++++++ drivers/fi/interceptors/pf/pf_in.c | 446 ++++++++++++++ drivers/fi/interceptors/pf/pf_utils.c | 63 ++ drivers/fi/testing/Makefile | 9 drivers/fi/testing/fi_mock_cs.c | 41 + drivers/fi/testing/fi_mock_interceptor.c | 121 +++ drivers/fi/testing/fi_test.c | 304 ++++++++++ include/asm-i386/kirq.h | 27 include/asm-i386/kmmio.h | 33 + include/asm-i386/kprobes.h | 34 + include/linux/fi.h | 158 +++++ include/linux/kmmio.h | 67 ++ include/linux/kprobes.h | 60 + kernel/Makefile | 6 kernel/kmmio.c | 149 ++++ kernel/kprobes.c | 89 ++ 37 files changed, 4628 insertions(+), 14 deletions(-) # 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.1024 -> 1.1025 # 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.8 drivers/fi/codesegments/fi_sample_cs.c # (new) -> 1.11 drivers/fi/interceptors/fi_irq.c # (new) -> 1.1 arch/i386/kernel/kprobes.c # (new) -> 1.25 drivers/fi/interceptors/pf/pf.c # (new) -> 1.4 drivers/fi/README # (new) -> 1.13 drivers/fi/Makefile # (new) -> 1.4 include/linux/kmmio.h # (new) -> 1.1 drivers/fi/testing/Makefile # (new) -> 1.42 drivers/fi/fi_core.c # (new) -> 1.7 drivers/fi/interceptors/pf/Makefile # (new) -> 1.1 drivers/fi/interceptors/Makefile # (new) -> 1.9 drivers/fi/interceptors/pf/pf_in.c # (new) -> 1.8 arch/i386/kernel/kmmio.c # (new) -> 1.1 include/asm-i386/kprobes.h # (new) -> 1.14 drivers/fi/interceptors/dbp/fi_dbp.c # (new) -> 1.1 include/linux/kprobes.h # (new) -> 1.8 kernel/kmmio.c # (new) -> 1.15 include/linux/fi.h # (new) -> 1.16 drivers/fi/testing/fi_test.c # (new) -> 1.9 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.13 drivers/fi/testing/fi_mock_interceptor.c # (new) -> 1.6 include/asm-i386/kirq.h # (new) -> 1.1 drivers/fi/codesegments/Makefile # (new) -> 1.4 include/asm-i386/kmmio.h # (new) -> 1.9 drivers/fi/interceptors/pf/fi_pf.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/01/14 lo...@ha... 1.1017.1.2 # Trivially code clean. Make all but kprobes 80 cloumn width for patch. # -------------------------------------------- # 03/01/15 lo...@ha... 1.1025 # Merge hawk.sh.intel.com:/home/work/linux-2.5 # into hawk.sh.intel.com:/home/louis/2.5-fi # -------------------------------------------- # diff -Nru a/REPORTING-BUGS b/REPORTING-BUGS --- a/REPORTING-BUGS Wed Jan 15 09:25:57 2003 +++ b/REPORTING-BUGS Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 +++ b/arch/i386/Kconfig Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 +++ b/arch/i386/kernel/Makefile Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 +++ b/arch/i386/kernel/entry.S Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,123 @@ +/* Support for kernel irq interceptor. + (C) 2002 Stanley Wang <sta...@in...>. +*/ + +#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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,159 @@ +/* + * KMMIO + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ +#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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,160 @@ +/* + * Support for kernel probes. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ + +#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 Wed Jan 15 09:25:57 2003 +++ b/arch/i386/kernel/traps.c Wed Jan 15 09:25:57 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(®s, 7)) + return; if (!tsk->used_math) init_fpu(tsk); restore_fpu(tsk); @@ -831,9 +857,9 @@ #endif set_trap_gate(0,÷_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 Wed Jan 15 09:25:57 2003 +++ b/arch/i386/mm/fault.c Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 +++ b/drivers/Makefile Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,181 @@ +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. + +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 Wed Jan 15 09:25:57 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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,76 @@ +/* Copyright (C) 2002 Louis Zhuang <lou...@in...> */ +#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 <lou...@in...>" +#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 Wed Jan 15 09:25:57 2003 @@ -0,0 +1,941 @@ +/********************************************************************* + * Fault Injection Core Functionality + * Copyright (C) Intel Crop. + * + ********************************************************************* + * + * 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 <lou...@in...>. 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 <lou...@in...> + * Stanley Wang <sta...@in...> + * Rusty Lynch <ru...@li...> + */ + +#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; + ret... [truncated message content] |
From: Patrick M. <mo...@os...> - 2003-01-14 16:40:48
|
On 14 Jan 2003, Louis Zhuang wrote: > Dear Mochel, > I suggest to export kset_find_obj. Pls apply. ;-) > Thanks, applied. -pat |
From: Louis Z. <lou...@li...> - 2003-01-14 05:55:33
|
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 st...@ma... 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 <sta...@in...>. +*/ + +#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 <lou...@in...>. + */ +#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 <vam...@in...>. + */ + +#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(®s, 7)) + return; if (!tsk->used_math) init_fpu(tsk); restore_fpu(tsk); @@ -831,9 +857,9 @@ #endif set_trap_gate(0,÷_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 <lou...@in...> */ +#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 <lou...@in...>" +#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 <lou...@in...>. 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 <lou...@in...> + * Stanley Wang <sta...@in...> + * Rusty Lynch <ru...@li...> + */ + +#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 ... [truncated message content] |
From: Louis Z. <lou...@li...> - 2003-01-14 03:42:01
|
Dear Mochel, I suggest to export kset_find_obj. Pls apply. ;-) -- 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 You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== ChangeSet@1.970, 2003-01-14 11:34:48+08:00, lo...@ha... trivial fix and export kset_find_obj include/linux/kobject.h | 2 +- lib/kobject.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff -Nru a/include/linux/kobject.h b/include/linux/kobject.h --- a/include/linux/kobject.h Tue Jan 14 11:36:05 2003 +++ b/include/linux/kobject.h Tue Jan 14 11:36:05 2003 @@ -87,7 +87,7 @@ } -extern struct kobject * kset_find_obj(struct kset *, char *); +extern struct kobject * kset_find_obj(struct kset *, const char *); struct subsystem { diff -Nru a/lib/kobject.c b/lib/kobject.c --- a/lib/kobject.c Tue Jan 14 11:36:05 2003 +++ b/lib/kobject.c Tue Jan 14 11:36:05 2003 @@ -295,7 +295,7 @@ * looking for a matching kobject. Return object if found. */ -struct kobject * kset_find_obj(struct kset * kset, char * name) +struct kobject * kset_find_obj(struct kset * kset, const char * name) { struct list_head * entry; struct kobject * ret = NULL; @@ -386,6 +386,8 @@ EXPORT_SYMBOL(kobject_unregister); EXPORT_SYMBOL(kobject_get); EXPORT_SYMBOL(kobject_put); + +EXPORT_SYMBOL(kset_find_obj); EXPORT_SYMBOL(subsystem_init); EXPORT_SYMBOL(subsystem_register); =================================================================== This BitKeeper patch contains the following changesets: 1.970 ## Wrapped with gzip_uu ## begin 664 bkpatch3959 M'XL(`*6%(SX``\55:VO;,!3]'/V*"_W2Q^)<O6S'(Z/K@ZVLHR%=88-!46VY M]N)8Q5;2#/SC)[MK2]9FI:50VTB@*QT=G7.$-^"LUE74*\P\K\D&?#:UC7J9 MNIYZ=>;EI=6%%YN9JTR,<95!9F9ZT,T>,$_VTYRXVEC9.(.%KNJH1SU^-V)_ M7^FH-SG\=';\<4+(:`3[F2HO]:FV,!H1:ZJ%*I)Z5]FL,*5G*U76,VU5NV5S M-[5AB,R]D@8<I=]0'T70Q#2A5`FJ$V0B]`7I2.T^H+Z*PY%2X5K&_(8)I)P< M`/6&`0+R`=(!%4!IQ$4DPAT,(T18`PL[#/I(]N!U#[%/8K!5OLA5`6F^!%4F MH)=7IK(PK;4]3_,R.3<7O\@78%(*2<;WDI+^,Q]"4"'Y`#,39[K8-752>*:Z M;(K\8C!UF^C8>G%'G#K)G')#%`W*H>0-9VE*&2J%88B)3-?)]!#KKP-<"-9@ MZ/OL$0)Y&1?SQ.4L+^?+N^79*I6@010A-MSW*4L%7H2!#(20:ZG\!_6>%&VD M#,.@"^N:!6UT7Y7Q<]!:IIPZCD(XIAQ%%V`:/,@O?2J_%/KT+?-[H_,)]*OK M[G-Y'*^3_`71/A@B4'+4M7II=55";:MY[(C<H,+V*J7-V[(;A.UW$)NRMA!G MJH+MK?==(%;"_%@,7G!SGL9H+4<JF=\&2$I*UUG.GK*<O['EW77_Q_&5X[[$ M9S8,6Z-ONN=8W'6K/D.I9GJ+'/$P!$9^DL/OXY/)M_/3'U_W3HXW5[#:2-S^ 7YYR!\;2>ST9*.[.%4N0/H;:>H5@'```` ` end |
From: Zhuang, L. <lou...@in...> - 2003-01-13 01:34:00
|
Dear all, Here is FITH summary. 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 ---------------------------------------------------------- Documentation/fault_injection.txt | 195 --- arch/i386/kernel/fi/Makefile | 7 arch/i386/kernel/fi/aslt/Makefile | 10 arch/i386/kernel/fi/aslt/fi_aslt.c | 244 ---- arch/i386/kernel/fi/pf/Makefile | 10 arch/i386/kernel/fi/pf/fi_pf.h | 85 - arch/i386/kernel/fi/pf/pf.c | 295 ---- arch/i386/kernel/fi/pf/pf_in.c | 456 ------- arch/i386/kernel/fi/pf/pf_region.c | 210 --- arch/i386/kernel/fi/pf/pf_utils.c | 81 - drivers/char/fi/Makefile | 14 drivers/char/fi/README | 180 --- drivers/char/fi/dbp/Makefile | 9 drivers/char/fi/dbp/fi_dbp.c | 704 ----------- drivers/char/fi/dbp/fi_dbp.h | 88 - drivers/char/fi/fi_core.c | 863 -------------- drivers/char/fi/fi_irq.c | 248 ---- drivers/char/fi/fi_mock_cs.c | 41 drivers/char/fi/fi_mock_interceptor.c | 120 -- drivers/char/fi/fi_sample_cs.c | 73 - drivers/char/fi/fi_test.c | 204 --- drivers/char/fi/pf/Makefile | 10 drivers/char/fi/pf/fi_pf.h | 50 drivers/char/fi/pf/pf.c | 284 ---- drivers/char/fi/pf/pf_in.c | 453 ------- drivers/char/fi/pf/pf_utils.c | 78 - drivers/char/fi_mock_interceptor.c | 148 -- drivers/char/fi_test.c | 169 -- drivers/char/kprobes_printk.c | 298 ---- include/asm-i386/fi.h | 11 include/linux/fi/fi.h | 121 -- include/linux/fi/fi_interface.h | 61 - include/linux/fi/fi_internal.h | 49 include/linux/fi_internal.h | 35 kernel/fi_core.c | 693 ----------- kernel/fi_dm.c | 534 -------- Documentation/fault_injection.txt | 197 +++ REPORTING-BUGS | 2 arch/i386/Kconfig | 331 ++++- arch/i386/kernel/Makefile | 12 arch/i386/kernel/entry.S | 22 arch/i386/kernel/fi/Makefile | 13 arch/i386/kernel/fi/aslt/Makefile | 10 arch/i386/kernel/fi/aslt/fi_aslt.c | 244 ++++ arch/i386/kernel/fi/pf/Makefile | 18 arch/i386/kernel/fi/pf/fi_pf.h | 87 + arch/i386/kernel/fi/pf/pf.c | 1215 ++++++++++++-------- arch/i386/kernel/fi/pf/pf_in.c | 502 ++++++++ arch/i386/kernel/fi/pf/pf_region.c | 212 +++ arch/i386/kernel/fi/pf/pf_utils.c | 99 + arch/i386/kernel/i386_ksyms.c | 6 arch/i386/kernel/kirq.c | 240 +++- arch/i386/kernel/kmmio.c | 240 +++- arch/i386/kernel/kprobes.c | 160 ++ arch/i386/kernel/traps.c | 56 arch/i386/mm/fault.c | 14 drivers/Makefile | 2 drivers/char/Makefile | 8 drivers/char/fi/Makefile | 20 drivers/char/fi/README | 182 +++ drivers/char/fi/dbp/Makefile | 9 drivers/char/fi/dbp/fi_dbp.c | 766 ++++++++++++ drivers/char/fi/dbp/fi_dbp.h | 89 + drivers/char/fi/fi_core.c | 1165 ++++++++++++++++--- drivers/char/fi/fi_irq.c | 320 ++++- drivers/char/fi/fi_mock_cs.c | 45 drivers/char/fi/fi_mock_interceptor.c | 184 ++- drivers/char/fi/fi_sample_cs.c | 75 + drivers/char/fi/fi_test.c | 342 ++++- drivers/char/fi/pf/Makefile | 10 drivers/char/fi/pf/fi_pf.h | 128 +- drivers/char/fi/pf/pf.c | 324 +++++ drivers/char/fi/pf/pf_in.c | 463 +++++++ drivers/char/fi/pf/pf_utils.c | 88 + drivers/char/fi_mock_interceptor.c | 148 ++ drivers/char/fi_test.c | 941 +++++++++------ drivers/char/kprobes_printk.c | 298 ++++ drivers/fi/Makefile | 13 drivers/fi/README | 182 +++ drivers/fi/codesegments/Makefile | 7 drivers/fi/codesegments/fi_sample_cs.c | 73 + drivers/fi/fi_core.c | 1257 ++++++++++++++++++--- drivers/fi/interceptors/Makefile | 9 drivers/fi/interceptors/dbp/Makefile | 9 drivers/fi/interceptors/dbp/fi_dbp.c | 981 +++++++++++++--- drivers/fi/interceptors/fi_irq.c | 248 ++++ drivers/fi/interceptors/pf/Makefile | 10 drivers/fi/interceptors/pf/fi_pf.h | 50 drivers/fi/interceptors/pf/pf.c | 284 ++++ drivers/fi/interceptors/pf/pf_in.c | 453 +++++++ drivers/fi/interceptors/pf/pf_utils.c | 78 + drivers/fi/testing/Makefile | 9 drivers/fi/testing/fi_mock_cs.c | 41 drivers/fi/testing/fi_mock_interceptor.c | 120 ++ drivers/fi/testing/fi_test.c | 323 +++++ include/asm-i386/fi.h | 15 include/asm-i386/kirq.h | 59 include/asm-i386/kmmio.h | 35 include/asm-i386/kprobes.h | 34 include/linux/fi.h | 200 ++- include/linux/fi/fi.h | 185 ++- include/linux/fi/fi_interface.h | 113 + include/linux/fi/fi_internal.h | 153 +- include/linux/fi_internal.h | 65 - include/linux/kmmio.h | 68 + include/linux/kprobes.h | 60 + include/linux/module.h | 6 kernel/Makefile | 12 kernel/fi_core.c | 1851 ++++++++++++++++++++----------- kernel/fi_dm.c | 548 +++++++++ kernel/kmmio.c | 173 ++ kernel/kprobes.c | 89 + kernel/module.c | 67 - lib/vsprintf.c | 1 114 files changed, 14544 insertions(+), 9755 deletions(-) through these ChangeSets: <lo...@ha...> (03/01/10 1.879.1.104) * fix a mistake in previous changeset. unregistering a kobj when register_kobj fail does not work. This is should be a bug in sysfs. More fix should be in sysfs. <lo...@ha...> (03/01/10 1.879.1.103) * remove relevant triggers when fi_unregister_interceptor * fix 'oops and corrupted when two code segments use the same name' <lo...@ha...> (03/01/08 1.879.1.102) change attaching mechanism in code segment echo "attach trigger_name | detach" > /sys/fault_injection/code_segments/<code_segment>/ctl <lo...@ha...> (03/01/08 1.879.1.101) rearrange fi_core.c <lo...@ha...> (03/01/08 1.879.24.1) make one-to-multi relationship between trigger and code segment <st...@ma...> (03/01/08 1.879.1.99) Add "0x" prefix for module's base address in kernel/module.c <st...@ma...> (03/01/07 1.879.1.98) Clean up code in drivers/fi/interceptor/dbp/fi_dbp.c <st...@ma...> (03/01/07 1.879.16.3) Clean up code and fix bug for fi_dbp. Can't clear bug fixed. <lo...@ha...> (03/01/07 1.879.1.96) Add missed license <st...@ma...> (03/01/07 1.879.16.2) Add PIO access support for FITH's test module. <st...@ma...> (03/01/07 1.879.16.1) Rewrite fi_dbp. We get module->module_core from /proc/modules now. <ke...@ke...> (03/01/07 1.879.14.1) fi_core.c: Remove codesegment before detach trigger issue <lo...@ha...> (03/01/07 1.879.1.94) make fi_core moduleable <rusty@penguin.(none)> (03/01/06 1.838.164.28) Implemented the new file layout documented a few days before in the README file. Fault injection is now rooted in drivers/fi. <lo...@ha...> (03/01/06 1.838.164.27) fix xxx_store() return value issue <lo...@ha...> (03/01/06 1.838.164.26) fix 'dbg' 'trace' redefine warning. <rusty@penguin.(none)> (03/01/03 1.838.164.25) Adding new documention file <st...@ma...> (03/01/03 1.838.111.32) Remove fi_internal.h <st...@ma...> (03/01/03 1.838.166.1) Combin fi_get_module and fi_put_module into get_module and Remove fi_dbp. h <lo...@ha...> (03/01/03 1.838.111.30) merge fi_internal.h into fi.h <st...@ma...> (03/01/03 1.838.115.3) Move kirq_list to kirq.c <st...@ma...> (02/12/31 1.838.111.28) module.c: Clean fi_dbp infrastructure <st...@ma...> (02/12/31 1.838.111.27) Remove interceptor type <lo...@ha...> (02/12/31 1.838.111.25) fix bug -- forget reset 'field_width' in vsscanf() <st...@ma...> (02/12/31 1.838.150.1) Bug fix for fi_dbp <lo...@ha...> (02/12/31 1.838.111.24) fix redundant warning when echo into "cs/trigger" <lo...@ha...> (02/12/31 1.838.111.23) remove interceptor_type. now echo "add <tri_name> <interceptor_name> ..." > ctl <lo...@ha...> (02/12/31 1.838.111.22) fix command process in trigger_ctl_store() <lo...@ha...> (02/12/31 1.838.111.21) fi_execute_trigger(..., type, ...) type 0:READ, 1:WRITE <lo...@ha...> (02/12/31 1.838.111.20) fix return value check in arm_trigger <lo...@ha...> (02/12/30 1.838.130.4) arch/i386/kernel/kmmio.c fix error judgement in telling if the page fault is caused by kmmio. //shy kernel/kmmio.c fix bug in kmalloc GFP_KERNEL in spin_lock_irq <st...@ma...> (02/12/30 1.838.111.17) Bug fix for fi_dbp <st...@ma...> (02/12/30 1.838.111.16) Change name : "attach" -> "ctl" <st...@ma...> (02/12/27 1.838.111.15) fix warning. <lo...@ha...> (02/12/27 1.838.130.3) fix risk condition in unarm_code_segment <lo...@ha...> (02/12/27 1.838.130.2) refine trigger/<tri_name>/[opcode|operand] display <st...@ma...> (02/12/27 1.838.111.14) Add FI_DBP <lo...@ha...> (02/12/27 1.838.130.1) fix bug on fi_exit() <st...@ma...> (02/12/27 1.838.111.13) Split fi_find_module into fi_get_moudule and fi_put_module <st...@ma...> (02/12/27 1.838.111.12) Add FI_DBP infrastructure <st...@ma...> (02/12/26 1.838.111.11) Fix print issues. Add check to intercept timer's irq. <st...@ma...> (02/12/26 1.838.111.10) Bug fix for fi_irq <st...@ma...> (02/12/26 1.838.116.1) Add fi_irq <st...@ma...> (02/12/26 1.838.115.2) Add dispatch_kirq <lo...@ha...> (02/12/26 1.838.111.7) clean code <lo...@ha...> (02/12/26 1.838.111.6) replace deprecated MODULE_PARM with module_param <lo...@ha...> (02/12/25 1.838.84.23) * control 'mocks' by FI_MOCKS option. * add fi_sample_cs.c * add kmmio_invert_map function <lo...@ha...> (02/12/24 1.838.84.22) * refactor del_trigger (using find_trigger_by_name) * refactor fi_execute_trigger (breaking down small functions) <lo...@ha...> (02/12/24 1.838.84.21) drivers/char/fi/fi_core.c * fix a bug * add code segment support drivers/char/fi/fi_mock_cs.c reduce name length <lo...@ha...> (02/12/24 1.838.84.20) add mock_code_segment file <lo...@ha...> (02/12/24 1.838.84.19) * add code segment subsystem * add fi_mock_code_segment * clean some extern declarations in .c <st...@ma...> (02/12/24 1.838.84.18) Cleanup code <st...@ma...> (02/12/24 1.838.84.17) Make fi_test use sysfs <lo...@ha...> (02/12/23 1.838.84.16) use container_of instead of type cost in pf.c <lo...@ha...> (02/12/23 1.838.84.15) remove unused enum value in pf <lo...@ha...> (02/12/23 1.838.84.14) fix symbol export <lo...@ha...> (02/12/23 1.838.84.13) refine header files <lo...@ha...> (02/12/21 1.838.95.1) concentrate FITH files into driver/char/fi <st...@ma...> (02/12/21 1.838.93.1) kirq.c: Refine printk message and fix register fail bug. <rusty@penguin.(none)> (02/12/20 1.838.84.10) fixed a mistake in last merge <rusty@penguin.(none)> (02/12/20 1.838.89.1) * Added a new interceptor just for the purpose of testing fi_core.c * Added support for interceptor attributes * Added a new interceptor unregistration function to fi_core <lo...@ha...> (02/12/20 1.838.80.7) change PDEBUG/PERROR to dbg/err <st...@ma...> (02/12/20 1.838.84.6) Remove enabled file <lo...@ha...> (02/12/20 1.838.80.6) remove fi_enable <st...@ma...> (02/12/20 1.838.84.4) Refind config file <lo...@ha...> (02/12/20 1.838.80.5) modulized fi_core and fi_pf <st...@ma...> (02/12/20 1.838.72.3) Refine config file. <lo...@ha...> (02/12/20 1.838.80.4) fix copyright <lo...@ha...> (02/12/20 1.838.80.3) fix code style <lo...@ha...> (02/12/20 1.838.80.2) add corrupt in REG_READ <lo...@ha...> (02/12/19 1.838.80.1) fix stupid not-initing kmmio_page_table <st...@ma...> (02/12/19 1.838.59.9) Remove /sys/fault-injcetion/enabled <lo...@ha...> (02/12/19 1.838.59.8) fix copyright declaration <lo...@ha...> (02/12/19 1.838.59.7) * reconstruct code to use kmmio * delete unused member in kmmio_probe * remove pf_region.c * reconstruct code to use kmmio * fix misuse PAGE_HASH_TABLE <st...@ma...> (02/12/19 1.838.76.6) kobject_init will be invoked in kobject_register. <st...@ma...> (02/12/19 1.838.76.5) Add IRQ interceptor's infrastructure (KIRQ). <lo...@ha...> (02/12/19 1.838.59.4) flush tlb in suitable place <rusty@penguin.(none)> (02/12/18 1.838.76.4) dropping doc file <rusty@penguin.(none)> (02/12/18 1.838.76.3) minimal changeset to remove the kprobes_printk.c file <rusty@penguin.(none)> (02/12/18 1.838.76.2) These changes include a removal of a personal hack of mine in my own tree, and various work to move execute_trigger from an interceptor to the core. <st...@ma...> (02/12/18 1.838.72.2) Fix stupid bug. <lo...@ha...> (02/12/18 1.838.59.3) add kmmio mechanism. *NO TEST AT ALL* <st...@st...> (02/12/18 1.838.72.1) Add KIRQ Support <rusty@penguin.(none)> (02/12/17 1.838.23.16) Added a documentation file and then a few more printk's to the test driver <lo...@ha...> (02/12/17 1.838.43.2) remove Rules.mak in appended Makefile <rusty@penguin.(none)> (02/12/16 1.838.23.15) This changeset merges changes for a new implementation of the fault injection core, and the kprobes printk driver. <te...@ha...> (02/12/13 1.838.23.14) pf.c: add more debug info about 'removed region' pf_region.c: fix dark X bug. <te...@ha...> (02/12/13 1.838.23.13) Add FI_DEBUG, clean some awful stuffs... <st...@ma...> (02/12/12 1.838.23.12) Cleanup fi_test.c <lo...@ha...> (02/12/12 1.838.23.11) fi.h: remove FIIOC_QUERY_PHYADDR ioctl remove unused statements pf_utils.c, fi_pf.h: change 'line' to virt pf.c: fix TABLE_FULL error handling change 'line' to virt <lo...@ha...> (02/12/12 1.838.23.10) pf.c: fix invalid condition <st...@ma...> (02/12/11 1.838.23.9) Remove unused varible. <st...@ma...> (02/12/11 1.838.27.1) Buf fix. Remove fi_line_to_phy <ru...@st...> (02/12/11 1.838.26.1) Further cleanup of the test driver used for demonstraiting <st...@ma...> (02/12/11 1.838.25.1) Remove aslt <lo...@ha...> (02/12/11 1.838.23.5) fix symbol&name issues <ru...@st...> (02/12/10 1.838.23.4) This patchset adds fault injection capabilites to the Linux kernel <ru...@st...> (02/12/10 1.838.23.3) Adding last piece of kprobes, traps.c hooks <rusty@penguin.(none)> (02/12/10 1.838.23.2) Adding the kprobes patch submitted to lkml for the 2.5.50-bk2 tree <lm...@wo...> (02/12/10 1.838.23.1) TEST, TEST, TEST, TEST. Ignore, debugging BK logging. |
From: Zhuang, L. <lou...@in...> - 2003-01-13 00:57:35
|
FYI. The patch have been accepted by linux kernel. > -----Original Message----- > From: Patrick Mochel [mailto:mo...@os...] > Sent: Friday, January 10, 2003 11:22 PM > To: lou...@li... > Cc: lin...@vg... > Subject: Re: [Bug fix] delete kobject from list when > kobject_add() fail > > > > On Fri, 10 Jan 2003 lou...@li... wrote: > > > Dear Mochel, > > I found there were still issues in failed > kobject_add(). For example, > > if you try to register two kobjects with the same name into > > subsystem, the second registration will fail but the second > will keep in > > the list of subsystem. Below patch might fix the bug. Please apply. > > Thanks. I applied it, though slightly modified (I detest > function names > with the '__' prefix). :) > > -pat > |
From: Wang, S. <sta...@in...> - 2003-01-13 00:38:51
|
Rusty Russell has submitted our patch to Linus :) Cheers, -Stan > -----Original Message----- > From: Rusty Russell [mailto:ru...@ru...] > Sent: 2003-01-11 18:03 > To: tor...@tr... > Cc: 'lin...@vg...'; le...@mo...; > Wang, Stanley > Subject: [PATCH] Put more useful stuff in /proc/modules > > > Linus, please apply. > > This puts the state of the module (useful for users) and the address > (required for ksymoops and oprofile). > > Cheers, > Rusty. > > Name: Put more information in /proc/modules > Author: Stanley Wang, Rusty Russell > Status: Tested on 2.5.56 > > D: Puts the state of the module and the address in /proc/modules. > > diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff > --minimal linux-2.5-bk/kernel/module.c > working-2.5-bk-procmodules-extra/kernel/module.c > --- linux-2.5-bk/kernel/module.c Fri Jan 10 10:55:43 2003 > +++ working-2.5-bk-procmodules-extra/kernel/module.c Sat Jan > 11 19:59:58 2003 > @@ -1422,6 +1422,15 @@ static int m_show(struct seq_file *m, vo > seq_printf(m, "%s %lu", > mod->name, mod->init_size + mod->core_size); > print_unload_info(m, mod); > + > + /* Informative for users. */ > + seq_printf(m, " %s", > + mod->state == MODULE_STATE_GOING ? "Unloading": > + mod->state == MODULE_STATE_COMING ? "Loading": > + "Live"); > + /* Used by oprofile and other similar tools. */ > + seq_printf(m, " 0x%p", mod->module_core); > + > seq_printf(m, "\n"); > return 0; > } > > -- > Anyone who quotes me in their sig is an idiot. -- Rusty Russell. > |
From: Gao, K. <kev...@in...> - 2003-01-10 02:56:17
|
Oh, that is a bug, I have submitted it into sourceforge.net, I means remove driver before remove triggers, sorry for confusion :-) -Kevin -----Original Message----- From: Lynch, Rusty Sent: 2003?1?10? 9:47 To: Gao, Kevin; Wang, Stanley; Zhuang, Louis; 'Rusty Lynch'; 'fau...@li...' Cc: Wang, Frank Subject: RE: [Fault-injection-developer] RE: [DISCUSSION] make decisions about ficl > From: Gao, Kevin [mailto:kev...@in...] <snip> > 2)Need discussion. > > I think locking modules is very dirty way, and make user feel not > comfortable. > But the problem is that, user always forgets to remove > trigger before remove > interceptor, and make system oops. Is there any method to solve this > problem. > The problem worried us since the early time of FITH, I hope > we can solve it > thoroughly. > Is this really still a problem with our current design for interceptors and triggers? Can you give a list of steps with our current code to cause a box to oops? -rustyl |
From: Lynch, R. <rus...@in...> - 2003-01-10 02:49:54
|
> From: Gao, Kevin [mailto:kev...@in...] <snip> > 2)Need discussion. > > I think locking modules is very dirty way, and make user feel not > comfortable. > But the problem is that, user always forgets to remove > trigger before remove > interceptor, and make system oops. Is there any method to solve this > problem. > The problem worried us since the early time of FITH, I hope > we can solve it > thoroughly. > Is this really still a problem with our current design for interceptors and triggers? Can you give a list of steps with our current code to cause a box to oops? -rustyl |
From: Zhuang, L. <lou...@in...> - 2003-01-10 02:45:18
|
> > > * In case the chicken-and-egg analogy is not obvious > across cultural > > > barriers... it refers to the evolutionary question of > which came > > In fact, chicken-and-egg is really across cluture, at least > > in China. ;-> > > Ah... I'll have to find another analogy to throw people off. :-> If and only if the word is not Darwinism ;-). |
From: Lynch, R. <rus...@in...> - 2003-01-10 02:28:45
|
> From: Zhuang, Louis [mailto:lou...@in...] > > But the problem is that, user always forgets to remove > > trigger before remove > > interceptor, and make system oops. > Oh, I'm resolving this problem now. Maybe in two or three hours. > > The *real* hard problem is, when user put a trigger on a > device driver's > MMIO space (the driver got it by calling "ioremap"), the PF > interceptor will > set the page of MMIO as 'UNPRESENT'. After a while, user > remove the device > driver without remove trigger firstly. In the case, the > iounmap called by > driver's cleanup method will find one of MMIO page is > UNPRESENT. It really > confuses iounmap and oops. So we should prevent user from > removing device > driver before removing trigger. But as Stan said, it much > mess up our code. > > > Yours truly, > Louis Zhuang Hmm... this really an implementation issue with one specific interceptor. I am inclined to resolve this via documentation and user space tools for a specific test case. (For example, a test case could be executed by a shell script that loads the driver, loads the fault set, does it's thing, unloads the fault set, and finally unloads the driver.) I would guess there are a lot of ways somebody could misuse the fault injection interfaces to do a LOT of bad stuff to a test machine. By definition fault injection is dangerous. If we try to make the basic interfaces fool proof then we will end up with an overly complex solution. -rusty |
From: Zhuang, L. <lou...@in...> - 2003-01-10 02:15:55
|
> But the problem is that, user always forgets to remove > trigger before remove > interceptor, and make system oops. Oh, I'm resolving this problem now. Maybe in two or three hours. The *real* hard problem is, when user put a trigger on a device driver's MMIO space (the driver got it by calling "ioremap"), the PF interceptor will set the page of MMIO as 'UNPRESENT'. After a while, user remove the device driver without remove trigger firstly. In the case, the iounmap called by driver's cleanup method will find one of MMIO page is UNPRESENT. It really confuses iounmap and oops. So we should prevent user from removing device driver before removing trigger. But as Stan said, it much mess up our code. 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 |
From: Lynch, R. <rus...@in...> - 2003-01-10 01:49:17
|
> From: Zhuang, Louis [mailto:lou...@in...] > > * In case the chicken-and-egg analogy is not obvious across cultural > > barriers... it refers to the evolutionary question of which came > In fact, chicken-and-egg is really across cluture, at least > in China. ;-> Ah... I'll have to find another analogy to throw people off. :-> > > According to ficl, we've some decisions to make. > First, ficl for current FITH should still use FSML as input? > a. yes > b. no I think the justification for FSML is still valid, so YES. We could also provide some other very simple tools like maybe a lstrigger, rmtrigger, addtrigger, etc. (Just thoughts off the top of my head.) > Second, ficl should lock relevant drivers/modules > automatically as before? > a. yes. > b. no > I'm not sure I completely understand the issue, but gut feeling is NO, and then see how bad the repercussions are after the fact. > For second item, locking modules is a really mess which is not really > relative with fault injection itself. But it can protect system from > mis-operating (for example, tester always forgets remove PF > trigger before > unload tested-driver. This will make kernel oops because > iounmap finds some > MMIO page is not present.) But we can not find a clean way to > lock module in > user space. Shall we investigate more on this? Or shall we > talk with Russell > for this feature? > > Any comments? > > > > 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 SF.NET email is sponsored by: > SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See! > http://www.vasoftware.com > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > |
From: Gao, K. <kev...@in...> - 2003-01-10 01:42:22
|
1)A. yes, I think use XML format is a good choise for user to use our FITH, User does not need write many XML files, only edit one template can = help them make the trigger they want.=20 In fsml file, we should add some other attributes, (e.g. = "interceptor"). So I think we need rediscuss the attribute. I hope we can hold the old = name for compatibility. 2)Need discussion. I think locking modules is very dirty way, and make user feel not comfortable. But the problem is that, user always forgets to remove trigger before = remove interceptor, and make system oops. Is there any method to solve this problem. The problem worried us since the early time of FITH, I hope we can = solve it thoroughly. -Kevin -----Original Message----- From: Wang, Stanley=20 Sent: 2003=C4=EA1=D4=C210=C8=D5 9:17 To: Zhuang, Louis; 'Rusty Lynch'; 'fau...@li...' Cc: Gao, Kevin; Wang, Frank Subject: RE: [DISCUSSION] make decisions about ficl A. yes B. no For question B, I think we could do some cleaning work when the=20 interceptor is remove to decrease the potionial issues. -Stan > -----Original Message----- > From: Zhuang, Louis=20 > Sent: 2003-01-10 9:12 > To: 'Rusty Lynch'; fau...@li... > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis > Subject: [DISCUSSION] make decisions about ficl >=20 >=20 > > * In case the chicken-and-egg analogy is not obvious across = cultural > > barriers... it refers to the evolutionary question of which came = > In fact, chicken-and-egg is really across cluture, at least=20 > in China. ;-> >=20 > According to ficl, we've some decisions to make.=20 > First, ficl for current FITH should still use FSML as input? > a. yes > b. no > Second, ficl should lock relevant drivers/modules=20 > automatically as before? > a. yes. > b. no >=20 > For second item, locking modules is a really mess which is=20 > not really relative with fault injection itself. But it can=20 > protect system from mis-operating (for example, tester always=20 > forgets remove PF trigger before unload tested-driver. This=20 > will make kernel oops because iounmap finds some MMIO page is=20 > not present.) But we can not find a clean way to lock module=20 > in user space. Shall we investigate more on this? Or shall we=20 > talk with Russell for this feature? >=20 > Any comments? >=20 >=20 >=20 > 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 >=20 |
From: Wang, S. <sta...@in...> - 2003-01-10 01:37:34
|
> > A. yes > > B. no > Reasons? Since there is no general kernel interface for locking other module, locking the tested module would cause messing the code. And it would be "too ugly to live" for the linux kernel. Regards, -Stan |
From: Zhuang, L. <lou...@in...> - 2003-01-10 01:28:31
|
> A. yes > B. no Reasons? |