[Fault-injection-developer] [PATCH 3/4] Decision Maker module against 2.5.47 + krobes + fi
Status: Alpha
Brought to you by:
rustyl
From: Zhuang, L. <lou...@in...> - 2002-11-25 10:13:09
|
Decision Maker modules is used to control other interceptors to inject faults. diff -Nur -X dontdiff linux-2.5-kp-fi/linux-2.5.47/arch/i386/Kconfig linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/Kconfig --- linux-2.5-kp-fi/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:15:40 2002 +++ linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:42:12 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. + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nur -X dontdiff linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi.h linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi.h --- linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi.h Mon Nov 25 15:42:49 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; +}; + +#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 + + +/** 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 dontdiff linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi_interface.h linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi_interface.h --- linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi_interface.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi_interface.h Mon Nov 25 15:42:49 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); +}; + + +/** + * 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 dontdiff linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi_internal.h linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi_internal.h --- linux-2.5-kp-fi/linux-2.5.47/include/linux/fi/fi_internal.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm/linux-2.5.47/include/linux/fi/fi_internal.h Mon Nov 25 15:42:49 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 dontdiff linux-2.5-kp-fi/linux-2.5.47/kernel/Makefile linux-2.5-kp-fi-dm/linux-2.5.47/kernel/Makefile --- linux-2.5-kp-fi/linux-2.5.47/kernel/Makefile Mon Nov 25 15:16:27 2002 +++ linux-2.5-kp-fi-dm/linux-2.5.47/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 dontdiff linux-2.5-kp-fi/linux-2.5.47/kernel/fi_dm.c linux-2.5-kp-fi-dm/linux-2.5.47/kernel/fi_dm.c --- linux-2.5-kp-fi/linux-2.5.47/kernel/fi_dm.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm/linux-2.5.47/kernel/fi_dm.c Mon Nov 25 16:57:33 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 linux-2.5-kp-fi/linux-2.5.47/scripts/kconfig/conf and linux-2.5-kp-fi-dm/linux-2.5.47/scripts/kconfig/conf differ |