[Fault-injection-developer] Re:[PATCH] 47-kp2-fi2-dm3 features
Status: Alpha
Brought to you by:
rustyl
From: Rusty L. <ru...@li...> - 2002-11-27 02:57:28
|
> diff -Nur -X /home/louis/dontdiff 47-kp-fi/arch/i386/Kconfig 47-kp-fi-dm/arch/i386/Kconfig > --- 47-kp-fi/arch/i386/Kconfig Mon Nov 25 15:15:40 2002 > +++ 47-kp-fi-dm/arch/i386/Kconfig Tue Nov 26 13:44:03 2002 > @@ -1577,6 +1577,13 @@ > Say Y here if you want to enable Fault Injection (FI) mechanism. > The FI can monitor MMIO/IO access in kernel. > > +config FI_DM > + tristate "Fault Injection Decision Maker" > + depends on FI > + help > + Only support M here. It is a bug to be fixed. Decision Maker is to > + control interceptors how/what to inject. > + If you want the choices to be module or nothing, then just code it that way. Also please add a more descriptive comment for this component. Keep in mind that the world will be stumbling across this option while trying to configure a kernel, and would like to know something more then the name of the module. > > config DEBUG_STACKOVERFLOW > bool "Check for stack overflows" > depends on DEBUG_KERNEL > diff -Nur -X /home/louis/dontdiff 47-kp-fi/include/linux/fi/fi.h 47-kp-fi-dm/include/linux/fi/fi.h > --- 47-kp-fi/include/linux/fi/fi.h Thu Jan 1 08:00:00 1970 > +++ 47-kp-fi-dm/include/linux/fi/fi.h Tue Nov 26 13:44:53 2002 > @@ -0,0 +1,189 @@ > +/****************************************************************************** > + * Fault Injection Test harness (FI) > + * Copyright (C) Intel Crop. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + ****************************************************************************** > + */ > + > +/* $Id: fi.h,v 1.3 2002/11/15 03:05:04 brlock Exp $ > + * Copyright by Intel Crop., 2002 > + * Louis Zhuang (lou...@in...) > + * > + */ > + > +/** @file fi.h > + * Fault Injection Test Harness Head File > + * This file defines common data struct/type used by fi modules and command line tools. > + */ > +#ifndef __FI_H > +#define __FI_H > +#define FI_VERSION "$Id: fi.h,v 1.3 2002/11/15 03:05:04 brlock Exp $" > + > +#include <asm/types.h> > +#include <asm/atomic.h> > + > +/** > + * define uniform watchpoint structure. > + */ > +#define FI_WPTYPE_MMIO 4 > +#define FI_WPTYPE_READ 8 > +#define FI_WPTYPE_WRITE 16 > +#define FI_WPTYPE_EXEC 32 > + > +#define FI_WPTYPE_LEN_MASK 3 > +#define FI_WPTYPE_ALL_MASK ( FI_WPTYPE_MMIO \ > + | FI_WPTYPE_READ \ > + | FI_WPTYPE_WRITE \ > + | FI_WPTYPE_EXEC \ > + | FI_WPTYPE_LEN_MASK \ > + ) > + > +struct watchpoint{ > + /*address intercepted.*/ > + unsigned long addr; > + /** > + * intercepted type. > + * bit 0-1 2^N bytes leng. > + * bit 2 IO-space IO/MMIO > + * bit 3 Read > + * bit 4 Write > + * bit 5 Execute(not implementation yet) > + * XXX: you can not register the same address with IO and MMIO, > + * but MMIO seldom uses low 64k space, so it is not a problem in fact.*/ > + unsigned int type; > +}; Use 8-char indents (see Documentation/CodingStyle) ditto on the rest of the file. > + > +#define WP_LEN(wp) (1<<((unsigned long)(wp.type)&3)) > + > +#if 0 > +/** > + * Define utitlty watchpoint inline function. > + */ > +inline struct watchpoint WP(void *addr, int type) { > + struct watchpoint wp; > + wp.addr = addr; > + wp.type =type; > + return wp; > +}; > +#endif > + Get rid of personal hacks. > + > +/** max number of triggers */ > +#define MAX_OP_PER_TRIGGER 4 > +#define MAX_TRIGGER_PER_FAULTSET 16 > +#define MAX_FAULTSET 16 > +struct fi_trigger{ > + /** > + * This part contains properties of the trigger. It is seldom changed after initialization. > + */ > + /**watchpoint which can trigger*/ > + struct watchpoint wp; > + > + /**bitmask for which you really care. 0-unmasked; 1-masked*/ > + __u32 bitmask; > + > + /**baseline you want to trigger after masked*/ > + int min; > + > + /**topline you want to trigger after masked > + * XXX: it is CLOSED region. min<=val<=max*/ > + int max; > + > + /**trigger can start to work after skip times*/ > + int skip; > + > + /**trigger can stop after work stop times*/ > + int stop; > + > + /**bitmask for protection*/ > + int protection; > + > + /**HZ for random error*/ > + int hertz; > + > + /***/ > + struct { > + /**0 - nothing; 1 - SET; 2 - AND; 3 - OR; 4 - NOT; 5 - XOR*/ > + enum{ FI_NOTHING=0, FI_SET=1, FI_AND=2, FI_OR=3, FI_NOT=4, FI_XOR=5, FI_NAND =6, FI_NOR=7, FI_ADD=8, FI_SUB=9, > + }opcode; > + int operand; > + }ops[MAX_OP_PER_TRIGGER]; > + > + > + /** > + * This part is statistic of the trigger. It should reflect the status of the trigger. > + */ > + /*Whether the trigger is registerd*/ > + int registered; > + /**times that is triggered*/ > + atomic_t count; > +}; > + > + > +struct fi_faultset{ > + /***/ > + struct fi_trigger trigger_tb[MAX_TRIGGER_PER_FAULTSET]; > + > + /**status: 0 - noused; 1 - enable; 2 - disable*/ > + enum { > + NOUSED=0, ENABLED=1, DISABLED=2 > + }stat; > + > + char modname[256]; > + > + /**more...*/ > +}; > + > +struct fi_irq_faultset{ > + int irq_spurious_hertz;//0 means never do this > + int irq_delay_hertz; > + int irq_delay_time;//0 means lost > + int num; > + char devname[80]; > + char modname[256]; > + void *id; > +}; > + > +struct fi_ins_record { > + unsigned char *addr; /* Instruction's virtual address */ > + unsigned char opcode; /* The original opcode */ > +}; > + > +struct fi_ins_record_header { > + char modname[256]; > + int counter; > + struct fi_ins_record inst[0]; > +}; > + > +/*Define IOCTL number*/ > +#define FI_IOCTL_BASE 'F' > +#define FIIOC_INSERT _IOW(FI_IOCTL_BASE, 0, struct fi_faultset) > +#define FIIOC_REMOVE _IOW(FI_IOCTL_BASE, 1, int) > +#define FIIOC_ENABLE _IOW(FI_IOCTL_BASE, 2, int) > +#define FIIOC_DISABLE _IOW(FI_IOCTL_BASE, 3, int) > +#define FIIOC_SET_IRQ_FAULTSET _IOW(FI_IOCTL_BASE, 4, struct fi_irq_faultset) > +#define FIIOC_CLEAR_IRQ_FAULTSET _IO(FI_IOCTL_BASE, 5) > +#define FIIOC_QUERY_PHYADDR _IOWR(FI_IOCTL_BASE, 6, unsigned long) > +#define FIIOC_TRANS_INST _IOW(FI_IOCTL_BASE, 7, struct fi_ins_record_header) > +#define FIIOC_QUERY_INTCPT _IO(FI_IOCTL_BASE, 8) > + > +#if 0 > +/** this is switch for fi*/ > +extern int g_fiIsEnabled; > +#endif > + > +#endif/*__FI_H*/ > diff -Nur -X /home/louis/dontdiff 47-kp-fi/include/linux/fi/fi_interface.h 47-kp-fi-dm/include/linux/fi/fi_interface.h > --- 47-kp-fi/include/linux/fi/fi_interface.h Thu Jan 1 08:00:00 1970 > +++ 47-kp-fi-dm/include/linux/fi/fi_interface.h Tue Nov 26 13:44:53 2002 > @@ -0,0 +1,160 @@ > +/****************************************************************************** > + * Fault Injection Test harness (FI) > + * Copyright (C) Intel Crop. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + ****************************************************************************** > + */ > + > +/* $Id: fi_interface.h,v 1.1.1.1 2002/11/12 05:56:30 brlock Exp $ > + * Copyright by Intel Crop., 2002 > + * Louis Zhuang (lou...@in...) > + * > + */ > + > +/** > + * @file interfaces.h > + * This file defines interfaces among components. > + */ > +#ifndef __FI_INTERFACE_H > +#define __FI_INTERFACE_H > + > +#include <linux/fi/fi.h> > + > + > +/** > + * A interface exports to another component for callback. > + */ > +struct iInterceptHook{ > + /** > + * trigger a process of IO access interceptor > + * @param wp the watchpoint which triggers the callback. > + * @param len the length of resource access > + * @param type 0 read, 1 write > + * @param data XXX:context of the trigger. > + * impl of trigger must send it back in corrput interface. > + */ > + void (*trigger) (int id, __u32 val, int len, int type, void *data); > +}; > + Ahh! dOntDoThat! Follow the Documentation/CodingStyle for nameing of things. As soon as lkml sees a name like iInterceptHook the result will be windows code ==> /dev/null > + > +/** > + * A interface between Interceptor and DM components in order to > + * intercept resource accesses. > + */ > +struct iIntercept{ > + /** > + * Register a watchpoint which will be triggered when access based on this address. > + * @param wp the intercepted watchpoint > + * @param id calling should assign a id to this wp. > + * @param hook ptr can be used to call back process function. > + * @param return 0 successful; > + * -EFI_INVALID if wp is invaild; > + * -EFI_REGISTERED if wp has been registered > + * -EFI_TABFULL if wp table is full > + */ > + int (*wp_register) (struct watchpoint wp, > + int id, > + struct iInterceptHook *hook, > + char *modname); > + > + /** > + * Unregister a watchpoint > + * @param return 0 successful > + * -EFI_NOTFOUND there is not the id. > + */ > + int (*wp_unregister)(int id, char *modname); > + > + /** > + * corrput access in requirement > + */ > + int (*corrupt) (int id, __u32 dirty, void *data); > +}; > + > + > +/** > + * trigger a process of IRQ interceptor > + */ > +struct iIRQHook{ > + /** > + * callback for IRQ interceptor > + */ > + void (*event) (int num, void *id, void *regs); > +}; > + > + > +/** > + * A interface to intercept IRQ > + * > + * any snatched IRQ event will be called into hook interface. And hook > + * interface should in turn call dispatch event to invoke real driver's > + * IRQ handler. > + * > + * And DM can also hook on other IRQ source and dispatch event into driver's > + * handler in order to implement suprious IRQ event. > + */ > +struct iIRQ{ > + /** > + * Snatch a IRQ handler from IRQ chain. > + * @param hook hook interface for this IRQ handler > + * @param num IRQ number > + * @param id id for shared IRQ device > + */ > + int (*irq_snatch) (struct iIRQHook *hook, int num, char *devname, void** dev_id, char *modname); > + int (*irq_unload) (int num, char *devname); > + /** > + * dispatch a fake IRQ event into handler > + */ > + int (*dispatch) (int num, void *id, void *regs); > +}; > + > +/** > + * A interface between fi_dbp and DM components in order to > + * transfer information. > + */ > +struct iGetinfo{ > + /** > + * Transfer all information of the replaced IO instructions to fi_dbp. > + * @param header data structure header of all the IO instructions. > + * @param return 0 successful; > + * -ENOMEM if kmalloc failed > + * -EFI_TABFULL if wp table is full > + */ > + int (*getinfo) (struct fi_ins_record_header *header); > +}; > + > +/** > + * A interface for translating address between linear address and physical address. > + */ > +struct iAslt{ > + /** > + * Translate address bwteen linear address and physical address. > + * @param header data structure header of all the IO instructions. > + * @param return 0 failed; > + * phy_addr if found. > + */ > + unsigned long (*fi_line_to_phy) (unsigned long line_addr); > + > + /** > + * Check if the wp is pending. > + * @param wp the intercepted watchpoin. > + * @param return 0 enable; > + * 1 pending. > + */ > + int (*check_wp) (struct watchpoint wp); > +}; > + > +#endif/*__FI_INTERFACE_H*/ > diff -Nur -X /home/louis/dontdiff 47-kp-fi/include/linux/fi/fi_internal.h 47-kp-fi-dm/include/linux/fi/fi_internal.h > --- 47-kp-fi/include/linux/fi/fi_internal.h Thu Jan 1 08:00:00 1970 > +++ 47-kp-fi-dm/include/linux/fi/fi_internal.h Tue Nov 26 13:44:53 2002 > @@ -0,0 +1,126 @@ > +/****************************************************************************** > + * Fault Injection Test harness (FI) > + * Copyright (C) Intel Crop. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + ****************************************************************************** > + */ > + > +/* $Id: fi_internal.h,v 1.1.1.1 2002/11/12 05:56:30 brlock Exp $ > + * Copyright by Intel Crop., 2002 > + * Louis Zhuang (lou...@in...) > + * > + */ > + > +/** @file fi_internal.h > + * This is a FI internal header file to define some internal utilities. > + */ > +#ifndef __FI_INTERNAL_H > +#define __FI_INTERNAL_H > + > +#ifndef PREFIX_NAME > +#define PREFIX_NAME "FI_DEFAULT" > +#endif > +extern long globalcounter; > + > +/*define help macro to debug */ > +/*XXX there should use eventlog in future */ > +#ifdef FI_DEBUG > +# ifdef __KERNEL__ > +# define PDEBUG(fmt, args...) printk(KERN_DEBUG PREFIX_NAME ": %ld :cpu[%d] " __func__ ": " fmt, globalcounter++, smp_processor_id(), ##args) > +# else > +# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args) > +# endif > +#else > +# define PDEBUG(fmt, args...) > +#endif > + > +#ifdef __KERNEL__ > +# define PINFO(fmt, args...) printk(KERN_INFO PREFIX_NAME ": %ld :%s:" fmt, globalcounter++, __func__, ##args) > +#else > +# define PINFO(fmt, args...) fprintf(stderr, fmt, ##args) > +#endif > + > +#ifdef __KERNEL__ > +# define PERROR(fmt, args...) printk(KERN_ERR PREFIX_NAME ": %ld :%s:" fmt, globalcounter++, __func__, ##args) > +#else > +# define PERROR(fmt, args...) fprintf(stderr, fmt, ##args) > +#endif > + > +/*define some macros*/ > +#define FI_MAJOR 0 > + > +#define FI_ID(fs_num, tri_num) (fs_num<<16|tri_num) > +#define FI_FS_NUM(id) (id>>16) > +#define FI_TRI_NUM(id) (id&0xffff) > + > +/*define macros for error code.*/ > +#define EFI_SUCCESS 0 > +#define EFI_INVALID 1 > +#define EFI_REGISTERED 2 > +#define EFI_TABFULL 3 > +#define EFI_NOTFOUND 4 > + > +/*define macros for WP type*/ > +inline static int is_MMIO(int type) { return (type&0x04)?1:0; }; > +inline static int is_IO(int type) { return (type&0x04)?0:1; }; > +inline static int is_read(int type) { return (type&0x08)?1:0; }; > +inline static int is_write(int type) { return (type&0x10)?1:0; }; > +inline static int is_execute(int type) { return (type&0x20)?1:0; }; > +inline static int access_len(int type) { return 1UL<<(type&0x03);}; > + > +/*Some functions for find and lock specific kernel module*/ > +extern struct module *module_list; > +static inline struct module *find_module(const char *name) > +{ > + struct module *mod; > + > + for (mod = module_list; mod ; mod = mod->next) { > + if (mod->flags & MOD_DELETED) > + continue; > + if (!strcmp(mod->name, name)) > + break; > + } > + > + return mod; > +} > + > +static inline int fi_lock_module(char *modname) > +{ > + struct module *mod; > + > + mod = find_module(modname); > + if (mod == NULL) > + return -EEXIST; > + __MOD_INC_USE_COUNT(mod); > + PDEBUG("Lock module:%s! @%s\n", modname, __FILE__); > + return EFI_SUCCESS; > +} > + > +static inline int fi_unlock_module(char *modname) > +{ > + struct module *mod; > + > + mod = find_module(modname); > + if (mod == NULL) > + return -EEXIST; > + PDEBUG("Unlock module:%s! @%s\n", modname, __FILE__); > + __MOD_DEC_USE_COUNT(mod); > + return EFI_SUCCESS; > +} > + > + > +#endif/*__FI_INTERNAL_H*/ > diff -Nur -X /home/louis/dontdiff 47-kp-fi/kernel/Makefile 47-kp-fi-dm/kernel/Makefile > --- 47-kp-fi/kernel/Makefile Mon Nov 25 15:16:27 2002 > +++ 47-kp-fi-dm/kernel/Makefile Mon Nov 25 15:40:23 2002 > @@ -22,6 +22,7 @@ > obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o > obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o > obj-$(CONFIG_KPROBES) += kprobes.o > +obj-$(CONFIG_FI_DM) += fi_dm.o > > ifneq ($(CONFIG_IA64),y) > # According to Alan Modra <al...@li...>, the -fno-omit-frame-pointer is > diff -Nur -X /home/louis/dontdiff 47-kp-fi/kernel/fi_dm.c 47-kp-fi-dm/kernel/fi_dm.c > --- 47-kp-fi/kernel/fi_dm.c Thu Jan 1 08:00:00 1970 > +++ 47-kp-fi-dm/kernel/fi_dm.c Tue Nov 26 13:44:54 2002 > @@ -0,0 +1,594 @@ > +/****************************************************************************** > + * Fault Injection Test harness (FI) > + * Copyright (C) Intel Crop. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + ****************************************************************************** > + */ > + > +/* $Id: dm_core.c,v 1.3 2002/11/14 07:11:37 brlock Exp $ > + * Copyright by Intel Crop., 2002 > + * Louis Zhuang (lou...@in...) > + */ > +/** > + * @file dm_core.c > + */ > + > +#include <linux/config.h> > +#include <linux/version.h> > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/version.h> > +#include <asm/system.h> > +#include <asm/uaccess.h> > +#include <asm/io.h> > +#include <asm/atomic.h> > +#include <asm/debugreg.h> > +#include <asm/desc.h> > +#include <linux/ioport.h> > +#include <asm/page.h> > +#include <asm/pgtable.h> > +#include <asm/pgalloc.h> > +#include <linux/sched.h> > +#include <asm/system.h> > +#include <linux/vmalloc.h> > +#include <linux/proc_fs.h> > +#include <linux/random.h> > +#include <linux/highmem.h> > +#include <linux/kprobes.h> > + > +#define PREFIX_NAME "FI" > +#include <linux/fi/fi.h> > +#include <linux/fi/fi_internal.h> > +#include <linux/fi/fi_interface.h> > + > +#define MAX_MOD 16 > + > +#define MODULE_NAME "fi_dm" > +#define MODULE_VERSION "0.1" > + > +static int insert_faultset(struct fi_faultset *fs); > +static int remove_faultset(int index); > +static int enable_faultset(int index); > +static int disable_faultset(int index); > + > + > +long globalcounter=0; > +static struct fi_faultset fs_tb[MAX_FAULTSET]; > +static struct iIntercept *intcpt = NULL; > + > +#define ASLT_INTERFACE "fi.interceptor.aslt.iIntercept" > +#define ASLT_MODULE "fi_aslt" > + > +void dm_trigger(int id, __u32 val, int len, int type, void *data){ > + int fs_num= FI_FS_NUM(id); > + int tri_num=FI_TRI_NUM(id); > + int tmp=0, i=0; > + struct fi_trigger *tri = NULL; > + __u32 old = val; > + > + PDEBUG("entry, id=%#x, val=%#x, len=%d, type=%d, data=%#x\n", > + id, val, len, type, data); > + if (fs_num>=MAX_FAULTSET || fs_num<0 > + || tri_num>=MAX_TRIGGER_PER_FAULTSET || tri_num<0){ > + PERROR(":error id number %d\n", id); > + goto exit; > + } > + > + tri = &fs_tb[fs_num].trigger_tb[tri_num]; > + > + if (!tri->registered){ > + PERROR("Should not trigger an unregistered wp %d!?\n", id); > + } > + > + > + get_random_bytes(&tmp, sizeof(tmp)); > + if (tri->hertz==0) {tri->hertz=1;};//divid is not 0! > + if (tmp >= 0xFFFFFFFF/tri->hertz){ > + PDEBUG("rnd=%d, HERZ=%d\n", tmp, tri->hertz); > + goto exit; > + } > + > + tmp = val & (~tri->bitmask); > + if (tri->min>tmp || tmp>=tri->max){ > + PDEBUG("min=%d, max=%d, val=%d\n", tri->min, tri->max, val); > + if(!(tri->min==0 && tri->max==0)) > + goto exit; > + } > + > + // Increase count only when passing all conditions > + atomic_inc(&tri->count); > + > + if (tri->skip >= atomic_read(&tri->count)){ > + PDEBUG("count=%d, skip=%d\n", atomic_read(&tri->count), tri->skip); > + goto exit; > + } > + > + if ( tri->stop!=0 && (tri->stop < (atomic_read(&tri->count)-tri->skip)) ) { > + PDEBUG("count=%d, stop=%d\n", atomic_read(&tri->count), tri->stop); > + goto exit; > + } > + > + PDEBUG("count=%d, skip=%d, min=%d, max=%d, val=%d\n", > + atomic_read(&tri->count), tri->skip, tri->min, tri->max, val); > + tmp = val; > + for (i=0; i<MAX_OP_PER_TRIGGER; i++) { > + switch (tri->ops[i].opcode){ > + case FI_NOTHING: > + goto exit_for; > + case FI_SET: > + tmp = tri->ops[i].operand; > + break; > + case FI_AND: > + tmp &= tri->ops[i].operand; > + break; > + case FI_OR: > + tmp |= tri->ops[i].operand; > + break; > + case FI_NOT: > + tmp = ~tmp; > + break; > + case FI_XOR: > + tmp ^= tri->ops[i].operand; > + break; > + case FI_NAND: > + tmp = ~(tmp & tri->ops[i].operand); > + break; > + case FI_NOR: > + tmp = ~(tmp | tri->ops[i].operand); > + break; > + case FI_ADD: > + tmp = tmp + tri->ops[i].operand; > + break; > + case FI_SUB: > + tmp = tmp - tri->ops[i].operand; > + break; > + default: > + PERROR("Not recognized opcode%d\n", tri->ops[i].opcode); > + break; > + } > + } > + exit_for: > + val = (val & (tri->protection)) | (tmp & (~tri->protection)); > + > + exit: > + > + PINFO("id=%#x, val=%#x, old=%#x, len=%d, type=%d, data=%p\n", > + id, val, old, len, type, data); > + intcpt->corrupt(id, val, data); > + return; > +} > + > +static struct iInterceptHook intcpt_hook[1] = { > + { > + trigger: dm_trigger > + } > +}; > + > + > +/*manipulate fault set*/ > +static int insert_faultset(struct fi_faultset *fs){ > + int rv=0; > + int i=0; > + > + for (i=0; i<MAX_FAULTSET; i++) { > + if (fs_tb[i].stat == NOUSED) break; > + } > + if (i < MAX_FAULTSET) { > + int rv1; > + copy_from_user(&fs_tb[i], fs, sizeof(fs_tb[i])); > + fs_tb[i].stat = DISABLED; > + rv = i; > + PDEBUG("modname: %s\n", fs_tb[i].modname); > + PINFO("insert #%d fs\n", i); > + rv1 = enable_faultset(i); > + if(rv1<0) { > + PERROR("can not enable faultset# %d\n", i); > + } > + }else{ > + rv = -ENOSPC; > + } > + return rv; > +} > + > +static int remove_faultset(int index){ > + int rv=0; > + > + if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == NOUSED) { > + rv = -EPERM; > + goto exit1; > + } > + > + if (index>=0 && index<MAX_FAULTSET && fs_tb[index].stat == ENABLED) { > + disable_faultset(index); > + } > + > + if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == ENABLED) { > + PERROR("can not remove #%d fs when it is enabled\n", index); > + rv = -EPERM; > + }else{ > + fs_tb[index].stat = NOUSED; > + } > + PINFO("remove #%d fs\n", index); > + exit1: > + return rv; > +} > + > +static int enable_faultset(int index){ > + int rv=0; > + int i=0; > + int id_high; > + struct fi_faultset *fs; > + > + PDEBUG("trying to enable faultset# %d\n", index); > + > + if (index<0 || index>= MAX_FAULTSET || fs_tb[index].stat != DISABLED) { > + rv = -EINVAL; > + goto exit; > + } > + > + id_high = index<<16; > + fs = &fs_tb[index]; > + /*register all wp into interceptor component*/ > + for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ > + PDEBUG("register WP, id=%d, hook=%p\n", id_high+i, intcpt_hook); > + atomic_set(&fs->trigger_tb[i].count, 0); > + fs->trigger_tb[i].registered = 1; > + rv = intcpt->wp_register(fs->trigger_tb[i].wp, id_high+i, intcpt_hook, fs->modname); > + > + if (rv<0) { > + fs->trigger_tb[i].registered = 0; > + PERROR("can not register WP, id = %d\n", id_high+i); > + continue; //goto exit;//XXX: I should remove registered trigger > + } > + fs->stat = ENABLED; > + } > + if (fs->stat == DISABLED) { > + PERROR("none of trigger can be active, enable faultset failed!\n"); > + goto exit; > + } > + PINFO("enable #%d fs\n", index); > + rv = 0; > + exit: > + return rv; > +} > + > +static int disable_faultset(int index){ > + int rv=0; > + int i=0; > + int id_high=0; > + struct fi_faultset *fs; > + > + PDEBUG("trying to disable faultset# %d\n", index); > + if(index<0 || index>MAX_FAULTSET || fs_tb[index].stat!=ENABLED) { > + rv=-EINVAL; > + goto exit; > + } > + > + id_high=index<<16; > + fs = &fs_tb[index]; > + > + for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ > + rv = intcpt->wp_unregister(id_high+i, fs->modname); > + if (rv>=0) { > + fs->trigger_tb[i].registered = 0; > + }else{ > + PERROR("can not unregister wp, id=%d\n", id_high+i); > + } > + } > + fs->stat = DISABLED; > + PINFO("disable #%d fs\n", index); > + rv = 0; > + exit: > + return rv; > +} > +/*END OF fault set functions*/ > + > + > +static int fi_ioctl(struct inode *inode, struct file *file, > + unsigned int cmd, unsigned long arg){ > + int rv=0; > + int i=0; > + unsigned long addr; > + struct iGetinfo *p = NULL; > + struct iAslt *q = NULL; > + > + switch (cmd){ > + default: > + rv = -ENOTTY; > + break; > + case FIIOC_INSERT: > + rv = insert_faultset((struct fi_faultset *)arg); > + break; > + case FIIOC_REMOVE: > + get_user(i, (int *)arg); > + rv = remove_faultset(i); > + break; > + case FIIOC_ENABLE: > + get_user(i, (int *)arg); > + rv = enable_faultset(i); > + break; > + case FIIOC_DISABLE: > + get_user(i, (int *)arg); > + rv = disable_faultset(i); > + break; > + case FIIOC_QUERY_PHYADDR: > + q = (struct iAslt *)inter_module_get_request("fi.interceptor.aslt.iLine_to_phy", "fi_aslt"); > + if(q != NULL) { > + get_user(addr, (unsigned long *)arg); > + addr = q->fi_line_to_phy(addr); > + put_user(addr, (unsigned long *)arg); > + inter_module_put("fi.interceptor.aslt.iLine_to_phy"); > + }else{ > + PERROR("Can not get fi_line_to_phy! @%s\n", __FILE__); > + } > + break; > + case FIIOC_TRANS_INST: > + rv = -1; > + p = (struct iGetinfo *)inter_module_get_request("fi.interceptor.dbp.iGetinfo", "fi_dbp"); > + if(p != NULL) { > + rv = p->getinfo((struct fi_ins_record_header *)arg); > + inter_module_put("fi.interceptor.dbp.iGetinfo"); > + } else { > + PERROR("Can not get fi.interceptor.dbp.iGetinfo! @%s\n", __FILE__); > + } > + break; > + case FIIOC_QUERY_INTCPT: > + rv = 0; > + break; > + }; > + return rv; > +}; > + > +static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; > +static int counter=0; > + > +static int fi_open(struct inode *inode, struct file *file){ > + int rv=0; > + > + spin_lock(&counter_lock); > + if (counter) { > + rv = -1; > + goto out; > + } > + counter++; > + MOD_INC_USE_COUNT; > + out: > + spin_unlock(&counter_lock); > + return rv; > +} > + > + > +static int fi_release(struct inode *inode, struct file *file){ > + spin_lock(&counter_lock); > + counter--; > + MOD_DEC_USE_COUNT; > + spin_unlock(&counter_lock); > + return 0; > +} > + > +static int dump_faultset(struct fi_faultset *fs, char *buf){ > + int i=0, n=0, k=0; > + int rv=0; > + struct iAslt *q=NULL; > + static char *op_name[]={ > + "NOTHING", "SET", "AND", "OR", "NOT", "XOR", "NAND", "NOR", "ADD", "SUB", > + }; > + > + if (fs->stat == NOUSED){ > + n += sprintf(buf+n, "This faultset is not used!\n"); > + goto exit1; > + } > + > + q = (struct iAslt *)inter_module_get_request("fi.interceptor.aslt.iLine_to_phy", "fi_aslt"); > + if(q == NULL) { > + PERROR("Can not get check_wp! @%s\n", __FILE__); > + return rv; > + } > + > + n += sprintf( buf+n, "This will dump fault set information, stat=%d\n", > + fs->stat); > + n += sprintf( buf+n, "The faultset is %s\n", > + (fs->stat==ENABLED)? "ENABLED" : > + ((fs->stat==DISABLED)? "DISABLED": > + "UNKNOWN!")); > + for(i=0; i<MAX_TRIGGER_PER_FAULTSET; i++){ > + int j=0; > + struct fi_trigger *tri; > + > + tri = &fs->trigger_tb[i]; > + if (tri->wp.addr==NULL) break; > + n += sprintf(buf+n, "watchpoint #%d phy_addr=%#lx, type=%#x, len=%d\n", > + i, tri->wp.addr, tri->wp.type, access_len(tri->wp.type)); > + n += sprintf(buf+n, "bitmask=%#x, min=%#x, max=%#x, skip=%d, " > + "stop=%d, protection=%#x, Hertz=%#x\n", > + tri->bitmask, tri->min, tri->max, tri->skip, > + tri->stop, tri->protection, tri->hertz); > + > + n += sprintf(buf+n, "ops list\n"); > + for(j=0; j<MAX_OP_PER_TRIGGER; j++){ > + char *name; > + if (tri->ops[j].opcode==FI_NOTHING) break; > + n += sprintf(buf+n, "opcode=%s, operand=%#x\n", > + op_name[tri->ops[j].opcode], tri->ops[j].operand); > + } > + > + if (is_MMIO(tri->wp.type)) { > + k = q->check_wp(tri->wp); > + n += sprintf(buf+n, "watchpoint status:%s\n", > + (tri->registered==1) ? > + ((k==1) ? "PENDING" : "ENABLED") : > + "DISABLED"); > + } else { > + n += sprintf(buf+n, "watchpoint status:%s\n", > + (tri->registered==1) ? "ENABLED" : "DISABLED"); > + } > + > + n += sprintf(buf+n, "-----------------\n"); > + } > + > + inter_module_put("fi.interceptor.aslt.iLine_to_phy"); > + > + exit1: > + n += sprintf(buf+n, "\n"); > + rv = n; > + return rv; > +} > + > +static int fi_proc_read( char* page, char **start, off_t off, int count, int *eof, void *data){ > + return dump_faultset((struct fi_faultset *)data, page); > +}; > + > +static int fi_proc_write( struct file *file, const char *buffer, unsigned long count, void *data){ > + return 0;//dummy now :-) > +}; > + > +static int fi_gc_read( char* page, char **start, off_t off, int count, int *eof, void *data) { > + int n=0; > + > + n = sprintf(page, "%ld", globalcounter); > + return ((n>0)?n:0); > +}; > + > +static struct file_operations fi_fops[1]={ > + { > + owner: THIS_MODULE, > + ioctl: fi_ioctl, > + open: fi_open, > + release: fi_release > + } > +}; > + > + > +static struct proc_dir_entry *root_entry; > +static struct proc_dir_entry *fs_entry; > +static struct proc_dir_entry *gc_entry; > +static int fi_major = FI_MAJOR; > + > +static int __init fi_dm_init(void){ > + int i=0 ; > + int rv=0; > + > + PDEBUG("FI version: %s\n", FI_VERSION); > + > + /*Setup proc file*/ > + root_entry = proc_mkdir(MODULE_NAME, NULL); > + if (!root_entry){ > + PERROR("can not register proc %s\n", MODULE_NAME); > + rv = -ENOMEM; > + goto exit1; > + } > + root_entry->owner=THIS_MODULE; > + > + for (i=0; i<MAX_FAULTSET; i++){ > + char name[20]; > + > + sprintf(name, "fs%d", i); > + fs_entry = create_proc_entry(name, 0644, root_entry); > + if (!fs_entry){ > + PERROR("can not register proc %s\n", name); > + rv = -ENOMEM; > + goto exit2; > + } > + fs_entry->owner = THIS_MODULE; > + fs_entry->read_proc = fi_proc_read; > + fs_entry->write_proc= fi_proc_write; > + fs_entry->data = &fs_tb[i]; > + } > + > + gc_entry = create_proc_entry("globalcounter", 0644, root_entry); > + if (gc_entry==NULL) { > + PERROR("can not register proc %s\n", "globalcounter"); > + rv = -ENOMEM; > + goto exit3; > + } > + gc_entry->owner = THIS_MODULE; > + gc_entry->read_proc = fi_gc_read; > + > + intcpt= (struct iIntercept *)inter_module_get_request(ASLT_INTERFACE, ASLT_MODULE); > + if (intcpt == NULL) { > + PERROR("Can not get interface : aslt @%s\n", __FILE__); > + rv = -1; > + goto exit4; > + } > + > + rv = register_chrdev(fi_major, MODULE_NAME, fi_fops); > + if (rv<0){ > + PERROR("can not register device, major=%d\n", fi_major); > + goto exit5; > + } > + if (fi_major==0) fi_major = rv;/*dynamic alloc major number*/ > + PDEBUG("Setup IOCTL as char device, major=%d\n", fi_major); > + > + /*clear fs_tb */ > + memset(fs_tb, 0, sizeof(fs_tb)); > + EXPORT_NO_SYMBOLS; > + return 0; > + > + exit5: > + inter_module_put(ASLT_INTERFACE); > + exit4: > + remove_proc_entry("globalcounter", root_entry); > + exit3: > + > + i=MAX_FAULTSET;/* error happen above 2, you must clear ALL entries*/ > + exit2: > + i--; > + for (;i>=0;i--){ > + char name[20]; > + > + sprintf(name, "fs%d", i); > + remove_proc_entry(name, root_entry); > + } > + remove_proc_entry(MODULE_NAME, NULL); > + exit1: > + return rv; > +}; > + > + > +static void __exit fi_dm_cleanup(void){ > + int i=0; > + > + inter_module_put(ASLT_INTERFACE); > + > + unregister_chrdev(fi_major, MODULE_NAME); > + > + /*unregister proc files*/ > + remove_proc_entry("globalcounter", root_entry); > + for (i=MAX_FAULTSET-1;i>=0;i--){ > + char name[20]; > + > + sprintf(name, "fs%d", i); > + remove_proc_entry(name, root_entry); > + } > + remove_proc_entry(MODULE_NAME, NULL); > + > + /* remove all faultset */ > + for(i=0; i<MAX_FAULTSET; i++) { > + remove_faultset(i); > + } > + > +}; > + > + > +module_init(fi_dm_init); > +module_exit(fi_dm_cleanup); > +MODULE_AUTHOR("Louis Zhuang"); > +MODULE_DESCRIPTION("Decision Maker component for FI"); > +MODULE_LICENSE("GPL"); > + > Binary files 47-kp-fi/scripts/kconfig/conf and 47-kp-fi-dm/scripts/kconfig/conf differ > Read over your patch before sending it out. Messages like these should not be in the patch file. |