fault-injection-developer Mailing List for Fault Injection Test Harness (Page 8)
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: Gao, K. <kev...@in...> - 2002-12-23 01:02:45
|
L M B E N C H 2 . 0 S U M M A R Y ------------------------------------ Basic system parameters ---------------------------------------------------- Host OS Description Mhz --------- ------------- ----------------------- ---- 52-pure Linux 2.5.52 i686-pc-linux-gnu 932 cs@1901 <mailto:cs@1901> Linux 2.5.52 i686-pc-linux-gnu 932 cs@1907 <mailto:cs@1907> Linux 2.5.52 i686-pc-linux-gnu 931 Processor, Processes - times in microseconds - smaller is better ---------------------------------------------------------------- Host OS Mhz null null open selct sig sig fork exec sh call I/O stat clos TCP inst hndl proc proc proc --------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ---- ---- 52-pure Linux 2.5.52 932 0.39 0.68 22.9 24.4 27.2 1.09 4.47 210. 996. 5050 cs@1901 <mailto:cs@1901> Linux 2.5.52 932 0.37 0.68 22.7 24.0 31.5 1.06 4.51 221. 1052 5202 cs@1907 <mailto:cs@1907> Linux 2.5.52 931 0.37 0.68 22.8 24.0 29.1 1.06 4.43 216. 1015 5048 Context switching - times in microseconds - smaller is better ------------------------------------------------------------- Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw --------- ------------- ----- ------ ------ ------ ------ ------- ------- 52-pure Linux 2.5.52 cs@1901 <mailto:cs@1901> Linux 2.5.52 cs@1907 <mailto:cs@1907> Linux 2.5.52 *Local* Communication latencies in microseconds - smaller is better ------------------------------------------------------------------- Host OS 2p/0K Pipe AF UDP RPC/ TCP RPC/ TCP ctxsw UNIX UDP TCP conn --------- ------------- ----- ----- ---- ----- ----- ----- ----- ---- 52-pure Linux 2.5.52 7.109 33.4 41.7 61.6 81.1 110.2 110. cs@1901 <mailto:cs@1901> Linux 2.5.52 7.137 15.2 41.8 61.1 81.1 109.8 134. cs@1907 <mailto:cs@1907> Linux 2.5.52 7.123 19.1 41.7 61.1 75.1 109.4 133. File & VM system latencies in microseconds - smaller is better -------------------------------------------------------------- Host OS 0K File 10K File Mmap Prot Page Create Delete Create Delete Latency Fault Fault --------- ------------- ------ ------ ------ ------ ------- ----- ----- 52-pure Linux 2.5.52 92.5 46.0 225.6 75.3 2053.0 0.885 2.00000 cs@1901 <mailto:cs@1901> Linux 2.5.52 93.4 46.5 229.2 77.1 2063.0 0.765 2.00000 cs@1907 <mailto:cs@1907> Linux 2.5.52 91.8 44.9 221.6 75.1 2010.0 0.852 2.00000 *Local* Communication bandwidths in MB/s - bigger is better ----------------------------------------------------------- Host OS Pipe AF TCP File Mmap Bcopy Bcopy Mem Mem UNIX reread reread (libc) (hand) read write --------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- ----- 52-pure Linux 2.5.52 40.7 cs@1901 <mailto:cs@1901> Linux 2.5.52 41.0 cs@1907 <mailto:cs@1907> Linux 2.5.52 44.4 Memory latencies in nanoseconds - smaller is better (WARNING - may not be correct, check graphs) --------------------------------------------------- Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- ---- ----- ------ -------- ------- 52-pure Linux 2.5.52 932 - - - Bad mhz? cs@1901 <mailto:cs@1901> Linux 2.5.52 932 - - - Bad mhz? cs@1907 <mailto:cs@1907> Linux 2.5.52 931 - - - Bad mhz? |
From: Zhuang, L. <lou...@in...> - 2002-12-21 15:08:30
|
Hi all This is updated kmmio patch. Please comment ;-> - Louis diff -Nur a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig 2002-12-21 22:51:54.000000000 +0800 +++ b/arch/i386/Kconfig 2002-12-21 22:46:34.000000000 +0800 @@ -1506,6 +1506,14 @@ 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 DEBUG_SLAB bool "Debug memory allocations" diff -Nur a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile 2002-12-21 22:53:56.000000000 +0800 +++ b/arch/i386/kernel/Makefile 2002-12-21 22:48:11.000000000 +0800 @@ -30,6 +30,7 @@ obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KMMIO) += kmmio.o obj-y += sysenter.o EXTRA_AFLAGS := -traditional diff -Nur a/arch/i386/kernel/kmmio.c b/arch/i386/kernel/kmmio.c --- a/arch/i386/kernel/kmmio.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/i386/kernel/kmmio.c 2002-12-21 22:21:25.000000000 +0800 @@ -0,0 +1,140 @@ +/* + * KMMIO + * Benfit many code from kprobes + * (C) 2002 Louis Zhuang <lou...@in...>. + */ + +#include <linux/config.h> +#include <linux/kmmio.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/preempt.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> +#include <asm/highmem.h> + +static struct kmmio_probe *current_kmmio = NULL; +static int is_trigger; +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) +{ + struct kmmio_probe *p; + struct kmmio_fault_page *f; + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + lock_kmmio(); + + is_trigger = 1; + f = get_kmmio_fault_page((void *)addr); + if (!f) { + /* this page fault is not caused by kmmio */ + /* XXX some pending fault on other cpu may cause problem! */ + unlock_kmmio(); + goto no_kmmio; + } + + p = get_kmmio_probe((void *)addr); + if (!p) { + /* The fault is caused by kmmio, but no trigger care the adress */ + is_trigger = 0; + } + + current_kmmio = p; + kmmio_saved_eflags = (regs->eflags & (TF_MASK|IF_MASK)); + + if (is_trigger) p->pre_handler(p, 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(f->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 (!current_kmmio) + return 0; + + if (is_trigger && current_kmmio->post_handler) + current_kmmio->post_handler(current_kmmio, condition, regs); + + arm_kmmio_fault_page(get_kmmio_fault_page(current_kmmio->addr)->page ); + __flush_tlb_one(get_kmmio_fault_page(current_kmmio->addr)->page); + + regs->eflags &= ~TF_MASK; + regs->eflags |= kmmio_saved_eflags; + + current_kmmio = NULL; + + 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 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 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 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); +} diff -Nur a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c 2002-12-21 22:52:41.000000000 +0800 +++ b/arch/i386/kernel/traps.c 2002-12-21 22:20:35.000000000 +0800 @@ -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> @@ -598,6 +599,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 -Nur a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c 2002-12-21 22:54:30.000000000 +0800 +++ b/arch/i386/mm/fault.c 2002-12-21 22:20:11.000000000 +0800 @@ -20,6 +20,7 @@ #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ #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 -Nur a/include/asm-i386/kmmio.h b/include/asm-i386/kmmio.h --- a/include/asm-i386/kmmio.h 1970-01-01 08:00:00.000000000 +0800 +++ b/include/asm-i386/kmmio.h 2002-12-21 22:22:19.000000000 +0800 @@ -0,0 +1,24 @@ +/* + * 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); +#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 -Nur a/include/linux/kmmio.h b/include/linux/kmmio.h --- a/include/linux/kmmio.h 1970-01-01 08:00:00.000000000 +0800 +++ b/include/linux/kmmio.h 2002-12-21 22:20:52.000000000 +0800 @@ -0,0 +1,62 @@ +#ifndef _LINUX_KMMIO_H +#define _LINUX_KMMIO_H +#include <linux/config.h> +#include <linux/list.h> +#include <linux/notifier.h> +#include <linux/smp.h> +#include <asm/kmmio.h> + +struct kmmio_probe; +struct kmmio_fault_page; +struct pt_regs; + +typedef void (*kmmio_pre_handler_t)(struct kmmio_probe *, struct pt_regs *, unsigned long addr); +typedef void (*kmmio_post_handler_t)(struct kmmio_probe *, unsigned long condition, struct pt_regs *); +struct kmmio_probe { + struct list_head list; + + /* location of the probe point */ + kmmio_addr_t addr; + + /* Called before addr is executed. */ + kmmio_pre_handler_t pre_handler; + + /* Called after addr is executed, unless... */ + kmmio_post_handler_t post_handler; +}; + +struct kmmio_fault_page { + struct list_head list; + + /* location of the fault page */ + kmmio_addr_t page; + + int count; +}; + +#ifdef CONFIG_KMMIO +/* Locks kmmio: irq must be disabled */ +void lock_kmmio(void); +void unlock_kmmio(void); + +/* kmmio is active by some kmmio_probes? */ +static inline int is_kmmio_active(void) +{ + extern unsigned int kmmio_count; + return kmmio_count; +} + +/* Get the kmmio at this addr (if any). Must have called lock_kmmio */ +struct kmmio_probe *get_kmmio_probe(kmmio_addr_t addr); +struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page); +int add_kmmio_fault_page(kmmio_addr_t page); +void release_kmmio_fault_page(kmmio_addr_t page); + +int register_kmmio_probe(struct kmmio_probe *p); +void unregister_kmmio_probe(struct kmmio_probe *p); +#else +static inline int is_kmmio_active(void) { return 0; } +static inline int register_kmmio_probe(struct kmmio_probe *p) { return -ENOSYS; } +static inline void unregister_kmmio_probe(struct kmmio_probe *p) { } +#endif +#endif /* _LINUX_KMMIO_H */ diff -Nur a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile 2002-12-21 22:54:51.000000000 +0800 +++ b/kernel/Makefile 2002-12-21 22:20:36.000000000 +0800 @@ -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 -Nur a/kernel/kmmio.c b/kernel/kmmio.c --- a/kernel/kmmio.c 1970-01-01 08:00:00.000000000 +0800 +++ b/kernel/kmmio.c 2002-12-21 22:21:57.000000000 +0800 @@ -0,0 +1,144 @@ +/* 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)]); + + add_kmmio_fault_page(p->addr); + + 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_KERNEL); + 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: Wang, S. <sta...@in...> - 2002-12-21 10:36:31
|
Thanks for your careful review and helpful comments :) I will apply your comments to the code:) -Stan > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: 2002=C4=EA12=D4=C221=C8=D5 1:31 > To: Wang, Stanley; fau...@li... > Subject: Re: [Fault-injection-developer] RFC: KIRQ >=20 >=20 > > Hi, folks > > I revised the KIRQ according to Rusty's comment. > >=20 > > # This is a BitKeeper generated patch for the following project: > > # Project Name: Linux kernel tree > > # This patch format is intended for GNU patch command=20 > version 2.5 or higher. > > # This patch includes the following deltas: > > # ChangeSet 1.901 -> 1.902 =20 > > # arch/i386/Kconfig 1.14 -> 1.16 =20 > > # arch/i386/kernel/Makefile 1.31 -> 1.32 =20 > > # (new) -> 1.4 arch/i386/kernel/kirq.c > > # (new) -> 1.3 include/asm-i386/kirq.h > > # > > # The following is the BitKeeper ChangeSet Log > > # -------------------------------------------- > > # 02/12/20 st...@ma... 1.892.1.3 > > # Refine config file. > > # -------------------------------------------- > > # 02/12/20 st...@ma... 1.902 > > # 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 Dec 20 14:24:01 2002 > > +++ b/arch/i386/Kconfig Fri Dec 20 14:24:01 2002 > > @@ -1544,6 +1544,14 @@ > > best used in conjunction with the NMI watchdog so that spinlock > > deadlocks are also debuggable. > > =20 > > +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 Dec 20 14:24:01 2002 > > +++ b/arch/i386/kernel/Makefile Fri Dec 20 14:24:01 2002 > > @@ -4,7 +4,7 @@ > > =20 > > EXTRA_TARGETS :=3D head.o init_task.o > > =20 > > -export-objs :=3D mca.o i386_ksyms.o time.o > > +export-objs :=3D mca.o i386_ksyms.o time.o kirq.o > > =20 > > obj-y :=3D process.o semaphore.o signal.o entry.o traps.o=20 > irq.o vm86.o \ > > ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ > > @@ -29,6 +29,7 @@ > > obj-$(CONFIG_PROFILING) +=3D profile.o > > obj-$(CONFIG_EDD) +=3D edd.o > > obj-$(CONFIG_MODULES) +=3D module.o > > +obj-$(CONFIG_KIRQ) +=3D kirq.o > > obj-y +=3D sysenter.o > > =20 > > EXTRA_AFLAGS :=3D -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 Dec 20 14:24:01 2002 > > @@ -0,0 +1,103 @@ > > +/* 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> > > + > > +void kirq_handler(int irq, void *dev_id, struct pt_regs *regs) > > +{ > > + int i; > > + struct kirq *p =3D kirq_list + irq; > > + if (p->handler !=3D NULL){ > > + i =3D (*(p->handler))(p, irq, dev_id, regs); > > + if ( i =3D=3D 0 ) > > + (*(p->isr))(irq, dev_id, regs); > > + }else{ > > + printk(KERN_ERR "Miss KIRQ handler!\n"); >=20 > This might be a little too cryptic for a system admin > to figure out what is happening from the system log file. >=20 > How about: > printk(KERN_ERR "%s: Dropping unexpected interrupt #%i\n",=20 > __FUNCTION__, irq);=20 >=20 > > + } > > + return; > > +} > > + > > +int register_kirq(int irq, char *devname, kirq_handler_t handler) > > +{ > > + struct irqaction *action; > > + irq_desc_t *desc =3D irq_desc + irq; > > + struct kirq *p =3D kirq_list + irq; > > + unsigned long flags; > > +=20 > > + if (handler =3D=3D NULL) { > > + printk(KERN_ERR "Register KIRQ failed: Missing handler!\n"); > > + } > > + > > + if (p->handler) { > > + printk(KERN_ERR "Register KIRQ failed: KIRQ already > > exist!\n"); > > + } >=20 > Did you mean to return an error on the conditions above? >=20 > > +=20 > > + spin_lock_irqsave(&desc->lock,flags); > > +=20 > > + action =3D desc->action; > > + while (action) { > > + if (strcmp(action->name,devname)) { > > + action =3D action->next; > > + }else{ > > + break; > > + } > > + } > > + > > + if (!action) { > > + spin_unlock_irqrestore(&desc->lock,flags); > > + return -1;=20 > > + } > > + > > + p->isr =3D action->handler; > > + p->handler =3D handler; > > + p->dev_id =3D action->dev_id; > > +=20 > > + action->handler =3D kirq_handler; > > +=20 > > + spin_unlock_irqrestore(&desc->lock,flags); > > + > > + return 0; > > +} > > + > > +int unregister_kirq(int irq) > > +{ > > + struct irqaction *action; > > + irq_desc_t *desc =3D irq_desc + irq; > > + struct kirq *p =3D kirq_list + irq; > > + unsigned long flags; > > +=20 > > + spin_lock_irqsave(&desc->lock,flags); > > +=20 > > + action =3D desc->action; > > + while ( action && action->dev_id !=3D p->dev_id) { > > + action =3D action->next; > > + } > > + > > + if (!action) { > > + printk(KERN_ERR "Unregister KIRQ failed!\n"); > > + spin_unlock_irqrestore(&desc->lock,flags); > > + return -1; > > + } > > + > > + action->handler =3D p->isr; > > +=20 > > + p->isr =3D NULL; > > + p->handler =3D NULL; > > + p->dev_id =3D NULL; > > +=20 > > + spin_unlock_irqrestore(&desc->lock,flags); > > + > > + return 0; > > +} > > +EXPORT_SYMBOL_GPL(register_kirq); > > +EXPORT_SYMBOL_GPL(unregister_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 Dec 20 14:24:01 2002 > > @@ -0,0 +1,28 @@ > > +#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 *,=20 > struct pt_regs > > *); > > +struct kirq { > > + void *dev_id; > > + void (*isr)(int, void *, struct pt_regs *); > > + kirq_handler_t handler; > > +}; > > + > > +struct kirq kirq_list[NR_IRQS] =3D > > + { [0 ... NR_IRQS-1] =3D { NULL, NULL, NULL}}; > > + > > +#ifdef CONFIG_KIRQ > > +extern int register_kirq(int irq, char *devname,=20 > kirq_handler_t handler); > > +extern int unregister_kirq(int irq); > > +#else > > +int register_kirq(int irq, char *devname, kirq_handler_t=20 > handler) { return > > -ENOSYS; } > > +int unregister_kirq(int irq) {} > > +#endif /*CONFIG_KIRQ*/ > > +#endif /*_ASM_KIRQ_H*/ > >=20 > > Your Sincerely, > > Stanley Wang=20 > >=20 > > SW Engineer, Intel Corporation. > > Intel China Software Lab.=20 > > Tel: 021-52574545 ext. 1171=20 > > iNet: 8-752-1171=20 > > =20 > > Opinions expressed are those of the author and do not=20 > represent Intel > > Corporation > >=20 > >=20 > > ------------------------------------------------------- > > This SF.NET email is sponsored by: Geek Gift Procrastinating? > > Get the perfect geek gift now! Before the Holidays pass you by. > > T H I N K G E E K . C O M http://www.thinkgeek.com/sf/ > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Rusty L. <ru...@li...> - 2002-12-21 01:59:37
|
I added a new "mock" interceptor to aid in testing fi_core.c, but it could also be viewed as a near minimal interceptor implementation. If you build drivers/char/fi_mock_interceptor.c as a module you can then control what type of interceptor it will register as with a 'mock_type' parameter. Once the module is loaded and a new trigger is added that uses the interceptor, then mock will create a 'trip' file in the trigger's sysfs directory. Writing anything to the 'trip' file will cause fi_execute_trigger() to be called for that trigger. All functions print tracing information to the log, so you should be able to trace proper interceptor/core interactions. In implementing this I moved the definitions for trigger and interceptor attributes to the header file, and added the missing logic to fi_core.c to allow any interceptor to: * add files to the trigger directories for the triggers that arm the interceptor * add files to an interceptors own interceptor directory Have a good holidays. -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.908 -> 1.910 # arch/i386/Kconfig 1.24 -> 1.25 # kernel/fi_core.c 1.15 -> 1.17 # include/linux/fi.h 1.3 -> 1.4 # drivers/char/Makefile 1.54 -> 1.55 # (new) -> 1.1 drivers/char/fi_mock_interceptor.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/20 rusty@penguin.(none) 1.885.7.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 # -------------------------------------------- # 02/12/20 rusty@penguin.(none) 1.909 # Fixed merge conflict # -------------------------------------------- # 02/12/20 rusty@penguin.(none) 1.910 # fixed a mistake in last merge # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Fri Dec 20 17:43:51 2002 +++ b/arch/i386/Kconfig Fri Dec 20 17:43:51 2002 @@ -1585,6 +1585,17 @@ Unless you are intending to experiment with fault injection testing, just say N. +config FI_MOCK_INTERCEPTOR + tristate "Fault Injection Mock Interceptor (EXPERIMENTAL)" + depends on FI + help + This is a mock or fake 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 fault injection. + + If in doubt say N. + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Fri Dec 20 17:43:51 2002 +++ b/drivers/char/Makefile Fri Dec 20 17:43:51 2002 @@ -77,6 +77,7 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_FI_TEST) += fi_test.o +obj-$(CONFIG_FI_MOCK_INTERCEPTOR) += fi_mock_interceptor.o obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ diff -Nru a/drivers/char/fi_mock_interceptor.c b/drivers/char/fi_mock_interceptor.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/fi_mock_interceptor.c Fri Dec 20 17:43:51 2002 @@ -0,0 +1,148 @@ +/* + * Fault Injection Mock Interceptor Driver + * --------------------------------------- + * + * This is a fault injection interceptor interceptor created + * for the sole purpose of testing the core fault injection code. + * By loading this driver a new interceptor named 'mock_interceptor' + * will appear in the list of available interceptors. + * + * When a trigger is loaded that utilizes this interceptor: + * - you should be able to trace of the interceptor <==> core + * by looking at dmesg + * - a new file called 'trip' will created in the trigger directory + * that when written to will trip the trigger + * + * In addition to this, the type of intercepor (interceptor_type_t) + * that this moc implementation claims to be when it registers + * with the fault injection core can be controled with the + * 'mock_type' parameter. + * + * For example, to pretend to be a a INTERCEPTOR_TYPE_PIO + * interceptor (which is really just the number '2' as defined + * in the fi.h enum declaration), you would load: + * $ insmod fi_mock_interceptor mod_type=2 + * + * You can find out what the current type is by reading the + * 'type' file in the mock_interceptor directory. + * (i.e. 'cat fault_injection/interceptors/mock_interceptor/type') + * + * Copyright (C) 2002 Rusty Lynch <ru...@li...> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/kobject.h> +#include <linux/fi.h> + +#define DRIVER_AUTHOR "Rusty Lynch <ru...@li...>" +#define DRIVER_DESC "Fault Injection Mock Interceptor" + +#define dbg(format, arg...) \ + printk (KERN_DEBUG "%s: " format "\n",__FUNCTION__, ## arg); +#define trace(format, arg...) \ + printk(KERN_INFO "%s(" format ")\n", __FUNCTION__ , ## arg) + +extern int fi_register_interceptor(struct interceptor *); +extern int fi_unregister_interceptor(struct interceptor *); +extern void fi_execute_trigger(struct trigger*,struct interceptor*, + __u32,int,int,void*); + +static struct interceptor mock_interceptor; + +/* local variables */ +static int mock_type = INTERCEPTOR_TYPE_MMIO; + +static ssize_t trip_store(struct trigger * p, const char * page, + size_t count, loff_t off) +{ + trace("%s, %p, %i, %i", p ? p->kobj.name:"NULL",page,count,(int)off); + fi_execute_trigger(p, &mock_interceptor, 0, 0, 0, 0); + return count; +} +static struct trigger_attribute attr_trip = { + .attr = { .name = "trip", .mode = 0644 }, + .store = &trip_store, +}; + +static ssize_t type_show(struct interceptor * p, char * page, + size_t count, loff_t off) +{ + trace("%s, %p, %i, %i", p ? p->kobj.name:"NULL",page,count,(int)off); + return off ? 0 : snprintf(page,count,"%i\n",mock_type); +} +static struct interceptor_attribute attr_type = { + .attr = { .name = "type", .mode = 0644 }, + .show = &type_show, +}; + +static int arm(struct trigger *t) +{ + trace("%s", t ? t->kobj.name : "NULL"); + if (!t) { + dbg("Null trigger passed into arming function!"); + return -EINVAL; + } + + sysfs_create_file(&t->kobj, &attr_trip.attr); + return 0; +}; + +static void disarm(struct trigger *t) +{ + trace("%s", t ? t->kobj.name : "NULL"); + if (!t) { + dbg("Null trigger passed into disarming function!"); + return; + } + + sysfs_remove_file(&t->kobj, &attr_trip.attr); + return; +}; + +static void corrupt(__u32 dirty, void *data) +{ + trace("%ul, %p", dirty, data); + return; +}; + +static struct interceptor mock_interceptor = { + .kobj = {.name = "mock"}, + .arm = &arm, + .disarm = &disarm, + .corrupt = &corrupt +}; + +static int __init mock_init(void) +{ + trace(); + + mock_interceptor.type = mock_type; + kobject_init(&mock_interceptor.kobj); + if (!fi_register_interceptor(&mock_interceptor)) { + dbg("Failed to register Mock Interceptor"); + + /* FIXME!! For some reason kobject_register */ + /* is returning an error when none occured */ + /*return -EINVAL;*/ + } + + sysfs_create_file(&mock_interceptor.kobj, &attr_type.attr); + return 0; +} + +static void __exit mock_exit (void) +{ + trace(); + fi_unregister_interceptor(&mock_interceptor); +} + +module_init(mock_init); +module_exit(mock_exit); + +MODULE_PARM(mock_type, "i"); +MODULE_PARM_DESC(mock_type, "(interceptor_type_t) Type of interceptor"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru a/include/linux/fi.h b/include/linux/fi.h --- a/include/linux/fi.h Fri Dec 20 17:43:51 2002 +++ b/include/linux/fi.h Fri Dec 20 17:43:51 2002 @@ -25,7 +25,8 @@ typedef enum { INTERCEPTOR_TYPE_UNKNOWN=0, - INTERCEPTOR_TYPE_MMIO=1 + INTERCEPTOR_TYPE_MMIO=1, + INTERCEPTOR_TYPE_PIO=2, } interceptor_type_t; struct trigger { @@ -54,6 +55,18 @@ void (*disarm) (struct trigger *); void (*corrupt)(__u32, void *); struct kobject kobj; +}; + +struct interceptor_attribute { + struct attribute attr; + ssize_t (*show) (struct interceptor *,char *,size_t,loff_t); + ssize_t (*store)(struct interceptor *,const char *,size_t, loff_t); +}; + +struct trigger_attribute { + struct attribute attr; + ssize_t (*show) (struct trigger *,char *,size_t,loff_t); + ssize_t (*store)(struct trigger *,const char *,size_t,loff_t); }; #endif /* __KERNEL__ */ diff -Nru a/kernel/fi_core.c b/kernel/fi_core.c --- a/kernel/fi_core.c Fri Dec 20 17:43:51 2002 +++ b/kernel/fi_core.c Fri Dec 20 17:43:51 2002 @@ -51,16 +51,10 @@ static struct subsystem interceptor_subsys; static int is_initialized = 0; - int fi_debug = 1; int fi_register_interceptor(struct interceptor *); -struct trigger_attribute { - struct attribute attr; - ssize_t (*show)(struct trigger *,char *,size_t,loff_t); -}; - static struct trigger_attribute trigger_attr_wp; static struct trigger_attribute trigger_attr_bitmask; static struct trigger_attribute trigger_attr_min; @@ -247,9 +241,42 @@ * --------------------------------------------------------------- */ +static ssize_t interceptor_attr_show(struct kobject * kobj, + struct attribute * attr, + char * page, size_t count, + loff_t off) +{ + 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,count,off) : 0; +} + +static ssize_t interceptor_attr_store(struct kobject * kobj, + struct attribute * attr, + const char * page, + size_t count, + loff_t off) +{ + 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,off) : 0; +}; + +static struct sysfs_ops interceptor_sysfs_ops = { + .show = interceptor_attr_show, + .store = interceptor_attr_store, +}; + static struct subsystem interceptor_subsys = { - .kobj = { .name = "interceptors" }, - .parent = &fi_subsys, + .kobj = { .name = "interceptors" }, + .sysfs_ops = &interceptor_sysfs_ops, + .parent = &fi_subsys, }; /* @@ -271,6 +298,19 @@ return trigger_attr->show ? trigger_attr->show(n,page,count,off) : 0; } +static ssize_t trigger_attr_store(struct kobject * kobj, + struct attribute * attr, + const char * page, size_t count, + loff_t off) +{ + 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,off) : 0; +} + static ssize_t trigger_wp_read(struct trigger * p, char * page, size_t count, loff_t off) { @@ -497,6 +537,7 @@ static struct sysfs_ops trigger_sysfs_ops = { .show = trigger_attr_show, + .store = trigger_attr_store, }; static struct subsystem trigger_subsys = { |
From: Rusty L. <ru...@li...> - 2002-12-20 17:31:19
|
> Hi, folks > I revised the KIRQ according to Rusty's comment. > > # 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.901 -> 1.902 > # arch/i386/Kconfig 1.14 -> 1.16 > # arch/i386/kernel/Makefile 1.31 -> 1.32 > # (new) -> 1.4 arch/i386/kernel/kirq.c > # (new) -> 1.3 include/asm-i386/kirq.h > # > # The following is the BitKeeper ChangeSet Log > # -------------------------------------------- > # 02/12/20 st...@ma... 1.892.1.3 > # Refine config file. > # -------------------------------------------- > # 02/12/20 st...@ma... 1.902 > # 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 Dec 20 14:24:01 2002 > +++ b/arch/i386/Kconfig Fri Dec 20 14:24:01 2002 > @@ -1544,6 +1544,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 Dec 20 14:24:01 2002 > +++ b/arch/i386/kernel/Makefile Fri Dec 20 14:24:01 2002 > @@ -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 \ > @@ -29,6 +29,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 Dec 20 14:24:01 2002 > @@ -0,0 +1,103 @@ > +/* 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> > + > +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 "Miss KIRQ handler!\n"); This might be a little too cryptic for a system admin to figure out what is happening from the system log file. How about: 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 "Register KIRQ failed: Missing handler!\n"); > + } > + > + if (p->handler) { > + printk(KERN_ERR "Register KIRQ failed: KIRQ already > exist!\n"); > + } Did you mean to return an error on the conditions above? > + > + 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 "Unregister KIRQ failed!\n"); > + 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; > +} > +EXPORT_SYMBOL_GPL(register_kirq); > +EXPORT_SYMBOL_GPL(unregister_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 Dec 20 14:24:01 2002 > @@ -0,0 +1,28 @@ > +#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; > +}; > + > +struct kirq kirq_list[NR_IRQS] = > + { [0 ... NR_IRQS-1] = { NULL, NULL, NULL}}; > + > +#ifdef CONFIG_KIRQ > +extern int register_kirq(int irq, char *devname, kirq_handler_t handler); > +extern int unregister_kirq(int irq); > +#else > +int register_kirq(int irq, char *devname, kirq_handler_t handler) { return > -ENOSYS; } > +int unregister_kirq(int irq) {} > +#endif /*CONFIG_KIRQ*/ > +#endif /*_ASM_KIRQ_H*/ > > Your Sincerely, > Stanley Wang > > SW Engineer, Intel Corporation. > Intel China Software Lab. > Tel: 021-52574545 ext. 1171 > iNet: 8-752-1171 > > Opinions expressed are those of the author and do not represent Intel > Corporation > > > ------------------------------------------------------- > This SF.NET email is sponsored by: Geek Gift Procrastinating? > Get the perfect geek gift now! Before the Holidays pass you by. > T H I N K G E E K . C O M http://www.thinkgeek.com/sf/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Wang, S. <sta...@in...> - 2002-12-20 08:24:08
|
Hi, folks I revised the KIRQ according to Rusty's comment. # 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.901 -> 1.902 # arch/i386/Kconfig 1.14 -> 1.16 # arch/i386/kernel/Makefile 1.31 -> 1.32 # (new) -> 1.4 arch/i386/kernel/kirq.c # (new) -> 1.3 include/asm-i386/kirq.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/20 st...@ma... 1.892.1.3 # Refine config file. # -------------------------------------------- # 02/12/20 st...@ma... 1.902 # 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 Dec 20 14:24:01 2002 +++ b/arch/i386/Kconfig Fri Dec 20 14:24:01 2002 @@ -1544,6 +1544,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 Dec 20 14:24:01 2002 +++ b/arch/i386/kernel/Makefile Fri Dec 20 14:24:01 2002 @@ -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 \ @@ -29,6 +29,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 Dec 20 14:24:01 2002 @@ -0,0 +1,103 @@ +/* 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> + +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 "Miss KIRQ handler!\n"); + } + 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 "Register KIRQ failed: Missing handler!\n"); + } + + if (p->handler) { + printk(KERN_ERR "Register KIRQ failed: KIRQ already exist!\n"); + } + + 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 "Unregister KIRQ failed!\n"); + 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; +} +EXPORT_SYMBOL_GPL(register_kirq); +EXPORT_SYMBOL_GPL(unregister_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 Dec 20 14:24:01 2002 @@ -0,0 +1,28 @@ +#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; +}; + +struct kirq kirq_list[NR_IRQS] = + { [0 ... NR_IRQS-1] = { NULL, NULL, NULL}}; + +#ifdef CONFIG_KIRQ +extern int register_kirq(int irq, char *devname, kirq_handler_t handler); +extern int unregister_kirq(int irq); +#else +int register_kirq(int irq, char *devname, kirq_handler_t handler) { return -ENOSYS; } +int unregister_kirq(int irq) {} +#endif /*CONFIG_KIRQ*/ +#endif /*_ASM_KIRQ_H*/ Your Sincerely, Stanley Wang SW Engineer, Intel Corporation. Intel China Software Lab. Tel: 021-52574545 ext. 1171 iNet: 8-752-1171 Opinions expressed are those of the author and do not represent Intel Corporation |
From: Zhuang, L. <lou...@in...> - 2002-12-19 08:46:19
|
Reconstruction is completed, now is refining and testing... |
From: Wang, S. <sta...@in...> - 2002-12-19 01:05:02
|
> -----Original Message----- > From: Wang, Stanley=20 > Sent: 2002=E5=B9=B412=E6=9C=8819=E6=97=A5 8:47 > To: Lynch, Rusty > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO >=20 >=20 > Sure. I've claped my eye on it since 2.5.48 released :) > I would like to add "insmod" feature into fith-tool with the new=20 > kernel module loader. And I could calculate the offset of all PIO > instructions in user mode before load the module. Then I could > calculate the start address of the module's ".text" segment by=20 > searching "modules" list. FinallyI could combine them and pass=20 > them to Kprobes. I think it should work :) > How do you think about this? >=20 > -Stan >=20 > > -----Original Message----- > > From: Lynch, Rusty=20 > > Sent: 2002=E5=B9=B412=E6=9C=8819=E6=97=A5 1:44 > > To: Wang, Stanley; = 'fau...@li...' > > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO > >=20 > >=20 > >=20 > > > Stanley wrote:=20 > > > pros: > > > 1. As many breakpoints as you wish :) > > >=20 > > > cons: > > > 1. A user mode utility is needed for finding all IO related=20 > > > instructions > > > out. > > > 2. And we need to export the symbol "modules" for locating=20 > > the wanted > > > instructions. > > >=20 > >=20 > > Have you looked into the new kernel module loader? We might be = able > > to take advantage of some of the extra functionality it presents = (at > > least for loadable modules). > >=20 > > --rusty > >=20 >=20 |
From: Wang, S. <sta...@in...> - 2002-12-19 01:04:43
|
> -----Original Message----- > From: Wang, Stanley=20 > Sent: 2002=E5=B9=B412=E6=9C=8819=E6=97=A5 8:57 > To: Lynch, Rusty > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO >=20 >=20 > Please see my comment. >=20 > > -----Original Message----- > > From: Lynch, Rusty=20 > > Sent: 2002=E5=B9=B412=E6=9C=8819=E6=97=A5 2:12 > > To: Lynch, Rusty; Wang, Stanley;=20 > > 'fau...@li...' > > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO > >=20 > >=20 > > Now that I think about this some more, it would make more=20 > > sense to first=20 > Sure, I agree with you :) >=20 > > implement a PIO interceptor that uses kwatch, and just have=20 > > it fail if=20 > > to register a new trigger if the number of watchpoints are = exceeded. > >=20 > > After we have that in place and we are trying to use it,=20 > then it will > > become clear if the watchpoint limitation is too restrictive.=20 > > From the > > fault injection core's perspective, both implementations=20 > > would look the > > same. > Not true. The debug exception is a trap. Hence we could get=20 > control only > AFTER the watched address was accessed. And we couldn't injection > a write fault into the PIO access. So the implementation=20 > based on Kprobes > is mandatory. >=20 > -Stan >=20 > >=20 > > -rusty > >=20 > > > -----Original Message----- > > > From: Lynch, Rusty [mailto:rus...@in...] > > > Sent: Wednesday, December 18, 2002 9:44 AM > > > To: Wang, Stanley;=20 > 'fau...@li...' > > > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO > > >=20 > > >=20 > > >=20 > > > > Stanley wrote:=20 > > > > pros: > > > > 1. As many breakpoints as you wish :) > > > >=20 > > > > cons: > > > > 1. A user mode utility is needed for finding all IO related=20 > > > > instructions > > > > out. > > > > 2. And we need to export the symbol "modules" for locating=20 > > > the wanted > > > > instructions. > > > >=20 > > >=20 > > > Have you looked into the new kernel module loader? We=20 > might be able > > > to take advantage of some of the extra functionality it=20 > presents (at > > > least for loadable modules). > > >=20 > > > --rusty > > >=20 > > >=20 > > > ------------------------------------------------------- > > > This SF.NET email is sponsored by: Order your Holiday Geek=20 > > > Presents Now! > > > Green Lasers, Hip Geek T-Shirts, Remote Control Tanks,=20 > > > Caffeinated Soap, > > > MP3 Players, XBox Games, Flying Saucers, WebCams, Smart = Putty. > > > T H I N K G E E K . C O M http://www.thinkgeek.com/sf/ > > > _______________________________________________ > > > Fault-injection-developer mailing list > > > Fau...@li... > > >=20 > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > >=20 >=20 |
From: Lynch, R. <rus...@in...> - 2002-12-19 01:01:11
|
sure, just fix it before pushing to the tree. -rusty > -----Original Message----- > From: Zhuang, Louis > Sent: Wednesday, December 18, 2002 4:55 PM > To: Lynch, Rusty; Zhuang, Louis; > fau...@so... > Cc: Lynch, Rusty; Gao, Kevin; Wang, Frank; Wang, Stanley > Subject: RE: [Fault-injection-developer] [RFC] kmmio mechanism > > > > > One problem I did notice was the way you marked a couple of your new > > files as coded by Vamsi Krishna. It is correct to give > > credit to the author > > of code you utilized, but you need to make it clear that > you own the > > current file. Otherwise random people will stumble across > > this file and > > will submit patches/feedback/questions to Vamsi who will > have no idea > > what they are talking about. > This is a quick hacking without caring copyright ;-> > > > > -rusty > |
From: Zhuang, L. <lou...@in...> - 2002-12-19 00:57:44
|
> One problem I did notice was the way you marked a couple of your new > files as coded by Vamsi Krishna. It is correct to give > credit to the author > of code you utilized, but you need to make it clear that you own the > current file. Otherwise random people will stumble across > this file and > will submit patches/feedback/questions to Vamsi who will have no idea > what they are talking about. This is a quick hacking without caring copyright ;-> > > -rusty |
From: Rusty L. <ru...@li...> - 2002-12-18 20:54:00
|
I have tried to capture some basic information on who is working on what. Given the nature of our project anybody can be working on anything, but I still wanted to capture big picture items. Let me know if I missed or misrepresented something. http://fault-injection.sf.net/tasklist.php -rusty |
From: Lynch, R. <rus...@in...> - 2002-12-18 18:11:57
|
Now that I think about this some more, it would make more sense to first implement a PIO interceptor that uses kwatch, and just have it fail if to register a new trigger if the number of watchpoints are exceeded. After we have that in place and we are trying to use it, then it will become clear if the watchpoint limitation is too restrictive. From the fault injection core's perspective, both implementations would look the same. -rusty > -----Original Message----- > From: Lynch, Rusty [mailto:rus...@in...] > Sent: Wednesday, December 18, 2002 9:44 AM > To: Wang, Stanley; 'fau...@li...' > Subject: RE: [Fault-injection-developer] RFC: Interceptor for PIO > > > > > Stanley wrote: > > pros: > > 1. As many breakpoints as you wish :) > > > > cons: > > 1. A user mode utility is needed for finding all IO related > > instructions > > out. > > 2. And we need to export the symbol "modules" for locating > the wanted > > instructions. > > > > Have you looked into the new kernel module loader? We might be able > to take advantage of some of the extra functionality it presents (at > least for loadable modules). > > --rusty > > > ------------------------------------------------------- > This SF.NET email is sponsored by: Order your Holiday Geek > Presents Now! > Green Lasers, Hip Geek T-Shirts, Remote Control Tanks, > Caffeinated Soap, > MP3 Players, XBox Games, Flying Saucers, WebCams, Smart Putty. > T H I N K G E E K . C O M http://www.thinkgeek.com/sf/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > |
From: Lynch, R. <rus...@in...> - 2002-12-18 17:44:00
|
> Stanley wrote: > pros: > 1. As many breakpoints as you wish :) > > cons: > 1. A user mode utility is needed for finding all IO related > instructions > out. > 2. And we need to export the symbol "modules" for locating the wanted > instructions. > Have you looked into the new kernel module loader? We might be able to take advantage of some of the extra functionality it presents (at least for loadable modules). --rusty |
From: Lynch, R. <rus...@in...> - 2002-12-18 17:33:46
|
I think this is a good direction. Go ahead and add it to the tree. --rusty > Wang, Stanley wrote: > Hi folks, > There is the IRQ interceptor infrastructure: KIRQ > > <snip> |
From: Lynch, R. <rus...@in...> - 2002-12-18 17:08:58
|
I think this is looking very promising. Go ahead and add it to the tree. The only thing I ask is that if your code does not currently compile, then remove it from the Makefile until it does. When you have it working (even if it just limping along) then let the list know. I only casually looked at the code, but even with a casual glance it was obvious what you were trying to do. This is the way it should be. One problem I did notice was the way you marked a couple of your new files as coded by Vamsi Krishna. It is correct to give credit to the author of code you utilized, but you need to make it clear that you own the current file. Otherwise random people will stumble across this file and will submit patches/feedback/questions to Vamsi who will have no idea what they are talking about. -rusty > -----Original Message----- > From: Zhuang, Louis [mailto:lou...@in...] > Sent: Wednesday, December 18, 2002 4:09 AM > To: fau...@so... > Cc: Lynch, Rusty; Gao, Kevin; Wang, Frank; Wang, Stanley; > Zhuang, Louis > Subject: [Fault-injection-developer] [RFC] kmmio mechanism > > > > We'd like split instruction analysis code and general mmio > > probe code in pf > > module. That is, we'd like support a general mmio probe > > mechanism interface > > as the infrastructure of pf module. the interface is like > > > > struct kmmio_probe { > > kmmio_addr_t *addr; > > kmmio_pre_handler_t pre_handler; > > kmmio_post_handler_t post_handler; > > void *data; //opaque data structure > > } > > > > kmmio_probe_register(struct kmmio_probe *); > > kmmio_probe_unregister(struct kmmio_probe *); > > > > Then, pf module place probe on the address and analysis > instruction in > > pre/post_handler and feedback to fi_core. > > > I've developed a *very* primarily patch against our tip BK > tree. This is > only a compileable code, *NOT TEST AT ALL*. All comments? > - Louis > > -------------------------------------------------------------- > -------------- > ---------------- > # 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.887 -> 1.888 > # arch/i386/mm/fault.c 1.23 -> 1.24 > # arch/i386/Kconfig 1.18 -> 1.19 > # arch/i386/kernel/traps.c 1.38 -> 1.39 > # arch/i386/kernel/Makefile 1.33 -> 1.34 > # kernel/Makefile 1.26 -> 1.27 > # (new) -> 1.2 include/linux/kmmio.h > # (new) -> 1.1 > arch/i386/kernel/kmmio.c > # (new) -> 1.2 kernel/kmmio.c > # (new) -> 1.1 > include/asm-i386/kmmio.h > # > # The following is the BitKeeper ChangeSet Log > # -------------------------------------------- > # 02/12/18 lo...@ha... 1.888 > # add kmmio mechanism. > # *NO TEST AT ALL* > # -------------------------------------------- > # > diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig > --- a/arch/i386/Kconfig Wed Dec 18 20:02:43 2002 > +++ b/arch/i386/Kconfig Wed Dec 18 20:02:43 2002 > @@ -1506,6 +1506,13 @@ > 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" > + 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 FI > bool "Fault Injection (EXPERIMENTAL)" > diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile > --- a/arch/i386/kernel/Makefile Wed Dec 18 20:02:43 2002 > +++ b/arch/i386/kernel/Makefile Wed Dec 18 20:02:43 2002 > @@ -31,6 +31,7 @@ > obj-$(CONFIG_EDD) += edd.o > obj-$(CONFIG_MODULES) += module.o > obj-$(CONFIG_KPROBES) += kprobes.o > +obj-$(CONFIG_KMMIO) += kmmio.o > obj-y += sysenter.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 Wed Dec 18 20:02:43 2002 > @@ -0,0 +1,134 @@ > +/* > + * Support for kernel probes. > + * (C) 2002 Vamsi Krishna S <vam...@in...>. > + */ > + > +#include <linux/config.h> > +#include <linux/kmmio.h> > +#include <linux/ptrace.h> > +#include <linux/spinlock.h> > +#include <linux/preempt.h> > +#include <linux/mm.h> > +#include <linux/slab.h> > +#include <asm/io.h> > + > +static struct kmmio_probe *current_kmmio = NULL; > +static int is_trigger; > +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) > +{ > + struct kmmio_probe *p; > + struct kmmio_fault_page *f; > + > + /* We're in an interrupt, but this is clear and BUG()-safe. */ > + preempt_disable(); > + > + lock_kmmio(); > + > + is_trigger = 1; > + f = get_kmmio_fault_page((void *)addr); > + if (!f) { > + /* this page fault is not caused by kmmio */ > + /* XXX some pending fault on other cpu may > cause problem! */ > > + unlock_kmmio(); > + goto no_kmmio; > + } > + > + p = get_kmmio_probe((void *)addr); > + if (!p) { > + > + /* The fault is caused by kmmio, but no trigger care the > adress */ > + is_trigger = 0; > + goto no_trigger; > + } > + > + current_kmmio = p; > + kmmio_saved_eflags = (regs->eflags & (TF_MASK|IF_MASK)); > + > + p->pre_handler(p, regs, addr); > + > +no_trigger: > + 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(f->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 (!current_kmmio) > + return 0; > + > + if (is_trigger && current_kmmio->post_handler) > + current_kmmio->post_handler(current_kmmio, > condition, regs); > + > + > arm_kmmio_fault_page(get_kmmio_fault_page(current_kmmio->addr)->page > ); > + regs->eflags &= ~TF_MASK; > + regs->eflags |= kmmio_saved_eflags; > + > + 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 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 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 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(page, _PAGE_PRESENT); > +} > + > +void disarm_kmmio_fault_page(kmmio_addr_t page) > +{ > + (unsigned long)page &= PAGE_MASK; > + set_pte_bits(page, _PAGE_PRESENT); > +} > diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c > --- a/arch/i386/kernel/traps.c Wed Dec 18 20:02:43 2002 > +++ b/arch/i386/kernel/traps.c Wed Dec 18 20:02:43 2002 > @@ -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> > @@ -47,7 +48,6 @@ > #include <asm/smp.h> > #include <asm/pgalloc.h> > #include <asm/arch_hooks.h> > -#include <asm/fi.h> > > #include <linux/irq.h> > #include <linux/module.h> > @@ -599,7 +599,7 @@ > if (post_kprobe_handler(regs)) > return 1; > > - if (fi_post_page_fault(condition, regs)) > + 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 Wed Dec 18 20:02:43 2002 > +++ b/arch/i386/mm/fault.c Wed Dec 18 20:02:43 2002 > @@ -20,6 +20,7 @@ > #include <linux/tty.h> > #include <linux/vt_kern.h> /* For unblank_screen() */ > #include <linux/kprobes.h> > +#include <linux/kmmio.h> > > #include <asm/system.h> > #include <asm/uaccess.h> > @@ -166,7 +167,7 @@ > if (kprobe_running() && kprobe_fault_handler(regs, 14)) > return; > > - if (fi_page_fault(regs, address)) > + 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 Wed Dec 18 20:02:43 2002 > @@ -0,0 +1,24 @@ > +#ifndef _ASM_KMMIO_H > +#define _ASM_KMMIO_H > +/* > + * Dynamic Probes (kprobes) support > + * Vamsi Krishna S <vam...@in...>, July, 2002 > + * Mailing list: dp...@ww... > + */ > +#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); > +#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 Wed Dec 18 20:02:43 2002 > @@ -0,0 +1,65 @@ > +#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; > + > + /* opaque data structure used by register */ > + void *data; > +}; > + > +struct kmmio_fault_page { > + struct list_head list; > + > + /* location of the fault page */ > + kmmio_addr_t page; > + > + int count; > +}; > + > +#ifdef CONFIG_KMMIO > +/* Locks kmmio: irq must be disabled */ > +void lock_kmmio(void); > +void unlock_kmmio(void); > + > +/* kmmio is active by some kmmio_probes? */ > +static inline int is_kmmio_active(void) > +{ > + extern unsigned int kmmio_count; > + return kmmio_count; > +} > + > +/* Get the kmmio at this addr (if any). Must have called > lock_kmmio */ > +struct kmmio_probe *get_kmmio_probe(kmmio_addr_t addr); > +struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page); > +int add_kmmio_fault_page(kmmio_addr_t page); > +void release_kmmio_fault_page(kmmio_addr_t page); > + > +int register_kmmio_probe(struct kmmio_probe *p); > +void unregister_kmmio_probe(struct kmmio_probe *p); > +#else > +static inline int is_kmmio_active(void) { return 0; } > +static inline int register_kmmio_probe(struct kmmio_probe > *p) { return > -ENOSYS; } > +static inline void unregister_kmmio_probe(struct kmmio_probe *p) { } > +#endif > +#endif /* _LINUX_KMMIO_H */ > diff -Nru a/kernel/Makefile b/kernel/Makefile > --- a/kernel/Makefile Wed Dec 18 20:02:43 2002 > +++ b/kernel/Makefile Wed Dec 18 20:02:43 2002 > @@ -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 > obj-$(CONFIG_FI) += fi_core.o > > ifneq ($(CONFIG_IA64),y) > diff -Nru a/kernel/kmmio.c b/kernel/kmmio.c > --- /dev/null Wed Dec 31 16:00:00 1969 > +++ b/kernel/kmmio.c Wed Dec 18 20:02:43 2002 > @@ -0,0 +1,141 @@ > +/* Support for MMIO probes. > + * Stolen 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> > + > +#define KMMIO_HASH_BITS 6 > +#define KMMIO_TABLE_SIZE (1 << KMMIO_HASH_BITS) > + > +static struct list_head kmmio_table[KMMIO_TABLE_SIZE]; > + > +#define KMMIO_FAULT_HASH_BITS 4 > +#define KMMIO_FAULT_HASH_SIZE (1 << KMMIO_FAULT_HASH_BITS) > +static struct list_head kmmio_fault_table[KMMIO_FAULT_HASH_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; > + > + kmmio_count++; > + spin_lock_irq(&kmmio_lock); > + if (get_kmmio_probe(p->addr)) { > + ret = -EEXIST; > + goto out; > + } > + list_add(&p->list, &kmmio_table[hash_ptr(p->addr, > KMMIO_HASH_BITS)]); > + > + add_kmmio_fault_page(p->addr); > + > + out: > + spin_unlock_irq(&kmmio_lock); > + 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); > + spin_unlock_irq(&kmmio_lock); > + kmmio_count--; > +} > + > +struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page) > +{ > + struct list_head *head, *tmp; > + > + (unsigned long)page &= PAGE_MASK; > + head = &kmmio_fault_table[hash_ptr(page, KMMIO_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_KERNEL); > + f->count = 1; > + f->page = page; > + list_add(&f->list, &kmmio_fault_table[hash_ptr(f->page, > KMMIO_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]); > + > + return 0; > +} > +__initcall(init_kmmio); > + > +EXPORT_SYMBOL_GPL(register_kmmio_probe); > +EXPORT_SYMBOL_GPL(unregister_kmmio_probe); > > |
From: Wang, S. <sta...@in...> - 2002-12-18 13:16:19
|
Hi folks, There is the IRQ interceptor infrastructure: KIRQ # 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.892 -> 1.894 # arch/i386/Kconfig 1.14 -> 1.15 # arch/i386/kernel/Makefile 1.31 -> 1.32 # (new) -> 1.3 arch/i386/kernel/kirq.c # (new) -> 1.2 include/asm-i386/kirq.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/18 st...@st... 1.893 # Add KIRQ Support # -------------------------------------------- # 02/12/18 st...@ma... 1.894 # Fix stupid bug. # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Wed Dec 18 20:54:04 2002 +++ b/arch/i386/Kconfig Wed Dec 18 20:54:04 2002 @@ -1544,6 +1544,12 @@ best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +config KIRQ + bool "Kernel Irq interceptor" + depends on DEBUG_KERNEL + help + This option enable an IRQ interceptor. + 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 Wed Dec 18 20:54:04 2002 +++ b/arch/i386/kernel/Makefile Wed Dec 18 20:54:04 2002 @@ -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 \ @@ -29,6 +29,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 Wed Dec 18 20:54:04 2002 @@ -0,0 +1,99 @@ +#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> + +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 "Miss KIRQ handler!\n"); + } + 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 "Register KIRQ failed: Missing handler!\n"); + } + + if (p->handler) { + printk(KERN_ERR "Register KIRQ failed: KIRQ already exist!\n"); + } + + 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 "Unregister KIRQ failed!\n"); + 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; +} +EXPORT_SYMBOL_GPL(register_kirq); +EXPORT_SYMBOL_GPL(unregister_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 Wed Dec 18 20:54:04 2002 @@ -0,0 +1,24 @@ +#ifndef _ASM_KIRQ_H +#define _ASM_KIRQ_H + +#include <linux/errno.h> + +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; +}; + +struct kirq kirq_list[NR_IRQS] = + { [0 ... NR_IRQS-1] = { NULL, NULL, NULL}}; + +#ifdef CONFIG_KIRQ +extern int register_kirq(int irq, char *devname, kirq_handler_t handler); +extern int unregister_kirq(int irq); +#else +int register_kirq(int irq, char *devname, kirq_handler_t handler) { return -ENOSYS; } +int unregister_kirq(int irq) {} +#endif /*CONFIG_KIRQ*/ +#endif /*_ASM_KIRQ_H*/ Your Sincerely, Stanley Wang SW Engineer, Intel Corporation. Intel China Software Lab. Tel: 021-52574545 ext. 1171 iNet: 8-752-1171 Opinions expressed are those of the author and do not represent Intel Corporation |
From: Wang, S. <sta...@in...> - 2002-12-18 13:14:04
|
Hi, folks I would like to build IRQ interceptor by ransacking the "irq_desc". We could replace the specified ISR with ours directly and change the kernel control path. How do you guys think about it? And I would like to build some infrastructure looks like Kprobes for it. The infrastructure will be responsible for replacing and restoring the specified ISR. I will publish a piece of code about the infrastructure later. Your Sincerely, Stanley Wang SW Engineer, Intel Corporation. Intel China Software Lab. Tel: 021-52574545 ext. 1171 iNet: 8-752-1171 Opinions expressed are those of the author and do not represent Intel Corporation |
From: Zhuang, L. <lou...@in...> - 2002-12-18 12:12:04
|
> We'd like split instruction analysis code and general mmio > probe code in pf > module. That is, we'd like support a general mmio probe > mechanism interface > as the infrastructure of pf module. the interface is like > > struct kmmio_probe { > kmmio_addr_t *addr; > kmmio_pre_handler_t pre_handler; > kmmio_post_handler_t post_handler; > void *data; //opaque data structure > } > > kmmio_probe_register(struct kmmio_probe *); > kmmio_probe_unregister(struct kmmio_probe *); > > Then, pf module place probe on the address and analysis instruction in > pre/post_handler and feedback to fi_core. > I've developed a *very* primarily patch against our tip BK tree. This is only a compileable code, *NOT TEST AT ALL*. All comments? - Louis ---------------------------------------------------------------------------- ---------------- # 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.887 -> 1.888 # arch/i386/mm/fault.c 1.23 -> 1.24 # arch/i386/Kconfig 1.18 -> 1.19 # arch/i386/kernel/traps.c 1.38 -> 1.39 # arch/i386/kernel/Makefile 1.33 -> 1.34 # kernel/Makefile 1.26 -> 1.27 # (new) -> 1.2 include/linux/kmmio.h # (new) -> 1.1 arch/i386/kernel/kmmio.c # (new) -> 1.2 kernel/kmmio.c # (new) -> 1.1 include/asm-i386/kmmio.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/18 lo...@ha... 1.888 # add kmmio mechanism. # *NO TEST AT ALL* # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Wed Dec 18 20:02:43 2002 +++ b/arch/i386/Kconfig Wed Dec 18 20:02:43 2002 @@ -1506,6 +1506,13 @@ 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" + 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 FI bool "Fault Injection (EXPERIMENTAL)" diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Wed Dec 18 20:02:43 2002 +++ b/arch/i386/kernel/Makefile Wed Dec 18 20:02:43 2002 @@ -31,6 +31,7 @@ obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KMMIO) += kmmio.o obj-y += sysenter.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 Wed Dec 18 20:02:43 2002 @@ -0,0 +1,134 @@ +/* + * Support for kernel probes. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ + +#include <linux/config.h> +#include <linux/kmmio.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/preempt.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> + +static struct kmmio_probe *current_kmmio = NULL; +static int is_trigger; +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) +{ + struct kmmio_probe *p; + struct kmmio_fault_page *f; + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + lock_kmmio(); + + is_trigger = 1; + f = get_kmmio_fault_page((void *)addr); + if (!f) { + /* this page fault is not caused by kmmio */ + /* XXX some pending fault on other cpu may cause problem! */ + unlock_kmmio(); + goto no_kmmio; + } + + p = get_kmmio_probe((void *)addr); + if (!p) { + + /* The fault is caused by kmmio, but no trigger care the adress */ + is_trigger = 0; + goto no_trigger; + } + + current_kmmio = p; + kmmio_saved_eflags = (regs->eflags & (TF_MASK|IF_MASK)); + + p->pre_handler(p, regs, addr); + +no_trigger: + 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(f->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 (!current_kmmio) + return 0; + + if (is_trigger && current_kmmio->post_handler) + current_kmmio->post_handler(current_kmmio, condition, regs); + + arm_kmmio_fault_page(get_kmmio_fault_page(current_kmmio->addr)->page ); + regs->eflags &= ~TF_MASK; + regs->eflags |= kmmio_saved_eflags; + + 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 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 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 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(page, _PAGE_PRESENT); +} + +void disarm_kmmio_fault_page(kmmio_addr_t page) +{ + (unsigned long)page &= PAGE_MASK; + set_pte_bits(page, _PAGE_PRESENT); +} diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Wed Dec 18 20:02:43 2002 +++ b/arch/i386/kernel/traps.c Wed Dec 18 20:02:43 2002 @@ -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> @@ -47,7 +48,6 @@ #include <asm/smp.h> #include <asm/pgalloc.h> #include <asm/arch_hooks.h> -#include <asm/fi.h> #include <linux/irq.h> #include <linux/module.h> @@ -599,7 +599,7 @@ if (post_kprobe_handler(regs)) return 1; - if (fi_post_page_fault(condition, regs)) + 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 Wed Dec 18 20:02:43 2002 +++ b/arch/i386/mm/fault.c Wed Dec 18 20:02:43 2002 @@ -20,6 +20,7 @@ #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ #include <linux/kprobes.h> +#include <linux/kmmio.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -166,7 +167,7 @@ if (kprobe_running() && kprobe_fault_handler(regs, 14)) return; - if (fi_page_fault(regs, address)) + 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 Wed Dec 18 20:02:43 2002 @@ -0,0 +1,24 @@ +#ifndef _ASM_KMMIO_H +#define _ASM_KMMIO_H +/* + * Dynamic Probes (kprobes) support + * Vamsi Krishna S <vam...@in...>, July, 2002 + * Mailing list: dp...@ww... + */ +#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); +#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 Wed Dec 18 20:02:43 2002 @@ -0,0 +1,65 @@ +#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; + + /* opaque data structure used by register */ + void *data; +}; + +struct kmmio_fault_page { + struct list_head list; + + /* location of the fault page */ + kmmio_addr_t page; + + int count; +}; + +#ifdef CONFIG_KMMIO +/* Locks kmmio: irq must be disabled */ +void lock_kmmio(void); +void unlock_kmmio(void); + +/* kmmio is active by some kmmio_probes? */ +static inline int is_kmmio_active(void) +{ + extern unsigned int kmmio_count; + return kmmio_count; +} + +/* Get the kmmio at this addr (if any). Must have called lock_kmmio */ +struct kmmio_probe *get_kmmio_probe(kmmio_addr_t addr); +struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page); +int add_kmmio_fault_page(kmmio_addr_t page); +void release_kmmio_fault_page(kmmio_addr_t page); + +int register_kmmio_probe(struct kmmio_probe *p); +void unregister_kmmio_probe(struct kmmio_probe *p); +#else +static inline int is_kmmio_active(void) { return 0; } +static inline int register_kmmio_probe(struct kmmio_probe *p) { return -ENOSYS; } +static inline void unregister_kmmio_probe(struct kmmio_probe *p) { } +#endif +#endif /* _LINUX_KMMIO_H */ diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Wed Dec 18 20:02:43 2002 +++ b/kernel/Makefile Wed Dec 18 20:02:43 2002 @@ -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 obj-$(CONFIG_FI) += fi_core.o ifneq ($(CONFIG_IA64),y) diff -Nru a/kernel/kmmio.c b/kernel/kmmio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/kernel/kmmio.c Wed Dec 18 20:02:43 2002 @@ -0,0 +1,141 @@ +/* Support for MMIO probes. + * Stolen 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> + +#define KMMIO_HASH_BITS 6 +#define KMMIO_TABLE_SIZE (1 << KMMIO_HASH_BITS) + +static struct list_head kmmio_table[KMMIO_TABLE_SIZE]; + +#define KMMIO_FAULT_HASH_BITS 4 +#define KMMIO_FAULT_HASH_SIZE (1 << KMMIO_FAULT_HASH_BITS) +static struct list_head kmmio_fault_table[KMMIO_FAULT_HASH_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; + + kmmio_count++; + spin_lock_irq(&kmmio_lock); + if (get_kmmio_probe(p->addr)) { + ret = -EEXIST; + goto out; + } + list_add(&p->list, &kmmio_table[hash_ptr(p->addr, KMMIO_HASH_BITS)]); + + add_kmmio_fault_page(p->addr); + + out: + spin_unlock_irq(&kmmio_lock); + 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); + spin_unlock_irq(&kmmio_lock); + kmmio_count--; +} + +struct kmmio_fault_page *get_kmmio_fault_page(kmmio_addr_t page) +{ + struct list_head *head, *tmp; + + (unsigned long)page &= PAGE_MASK; + head = &kmmio_fault_table[hash_ptr(page, KMMIO_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_KERNEL); + f->count = 1; + f->page = page; + list_add(&f->list, &kmmio_fault_table[hash_ptr(f->page, KMMIO_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]); + + return 0; +} +__initcall(init_kmmio); + +EXPORT_SYMBOL_GPL(register_kmmio_probe); +EXPORT_SYMBOL_GPL(unregister_kmmio_probe); |
From: Zhuang, L. <lou...@in...> - 2002-12-18 08:25:43
|
We'd like split instrcution analisys code and general mmio probe code in pf moudle. That is, we'd like support a general mmio probe mechanism interface as the infrastructure of pf module. the interface is like struct kmmio_probe { kmmio_addr_t *addr; kmmio_pre_handler_t pre_handler; kmmio_post_handler_t post_handler; void *data; //opaque data structure } kmmio_probe_register(struct kmmio_probe *); kmmio_probe_unregister(struct kmmio_probe *); Then, pf module place probe on the address and analysis instruction in pre/post_handler and feedback to fi_core. |
From: Wang, S. <sta...@in...> - 2002-12-18 02:58:52
|
Hi, folks I would like to build PIO interceptor on a base of Kprobes. There are two methods that could be used : Kprobes or Kwatch. And I would like to implement two PIO interceptor, one based on Kwatch and another based on Kprobes. I'll illustrate the workflow of them. The one (whose name is "DR") based on Kwatch: Registration/Unregistration: wp_register core -------------------->dr_register--------------> register_kwatch wp_unregister core -------------------->dr_unregister--------------> unregister_kwatch Fault injection: do_debug-------------->dr_kwatch_handler------------------>core------------- ---->injection fault pros: 1. Kwatch's API looks pretty good and make the life easy :) cons: 1. The number of debug register is limited (only 4). 2. The debug exception is triggered after the watched IO port was accessed, hence we couldn't do nothing about wrtie access. The one (whose name is "DBP") based on Kprobes: Registration/Unregistration: wp_register core -------------------->dbp_register--------------> register_kprobe wp_unregister core -------------------->dbp_unregister--------------> unregister_kprobe Fault injection: there is write fault do_int3----------------->dbp_pre_kprobe_handler-------------------------->co re-------------->(inject write fault) do_debug------------->dbp_post_kpobe_handler-------------------------->core- -------------- ------->inject read fault or restore context for injected write fault pros: 1. As many breakpoints as you wish :) cons: 1. A user mode utility is needed for finding all IO related instructions out. 2. And we need to export the symbol "modules" for locating the wanted instructions. Your Sincerely, Stanley Wang SW Engineer, Intel Corporation. Intel China Software Lab. Tel: 021-52574545 ext. 1171 iNet: 8-752-1171 Opinions expressed are those of the author and do not represent Intel Corporation |
From: Rusty L. <ru...@li...> - 2002-12-18 01:10:35
|
Message> Louis said: > I'd like to do the optimization on pf and > fi_core.c as soon as Rusty's reconstruction is > completed. Good, let's finalize on what will change in the core. Spend some time looking over my proposal and let me know what you think about it. -rusty |
From: Zhuang, L. <lou...@in...> - 2002-12-18 01:04:21
|
I'd like to do the optimization on pf and fi_core.c as soon as Rusty's reconstruction is completed. -----Original Message----- From: Rusty Lynch [mailto:ru...@li...] Sent: Wednesday, December 18, 2002 12:27 AM To: Gao, Kevin; fau...@so...; Zhuang, Louis; Wang, Stanley Subject: Re: [Fault-injection-developer] Overhead summary. Wow! Well, we have to start somewhere. I suspected this just from my systems response time while hacking on a patched box. It will be very interesting to see how these numbers improve after a critical eye is taken to pf. --rusty ----- Original Message ----- From: Gao, <mailto:kev...@in...> Kevin To: 'fau...@so...' <mailto:'fau...@so...'> ; Zhuang, Louis <mailto:lou...@in...> ; Wang, <mailto:sta...@in...> Stanley Sent: Monday, December 16, 2002 11:05 PM Subject: [Fault-injection-developer] Overhead summary. According to the results of performance testing. We can get some important conlusion. Compare 2.5.51 with our FITH with pure kernel(2.5.51) The over head is as follow: Mmap Latency about 17.8% Prot Fault about 63.5% Page Fault about 50% |
From: Rusty L. <ru...@li...> - 2002-12-17 23:55:23
|
Ok, here is something to chew on. When I reviewed the feedback on my changes to fi_core.c, I realized that part of my problem with having the core code 'execute' the trigger was that too many assumptions were made about the design of the interceptor (in our case pf*.c). I think that this model for fault injection can be made to do more then just corrupt some data. For example, I can envision a trigger that results in a code segment being executed just before a specific address is execute if a set of filtering criteria is first meet. What if we: 1. (as Louis hinted) narrow our notion of an interceptor to strictly be a component that knows how to divert a thread of execution to the core. ** An interceptor knows how to intercept type of condition ** ** Possible Examples: - MMIO Given a physical address, a MMIO interceptor can intercept the specific address before the caller reading/writing to the address returns from a read/write operation. - PIO Given an io port, a PIO interceptor can intercept the data being read/written from/to that port. - Executable Given a kernel mapped address, a EXEC interceptor can intercept just before the location is executed. 2. introduce the concept of an 'injector' that only knows how to inject a given fault. (It could be that a block of code implements both interfaces, but as far as the core is concerned, they are two different components.) ** An injector knows how to inject a specific type of fault ** ** Possible Examples: - MMIO Given a physical address, a MMIO injector can write to that address without the owner of that mmaped io realizing it. (Given the nature of how mmio is implemented in the kernel, this injector will probably have to be implemented by the same code as the injector.) - Executable Given a kernel mapped address, a EXEC injector can cause an arbitrary block of code to be executed just before the kernel address. I created the text below as a new entry for Documentation/fault_injection.txt. It is still fairly empty, but I attempted to further explain the notion of injections and interceptors and how they interact with the core. I also took a stab at how the datatypes, but I have not yet implemented any of this, so there could be some fundamental problems with the model. -rusty ******************************************************************************* * Fault Injection ******************************************************************************* Original Author: Rusty Lynch <ru...@li...> Contributors: Fault injection is composed of: 1. core functionality (kernel/fi_core.c) a. handles all user space interaction b. contains core logic for handling faults 2. interceptors a. enables core to intercept various types of events b. the core knows how to use specific types of interceptors, but does not know how the interceptors are implemented 3. injectors a. enables core to inject specific types of faults b. the core knows how to use specific types of injectors, but does not know how the injectors are implemented User space interaction ---------------------- Interceptor / Injector interaction with the fault injection core ---------------------------------------------------------------- Registration: ------ fi_register_interceptor() ------------------------ | core | <----------------------------------- | interceptor (MMIO type)| ------ ------------------------ ------ fi_register_injector() --------------------- | core | <----------------------------------- | injector (MMIO type)| ------ --------------------- Configuration: Add the following MMIO trigger ------ User space --------------------------------------> | core | ------ ** Core searches for and finds the previously registered MMIO interceptor ** ------ interceptor->arm(physical_address) ------------------------ | core | ------------------------------------> | interceptor (MMIO type)| ------ ------------------------ Interceptor is triggered: ------ fi_event_handler(i) ------------------------ | core | <------------------------------ | interceptor (MMIO type)| ------ ------------------------ ** Inside the fi_event_handler(): -- core determines what action is to be taken, and decides to replace the data that is about to be returned by the caller of the MMIO data -- core searches for and finds an appropriate injector ------ injector->inject() --------------------- | core | ----------------------> | injector (MMIO type)| ------ --------------------- ------ ok ------------------------ | core | ------------------------------> | interceptor (MMIO type)| ------ ------------------------ Deactivating specific interceptors: Disable the following interceptor ------ User space --------------------------------------> | core | ------ ------ interceptor->set_status(FI_INTERCEPTOR_STATUS_DISABLED) ------------- | core | -----------------------------------------------------> | interceptor | ------ ------------- Removing a configuration: Remove the following trigger ------ User space --------------------------------------> | core | ------ ------ interceptor->disarm() ------------------------ | core | ------ ------------------------------> | interceptor (MMIO type)| ------ ------------------------ /* Core */ extern int fi_register_interceptor(struct fi_interceptor *); extern int fi_unregister_interceptor(struct fi_interceptor *); extern int fi_register_injector(struct fi_injector *); extern int fi_unregister_injector(struct fi_injector *); extern int fi_event_handler(struct pt_regs *, struct fi_interceptor *, void *); /* Interceptors */ typedef enum { INTERCEPTOR_STATUS_UNKNOWN=0, INTERCEPTOR_STATUS_ENABLED=1, INTERCEPTOR_STATUS_DISABLED=2 } fi_interceptor_status_t; typedef enum { FI_INTERCEPTOR_TYPE_UNKNOWN=0, FI_INTERCEPTOR_TYPE_MMIO=1 } fi_interceptor_type_t; struct fi_interceptor { interceptor_type_t type; interceptor_status_t get_status(void); int set_status(interceptor_status_t status); int arm(void *data); int disarm(void *data); kobject kobj; }; /* Injectors */ typedef enum { FI_INJECTOR_TYPE_UNKNOWN=0, FI_INJECTOR_TYPE_MMIO=1 } fi_injector_type_t; struct fi_injector { fi_injector_type_t type; int inject(struct pt_regs * regs, void *data); kobject kobj; }; |
From: Rusty L. <ru...@li...> - 2002-12-17 16:36:25
|
Ok, you made some good points. I think the model I implemented in my patch needs some tweaking. Let me try to summarize all the feedback in a new email along with a fresh description of what the fault injection core should provide. I should have something together by morning in Asia. --rusty > > It seems to me that something more then just > > mucking up a chunk of data could be implemented > > by an interceptor. Doesn't this seem like an > > artificial limitation? > I think fi_core should know these things more then mucking. In my meaning, > fi_core should know all these things such as 'cancel IO write', 'corrupt IO > access' etc. and tell interceptor what they should do. if interceptor can > not understand this hint or do this hits, it can ignore it w/ a warning. we > should not assign interceptor too many responsibilities... > * Interceptors should only intercept somthing wanted by others, report this > intercepting event and do mucking what they can underderstand and can also > do. > * fi_core should assign triggers to interceptors, recieve intecepting > events from interceptors, computing logic to determine what should do and > tell interceptor do it. > Interceptors should not compute logic because they *only* have information > about trigger... fi_core should delegate mucking to interceptors beacuse it > do not know hardware details. > > > Also, wouldn't you want your trigger executed > > with as little overhead as possible if your > Yes, I want. But I perfer to minimize overhead as little as possible when no > triggers. When there are triggers, there are two more overheads, one is > judging if the pagefault is caused by FITH, the other is processing the > trigger if pagefault is caused by trigger. The first overhead can be > optimized by searching algorithm. Then second overhead is *unavoidable*. the > overhead is as much as what we do in FI. Less we do, Less overhead is... > > interceptor is getting triggered very often > > (like in a page fault handler.) It seems like it > > would be a good idea to include the trigger execution > > inline instead of making yet another function call. > In our view, we'll update the limited computing logic code with code > segment. So I do not think inline computing logic code is very helpful. > > > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |