fault-injection-developer Mailing List for Fault Injection Test Harness (Page 11)
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: Lynch, R. <rus...@in...> - 2002-11-26 00:37:41
|
Ok, thanks. BTW, patches should normally apply from the kernel root, not one directory above. In other words, if someone hands you over a patch for the kernel, you should be able to apply the patch by: $ cd YOURKERNELROOT $ patch -p1 < PATH_TO_PATCH/somepatch.diff -rusty -----Original Message----- From: Zhuang, Louis [mailto:lou...@in...] Sent: Monday, November 25, 2002 4:22 PM To: 'Rusty Lynch'; Zhuang, Louis; FITHML (E-mail) Subject: [Fault-injection-developer] RE: [PATCH 0/3] FITH patch against 2.5. 47 All patch files are included in fith-mini-8.tgz http://prdownloads.sourceforge.net/fault-injection/fith-mini-8.tgz?download > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: Tuesday, November 26, 2002 1:41 AM > To: Zhuang, Louis; FITHML (E-mail) > Subject: Re: [Fault-injection-developer] [PATCH 0/3] FITH > patch against > 2.5.47 > > > Louis, your emailer seems to have messed up the patch files by > adding new lines. Could you put them up on a public server > (like maybe the sourceforge site) if you are having problems > posting a patchfile that doesn't get corrupted? > > -rustyl > > ----- Original Message ----- > From: "Zhuang, Louis" <lou...@in...> > To: "FITHML (E-mail)" <fau...@so...> > Sent: Monday, November 25, 2002 2:02 AM > Subject: [Fault-injection-developer] [PATCH 0/3] FITH > patch against 2.5.47 > > > > Dear all, > > We'd like to put these patches as minimal as possible > in order to > > give more feedback. > > Any comments, especially about the addon patches welcome. > > > > - Louis > > > > > > > > ------------------------------------------------------- > > This sf.net email is sponsored by:ThinkGeek > > Welcome to geek heaven. > > http://thinkgeek.com/sf > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > > > https://lists.sourceforge.net/lists/listinfo/fault-injecti > on-developer > ------------------------------------------------------- This SF.net email is sponsored by: Get the new Palm Tungsten T handheld. Power & Color in a compact size! http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0002en _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Zhuang, L. <lou...@in...> - 2002-11-26 00:23:52
|
All patch files are included in fith-mini-8.tgz http://prdownloads.sourceforge.net/fault-injection/fith-mini-8.tgz?download > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: Tuesday, November 26, 2002 1:41 AM > To: Zhuang, Louis; FITHML (E-mail) > Subject: Re: [Fault-injection-developer] [PATCH 0/3] FITH > patch against > 2.5.47 > > > Louis, your emailer seems to have messed up the patch files by > adding new lines. Could you put them up on a public server > (like maybe the sourceforge site) if you are having problems > posting a patchfile that doesn't get corrupted? > > -rustyl > > ----- Original Message ----- > From: "Zhuang, Louis" <lou...@in...> > To: "FITHML (E-mail)" <fau...@so...> > Sent: Monday, November 25, 2002 2:02 AM > Subject: [Fault-injection-developer] [PATCH 0/3] FITH > patch against 2.5.47 > > > > Dear all, > > We'd like to put these patches as minimal as possible > in order to > > give more feedback. > > Any comments, especially about the addon patches welcome. > > > > - Louis > > > > > > > > ------------------------------------------------------- > > This sf.net email is sponsored by:ThinkGeek > > Welcome to geek heaven. > > http://thinkgeek.com/sf > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > > > https://lists.sourceforge.net/lists/listinfo/fault-injecti > on-developer > |
From: Rusty L. <ru...@li...> - 2002-11-25 17:52:00
|
Louis, your emailer seems to have messed up the patch files by adding new lines. Could you put them up on a public server (like maybe the sourceforge site) if you are having problems posting a patchfile that doesn't get corrupted? -rustyl ----- Original Message ----- From: "Zhuang, Louis" <lou...@in...> To: "FITHML (E-mail)" <fau...@so...> Sent: Monday, November 25, 2002 2:02 AM Subject: [Fault-injection-developer] [PATCH 0/3] FITH patch against 2.5.47 > Dear all, > We'd like to put these patches as minimal as possible in order to > give more feedback. > Any comments, especially about the addon patches welcome. > > - Louis > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Zhuang, L. <lou...@in...> - 2002-11-25 10:18:24
|
The pagefault interceptor can catch MMIO access by placing 'page absent bit' in PTE and handle the pagefault execption. FITH user space utility can be downloaded in http://prdownloads.sourceforge. net/fault-injection/fith-mini-8.tgz?download diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/Kconfig linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/Kconfig --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:42:12 2002 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 17:06:12 2002 @@ -1584,6 +1584,12 @@ Only support M here. It is a bug to be fixed. Decision Maker is to control interceptors how/what to inject. +config FI_PF + tristate "Pagefault interceptor" + depends on FI_DM + help + The interceptor can catch MMIO access by page-absent execption. + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/Makefile linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/Makefile --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/Makefile Mon Nov 25 15:42:12 2002 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/Makefile Mon Nov 25 17:06:12 2002 @@ -12,6 +12,7 @@ obj-y += cpu/ obj-y += timers/ +obj-y += fi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_X86_MSR) += msr.o diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/Makefile linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/Makefile --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/Makefile Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/Makefile Mon Nov 25 17:06:12 2002 @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# + +obj-y += pf/ +obj-y += aslt/ + +EXTRA_AFLAGS := -traditional + +include $(TOPDIR)/Rules.make diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/aslt/Makefile linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/aslt/Makefile --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/aslt/Makefile Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/aslt/Makefile Mon Nov 25 17:18:49 2002 @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# +export-objs := fi_aslt.o +obj-$(CONFIG_FI_PF) += fi_aslt.o + + +EXTRA_AFLAGS := -traditional + +include $(TOPDIR)/Rules.make diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/aslt/fi_aslt.c linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/aslt/fi_aslt.c --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/aslt/fi_aslt.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/aslt/fi_aslt.c Mon Nov 25 17:18:49 2002 @@ -0,0 +1,282 @@ +/************************************************************************** **** + * 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: aslt.c,v 1.3 2002/11/14 07:11:40 brlock Exp $ + * Copyright by Intel Crop., 2002 + * Stanley Wang (sta...@in...) + */ + +/** + * @file aslt.c + */ + +#include <linux/config.h> +#include <linux/version.h> + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> +#include <linux/highmem.h> +#include <asm/pgtable.h> + + +#define PREFIX_NAME "FI_ASLT" +#include <linux/fi/fi.h> +#include <linux/fi/fi_interface.h> +#include <linux/fi/fi_internal.h> + +#define COMPONENT_NAME "fi.interceptor.aslt" +#define INTERFACE_NAME COMPONENT_NAME ".iIntercept" +#define LINE_TO_PHY COMPONENT_NAME ".iLine_to_phy" + +#define PF_COMPONENT_NAME "fi.interceptor.pf" +#define PF_INTERFACE_NAME PF_COMPONENT_NAME ".iIntercept" +#define PF_INTERCEPTOR_MODULE "fi_pf" + +#define MAX_WP 32 + +long globalcounter=0; +int aslt_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname); +int aslt_unregister(int id, char *modname); +void * fi_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); +unsigned long fi_line_to_phy(unsigned long line_addr); +unsigned long fi_phy_to_line(unsigned long phy_addr); +int check_wp(struct watchpoint wp); + +/* Store all wps */ +static struct{ + struct watchpoint wp; + int id; + struct iInterceptHook * hook; + char modname[256]; +}wp_tb[MAX_WP] = { [0 ... MAX_WP-1] = { + wp: {0,0}, + id: -1, + hook: NULL } +}; + +static struct iIntercept intcpt[1] = { + { + wp_register: aslt_register, + wp_unregister: aslt_unregister, + corrupt: NULL, + } +}; + +static struct iAslt aslt[1] = { + { + fi_line_to_phy: fi_line_to_phy, + check_wp: check_wp, + } +}; + +static struct iIntercept *pf_intcpt=NULL; + +inline int find_wp(const void *addr, unsigned long len){ + int i=0; + + for (i=0; i<MAX_WP; i++) { + if (wp_tb[i].hook == NULL) continue; + if ( wp_tb[i].wp.addr >= addr && wp_tb[i].wp.addr < addr + len ) { + break; + } + } + return i; +}; + + +void * fi_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void *line_addr; + int idx; + int rv; + unsigned long offset; + + line_addr = __ioremap(phys_addr, size, flags); + + PDEBUG("Linear address: %#lX\n", (unsigned long)line_addr); + + while ((idx = find_wp((void *)phys_addr, size)) < MAX_WP){ + offset = (unsigned long)(wp_tb[idx].wp.addr) - phys_addr; + wp_tb[idx].wp.addr = (void *)((unsigned long)line_addr + offset); + rv = pf_intcpt->wp_register(wp_tb[idx].wp, wp_tb[idx].id, wp_tb[idx].hook, wp_tb[idx].modname); + if (rv < 0) { + PERROR("Register fault set fail! @%s\n", __FILE__); + } + wp_tb[idx].hook = NULL; + wp_tb[idx].id = -1; + wp_tb[idx].wp.addr = 0; + wp_tb[idx].wp.type = 0; + (wp_tb[idx].modname)[0] = '\0'; + } + return line_addr; +} + +unsigned long fi_line_to_phy(unsigned long line_addr) { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long phy_addr; + + pgd = pgd_offset_k(line_addr); + if ( !(pgd_val(*pgd)&_PAGE_PRESENT) ) { + PERROR("Linear address is not present! @%s\n", __FILE__); + return 0; + }; + pmd = pmd_offset(pgd, line_addr); + if (pmd_large(*pmd)) { + pte = (pte_t *)pmd; + } else { + pte = pte_offset_kernel(pmd, line_addr); + } + phy_addr = (pte_val(*pte)&PAGE_MASK) | (line_addr&(~PAGE_MASK)); + return phy_addr; +}; + +unsigned long fi_phy_to_line(unsigned long phy_addr) { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long line_addr; + + for (line_addr=VMALLOC_START; line_addr<VMALLOC_END; + line_addr+=PAGE_SIZE ) { + pgd = pgd_offset_k(line_addr); + if ( !(pgd_val(*pgd)&_PAGE_PRESENT) ) { + continue; + }; + pmd = pmd_offset(pgd, line_addr); + if (pmd_large(*pmd)) { + pte = (pte_t *)pmd; + } else { + pte = pte_offset_kernel(pmd, line_addr); + } + if ( (pte_val(*pte)&PAGE_MASK) == (phy_addr&PAGE_MASK) ) { + return line_addr + (phy_addr&(~PAGE_MASK)); + }; + } + return 0; //can not find the line address +}; + +int check_wp(struct watchpoint wp) +{ + int idx; + + idx = find_wp(wp.addr, 1); + if (idx < MAX_WP) { + return 1; /*found*/ + } + return 0; +} + +int aslt_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname) +{ + void *line_addr; + int idx; + + line_addr = (void *)fi_phy_to_line((unsigned long)(wp.addr)); + if (line_addr != 0) { + wp.addr = line_addr; + return pf_intcpt->wp_register(wp, id, hook, modname); + } else { + PDEBUG("Address is not present, delay register until \"insmod\"! @%s\n", __FILE__); + idx = find_wp(wp.addr, 1); + if (idx < MAX_WP) { + PDEBUG("Address is duplicated, fail! @%s\n", __FILE__); + return -EFI_INVALID; + } + for (idx=0; idx<MAX_WP; idx++){ + if (wp_tb[idx].hook == NULL){ + break; + } + } + if (idx>=MAX_WP) return -EFI_TABFULL; + + wp_tb[idx].hook = hook; + wp_tb[idx].id = id; + wp_tb[idx].wp.addr = wp.addr; + wp_tb[idx].wp.type = wp.type; + if (modname != NULL) + strncpy(wp_tb[idx].modname, modname, sizeof(wp_tb[idx].modname)); + } + return EFI_SUCCESS; +} + +int aslt_unregister (int id, char *modname) +{ + int idx; + + for (idx=0;idx<MAX_WP;idx++) { + if (wp_tb[idx].id == id) + break; + } + if (idx >= MAX_WP) + return pf_intcpt->wp_unregister(id, modname); + + wp_tb[idx].hook = NULL; + wp_tb[idx].id = -1; + wp_tb[idx].wp.addr = 0; + wp_tb[idx].wp.type = 0; + return EFI_SUCCESS; +} + +static int __init aslt_start(void) +{ + pf_intcpt = (struct iIntercept *)inter_module_get_request(PF_INTERFACE_NAME, PF_INTERCEPTOR_MODULE); + if (pf_intcpt != NULL) { +// intcpt[0].wp_unregister = pf_intcpt->wp_unregister; + intcpt[0].corrupt = pf_intcpt->corrupt; + inter_module_register(INTERFACE_NAME, THIS_MODULE, intcpt); + } else { + PERROR("Can not get interface %s!\n", PF_INTERFACE_NAME); + return -1; + } + + inter_module_register(LINE_TO_PHY, THIS_MODULE, aslt); + + return 0; +} + +static void __exit aslt_stop(void) +{ + inter_module_unregister(LINE_TO_PHY); + inter_module_unregister(INTERFACE_NAME); + inter_module_put(PF_INTERFACE_NAME); +} + +module_init(aslt_start); +module_exit(aslt_stop); + +EXPORT_SYMBOL_NOVERS(fi_ioremap); + +MODULE_AUTHOR("Stanley Wang"); +MODULE_DESCRIPTION("ASLT component for FI."); +MODULE_LICENSE("GPL"); + diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/Makefile linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/Makefile --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/Makefile Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/Makefile Mon Nov 25 17:06:12 2002 @@ -0,0 +1,11 @@ +# +# Makefile for the linux kernel. +# + +obj-$(CONFIG_FI_PF) += fi_pf.o +fi_pf-objs := pf_interface.o pf.o pf_in.o pf_region.o + + +EXTRA_AFLAGS := -traditional + +include $(TOPDIR)/Rules.make diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/fi_pf.h linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/fi_pf.h --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/fi_pf.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/fi_pf.h Mon Nov 25 17:19:10 2002 @@ -0,0 +1,81 @@ +/************************************************************************** **** + * Fault Injection Test harness (FI) + * Copyright (C) Intel Crop. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** ** + */ + +#ifndef __PF_H_ +#define __PF_H_ + + +#define PF_MAJOR 1 +#define PF_MINOR 1 +#define PF_PATCH 0 + + +/* + * Delcare typedefs + */ +enum reason_type{ + NOT_ME = 0, /* page fault is not in regions */ + NOTHING = 1, /* access others point in regions */ + REG_READ = 2, /* read from addr to reg */ + REG_WRITE = 3, /* write from reg to addr */ + IMM_WRITE = 4, /* write from imm to addr */ + OTHERS = 5 /* Other instructions can not intercept */ +}; + +/* + * Declare functions in pf_interface.c + */ +void register_pf_interface(void); +void unregister_pf_interface(void); + + +/* + * Declare functions in pf_region.c + */ +void pf_lock_region_irqsave(unsigned long *flags); +void pf_lock_region(void); +void pf_unlock_region_irqrestore(unsigned long flags); +void pf_unlock_region(void); +int pf_find_region(unsigned long addr); +int pf_add_region(unsigned long addr); +void pf_release_region(int ri); +int pf_is_removed_regions(unsigned long addr); +void pf_clr_pte_bits(unsigned long addr, unsigned long bitmask); +void pf_set_pte_bits(unsigned long addr, unsigned long bitmask); +/* + * Declare functions in pf_in.c + */ +enum reason_type get_ins_type(unsigned long ins_addr); +unsigned int get_ins_width(unsigned long ins_addr); +unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs); +void set_ins_reg_val(unsigned long addr, struct pt_regs *regs, unsigned long val); +unsigned long get_ins_imm_val(unsigned long ins_addr); +void set_ins_imm_val(unsigned long ins_addr, unsigned long val); + + +/* + * Declare functions in pf.c + */ +int pf_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname); +int pf_unregister(int id, char *modname); +int pf_corrupt(int id, __u32 dirty, void *data); + +#endif//__PF_H_ diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf.c linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf.c --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf.c Mon Nov 25 17:19:41 2002 @@ -0,0 +1,449 @@ +/************************************************************************** **** + * Fault Injection Test harness (FI) + * Copyright (C) Intel Crop. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** ** + */ + +/* $Id: pf.c,v 1.2 2002/11/14 06:19:49 yzhuang Exp $ + * Copyright by Intel Crop., 2002 + * Louis Zhuang (lou...@in...) + */ + +/** + * @file pf.c + */ + +#include <linux/config.h> +#include <linux/version.h> + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/pgalloc.h> +#include <asm/io.h> +#include <asm/tlbflush.h> + +#include <asm/fi.h> + +#define PREFIX_NAME "FI_PF" +#include <linux/fi/fi.h> +#include <linux/fi/fi_interface.h> +#include <linux/fi/fi_internal.h> + +#include "fi_pf.h" + +long globalcounter=0; + +#define MAX_WP 32 + +/* Store all wps */ +static struct{ + int page_index; + struct watchpoint wp; + int id; + struct iInterceptHook * hook; +}wp_tb[MAX_WP] = { [0 ... MAX_WP-1] = { + wp: {0,0}, + id: -1, + hook: NULL } +}; + +static void fi_do_flush_tlb_ipi(void* addr) { + __flush_tlb_one(addr); +}; +static void fi_flush_tlb_all(unsigned long addr) { + if ((smp_call_function(fi_do_flush_tlb_ipi,(void*)addr,1,1))!=0) { + PERROR("can not flush tlb\n"); + } + __flush_tlb_one(addr); +}; + +int pf_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname){ + unsigned long flags; + int wi=0; //watchpoint index + int ri=0; //region index + int rv=0; + + /* Make sure that wp is vaild */ + if ( hook==NULL ) { + PERROR("Reason: %s\n", "/* There are no callback */"); + return -EFI_INVALID; + } + if ( wp.type& (~FI_WPTYPE_ALL_MASK) ) { + PERROR("Reason: %s\n", "/* There are reserved bits in use*/"); + return -EFI_INVALID; + } + if ( is_IO(wp.type) && (unsigned int)wp.addr>0xffff ) { + PERROR("Reason: %s\n", "/* beyond 64k IO space*/"); + return -EFI_INVALID; + } + + pf_lock_region_irqsave(&flags);//lock regions + + /* Make sure there are no the same wp or id */ + for (wi=0; wi<MAX_WP; wi++) { + if (wp_tb[wi].hook==NULL) continue; + if ((id==wp_tb[wi].id) || (wp.addr==wp_tb[wi].wp.addr)) { + PERROR("Reason: %s\n", "/* there are same wp or id */"); + rv = -EFI_REGISTERED; + goto err1; + } + } + + ri = pf_add_region((unsigned long)wp.addr); + if (ri<0) { + PERROR("can not add this region, %p\n", wp.addr); + goto err; + } + + /* find empty item in wp_tb */ + for (wi=0; wi<MAX_WP; wi++){ + if (wp_tb[wi].hook==NULL){ + break; + } + } + if (wi>=MAX_WP) { + rv = -EFI_TABFULL; + goto err1; + } + + /* register this wp into wp_tb*/ + wp_tb[wi].wp.addr = wp.addr; + wp_tb[wi].wp.type = wp.type; + wp_tb[wi].id = id; + wp_tb[wi].hook = hook; + + if(modname != NULL) + fi_lock_module(modname); + + PDEBUG("register WP: index=%d, addr=0X%p, type=0x%x, id=%d, hook=0x%p\n", + wi, wp_tb[wi].wp.addr, wp_tb[wi].wp.type, + wp_tb[wi].id, wp_tb[wi].hook); + err1: + err: + pf_unlock_region_irqrestore(flags); + fi_flush_tlb_all((unsigned long)wp.addr); + return rv; +}; + + +int pf_unregister(int id, char *modname) { + unsigned long flags; + int wi=0; + int ri=0; + int rv=0; + + pf_lock_region_irqsave(&flags); + + /* find the id */ + for (wi=0; wi<MAX_WP; wi++) { + if (wp_tb[wi].hook!=NULL && wp_tb[wi].id == id) { + break; + } + } + if (wi>=MAX_WP) { + rv = -EFI_NOTFOUND; + goto err; + } + + ri = pf_find_region((unsigned long)wp_tb[wi].wp.addr); + if (ri>=0) { + pf_release_region(ri); + }else{ + PERROR("can not release region #%d\n", ri); + } + + wp_tb[wi].wp.addr = 0; + wp_tb[wi].wp.type = 0; + wp_tb[wi].id = -1; + wp_tb[wi].hook = 0; + + if (modname != NULL) + fi_unlock_module(modname); + err: + pf_unlock_region_irqrestore(flags); + return rv; +}; + + +/** + * This is a KEY data structure. When interceptor triggers DM + * and then DM call iAction method. iAction remembers this corrupted data. + * Then DM returns to Interceptor and Interceptor returns corrupted data + * to intercepted access. + */ +struct fi_corrupt{ + __u32 corrupted_data; +}; + +int pf_corrupt(int id, __u32 dirty, void *data){ + ((struct fi_corrupt *)data)->corrupted_data = dirty; + return 0; +}; + + +inline static int find_wp(unsigned long addr){ + int i=0; + + for (i=0; i<MAX_WP; i++) { + if (wp_tb[i].hook == NULL) continue; + if (addr == (unsigned long)wp_tb[i].wp.addr) { + break; + } + } + return i; +}; + + +/* + * Handle page fault exception and debug exception + */ +struct { + unsigned long addr; + unsigned long eip; + enum reason_type type; + unsigned long val; + int index; +}pf_reason[NR_CPUS] = { [0 ... NR_CPUS-1] = {0, 0, NOT_ME, 0, 0} }; + +static unsigned long crpt_mask[] = +{ 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF}; + +int pf_do_page_fault(struct pt_regs * regs, unsigned long address) { + unsigned long cpu = smp_processor_id(); + struct fi_corrupt crpt; + int i; + int ins_len, crpt_len; + + pf_lock_region(); //lock it! + if (pf_find_region(address)<0) { + if (pf_is_removed_regions(address)) { + pf_unlock_region(); + return 1; + } else { + goto not_me; + } + } + + pf_reason[cpu].type = NOTHING; + pf_reason[cpu].addr = address; + pf_reason[cpu].eip = regs->eip; + + i = find_wp(address); + if (i>=MAX_WP) { + PDEBUG("address=%#08lx is not watched, cpuid=%ld, type=%d\n", + address, cpu, pf_reason[cpu].type); + goto out; + } + + /* We find a wp for this pagefault */ + pf_reason[cpu].index= i; + pf_reason[cpu].type = get_ins_type(pf_reason[cpu].eip); + + PDEBUG("address=%#08lx is watched, cpuid=%ld, type=%d\n", + address, cpu, pf_reason[cpu].type); + + switch (pf_reason[cpu].type) { + case OTHERS: + PDEBUG("Hmm? Can not analyze the instruction, *eip=0x%08lx\n", + *(unsigned long *)pf_reason[cpu].eip); + break; + case REG_WRITE: + PDEBUG("reg_write instruction eip=0x%08lx\n", + pf_reason[cpu].eip); + if (is_write(wp_tb[i].wp.type)) { + + ins_len = get_ins_width(pf_reason[cpu].eip); + pf_reason[cpu].val = get_ins_reg_val(pf_reason[cpu]. eip, regs); + + crpt_len = (WP_LEN(wp_tb[i].wp)<ins_len)? + WP_LEN(wp_tb[i].wp):ins_len; + crpt.corrupted_data = + pf_reason[cpu].val & crpt_mask[crpt_len-1]; + ( *(wp_tb[i].hook->trigger) )( wp_tb[i].id, crpt.corrupted_data, + crpt_len, 0, &crpt); + + set_ins_reg_val(pf_reason[cpu].eip, regs, + (crpt.corrupted_data&crpt_mask[crpt_ len-1]) + | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); + } + break; + case IMM_WRITE: + PDEBUG("imm_write instruction eip=0x%08lx\n", + pf_reason[cpu].eip); + if (is_write(wp_tb[i].wp.type)) { + + ins_len = get_ins_width(pf_reason[cpu].eip); + pf_reason[cpu].val = get_ins_imm_val(pf_reason[cpu]. eip); + + crpt_len = (WP_LEN(wp_tb[i].wp)<ins_len)? + WP_LEN(wp_tb[i].wp):ins_len; + crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; + ( *(wp_tb[i].hook->trigger) )( wp_tb[i].id, crpt.corrupted_data, + crpt_len, 0, &crpt); + + set_ins_imm_val(pf_reason[cpu].eip, + (crpt.corrupted_data&crpt_mask[crpt_ len-1]) + | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); + } + break; + case REG_READ: + PDEBUG("reg_read instruction eip=0x%08lx\n", + pf_reason[cpu].eip); + /* we should trigger it in do_debug*/ + break; + default: + PERROR("error when getting instruction eip=0x%08lx\n", + pf_reason[cpu].eip); + break; + } + + out: + /* set TF */ + regs->eflags |= X86_EFLAGS_TF; + + /* clean page fault and tlb ONLY on this cpu */ + pf_set_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); + + //__flush_tlb_one(pf_reason[cpu].addr); + + //NOTICE!!! we hold region lock and wp_tb lock now, release it in do_debug + return 1; + not_me: + pf_reason[cpu].type = NOT_ME; + pf_unlock_region(); + return 0; +}; + +int pf_do_debug(unsigned long condition, struct pt_regs * regs) { + unsigned long cpu = smp_processor_id(); + struct fi_corrupt crpt; + int ins_len, crpt_len; + + /* + * DProbes make do_debug disallow irq. So we are safty from irq now. + */ + + PDEBUG("cpuid=%ld, type=%d\n", cpu, pf_reason[cpu].type); + if (pf_reason[cpu].type == NOT_ME) goto not_me; + + switch (pf_reason[cpu].type) { + case OTHERS: + PDEBUG("can not analyze the instruction cond=0x%08lx\n", condition); + break; + case REG_WRITE: + PDEBUG( "restore regval after reg_write corrupting, val=0x%08lx\n", + pf_reason[cpu].val); + if (is_write(wp_tb[pf_reason[cpu].index].wp.type)) { + set_ins_reg_val(pf_reason[cpu].eip, regs, pf_reason[cpu].val); + } + break; + case IMM_WRITE: + PDEBUG("restore immval after imm_write corrputing, val=0x%08lx\n", + pf_reason[cpu].val); + if (is_write(wp_tb[pf_reason[cpu].index].wp.type)) { + set_ins_imm_val(pf_reason[cpu].eip, pf_reason[cpu].val); + } + break; + case REG_READ: + PDEBUG("corrupt reg after reg_read! cond=0x%08lx\n", condition); + + if (is_read(wp_tb[pf_reason[cpu].index].wp.type)) { + + ins_len = get_ins_width(pf_reason[cpu].eip); + pf_reason[cpu].val = get_ins_reg_val(pf_reason[cpu]. eip, regs); + + crpt_len = (WP_LEN(wp_tb[pf_reason[cpu].index].wp)<ins_len)? + WP_LEN(wp_tb[pf_reason[cpu].index].wp):ins_l en; + crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; + ( *(wp_tb[pf_reason[cpu].index].hook->trigger) )( + wp_tb[pf_reason[cpu].index].id, crpt.corrupted_data, + crpt_len, 0, &crpt); + + set_ins_reg_val(pf_reason[cpu].eip, regs, + (crpt.corrupted_data&crpt_mask[crpt_ len-1]) + | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); + } + break; + case NOTHING: + PDEBUG("just restore page fault! address=%#08lx\n", pf_reason[cpu].addr); + break; + case NOT_ME: + default: + PERROR("should never reach here! cond=0x%08lx\n", condition); + break; + } + pf_reason[cpu].type = NOT_ME; + + exit: + /* clear TF */ + regs->eflags &= ~X86_EFLAGS_TF; + /* clean page fault and tlb ONLY on this cpu */ + pf_clr_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); + + __flush_tlb_one(pf_reason[cpu].addr); + + //Release lock which is locked in do_page_fault + pf_unlock_region(); + return 1; + + not_me: + return 0; +}; + + +/* + * Initialize/Uninitialize modules + */ +static int __init fi_pf_init(void) { + int rv=0; + + register_pf_interface(); + fi_post_page_fault=pf_do_debug; + fi_page_fault=pf_do_page_fault; + + PINFO("FI Pagefault interceptor v%d.%d.%d loaded.\n", PF_MAJOR, PF_MINOR, PF_PATCH); + EXPORT_NO_SYMBOLS; + return 0; +}; + +static void __exit fi_pf_cleanup(void) { + fi_page_fault=NULL; + fi_post_page_fault=NULL; + unregister_pf_interface(); +}; + +module_init(fi_pf_init); +module_exit(fi_pf_cleanup); +MODULE_AUTHOR("Louis Zhuang"); +MODULE_DESCRIPTION("Pagefault interceptor component for FI"); +MODULE_LICENSE("GPL"); diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_in.c linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_in.c --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_in.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_in.c Mon Nov 25 17:20:03 2002 @@ -0,0 +1,443 @@ +/************************************************************************** **** + * Fault Injection Test harness (FI) + * Copyright (C) Intel Crop. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** ** + */ + +/* $Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp $ + * Copyright by Intel Crop., 2002 + * Louis Zhuang (lou...@in...) + */ + +/** + * @file pf_hooks.c + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> + +#define PREFIX_NAME "FI_PF" +#include <linux/fi/fi.h> +#include <linux/fi/fi_interface.h> +#include <linux/fi/fi_internal.h> + +#include "fi_pf.h" + +#define NR_ELEMENTS(array) (sizeof(array)/sizeof(array[0])) + +/* IA32 Manual 3, 2-1 */ +static unsigned char prefix_codes[] = { + 0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64, + 0x65, 0x2E, 0x3E, 0x66, 0x67 +}; +int skip_prefix(unsigned char *addr, int *shorted) { + int i=0; + unsigned char *p=addr; + *shorted=0; + + restart: + for (i=0; i<NR_ELEMENTS(prefix_codes); i++) { + if (*p == prefix_codes[i]){ + if (*p == 0x66) *shorted = 1; + p++; + goto restart; + } + } + return p-addr; +}; + +int get_opcode(unsigned char *addr, unsigned int *opcode) { + int rv; + if (*addr == 0x0F){/*0x0F is extension instruction*/ + *opcode = *(unsigned short*)addr; + rv=2; + }else{ + *opcode = *addr; + rv=1; + } + return rv; +}; + +/* IA32 Manual 3, 3-432*/ +static unsigned int reg_rop[] = {0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F}; +static unsigned int reg_wop[] = {0x88, 0x89}; +static unsigned int imm_wop[] = {0xC6, 0xC7}; + +enum reason_type get_ins_type(unsigned long ins_addr) { + unsigned int opcode; + unsigned char *p; + int shorted=0; + int i=0; + enum reason_type rv=OTHERS; + + p = (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + + for (i=0; i<NR_ELEMENTS(reg_rop); i++) { + if (reg_rop[i]==opcode) { + rv = REG_READ; + goto exit; + } + } + + for (i=0; i<NR_ELEMENTS(reg_wop); i++) { + if (reg_wop[i]==opcode) { + rv = REG_WRITE; + goto exit; + } + } + + for (i=0; i<NR_ELEMENTS(imm_wop); i++) { + if (imm_wop[i]==opcode) { + rv = IMM_WRITE; + goto exit; + } + } + + exit: + return rv; +}; + +/* IA32 Manual 3, 3-432*/ +static unsigned int w8[] = {0x88, 0x8A, 0xC6}; +static unsigned int w32[]= {0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F}; +unsigned int get_ins_width(unsigned long ins_addr) { + unsigned int opcode; + unsigned char *p; + int shorted=0; + int i=0; + + p = (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + + for (i=0; i<NR_ELEMENTS(w8); i++) { + if (w8[i]==opcode) { + return 1; + } + } + for (i=0; i<NR_ELEMENTS(w32); i++) { + if (w32[i]==opcode) { + if (shorted) { + return 2; + } else { + return 4; + } + } + } + + PERROR("Unknow opcode=0x%02x\n", opcode); + return 0; +}; +/* define register ident in mod/rm byte after undefine it in ptrace*/ +#undef EAX +#define EAX 0 +#define ECX 1 +#define EDX 2 +#undef EBX +#define EBX 3 +#define ESP 4 +#define EBP 5 +#undef ESI +#define ESI 6 +#undef EDI +#define EDI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 +#define AH 4 +#define CH 5 +#define DH 6 +#define BH 7 +unsigned char *get_reg_w8(int no, struct pt_regs *regs){ + unsigned char *rv=NULL; + + switch (no) { + case AL: + rv = (unsigned char *)®s->eax; + break; + case BL: + rv = (unsigned char *)®s->ebx; + break; + case CL: + rv = (unsigned char *)®s->ecx; + break; + case DL: + rv = (unsigned char *)®s->edx; + break; + case AH: + rv = 1+(unsigned char *)®s->eax; + break; + case BH: + rv = 1+(unsigned char *)®s->ebx; + break; + case CH: + rv = 1+(unsigned char *)®s->ecx; + break; + case DH: + rv = 1+(unsigned char *)®s->edx; + break; + default: + PERROR("Error reg no# %d\n", no); + break; + } + return rv; +}; + +unsigned long *get_reg_w32(int no, struct pt_regs *regs){ + unsigned long *rv=NULL; + + switch (no) { + case EAX: + rv = ®s->eax; + break; + case EBX: + rv = ®s->ebx; + break; + case ECX: + rv = ®s->ecx; + break; + case EDX: + rv = ®s->edx; + break; + case ESP: + rv = ®s->esp; + break; + case EBP: + rv = ®s->ebp; + break; + case ESI: + rv = ®s->esi; + break; + case EDI: + rv = ®s->edi; + break; + default: + PERROR("Error reg no# %d\n", no); + } + return rv; +}; + +unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) { + unsigned int opcode; + unsigned char mod_rm; + int reg; + unsigned char *p; + int shorted=0; + int i=0; + unsigned long rv; + + p = (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + for (i=0; i<NR_ELEMENTS(reg_rop); i++) { + if (reg_rop[i]==opcode) { + rv = REG_READ; + goto do_work; + } + } + + for (i=0; i<NR_ELEMENTS(reg_wop); i++) { + if (reg_wop[i]==opcode) { + rv = REG_WRITE; + goto do_work; + } + } + PERROR("Not a register instruction, opcode=0x%02x\n", opcode); + goto err; + do_work: + mod_rm = *p; + reg = (mod_rm>>3)&0x7; + if (get_ins_width(ins_addr)==1) { + return *get_reg_w8(reg, regs); + }else if (get_ins_width(ins_addr)==2) { + return *(unsigned short*)get_reg_w32(reg, regs); + }else if (get_ins_width(ins_addr)==4) { + return *get_reg_w32(reg, regs); + }else{ + PERROR("Error width# %d\n", reg); + goto err; + } + err: + return 0; +}; + + +void set_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs, unsigned long val) { + unsigned int opcode; + unsigned char mod_rm; + int reg; + unsigned char *p; + int shorted=0; + int i=0; + unsigned long rv; + + p= (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + for (i=0; i<NR_ELEMENTS(reg_rop); i++) { + if (reg_rop[i]==opcode) { + rv = REG_READ; + goto do_work; + } + } + + for (i=0; i<NR_ELEMENTS(reg_wop); i++) { + if (reg_wop[i]==opcode) { + rv = REG_WRITE; + goto do_work; + } + } + PERROR("Not a register instruction, opcode=0x%02x\n", opcode); + goto err; + do_work: + mod_rm = *p; + reg = (mod_rm>>3)&0x7; + if (get_ins_width(ins_addr)==1) { + *get_reg_w8(reg, regs) = val; + }else if (get_ins_width(ins_addr)==2) { + *(unsigned short*)get_reg_w32(reg, regs) = val; + }else if (get_ins_width(ins_addr)==4) { + *get_reg_w32(reg, regs) = val; + }else{ + PERROR("Error width, reg=%d\n", reg); + goto err; + } + err: + return; + +}; + +unsigned long get_ins_imm_val(unsigned long ins_addr) { + unsigned int opcode; + unsigned char mod_rm; + unsigned char mod; + unsigned char *p; + int shorted=0; + int i=0; + unsigned long rv; + + p= (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + for (i=0; i<NR_ELEMENTS(imm_wop); i++) { + if (imm_wop[i]==opcode) { + rv = IMM_WRITE; + goto do_work; + } + } + PERROR("Not a imm instruction, opcode=0x%02x\n", opcode); + goto err; + do_work: + mod_rm = *p; + mod = mod_rm>>6; + p++; + switch (mod) { + case 0: + break; + case 1: + p += 1; + break; + case 2: + p += 4; + case 3: + default: + PERROR("it is not a memory access instruction, rm_mod=0x%02x\n", mod_rm); + } + if (get_ins_width(ins_addr)==1) { + return *(unsigned char *)p; + }else if (get_ins_width(ins_addr)==2) { + return *(unsigned short*)p; + }else if (get_ins_width(ins_addr)==4) { + return *(unsigned long*)p; + }else{ + PERROR("Error width%s\n", "."); + goto err; + } + err: + return 0; +}; + +void set_ins_imm_val(unsigned long ins_addr, unsigned long val) { + unsigned int opcode; + unsigned char mod_rm; + unsigned char mod; + unsigned char *p; + int shorted=0; + int i=0; + unsigned long rv; + + p= (unsigned char *)ins_addr; + p += skip_prefix(p, &shorted); + p += get_opcode(p, &opcode); + for (i=0; i<NR_ELEMENTS(imm_wop); i++) { + if (imm_wop[i]==opcode) { + rv = IMM_WRITE; + goto do_work; + } + } + PERROR("Not a imm instruction, opcode=0x%02x\n", opcode); + goto err; + do_work: + mod_rm = *p; + mod = mod_rm>>6; + p++; + switch (mod) { + case 0: + break; + case 1: + p += 1; + break; + case 2: + p += 4; + break; + case 3: + default: + PERROR("it is not a memory access instruction, rm_mod=0x%02x\n", mod_rm); + } + if (get_ins_width(ins_addr)==1) { + *(unsigned char *)p = val; + }else if (get_ins_width(ins_addr)==2) { + *(unsigned short*)p = val; + }else if (get_ins_width(ins_addr)==4) { + *(unsigned long*)p = val; + }else{ + PERROR("Error width%s\n", "."); + goto err; + } + err: + return; +}; diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_interface.c linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_interface. c --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_interface.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_interface. c Mon Nov 25 17:20:21 2002 @@ -0,0 +1,81 @@ +/************************************************************************** **** + * Fault Injection Test harness (FI) + * Copyright (C) Intel Crop. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** ** + */ + +/* $Id: pf_interface.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp $ + * Copyright by Intel Crop., 2002 + * Louis Zhuang (lou...@in...) + */ + +/** + * @file pf_interface.c + */ + +#include <linux/config.h> +#include <linux/version.h> + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> + +#define PREFIX_NAME "FI_PF" +#include <linux/fi/fi.h> +#include <linux/fi/fi_interface.h> +#include <linux/fi/fi_internal.h> + +#include "fi_pf.h" + + +#define COMPONENT_NAME "fi.interceptor.pf" +#define INTERFACE_NAME COMPONENT_NAME ".iIntercept" + +static struct iIntercept intcpt[1] = { + { + wp_register: pf_register, + wp_unregister: pf_unregister, + corrupt: pf_corrupt, + } +}; + + +void register_pf_interface(void) { + inter_module_register(INTERFACE_NAME, THIS_MODULE, intcpt); + PDEBUG("register interface: %s\n", INTERFACE_NAME); +}; + +void unregister_pf_interface(void) { + inter_module_unregister(INTERFACE_NAME); + PDEBUG("unregister interface: %s\n", INTERFACE_NAME); +}; diff -Nur -X dontdiff linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_region.c linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_region.c --- linux-2.5-kp-fi-dm/linux-2.5.47/arch/i386/kernel/fi/pf/pf_region.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi-dm-intcpts/linux-2.5.47/arch/i386/kernel/fi/pf/pf_region.c Mon Nov 25 17:20:31 2002 @@ -0,0 +1,212 @@ +/************************************************************************** **** + * Fault Injection Test harness (FI) + * Copyright (C) Intel Crop. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** ** + */ + +/* $Id: pf_region.c,v 1.2 2002/11/14 06:19:49 yzhuang Exp $ + * Copyright by Intel Crop., 2002 + * Louis Zhuang (lou...@in...) + */ + +/** + * @file pf_utils.c + */ + +#include <linux/config.h> +#include <linux/version.h> + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/delay.h> +#include <asm/io.h> +#include <asm/pgalloc.h> + +#define PREFIX_NAME "FI_PF" +#include <linux/fi/fi.h> +#include <linux/fi/fi_interface.h> +#include <linux/fi/fi_internal.h> + +#include "fi_pf.h" + +#define MAX_REGION 32 + +/* Store all pages which we intercept, other page info can be found + * in page directory entry */ +static struct{ + unsigned long addr; + int count;//count==0 is criterion of empty region +}region[MAX_REGION] = { [0 ... MAX_REGION-1] = {0, 0} }; +static spinlock_t region_lock = SPIN_LOCK_UNLOCKED; + + +static unsigned long removed_region[MAX_REGION] = { + [0 ... MAX_REGION-1] = 0 +}; + + +static int is_in_region(int i, unsigned long addr) { + if ( region[i].count!=0 + && (addr&PAGE_MASK)==(region[i].addr&PAGE_MASK)) { + return 1; + }else{ + return 0; + } +}; + +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 + */ +void pf_clr_pte_bits(unsigned long addr, unsigned long bitmask) { + pte_t *pte; + pte = get_pte(addr); + set_pte( pte, __pte( pte_val(*pte) & ~bitmask) ); +}; + +void pf_set_pte_bits(unsigned long addr, unsigned long bitmask) { + pte_t *pte; + pte = get_pte(addr); + set_pte( pte, __pte( pte_val(*pte) | bitmask) ); +}; + +/** + * lock_region_irqsave lock the region (that means lock all regions access). + * @param flags the saved flags. + */ +void pf_lock_region_irqsave(unsigned long *flags) { + spin_lock_irqsave(®ion_lock, *flags); +}; +void pf_lock_region(void) { + spin_lock(®ion_lock); +}; + +/** + * unlock region which is locked by lock_region_irqsave. + * @param flags restoring flags. + */ +void pf_unlock_region_irqrestore(unsigned long flags) { + spin_unlock_irqrestore(®ion_lock, flags); +}; +void pf_unlock_region(void) { + spin_unlock(®ion_lock); +}; + +/* find region in region table + * @return < 0 error, no region is found, + * >=0 the region index. + * @param addr the address which is in region. + */ +int pf_find_region(unsigned long addr) { + int i=0; + + for (i=0; i<MAX_REGION; i++) { + if (is_in_region(i, addr)) { + break; + } + } + + if (i<MAX_REGION) { + return i; + }else{ + return -1;//region is not locked! + } +}; + +/** + * increase region count and add region for the addr + * if the region is not here. + * @return <0 can not add the region + * >0 region index + * @param addr adding address + */ +int pf_add_region(unsigned long addr) { + int i=0; + + for (i=0; i<MAX_REGION; i++) { + if (is_in_region(i, addr)) { + region[i].count++; + goto out; + } + } + + //if there is not this region. create one. + for (i=0; i<MAX_REGION; i++) { + if (region[i].count==0) { + region[i].count= 1; + region[i].addr = addr&PAGE_MASK; + pf_clr_pte_bits(region[i].addr, _PAGE_PRESENT); +// flush_tlb_all(); + goto out; + } + } + err: + return -1; + out: + return i; +}; + +/** + * release region. when count meet zero, set present in page table. + * move this into garbage. + */ +void pf_release_region(int ri) { + static int removed_pos=0; + + region[ri].count--; + if (region[ri].count==0) { + pf_set_pte_bits(region[ri].addr, _PAGE_PRESENT); + removed_region[removed_pos] = region[ri].addr; + removed_pos++; + removed_pos %= MAX_REGION; + }else if (region[ri].count<0) { + PERROR("remove region, count=%d\n", region[ri].count); + } +}; + +int pf_is_removed_regions(unsigned long addr) { + int i=0; + for (i=0; i<MAX_REGION; i++) { + if (removed_region[i]==(addr&PAGE_MASK)) { + return 1; + } + } + return 0; +}; |
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 |
From: Zhuang, L. <lou...@in...> - 2002-11-25 10:11:06
|
Here are basic FITH patch to places several hooks in kernel. diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/Makefile linux-2.5-kp-fi/linux-2.5.47/Makefile --- linux-2.5-kp/linux-2.5.47/Makefile Mon Nov 25 15:12:15 2002 +++ linux-2.5-kp-fi/linux-2.5.47/Makefile Mon Nov 25 15:15:38 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 47 -EXTRAVERSION = +EXTRAVERSION =kp-fi # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/arch/i386/Kconfig linux-2.5-kp-fi/linux-2.5.47/arch/i386/Kconfig --- linux-2.5-kp/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:12:19 2002 +++ linux-2.5-kp-fi/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:15:40 2002 @@ -1562,11 +1562,20 @@ config DEBUGREG bool "Global Debug Registers" - depend on DEBUG_KERNEL + depends on DEBUG_KERNEL + help config KWATCH bool "Kwatch points" - depend on DEBUGREG + depends on DEBUGREG + help + +config FI + bool "Fault Injection" + depends on KPROBES + help + Say Y here if you want to enable Fault Injection (FI) mechanism. + The FI can monitor MMIO/IO access in kernel. config DEBUG_STACKOVERFLOW bool "Check for stack overflows" diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/arch/i386/kernel/i386_ksyms. c linux-2.5-kp-fi/linux-2.5.47/arch/i386/kernel/i386_ksyms.c --- linux-2.5-kp/linux-2.5.47/arch/i386/kernel/i386_ksyms.c Mon Nov 25 15:12:19 2002 +++ linux-2.5-kp-fi/linux-2.5.47/arch/i386/kernel/i386_ksyms.c Mon Nov 25 15:15:40 2002 @@ -32,6 +32,7 @@ #include <asm/tlbflush.h> #include <asm/nmi.h> #include <asm/edd.h> +#include <asm/fi.h> extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -216,3 +217,9 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif + +#ifdef CONFIG_FI +EXPORT_SYMBOL(irq_desc); +EXPORT_SYMBOL(fi_page_fault); +EXPORT_SYMBOL(fi_post_page_fault); +#endif diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/arch/i386/kernel/traps.c linux-2.5-kp-fi/linux-2.5.47/arch/i386/kernel/traps.c --- linux-2.5-kp/linux-2.5.47/arch/i386/kernel/traps.c Mon Nov 25 15:12:19 2002 +++ linux-2.5-kp-fi/linux-2.5.47/arch/i386/kernel/traps.c Mon Nov 25 15:15:41 2002 @@ -47,6 +47,7 @@ #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> @@ -564,6 +565,9 @@ return 0; } +int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -599,7 +603,10 @@ if (kwatch_handler(condition, regs)) return 1; - +#ifdef CONFIG_FI + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) + return 1; +#endif /* Interrupts not disabled for normal trap handling. */ restore_interrupts(regs); diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/arch/i386/mm/fault.c linux-2.5-kp-fi/linux-2.5.47/arch/i386/mm/fault.c --- linux-2.5-kp/linux-2.5.47/arch/i386/mm/fault.c Mon Nov 25 15:12:20 2002 +++ linux-2.5-kp-fi/linux-2.5.47/arch/i386/mm/fault.c Mon Nov 25 15:15:41 2002 @@ -26,6 +26,7 @@ #include <asm/pgalloc.h> #include <asm/hardirq.h> #include <asm/desc.h> +#include <asm/fi.h> extern void die(const char *,struct pt_regs *,long); @@ -139,6 +140,7 @@ } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); +int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); /* * This routine handles page faults. It determines the address, @@ -166,7 +168,10 @@ if (kprobe_running() && kprobe_fault_handler(regs, 14)) return; - +#ifdef CONFIG_FI + if (fi_page_fault && fi_page_fault(regs, address)) + return; +#endif /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/include/asm-i386/fi.h linux-2.5-kp-fi/linux-2.5.47/include/asm-i386/fi.h --- linux-2.5-kp/linux-2.5.47/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp-fi/linux-2.5.47/include/asm-i386/fi.h Mon Nov 25 15:16:18 2002 @@ -0,0 +1,8 @@ +#ifndef _ASM_FI_H +#define _ASM_FI_H +#ifdef CONFIG_FI +extern int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); +extern int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); +#endif +#endif /* _ASM_FI_H */ diff -Nur -X dontdiff linux-2.5-kp/linux-2.5.47/kernel/ksyms.c linux-2.5-kp-fi/linux-2.5.47/kernel/ksyms.c --- linux-2.5-kp/linux-2.5.47/kernel/ksyms.c Mon Nov 25 15:13:04 2002 +++ linux-2.5-kp-fi/linux-2.5.47/kernel/ksyms.c Mon Nov 25 15:16:27 2002 @@ -601,3 +601,7 @@ /* debug */ EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_FI +EXPORT_SYMBOL(module_list); +#endif |
From: Zhuang, L. <lou...@in...> - 2002-11-25 10:08:37
|
In fact, it is not a part of FITH. FITH needs kprobes as its infrastructure. Here is our all-in-one kprobes-2 porting against 2.5.47 kernel. diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/Kconfig linux-2.5-kp/linux-2.5.47/arch/i386/Kconfig --- linux-2.5/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/Kconfig Mon Nov 25 15:12:19 2002 @@ -1551,6 +1551,23 @@ Say Y here if you are developing drivers or trying to debug and identify kernel problems. +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address, using + register_kprobe(), and providing a callback function. This is useful + for kernel debugging, non-intrusive instrumentation and testing. If + in doubt, say "N". + +config DEBUGREG + bool "Global Debug Registers" + depend on DEBUG_KERNEL + +config KWATCH + bool "Kwatch points" + depend on DEBUGREG + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/Makefile linux-2.5-kp/linux-2.5.47/arch/i386/kernel/Makefile --- linux-2.5/linux-2.5.47/arch/i386/kernel/Makefile Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/Makefile Mon Nov 25 15:12:19 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 debugreg.o kwatch.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 \ @@ -28,6 +28,9 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_DEBUGREG) += debugreg.o +obj-$(CONFIG_KWATCH) += kwatch.o EXTRA_AFLAGS := -traditional diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/debugreg.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/debugreg.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/debugreg.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/debugreg.c Mon Nov 25 15:12:19 2002 @@ -0,0 +1,178 @@ +/* + * This provides a debug register allocation mechanism, to be + * used by all debuggers, which need debug registers. + * + * Author: vam...@in... + * bh...@in... + */ +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <asm/system.h> +#include <asm/debugreg.h> + +struct debugreg dr_list[DR_MAX]; +unsigned long dr7_global_mask = 0; +static spinlock_t dr_lock = SPIN_LOCK_UNLOCKED; + +static inline void set_dr7_global_mask(int regnum) +{ + switch (regnum) { + case 0: dr7_global_mask |= DR7_DR0_BITS; break; + case 1: dr7_global_mask |= DR7_DR1_BITS; break; + case 2: dr7_global_mask |= DR7_DR2_BITS; break; + case 3: dr7_global_mask |= DR7_DR3_BITS; break; + } + return; +} + +static inline void clear_dr7_global_mask(int regnum) +{ + switch (regnum) { + case 0: dr7_global_mask &= ~DR7_DR0_BITS; break; + case 1: dr7_global_mask &= ~DR7_DR1_BITS; break; + case 2: dr7_global_mask &= ~DR7_DR2_BITS; break; + case 3: dr7_global_mask &= ~DR7_DR3_BITS; break; + } + return; +} + +static int get_dr(int regnum, int flag) +{ + if ((flag == DR_ALLOC_GLOBAL) && (dr_list[regnum].flag == DR_UNUSED)) { + dr_list[regnum].flag = DR_GLOBAL; + set_dr7_global_mask(regnum); + return regnum; + } + else if ((dr_list[regnum].flag == DR_UNUSED) || (dr_list[regnum].flag == DR_LOCAL)) { + dr_list[regnum].use_count++; + dr_list[regnum].flag = DR_LOCAL; + return regnum; + } + return -1; +} + +static int get_any_dr(int flag) +{ + int i; + if (flag == DR_ALLOC_LOCAL) { + for (i = 0; i < DR_MAX; i++) { + if (dr_list[i].flag == DR_LOCAL) { + dr_list[i].use_count++; + return i; + } else if (dr_list[i].flag == DR_UNUSED) { + dr_list[i].flag = DR_LOCAL; + dr_list[i].use_count = 1; + return i; + } + } + } else { + for (i = DR_MAX-1; i >= 0; i--) { + if (dr_list[i].flag == DR_UNUSED) { + dr_list[i].flag = DR_GLOBAL; + set_dr7_global_mask(i); + return i; + } + } + } + return -1; +} + +static inline void dr_free_local(int regnum) +{ + if (! (--dr_list[regnum].use_count)) + dr_list[regnum].flag = DR_UNUSED; + return; +} + +static inline void dr_free_global(int regnum) +{ + dr_list[regnum].flag = DR_UNUSED; + dr_list[regnum].use_count = 0; + clear_dr7_global_mask(regnum); + return; +} + +int dr_alloc(int regnum, int flag) +{ + int ret; + + spin_lock(&dr_lock); + if (regnum == DR_ANY) + ret = get_any_dr(flag); + else if (regnum >= DR_MAX) + ret = -1; + else + ret = get_dr(regnum, flag); + spin_unlock(&dr_lock); + return ret; +} + +int dr_free(int regnum) +{ + spin_lock(&dr_lock); + if (regnum >= DR_MAX || dr_list[regnum].flag == DR_UNUSED) { + spin_unlock(&dr_lock); + return -1; + } + if (dr_list[regnum].flag == DR_LOCAL) + dr_free_local(regnum); + else + dr_free_global(regnum); + spin_unlock(&dr_lock); + return 0; +} + +void dr_inc_use_count(unsigned long mask) +{ + int i; + + spin_lock(&dr_lock); + for (i =0; i < DR_MAX; i++) { + if (DR_IS_LOCAL(mask, i)) + dr_list[i].use_count++; + } + spin_unlock(&dr_lock); +} + +void dr_dec_use_count(unsigned long mask) +{ + int i; + + spin_lock(&dr_lock); + for (i =0; i < DR_MAX; i++) { + if (DR_IS_LOCAL(mask, i)) + dr_free_local(i); + } + spin_unlock(&dr_lock); +} + +/* + * This routine decides if the ptrace request is for enabling or disabling + * a debug reg, and accordingly calls dr_alloc() or dr_free(). + * + * gdb uses ptrace to write to debug registers. It assumes that writing to + * debug register always succeds and it doesn't check the return value of + * ptrace. Now with this new global debug register allocation/freeing, + * ptrace request for a local debug register can fail, if the required debug + * register is already globally allocated. Since gdb fails to notice this + * failure, it sometimes tries to free a debug register, which is not + * allocated for it. + */ +int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) +{ + int i, dr_shift = 1UL; + for (i = 0; i < DR_MAX; i++, dr_shift <<= 2) { + if ((old_dr7 ^ new_dr7) & dr_shift) { + if (new_dr7 & dr_shift) + dr_alloc(i, DR_ALLOC_LOCAL); + else + dr_free(i); + return 0; + } + } + return -1; +} + +EXPORT_SYMBOL(dr_alloc); +EXPORT_SYMBOL(dr_free); diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/entry.S linux-2.5-kp/linux-2.5.47/arch/i386/kernel/entry.S --- linux-2.5/linux-2.5.47/arch/i386/kernel/entry.S Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/entry.S Mon Nov 25 15:12:19 2002 @@ -404,9 +404,16 @@ jmp ret_from_exception ENTRY(debug) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_debug - jmp error_code + pushl %edx + call do_debug + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(nmi) pushl %eax @@ -419,9 +426,16 @@ RESTORE_ALL ENTRY(int3) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_int3 - jmp error_code + pushl %edx + call do_int3 + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(overflow) pushl $0 diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/kprobes.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/kprobes.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/kprobes.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/kprobes.c Mon Nov 25 15:12:19 2002 @@ -0,0 +1,170 @@ +/* + * Support for kernel probes. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ + +#include <linux/config.h> +#include <linux/kprobes.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/preempt.h> + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; + +/* + * returns non-zero if opcode modifies the interrupt flag. + */ +static inline int is_IF_modifier(u8 opcode) +{ + switch(opcode) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ + case 0xcf: /* iret/iretd */ + case 0x9d: /* popf/popfd */ + return 1; + } + return 0; +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + if (!p->at.inode) { + /* remember the address to be used when rearming the probe. */ + p->at.addr = (void *)(regs->eip - 1); + } + *p->at.addr = p->opcode; + regs->eip = (unsigned long)p->at.addr; +} + +/* + * Interrupts are disabled on entry as trap3 is an interrupt gate and they + * remain disabled thorough out this function. + */ +int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + u8 *addr = (u8 *)(regs->eip-1); + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + Disarm the probe we just hit, and ignore it. */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + /* Unregistered (on another cpu) after this hit? Ignore */ + if (*addr != BREAKPOINT_INSTRUCTION) + ret = 1; + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + kprobe_saved_eflags = kprobe_old_eflags + = (regs->eflags & (TF_MASK|IF_MASK)); + if (is_IF_modifier(p->opcode)) + kprobe_saved_eflags &= ~IF_MASK; + + p->pre_handler(p, regs); + + regs->eflags |= TF_MASK; + regs->eflags &= ~IF_MASK; + + /* We hold lock, now we remove breakpoint and single step. */ + disarm_kprobe(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +static void rearm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + regs->eflags &= ~TF_MASK; + *p->at.addr = BREAKPOINT_INSTRUCTION; +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thorough out this function. And we hold kprobe lock. + */ +int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + /* + * We singlestepped with interrupts disabled. So, the result on + * the stack would be incorrect for "pushfl" instruction. + * Note that regs->esp is actually the top of the stack when the + * trap occurs in kernel space. + */ + if (current_kprobe->opcode == 0x9c) { /* pushfl */ + unsigned long *tos; + + if (regs->eip > PAGE_OFFSET) + tos = ®s->esp; + else + tos = (unsigned long *)regs->esp; + *tos &= ~(TF_MASK | IF_MASK); + *tos |= kprobe_old_eflags; + } + + rearm_kprobe(current_kprobe, regs); + regs->eflags |= kprobe_saved_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + + /* + * if somebody else is singlestepping across a probe point, eflags + * will have TF set, in which case, continue the remaining processing + * of do_debug, as if this is not a probe hit. + */ + if (regs->eflags & TF_MASK) + return 0; + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + rearm_kprobe(current_kprobe, regs); + regs->eflags |= kprobe_old_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/kwatch.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/kwatch.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/kwatch.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/kwatch.c Mon Nov 25 15:12:19 2002 @@ -0,0 +1,135 @@ +/* + * Support for kernel watchpoints. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ +#include <linux/config.h> +#include <linux/kprobes.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <asm/kwatch.h> +#include <asm/debugreg.h> +#include <asm/bitops.h> + +static struct kwatch kwatch_list[DR_MAX]; +static spinlock_t kwatch_lock = SPIN_LOCK_UNLOCKED; +static unsigned long kwatch_in_progress; /* currently being handled */ + +struct dr_info { + int debugreg; + unsigned long addr; + int type; +}; + +static inline void write_smp_dr(void *info) +{ + struct dr_info *dr = (struct dr_info *)info; + + if (cpu_has_de && dr->type == DR_TYPE_IO) + set_in_cr4(X86_CR4_DE); + write_dr(dr->debugreg, dr->addr); +} + +/* Update the debug register on all CPUs */ +static void sync_dr(int debugreg, unsigned long addr, int type) +{ + struct dr_info dr; + dr.debugreg = debugreg; + dr.addr = addr; + dr.type = type; + smp_call_function(write_smp_dr, &dr, 0, 0); +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thorough out this function. + */ +int kwatch_handler(unsigned long condition, struct pt_regs *regs) +{ + int debugreg = dr_trap(condition); + unsigned long addr = dr_trap_addr(condition); + int retval = 0; + + if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) { + return 0; + } + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* If we are recursing, we already hold the lock. */ + if (kwatch_in_progress) { + goto recursed; + } + set_bit(debugreg, &kwatch_in_progress); + + spin_lock(&kwatch_lock); + if (kwatch_list[debugreg].addr != addr) + goto out; + + if (kwatch_list[debugreg].handler) { + kwatch_list[debugreg].handler(&kwatch_list[debugreg], regs); + } + + if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE) + regs->eflags |= RF_MASK; +out: + clear_bit(debugreg, &kwatch_in_progress); + spin_unlock(&kwatch_lock); + preempt_enable_no_resched(); + return retval; + +recursed: + if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE) + regs->eflags |= RF_MASK; + preempt_enable_no_resched(); + return 1; +} + +int register_kwatch(unsigned long addr, u8 length, u8 type, + kwatch_handler_t handler) +{ + int debugreg; + unsigned long dr7, flags; + + debugreg = dr_alloc(DR_ANY, DR_ALLOC_GLOBAL); + if (debugreg < 0) { + return -1; + } + + spin_lock_irqsave(&kwatch_lock, flags); + kwatch_list[debugreg].addr = addr; + kwatch_list[debugreg].length = length; + kwatch_list[debugreg].type = type; + kwatch_list[debugreg].handler = handler; + spin_unlock_irqrestore(&kwatch_lock, flags); + + write_dr(debugreg, (unsigned long)addr); + sync_dr(debugreg, (unsigned long)addr, type); + if (cpu_has_de && type == DR_TYPE_IO) + set_in_cr4(X86_CR4_DE); + + dr7 = read_dr(7); + SET_DR7(dr7, debugreg, type, length); + write_dr(7, dr7); + sync_dr(7, dr7, 0); + return debugreg; +} + +void unregister_kwatch(int debugreg) +{ + unsigned long flags; + unsigned long dr7 = read_dr(7); + + RESET_DR7(dr7, debugreg); + write_dr(7, dr7); + sync_dr(7, dr7, 0); + dr_free(debugreg); + + spin_lock_irqsave(&kwatch_lock, flags); + kwatch_list[debugreg].addr = 0; + kwatch_list[debugreg].handler = NULL; + spin_unlock_irqrestore(&kwatch_lock, flags); +} +EXPORT_SYMBOL_GPL(register_kwatch); +EXPORT_SYMBOL_GPL(unregister_kwatch); diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/process.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/process.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/process.c Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/process.c Mon Nov 25 15:12:19 2002 @@ -47,6 +47,7 @@ #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif +#include <asm/debugreg.h> #include <linux/irq.h> #include <linux/err.h> @@ -241,12 +242,16 @@ kfree(tsk->thread.ts_io_bitmap); tsk->thread.ts_io_bitmap = NULL; } + if (tsk->thread.debugreg[7]) + dr_dec_use_count(tsk->thread.debugreg[7]); } void flush_thread(void) { struct task_struct *tsk = current; + if (tsk->thread.debugreg[7]) + dr_dec_use_count(tsk->thread.debugreg[7]); memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* @@ -330,6 +335,9 @@ desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } + + if (current->thread.debugreg[7]) + dr_inc_use_count(current->thread.debugreg[7]); return 0; } @@ -464,6 +472,24 @@ /* * Now maybe reload the debug registers */ +#ifdef CONFIG_DEBUGREG +{ + /* + * Don't reload global debug registers. Don't touch the global debug + * register settings in dr7. + */ + unsigned long next_dr7 = next->debugreg[7]; + if (unlikely(next_dr7)) { + if (DR7_L0(next_dr7)) loaddebug(next, 0); + if (DR7_L1(next_dr7)) loaddebug(next, 1); + if (DR7_L2(next_dr7)) loaddebug(next, 2); + if (DR7_L3(next_dr7)) loaddebug(next, 3); + /* no 4 and 5 */ + loaddebug(next, 6); + load_process_dr7(next_dr7); + } +} +#else if (unlikely(next->debugreg[7])) { loaddebug(next, 0); loaddebug(next, 1); @@ -473,7 +499,7 @@ loaddebug(next, 6); loaddebug(next, 7); } - +#endif if (unlikely(prev->ts_io_bitmap || next->ts_io_bitmap)) { if (next->ts_io_bitmap) { /* diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/ptrace.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/ptrace.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/ptrace.c Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/ptrace.c Mon Nov 25 15:12:19 2002 @@ -269,6 +269,11 @@ addr -= (long) &dummy->u_debugreg; addr = addr >> 2; + + if (addr == 7 && (enable_debugreg(child->thread.debugreg[addr], data)) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg[addr] = data; ret = 0; } diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/signal.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/signal.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/signal.c Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/signal.c Mon Nov 25 15:12:19 2002 @@ -22,6 +22,7 @@ #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/debugreg.h> #define DEBUG_SIG 0 @@ -574,7 +575,7 @@ * have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7])); + load_process_dr7(current->thread.debugreg[7]); /* Whee! Actually deliver the signal. */ handle_signal(signr, &info, oldset, regs); diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/kernel/traps.c linux-2.5-kp/linux-2.5.47/arch/i386/kernel/traps.c --- linux-2.5/linux-2.5.47/arch/i386/kernel/traps.c Mon Nov 25 15:10:39 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/kernel/traps.c Mon Nov 25 15:12:19 2002 @@ -23,6 +23,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/highmem.h> +#include <linux/kprobes.h> #ifdef CONFIG_EISA #include <linux/ioport.h> @@ -38,6 +39,7 @@ #include <asm/io.h> #include <asm/atomic.h> #include <asm/debugreg.h> +#include <asm/kwatch.h> #include <asm/desc.h> #include <asm/i387.h> #include <asm/nmi.h> @@ -402,7 +404,6 @@ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) -DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -418,6 +419,9 @@ { if (regs->eflags & VM_MASK) goto gp_in_vm86; + + if (kprobe_running() && kprobe_fault_handler(regs, 13)) + return; if (!(regs->xcs & 3)) goto gp_in_kernel; @@ -549,6 +553,17 @@ nmi_callback = dummy_nmi_callback; } +asmlinkage int do_int3(struct pt_regs *regs, long error_code) +{ + if (kprobe_handler(regs)) + return 1; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); + return 0; +} + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -571,7 +586,7 @@ * find every occurrence of the TF bit that could be saved away even * by user code) */ -asmlinkage void do_debug(struct pt_regs * regs, long error_code) +asmlinkage int do_debug(struct pt_regs * regs, long error_code) { unsigned int condition; struct task_struct *tsk = current; @@ -579,6 +594,15 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + if (post_kprobe_handler(regs)) + return 1; + + if (kwatch_handler(condition, regs)) + return 1; + + /* Interrupts not disabled for normal trap handling. */ + restore_interrupts(regs); + /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) @@ -626,18 +650,16 @@ * the signal is delivered. */ clear_dr7: - __asm__("movl %0,%%db7" - : /* no output */ - : "r" (0)); - return; + load_process_dr7(0); + return 0; debug_vm86: handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); - return; + return 0; clear_TF: regs->eflags &= ~TF_MASK; - return; + return 0; } /* @@ -801,6 +823,8 @@ struct task_struct *tsk = current; clts(); /* Allow maths ops (or we recurse) */ + if (kprobe_running() && kprobe_fault_handler(®s, 7)) + return; if (!tsk->used_math) init_fpu(tsk); restore_fpu(tsk); @@ -894,9 +918,9 @@ #endif set_trap_gate(0,÷_error); - set_trap_gate(1,&debug); + _set_gate(idt_table+1,14,3,&debug); /* debug trap for kprobes */ set_intr_gate(2,&nmi); - set_system_gate(3,&int3); /* int3-5 can be called from all */ + _set_gate(idt_table+3,14,3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); diff -Nur -X dontdiff linux-2.5/linux-2.5.47/arch/i386/mm/fault.c linux-2.5-kp/linux-2.5.47/arch/i386/mm/fault.c --- linux-2.5/linux-2.5.47/arch/i386/mm/fault.c Mon Nov 25 15:10:40 2002 +++ linux-2.5-kp/linux-2.5.47/arch/i386/mm/fault.c Mon Nov 25 15:12:20 2002 @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ +#include <linux/kprobes.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -163,6 +164,9 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + if (kprobe_running() && kprobe_fault_handler(regs, 14)) + return; + /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); diff -Nur -X dontdiff linux-2.5/linux-2.5.47/include/asm-i386/debugreg.h linux-2.5-kp/linux-2.5.47/include/asm-i386/debugreg.h --- linux-2.5/linux-2.5.47/include/asm-i386/debugreg.h Mon Nov 25 15:11:24 2002 +++ linux-2.5-kp/linux-2.5.47/include/asm-i386/debugreg.h Mon Nov 25 15:12:55 2002 @@ -61,4 +61,166 @@ #define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */ #define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */ +struct debugreg { + unsigned long flag; + unsigned long use_count; +}; + +/* debugreg flags */ +#define DR_UNUSED 0 +#define DR_LOCAL 1 +#define DR_GLOBAL 2 + +#define DR_MAX 4 +#define DR_ANY DR_MAX + 1 + +/* global or local allocation requests */ +#define DR_ALLOC_GLOBAL 0 +#define DR_ALLOC_LOCAL 1 + +#define DR7_RW_SET(dr, regnum, rw) do { \ + (dr) &= ~(0x3 << (16 + (4 * (regnum)))); \ + (dr) |= (((rw) & 0x3) << (16 + (4 * (regnum)))); \ + } while (0) + +#define DR7_RW_VAL(dr, regnum) \ + (((dr) >> (16 + (4 * (regnum)))) & 0x3) + +#define DR7_LEN_SET(dr, regnum, len) do { \ + (dr) &= ~(0x3 << (18 + (4 * (regnum)))); \ + (dr) |= (((len-1) & 0x3) << (18 + (4 * (regnum)))); \ + } while (0) + +#define DR7_LEN_VAL(dr, regnum) \ + (((dr) >> (18 + (4 * (regnum)))) & 0x3) + +#define DR7_L0(dr) (((dr))&0x1) +#define DR7_L1(dr) (((dr)>>2)&0x1) +#define DR7_L2(dr) (((dr)>>4)&0x1) +#define DR7_L3(dr) (((dr)>>6)&0x1) + +#define DR_IS_LOCAL(dr, num) ((dr) & (1UL << (num <<1))) + +/* Set the rw, len and global flag in dr7 for a debug register */ +#define SET_DR7(dr, regnum, access, len) do { \ + DR7_RW_SET(dr, regnum, access); \ + DR7_LEN_SET(dr, regnum, len); \ + dr |= (2UL << regnum*2); \ + } while (0) + +/* Disable a debug register by clearing the global/local flag in dr7 */ +#define RESET_DR7(dr, regnum) dr &= ~(3UL << regnum*2) + +#define DR7_DR0_BITS 0x000F0003 +#define DR7_DR1_BITS 0x00F0000C +#define DR7_DR2_BITS 0x0F000030 +#define DR7_DR3_BITS 0xF00000C0 + +#define DR_TRAP_MASK 0xF + +#define DR_TYPE_EXECUTE 0x0 +#define DR_TYPE_WRITE 0x1 +#define DR_TYPE_IO 0x2 +#define DR_TYPE_RW 0x3 + +#define get_dr(regnum, val) \ + __asm__("movl %%db" #regnum ", %0" \ + :"=r" (val)) +static inline unsigned long read_dr(int regnum) +{ + unsigned long val = 0; + switch (regnum) { + case 0: get_dr(0, val); break; + case 1: get_dr(1, val); break; + case 2: get_dr(2, val); break; + case 3: get_dr(3, val); break; + case 6: get_dr(6, val); break; + case 7: get_dr(7, val); break; + } + return val; +} +#undef get_dr + +#define set_dr(regnum, val) \ + __asm__("movl %0,%%db" #regnum \ + : /* no output */ \ + :"r" (val)) +static inline void write_dr(int regnum, unsigned long val) +{ + switch (regnum) { + case 0: set_dr(0, val); break; + case 1: set_dr(1, val); break; + case 2: set_dr(2, val); break; + case 3: set_dr(3, val); break; + case 7: set_dr(7, val); break; + } + return; +} +#undef set_dr + +/* + * Given the debug status register, returns the debug register number + * which caused the debug trap. + */ +static inline int dr_trap(unsigned int condition) +{ + int i, reg_shift = 1UL; + for (i = 0; i < DR_MAX; i++, reg_shift <<= 1) + if ((condition & reg_shift)) + return i; + return -1; +} + +/* + * Given the debug status register, returns the address due to which + * the debug trap occured. + */ +static inline unsigned long dr_trap_addr(unsigned int condition) +{ + int regnum = dr_trap(condition); + + if (regnum == -1) + return -1; + return read_dr(regnum); +} + +/* + * Given the debug status register, returns the type of debug trap: + * execute, read/write, write or io. + */ +static inline int dr_trap_type(unsigned int condition) +{ + int regnum = dr_trap(condition); + + if (regnum == -1) + return -1; + return DR7_RW_VAL(read_dr(7), regnum); +} + +/* Function declarations */ + +#ifdef CONFIG_DEBUGREG +extern int dr_alloc(int regnum, int flag); +extern int dr_free(int regnum); +extern void dr_inc_use_count(unsigned long mask); +extern void dr_dec_use_count(unsigned long mask); +extern struct debugreg dr_list[DR_MAX]; +extern unsigned long dr7_global_mask; +extern int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7); + +static inline void load_process_dr7(unsigned long curr_dr7) +{ + write_dr(7, (read_dr(7) & dr7_global_mask) | curr_dr7); +} +#else +static inline int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) { return 0; } +static inline void void load_process_dr7(unsigned long curr_dr7) +{ + write_dr(7, curr_dr7); +} + +static void dr_inc_use_count(unsigned long mask) { } +static void dr_dec_use_count(unsigned long mask) { } + +#endif /* CONFIG_DEBUGREG */ #endif diff -Nur -X dontdiff linux-2.5/linux-2.5.47/include/asm-i386/kprobes.h linux-2.5-kp/linux-2.5.47/include/asm-i386/kprobes.h --- linux-2.5/linux-2.5.47/include/asm-i386/kprobes.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/include/asm-i386/kprobes.h Mon Nov 25 15:12:57 2002 @@ -0,0 +1,34 @@ +#ifndef _ASM_KPROBES_H +#define _ASM_KPROBES_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 u8 kprobe_opcode_t; +#define BREAKPOINT_INSTRUCTION 0xcc + +/* trap3/1 are intr gates for kprobes. So, restore the status of IF, + * if necessary, before executing the original int3/1 (trap) handler. + */ +static inline void restore_interrupts(struct pt_regs *regs) +{ + if (regs->eflags & IF_MASK) + __asm__ __volatile__ ("sti"); +} + +#ifdef CONFIG_KPROBES +extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +extern int post_kprobe_handler(struct pt_regs *regs); +extern int kprobe_handler(struct pt_regs *regs); +#else /* !CONFIG_KPROBES */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { return 0; } +static inline int post_kprobe_handler(struct pt_regs *regs) { return 0; } +static inline int kprobe_handler(struct pt_regs *regs) { return 0; } +#endif +#endif /* _ASM_KPROBES_H */ diff -Nur -X dontdiff linux-2.5/linux-2.5.47/include/asm-i386/kwatch.h linux-2.5-kp/linux-2.5.47/include/asm-i386/kwatch.h --- linux-2.5/linux-2.5.47/include/asm-i386/kwatch.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/include/asm-i386/kwatch.h Mon Nov 25 15:12:57 2002 @@ -0,0 +1,31 @@ +#ifndef _ASM_KWATCH_H +#define _ASM_KWATCH_H +/* + * Dynamic Probes (kwatch points) support + * Vamsi Krishna S <vam...@in...>, Oct, 2002 + */ +#include <linux/types.h> +#include <linux/ptrace.h> + +struct kwatch; +typedef void (*kwatch_handler_t)(struct kwatch *, struct pt_regs *); + +struct kwatch { + unsigned long addr; /* location of watchpoint */ + u8 length; /* range of address */ + u8 type; /* type of watchpoint */ + kwatch_handler_t handler; +}; + +#define RF_MASK 0x00010000 + +#ifdef CONFIG_KWATCH +extern int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler); +extern void unregister_kwatch(int debugreg); +extern int kwatch_handler(unsigned long condition, struct pt_regs *regs); +#else +static inline int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler) { return -ENOSYS; } +static inline void unregister_kwatch(int debugreg) { } +static inline int kwatch_handler(unsigned long condition, struct pt_regs *regs) { return 0; } +#endif +#endif /* _ASM_KWATCH_H */ diff -Nur -X dontdiff linux-2.5/linux-2.5.47/include/linux/kprobes.h linux-2.5-kp/linux-2.5.47/include/linux/kprobes.h --- linux-2.5/linux-2.5.47/include/linux/kprobes.h Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/include/linux/kprobes.h Mon Nov 25 15:13:03 2002 @@ -0,0 +1,66 @@ +#ifndef _LINUX_KPROBES_H +#define _LINUX_KPROBES_H +#include <linux/config.h> +#include <linux/list.h> +#include <linux/fs.h> +#include <linux/notifier.h> +#include <linux/smp.h> +#include <asm/kprobes.h> + +struct kprobe; +struct pt_regs; + +typedef void (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *); +typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *, + unsigned long flags); +typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *, + int trapnr); +struct probe_at { + kprobe_opcode_t *addr; + struct inode *inode; /* for user space probes */ + unsigned long offset; /* for user space probes */ +}; + +struct kprobe { + struct list_head list; + + /* location of the probe point */ + struct probe_at at; + + /* Called before addr is executed. */ + kprobe_pre_handler_t pre_handler; + + /* Called after addr is executed, unless... */ + kprobe_post_handler_t post_handler; + + /* ... called if executing addr causes a fault (eg. page fault). + * Return 1 if it handled fault, otherwise kernel will see it. */ + kprobe_fault_handler_t fault_handler; + + /* Saved opcode (which has been replaced with breakpoint) */ + kprobe_opcode_t opcode; +}; + +#ifdef CONFIG_KPROBES +/* Locks kprobe: irq must be disabled */ +void lock_kprobes(void); +void unlock_kprobes(void); + +/* kprobe running now on this CPU? */ +static inline int kprobe_running(void) +{ + extern unsigned int kprobe_cpu; + return kprobe_cpu == smp_processor_id(); +} + +/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ +struct kprobe *get_kprobe(void *addr); + +int register_kprobe(struct kprobe *p); +void unregister_kprobe(struct kprobe *p); +#else +static inline int kprobe_running(void) { return 0; } +static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; } +static inline void unregister_kprobe(struct kprobe *p) { } +#endif +#endif /* _LINUX_KPROBES_H */ diff -Nur -X dontdiff linux-2.5/linux-2.5.47/kernel/Makefile linux-2.5-kp/linux-2.5.47/kernel/Makefile --- linux-2.5/linux-2.5.47/kernel/Makefile Mon Nov 25 15:11:37 2002 +++ linux-2.5-kp/linux-2.5.47/kernel/Makefile Mon Nov 25 15:13:04 2002 @@ -4,7 +4,7 @@ export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ printk.o platform.o suspend.o dma.o module.o cpufreq.o \ - profile.o rcupdate.o + profile.o rcupdate.o kprobes.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ module.o exit.o itimer.o time.o softirq.o resource.o \ @@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o +obj-$(CONFIG_KPROBES) += kprobes.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <al...@li...>, the -fno-omit-frame-pointer is diff -Nur -X dontdiff linux-2.5/linux-2.5.47/kernel/kprobes.c linux-2.5-kp/linux-2.5.47/kernel/kprobes.c --- linux-2.5/linux-2.5.47/kernel/kprobes.c Thu Jan 1 08:00:00 1970 +++ linux-2.5-kp/linux-2.5.47/kernel/kprobes.c Mon Nov 25 15:13:04 2002 @@ -0,0 +1,157 @@ +/* Support for kernel probes. + (C) 2002 Vamsi Krishna S <vam...@in...>. +*/ +#include <linux/kprobes.h> +#include <linux/spinlock.h> +#include <linux/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/cacheflush.h> +#include <asm/errno.h> + +#define KPROBE_HASH_BITS 6 +#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) + +static struct list_head kprobe_table[KPROBE_TABLE_SIZE]; + +unsigned int kprobe_cpu = NR_CPUS; +static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED; + +/* Locks kprobe: irqs must be disabled */ +void lock_kprobes(void) +{ + spin_lock(&kprobe_lock); + kprobe_cpu = smp_processor_id(); +} + +void unlock_kprobes(void) +{ + kprobe_cpu = NR_CPUS; + spin_unlock(&kprobe_lock); +} + +/* + * We need to look up the inode and offset from the vma. We can't depend on + * the page->(mapping, index) as that would be incorrect if we ever swap this + * page out (possible for pages which are dirtied by GDB breakpoints etc) + * + * We acquire page_table_lock here to ensure that: + * - current page doesn't go away from under us (kswapd) + * - mm->mmap consistancy (vma are always added under this lock) + * + * We will never deadlock on page_table_lock, we always come here due to a + * probe in user space, no kernel code could have executed to take the + * page_table_lock. + */ +static struct kprobe *get_uprobe_at(struct inode *inode, unsigned long offset) +{ + struct list_head *head; + struct kprobe *p; + + head = &kprobe_table[hash_long((unsigned long)inode*offset, + KPROBE_HASH_BITS)]; + list_for_each_entry(p, head, list) { + if (p->at.inode == inode && p->at.offset == offset) + return p; + } + return NULL; +} + +static struct kprobe *get_uprobe(void *addr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct inode *inode; + unsigned long offset; + + spin_lock(&mm->page_table_lock); + vma = find_vma(mm, (unsigned long)addr); + offset = (unsigned long)addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); + if (!vma->vm_file) { + spin_unlock(&mm->page_table_lock); + return NULL; + } + inode = vma->vm_file->f_dentry->d_inode; + spin_unlock(&mm->page_table_lock); + + return get_uprobe_at(inode, offset); +} + +/* You have to be holding the kprobe_lock */ +struct kprobe *get_kprobe(void *addr) +{ + struct list_head *head, *tmp; + + if ((unsigned long)addr < PAGE_OFFSET) + return get_uprobe(addr); + + head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)]; + list_for_each(tmp, head) { + struct kprobe *p = list_entry(tmp, struct kprobe, list); + if (p->at.addr == addr) + return p; + } + return NULL; +} + +/* + * p->at.addr has to be writeable address for uspace probes. + */ +int register_kprobe(struct kprobe *p) +{ + int ret = 0; + kprobe_opcode_t *addr = p->at.addr; + + spin_lock_irq(&kprobe_lock); + if (!p->at.inode) { + if (get_kprobe(addr)) { + ret = -EEXIST; + goto out; + } + list_add(&p->list, &kprobe_table[hash_ptr(addr, + KPROBE_HASH_BITS)]); + } else { + if (get_uprobe_at(p->at.inode, p->at.offset)) { + ret = -EEXIST; + goto out; + } + list_add(&p->list, + &kprobe_table[hash_long( + (unsigned long)p->at.inode * p->at.offset, + KPROBE_HASH_BITS)]); + } + + p->opcode = *addr; + *addr = BREAKPOINT_INSTRUCTION; + flush_icache_range(addr, addr + sizeof(kprobe_opcode_t)); + out: + spin_unlock_irq(&kprobe_lock); + return ret; +} + +void unregister_kprobe(struct kprobe *p) +{ + kprobe_opcode_t *addr = p->at.addr; + + spin_lock_irq(&kprobe_lock); + *addr = p->opcode; + list_del(&p->list); + flush_icache_range(addr, addr + sizeof(kprobe_opcode_t)); + spin_unlock_irq(&kprobe_lock); +} + +static int __init init_kprobes(void) +{ + int i; + + /* FIXME allocate the probe table, currently defined statically */ + /* initialize all list heads */ + for (i = 0; i < KPROBE_TABLE_SIZE; i++) + INIT_LIST_HEAD(&kprobe_table[i]); + + return 0; +} +__initcall(init_kprobes); + +EXPORT_SYMBOL_GPL(register_kprobe); +EXPORT_SYMBOL_GPL(unregister_kprobe); |
From: Zhuang, L. <lou...@in...> - 2002-11-25 10:04:15
|
Dear all, We'd like to put these patches as minimal as possible in order to give more feedback. Any comments, especially about the addon patches welcome. - Louis |
From: Zhuang, L. <lou...@in...> - 2002-11-21 02:23:31
|
Minimal implementation of FITH for LKML is uploaded. Please take a look it and give us comments. http://prdownloads.sourceforge.net/fault-injection/fith-mini-5.tgz?download |
From: Zhuang, L. <lou...@in...> - 2002-11-15 10:02:08
|
Hi Folks, This is a kernel patch needed by FITH, which should be applied on 2. 5.47 kernel plus kprobes-2-4in1-1 - Louis diff -Nur -X /root/dontdiff 47-kp/Makefile 47-kp-fi/Makefile --- 47-kp/Makefile Mon Nov 11 11:28:04 2002 +++ 47-kp-fi/Makefile Fri Nov 15 17:25:20 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 47 -EXTRAVERSION = +EXTRAVERSION =kp-fi # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -Nur -X /root/dontdiff 47-kp/arch/i386/Kconfig 47-kp-fi/arch/i386/Kconfig --- 47-kp/arch/i386/Kconfig Fri Nov 15 17:22:47 2002 +++ 47-kp-fi/arch/i386/Kconfig Fri Nov 15 17:31:49 2002 @@ -1562,11 +1562,20 @@ config DEBUGREG bool "Global Debug Registers" - depend on DEBUG_KERNEL + depends on DEBUG_KERNEL + help config KWATCH bool "Kwatch points" - depend on DEBUGREG + depends on DEBUGREG + help + +config FI + bool "Fault Injection" + depends on KPROBES + help + Say Y here if you want to enable Fault Injection (FI) mechanism. + The FI can monitor MMIO/IO access in kernel. config DEBUG_STACKOVERFLOW bool "Check for stack overflows" diff -Nur -X /root/dontdiff 47-kp/arch/i386/kernel/i386_ksyms.c 47-kp-fi/arch/i386/kernel/i386_ksyms.c --- 47-kp/arch/i386/kernel/i386_ksyms.c Mon Nov 11 11:28:32 2002 +++ 47-kp-fi/arch/i386/kernel/i386_ksyms.c Fri Nov 15 17:25:20 2002 @@ -32,6 +32,7 @@ #include <asm/tlbflush.h> #include <asm/nmi.h> #include <asm/edd.h> +#include <asm/fi.h> extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -216,3 +217,9 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif + +#ifdef CONFIG_FI +EXPORT_SYMBOL(irq_desc); +EXPORT_SYMBOL(fi_page_fault); +EXPORT_SYMBOL(fi_post_page_fault); +#endif diff -Nur -X /root/dontdiff 47-kp/arch/i386/kernel/traps.c 47-kp-fi/arch/i386/kernel/traps.c --- 47-kp/arch/i386/kernel/traps.c Fri Nov 15 17:20:45 2002 +++ 47-kp-fi/arch/i386/kernel/traps.c Fri Nov 15 17:25:20 2002 @@ -47,6 +47,7 @@ #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> @@ -564,6 +565,9 @@ return 0; } +int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -599,7 +603,10 @@ if (kwatch_handler(condition, regs)) return 1; - +#ifdef CONFIG_FI + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) + return 1; +#endif /* Interrupts not disabled for normal trap handling. */ restore_interrupts(regs); diff -Nur -X /root/dontdiff 47-kp/arch/i386/mm/fault.c 47-kp-fi/arch/i386/mm/fault.c --- 47-kp/arch/i386/mm/fault.c Thu Nov 14 15:22:14 2002 +++ 47-kp-fi/arch/i386/mm/fault.c Fri Nov 15 17:25:20 2002 @@ -26,6 +26,7 @@ #include <asm/pgalloc.h> #include <asm/hardirq.h> #include <asm/desc.h> +#include <asm/fi.h> extern void die(const char *,struct pt_regs *,long); @@ -139,6 +140,7 @@ } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); +int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); /* * This routine handles page faults. It determines the address, @@ -166,7 +168,10 @@ if (kprobe_running() && kprobe_fault_handler(regs, 14)) return; - +#ifdef CONFIG_FI + if (fi_page_fault && fi_page_fault(regs, address)) + return; +#endif /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); diff -Nur -X /root/dontdiff 47-kp/drivers/net/e100/e100.h 47-kp-fi/drivers/net/e100/e100.h --- 47-kp/drivers/net/e100/e100.h Mon Nov 11 11:28:07 2002 +++ 47-kp-fi/drivers/net/e100/e100.h Fri Nov 15 17:25:20 2002 @@ -100,7 +100,7 @@ #define E100_MAX_NIC 16 -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ /* HWI feature related constant */ diff -Nur -X /root/dontdiff 47-kp/include/asm-i386/fi.h 47-kp-fi/include/asm-i386/fi.h --- 47-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 +++ 47-kp-fi/include/asm-i386/fi.h Fri Nov 15 17:25:20 2002 @@ -0,0 +1,8 @@ +#ifndef _ASM_FI_H +#define _ASM_FI_H +#ifdef CONFIG_FI +extern int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); +extern int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); +#endif +#endif /* _ASM_FI_H */ diff -Nur -X /root/dontdiff 47-kp/kernel/ksyms.c 47-kp-fi/kernel/ksyms.c --- 47-kp/kernel/ksyms.c Mon Nov 11 11:28:02 2002 +++ 47-kp-fi/kernel/ksyms.c Fri Nov 15 17:25:20 2002 @@ -601,3 +601,7 @@ /* debug */ EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_FI +EXPORT_SYMBOL(module_list); +#endif |
From: Zhuang, L. <lou...@in...> - 2002-11-15 09:58:22
|
Hi Folks, I've ported current kprobes into 2.5.47. The effort is a all-in-one patch including kprobes, debug register, kwatch, user space. - Louis diff -Nur -X /root/dontdiff 47/arch/i386/Kconfig 47-kp/arch/i386/Kconfig --- 47/arch/i386/Kconfig Mon Nov 11 11:28:05 2002 +++ 47-kp/arch/i386/Kconfig Fri Nov 15 17:22:47 2002 @@ -1551,6 +1551,23 @@ Say Y here if you are developing drivers or trying to debug and identify kernel problems. +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address, using + register_kprobe(), and providing a callback function. This is useful + for kernel debugging, non-intrusive instrumentation and testing. If + in doubt, say "N". + +config DEBUGREG + bool "Global Debug Registers" + depend on DEBUG_KERNEL + +config KWATCH + bool "Kwatch points" + depend on DEBUGREG + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nur -X /root/dontdiff 47/arch/i386/kernel/Makefile 47-kp/arch/i386/kernel/Makefile --- 47/arch/i386/kernel/Makefile Mon Nov 11 11:28:05 2002 +++ 47-kp/arch/i386/kernel/Makefile Fri Nov 15 17:20:45 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 debugreg.o kwatch.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 \ @@ -28,6 +28,9 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_DEBUGREG) += debugreg.o +obj-$(CONFIG_KWATCH) += kwatch.o EXTRA_AFLAGS := -traditional diff -Nur -X /root/dontdiff 47/arch/i386/kernel/debugreg.c 47-kp/arch/i386/kernel/debugreg.c --- 47/arch/i386/kernel/debugreg.c Thu Jan 1 08:00:00 1970 +++ 47-kp/arch/i386/kernel/debugreg.c Fri Nov 15 17:16:10 2002 @@ -0,0 +1,178 @@ +/* + * This provides a debug register allocation mechanism, to be + * used by all debuggers, which need debug registers. + * + * Author: vam...@in... + * bh...@in... + */ +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <asm/system.h> +#include <asm/debugreg.h> + +struct debugreg dr_list[DR_MAX]; +unsigned long dr7_global_mask = 0; +static spinlock_t dr_lock = SPIN_LOCK_UNLOCKED; + +static inline void set_dr7_global_mask(int regnum) +{ + switch (regnum) { + case 0: dr7_global_mask |= DR7_DR0_BITS; break; + case 1: dr7_global_mask |= DR7_DR1_BITS; break; + case 2: dr7_global_mask |= DR7_DR2_BITS; break; + case 3: dr7_global_mask |= DR7_DR3_BITS; break; + } + return; +} + +static inline void clear_dr7_global_mask(int regnum) +{ + switch (regnum) { + case 0: dr7_global_mask &= ~DR7_DR0_BITS; break; + case 1: dr7_global_mask &= ~DR7_DR1_BITS; break; + case 2: dr7_global_mask &= ~DR7_DR2_BITS; break; + case 3: dr7_global_mask &= ~DR7_DR3_BITS; break; + } + return; +} + +static int get_dr(int regnum, int flag) +{ + if ((flag == DR_ALLOC_GLOBAL) && (dr_list[regnum].flag == DR_UNUSED)) { + dr_list[regnum].flag = DR_GLOBAL; + set_dr7_global_mask(regnum); + return regnum; + } + else if ((dr_list[regnum].flag == DR_UNUSED) || (dr_list[regnum].flag == DR_LOCAL)) { + dr_list[regnum].use_count++; + dr_list[regnum].flag = DR_LOCAL; + return regnum; + } + return -1; +} + +static int get_any_dr(int flag) +{ + int i; + if (flag == DR_ALLOC_LOCAL) { + for (i = 0; i < DR_MAX; i++) { + if (dr_list[i].flag == DR_LOCAL) { + dr_list[i].use_count++; + return i; + } else if (dr_list[i].flag == DR_UNUSED) { + dr_list[i].flag = DR_LOCAL; + dr_list[i].use_count = 1; + return i; + } + } + } else { + for (i = DR_MAX-1; i >= 0; i--) { + if (dr_list[i].flag == DR_UNUSED) { + dr_list[i].flag = DR_GLOBAL; + set_dr7_global_mask(i); + return i; + } + } + } + return -1; +} + +static inline void dr_free_local(int regnum) +{ + if (! (--dr_list[regnum].use_count)) + dr_list[regnum].flag = DR_UNUSED; + return; +} + +static inline void dr_free_global(int regnum) +{ + dr_list[regnum].flag = DR_UNUSED; + dr_list[regnum].use_count = 0; + clear_dr7_global_mask(regnum); + return; +} + +int dr_alloc(int regnum, int flag) +{ + int ret; + + spin_lock(&dr_lock); + if (regnum == DR_ANY) + ret = get_any_dr(flag); + else if (regnum >= DR_MAX) + ret = -1; + else + ret = get_dr(regnum, flag); + spin_unlock(&dr_lock); + return ret; +} + +int dr_free(int regnum) +{ + spin_lock(&dr_lock); + if (regnum >= DR_MAX || dr_list[regnum].flag == DR_UNUSED) { + spin_unlock(&dr_lock); + return -1; + } + if (dr_list[regnum].flag == DR_LOCAL) + dr_free_local(regnum); + else + dr_free_global(regnum); + spin_unlock(&dr_lock); + return 0; +} + +void dr_inc_use_count(unsigned long mask) +{ + int i; + + spin_lock(&dr_lock); + for (i =0; i < DR_MAX; i++) { + if (DR_IS_LOCAL(mask, i)) + dr_list[i].use_count++; + } + spin_unlock(&dr_lock); +} + +void dr_dec_use_count(unsigned long mask) +{ + int i; + + spin_lock(&dr_lock); + for (i =0; i < DR_MAX; i++) { + if (DR_IS_LOCAL(mask, i)) + dr_free_local(i); + } + spin_unlock(&dr_lock); +} + +/* + * This routine decides if the ptrace request is for enabling or disabling + * a debug reg, and accordingly calls dr_alloc() or dr_free(). + * + * gdb uses ptrace to write to debug registers. It assumes that writing to + * debug register always succeds and it doesn't check the return value of + * ptrace. Now with this new global debug register allocation/freeing, + * ptrace request for a local debug register can fail, if the required debug + * register is already globally allocated. Since gdb fails to notice this + * failure, it sometimes tries to free a debug register, which is not + * allocated for it. + */ +int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) +{ + int i, dr_shift = 1UL; + for (i = 0; i < DR_MAX; i++, dr_shift <<= 2) { + if ((old_dr7 ^ new_dr7) & dr_shift) { + if (new_dr7 & dr_shift) + dr_alloc(i, DR_ALLOC_LOCAL); + else + dr_free(i); + return 0; + } + } + return -1; +} + +EXPORT_SYMBOL(dr_alloc); +EXPORT_SYMBOL(dr_free); diff -Nur -X /root/dontdiff 47/arch/i386/kernel/entry.S 47-kp/arch/i386/kernel/entry.S --- 47/arch/i386/kernel/entry.S Mon Nov 11 11:28:06 2002 +++ 47-kp/arch/i386/kernel/entry.S Thu Nov 14 15:22:14 2002 @@ -404,9 +404,16 @@ jmp ret_from_exception ENTRY(debug) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_debug - jmp error_code + pushl %edx + call do_debug + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(nmi) pushl %eax @@ -419,9 +426,16 @@ RESTORE_ALL ENTRY(int3) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_int3 - jmp error_code + pushl %edx + call do_int3 + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(overflow) pushl $0 diff -Nur -X /root/dontdiff 47/arch/i386/kernel/kprobes.c 47-kp/arch/i386/kernel/kprobes.c --- 47/arch/i386/kernel/kprobes.c Thu Jan 1 08:00:00 1970 +++ 47-kp/arch/i386/kernel/kprobes.c Fri Nov 15 17:21:23 2002 @@ -0,0 +1,170 @@ +/* + * Support for kernel probes. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ + +#include <linux/config.h> +#include <linux/kprobes.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/preempt.h> + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; + +/* + * returns non-zero if opcode modifies the interrupt flag. + */ +static inline int is_IF_modifier(u8 opcode) +{ + switch(opcode) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ + case 0xcf: /* iret/iretd */ + case 0x9d: /* popf/popfd */ + return 1; + } + return 0; +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + if (!p->at.inode) { + /* remember the address to be used when rearming the probe. */ + p->at.addr = (void *)(regs->eip - 1); + } + *p->at.addr = p->opcode; + regs->eip = (unsigned long)p->at.addr; +} + +/* + * Interrupts are disabled on entry as trap3 is an interrupt gate and they + * remain disabled thorough out this function. + */ +int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + u8 *addr = (u8 *)(regs->eip-1); + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + Disarm the probe we just hit, and ignore it. */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + /* Unregistered (on another cpu) after this hit? Ignore */ + if (*addr != BREAKPOINT_INSTRUCTION) + ret = 1; + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + kprobe_saved_eflags = kprobe_old_eflags + = (regs->eflags & (TF_MASK|IF_MASK)); + if (is_IF_modifier(p->opcode)) + kprobe_saved_eflags &= ~IF_MASK; + + p->pre_handler(p, regs); + + regs->eflags |= TF_MASK; + regs->eflags &= ~IF_MASK; + + /* We hold lock, now we remove breakpoint and single step. */ + disarm_kprobe(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +static void rearm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + regs->eflags &= ~TF_MASK; + *p->at.addr = BREAKPOINT_INSTRUCTION; +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thorough out this function. And we hold kprobe lock. + */ +int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + /* + * We singlestepped with interrupts disabled. So, the result on + * the stack would be incorrect for "pushfl" instruction. + * Note that regs->esp is actually the top of the stack when the + * trap occurs in kernel space. + */ + if (current_kprobe->opcode == 0x9c) { /* pushfl */ + unsigned long *tos; + + if (regs->eip > PAGE_OFFSET) + tos = ®s->esp; + else + tos = (unsigned long *)regs->esp; + *tos &= ~(TF_MASK | IF_MASK); + *tos |= kprobe_old_eflags; + } + + rearm_kprobe(current_kprobe, regs); + regs->eflags |= kprobe_saved_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + + /* + * if somebody else is singlestepping across a probe point, eflags + * will have TF set, in which case, continue the remaining processing + * of do_debug, as if this is not a probe hit. + */ + if (regs->eflags & TF_MASK) + return 0; + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + rearm_kprobe(current_kprobe, regs); + regs->eflags |= kprobe_old_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} diff -Nur -X /root/dontdiff 47/arch/i386/kernel/kwatch.c 47-kp/arch/i386/kernel/kwatch.c --- 47/arch/i386/kernel/kwatch.c Thu Jan 1 08:00:00 1970 +++ 47-kp/arch/i386/kernel/kwatch.c Fri Nov 15 17:20:45 2002 @@ -0,0 +1,135 @@ +/* + * Support for kernel watchpoints. + * (C) 2002 Vamsi Krishna S <vam...@in...>. + */ +#include <linux/config.h> +#include <linux/kprobes.h> +#include <linux/ptrace.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <asm/kwatch.h> +#include <asm/debugreg.h> +#include <asm/bitops.h> + +static struct kwatch kwatch_list[DR_MAX]; +static spinlock_t kwatch_lock = SPIN_LOCK_UNLOCKED; +static unsigned long kwatch_in_progress; /* currently being handled */ + +struct dr_info { + int debugreg; + unsigned long addr; + int type; +}; + +static inline void write_smp_dr(void *info) +{ + struct dr_info *dr = (struct dr_info *)info; + + if (cpu_has_de && dr->type == DR_TYPE_IO) + set_in_cr4(X86_CR4_DE); + write_dr(dr->debugreg, dr->addr); +} + +/* Update the debug register on all CPUs */ +static void sync_dr(int debugreg, unsigned long addr, int type) +{ + struct dr_info dr; + dr.debugreg = debugreg; + dr.addr = addr; + dr.type = type; + smp_call_function(write_smp_dr, &dr, 0, 0); +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thorough out this function. + */ +int kwatch_handler(unsigned long condition, struct pt_regs *regs) +{ + int debugreg = dr_trap(condition); + unsigned long addr = dr_trap_addr(condition); + int retval = 0; + + if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) { + return 0; + } + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* If we are recursing, we already hold the lock. */ + if (kwatch_in_progress) { + goto recursed; + } + set_bit(debugreg, &kwatch_in_progress); + + spin_lock(&kwatch_lock); + if (kwatch_list[debugreg].addr != addr) + goto out; + + if (kwatch_list[debugreg].handler) { + kwatch_list[debugreg].handler(&kwatch_list[debugreg], regs); + } + + if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE) + regs->eflags |= RF_MASK; +out: + clear_bit(debugreg, &kwatch_in_progress); + spin_unlock(&kwatch_lock); + preempt_enable_no_resched(); + return retval; + +recursed: + if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE) + regs->eflags |= RF_MASK; + preempt_enable_no_resched(); + return 1; +} + +int register_kwatch(unsigned long addr, u8 length, u8 type, + kwatch_handler_t handler) +{ + int debugreg; + unsigned long dr7, flags; + + debugreg = dr_alloc(DR_ANY, DR_ALLOC_GLOBAL); + if (debugreg < 0) { + return -1; + } + + spin_lock_irqsave(&kwatch_lock, flags); + kwatch_list[debugreg].addr = addr; + kwatch_list[debugreg].length = length; + kwatch_list[debugreg].type = type; + kwatch_list[debugreg].handler = handler; + spin_unlock_irqrestore(&kwatch_lock, flags); + + write_dr(debugreg, (unsigned long)addr); + sync_dr(debugreg, (unsigned long)addr, type); + if (cpu_has_de && type == DR_TYPE_IO) + set_in_cr4(X86_CR4_DE); + + dr7 = read_dr(7); + SET_DR7(dr7, debugreg, type, length); + write_dr(7, dr7); + sync_dr(7, dr7, 0); + return debugreg; +} + +void unregister_kwatch(int debugreg) +{ + unsigned long flags; + unsigned long dr7 = read_dr(7); + + RESET_DR7(dr7, debugreg); + write_dr(7, dr7); + sync_dr(7, dr7, 0); + dr_free(debugreg); + + spin_lock_irqsave(&kwatch_lock, flags); + kwatch_list[debugreg].addr = 0; + kwatch_list[debugreg].handler = NULL; + spin_unlock_irqrestore(&kwatch_lock, flags); +} +EXPORT_SYMBOL_GPL(register_kwatch); +EXPORT_SYMBOL_GPL(unregister_kwatch); diff -Nur -X /root/dontdiff 47/arch/i386/kernel/process.c 47-kp/arch/i386/kernel/process.c --- 47/arch/i386/kernel/process.c Mon Nov 11 11:28:01 2002 +++ 47-kp/arch/i386/kernel/process.c Fri Nov 15 17:16:10 2002 @@ -47,6 +47,7 @@ #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif +#include <asm/debugreg.h> #include <linux/irq.h> #include <linux/err.h> @@ -241,12 +242,16 @@ kfree(tsk->thread.ts_io_bitmap); tsk->thread.ts_io_bitmap = NULL; } + if (tsk->thread.debugreg[7]) + dr_dec_use_count(tsk->thread.debugreg[7]); } void flush_thread(void) { struct task_struct *tsk = current; + if (tsk->thread.debugreg[7]) + dr_dec_use_count(tsk->thread.debugreg[7]); memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* @@ -330,6 +335,9 @@ desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } + + if (current->thread.debugreg[7]) + dr_inc_use_count(current->thread.debugreg[7]); return 0; } @@ -464,6 +472,24 @@ /* * Now maybe reload the debug registers */ +#ifdef CONFIG_DEBUGREG +{ + /* + * Don't reload global debug registers. Don't touch the global debug + * register settings in dr7. + */ + unsigned long next_dr7 = next->debugreg[7]; + if (unlikely(next_dr7)) { + if (DR7_L0(next_dr7)) loaddebug(next, 0); + if (DR7_L1(next_dr7)) loaddebug(next, 1); + if (DR7_L2(next_dr7)) loaddebug(next, 2); + if (DR7_L3(next_dr7)) loaddebug(next, 3); + /* no 4 and 5 */ + loaddebug(next, 6); + load_process_dr7(next_dr7); + } +} +#else if (unlikely(next->debugreg[7])) { loaddebug(next, 0); loaddebug(next, 1); @@ -473,7 +499,7 @@ loaddebug(next, 6); loaddebug(next, 7); } - +#endif if (unlikely(prev->ts_io_bitmap || next->ts_io_bitmap)) { if (next->ts_io_bitmap) { /* diff -Nur -X /root/dontdiff 47/arch/i386/kernel/ptrace.c 47-kp/arch/i386/kernel/ptrace.c --- 47/arch/i386/kernel/ptrace.c Mon Nov 11 11:28:07 2002 +++ 47-kp/arch/i386/kernel/ptrace.c Fri Nov 15 17:16:10 2002 @@ -269,6 +269,11 @@ addr -= (long) &dummy->u_debugreg; addr = addr >> 2; + + if (addr == 7 && (enable_debugreg(child->thread.debugreg[addr], data)) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg[addr] = data; ret = 0; } diff -Nur -X /root/dontdiff 47/arch/i386/kernel/signal.c 47-kp/arch/i386/kernel/signal.c --- 47/arch/i386/kernel/signal.c Mon Nov 11 11:28:12 2002 +++ 47-kp/arch/i386/kernel/signal.c Fri Nov 15 17:16:10 2002 @@ -22,6 +22,7 @@ #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/debugreg.h> #define DEBUG_SIG 0 @@ -574,7 +575,7 @@ * have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7])); + load_process_dr7(current->thread.debugreg[7]); /* Whee! Actually deliver the signal. */ handle_signal(signr, &info, oldset, regs); diff -Nur -X /root/dontdiff 47/arch/i386/kernel/traps.c 47-kp/arch/i386/kernel/traps.c --- 47/arch/i386/kernel/traps.c Mon Nov 11 11:28:05 2002 +++ 47-kp/arch/i386/kernel/traps.c Fri Nov 15 17:20:45 2002 @@ -23,6 +23,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/highmem.h> +#include <linux/kprobes.h> #ifdef CONFIG_EISA #include <linux/ioport.h> @@ -38,6 +39,7 @@ #include <asm/io.h> #include <asm/atomic.h> #include <asm/debugreg.h> +#include <asm/kwatch.h> #include <asm/desc.h> #include <asm/i387.h> #include <asm/nmi.h> @@ -402,7 +404,6 @@ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) -DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -418,6 +419,9 @@ { if (regs->eflags & VM_MASK) goto gp_in_vm86; + + if (kprobe_running() && kprobe_fault_handler(regs, 13)) + return; if (!(regs->xcs & 3)) goto gp_in_kernel; @@ -549,6 +553,17 @@ nmi_callback = dummy_nmi_callback; } +asmlinkage int do_int3(struct pt_regs *regs, long error_code) +{ + if (kprobe_handler(regs)) + return 1; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); + return 0; +} + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -571,7 +586,7 @@ * find every occurrence of the TF bit that could be saved away even * by user code) */ -asmlinkage void do_debug(struct pt_regs * regs, long error_code) +asmlinkage int do_debug(struct pt_regs * regs, long error_code) { unsigned int condition; struct task_struct *tsk = current; @@ -579,6 +594,15 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + if (post_kprobe_handler(regs)) + return 1; + + if (kwatch_handler(condition, regs)) + return 1; + + /* Interrupts not disabled for normal trap handling. */ + restore_interrupts(regs); + /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) @@ -626,18 +650,16 @@ * the signal is delivered. */ clear_dr7: - __asm__("movl %0,%%db7" - : /* no output */ - : "r" (0)); - return; + load_process_dr7(0); + return 0; debug_vm86: handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); - return; + return 0; clear_TF: regs->eflags &= ~TF_MASK; - return; + return 0; } /* @@ -801,6 +823,8 @@ struct task_struct *tsk = current; clts(); /* Allow maths ops (or we recurse) */ + if (kprobe_running() && kprobe_fault_handler(®s, 7)) + return; if (!tsk->used_math) init_fpu(tsk); restore_fpu(tsk); @@ -894,9 +918,9 @@ #endif set_trap_gate(0,÷_error); - set_trap_gate(1,&debug); + _set_gate(idt_table+1,14,3,&debug); /* debug trap for kprobes */ set_intr_gate(2,&nmi); - set_system_gate(3,&int3); /* int3-5 can be called from all */ + _set_gate(idt_table+3,14,3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); diff -Nur -X /root/dontdiff 47/arch/i386/mm/fault.c 47-kp/arch/i386/mm/fault.c --- 47/arch/i386/mm/fault.c Mon Nov 11 11:28:01 2002 +++ 47-kp/arch/i386/mm/fault.c Thu Nov 14 15:22:14 2002 @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ +#include <linux/kprobes.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -163,6 +164,9 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + if (kprobe_running() && kprobe_fault_handler(regs, 14)) + return; + /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); diff -Nur -X /root/dontdiff 47/include/asm-i386/debugreg.h 47-kp/include/asm-i386/debugreg.h --- 47/include/asm-i386/debugreg.h Mon Nov 11 11:28:28 2002 +++ 47-kp/include/asm-i386/debugreg.h Fri Nov 15 17:16:10 2002 @@ -61,4 +61,166 @@ #define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */ #define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */ +struct debugreg { + unsigned long flag; + unsigned long use_count; +}; + +/* debugreg flags */ +#define DR_UNUSED 0 +#define DR_LOCAL 1 +#define DR_GLOBAL 2 + +#define DR_MAX 4 +#define DR_ANY DR_MAX + 1 + +/* global or local allocation requests */ +#define DR_ALLOC_GLOBAL 0 +#define DR_ALLOC_LOCAL 1 + +#define DR7_RW_SET(dr, regnum, rw) do { \ + (dr) &= ~(0x3 << (16 + (4 * (regnum)))); \ + (dr) |= (((rw) & 0x3) << (16 + (4 * (regnum)))); \ + } while (0) + +#define DR7_RW_VAL(dr, regnum) \ + (((dr) >> (16 + (4 * (regnum)))) & 0x3) + +#define DR7_LEN_SET(dr, regnum, len) do { \ + (dr) &= ~(0x3 << (18 + (4 * (regnum)))); \ + (dr) |= (((len-1) & 0x3) << (18 + (4 * (regnum)))); \ + } while (0) + +#define DR7_LEN_VAL(dr, regnum) \ + (((dr) >> (18 + (4 * (regnum)))) & 0x3) + +#define DR7_L0(dr) (((dr))&0x1) +#define DR7_L1(dr) (((dr)>>2)&0x1) +#define DR7_L2(dr) (((dr)>>4)&0x1) +#define DR7_L3(dr) (((dr)>>6)&0x1) + +#define DR_IS_LOCAL(dr, num) ((dr) & (1UL << (num <<1))) + +/* Set the rw, len and global flag in dr7 for a debug register */ +#define SET_DR7(dr, regnum, access, len) do { \ + DR7_RW_SET(dr, regnum, access); \ + DR7_LEN_SET(dr, regnum, len); \ + dr |= (2UL << regnum*2); \ + } while (0) + +/* Disable a debug register by clearing the global/local flag in dr7 */ +#define RESET_DR7(dr, regnum) dr &= ~(3UL << regnum*2) + +#define DR7_DR0_BITS 0x000F0003 +#define DR7_DR1_BITS 0x00F0000C +#define DR7_DR2_BITS 0x0F000030 +#define DR7_DR3_BITS 0xF00000C0 + +#define DR_TRAP_MASK 0xF + +#define DR_TYPE_EXECUTE 0x0 +#define DR_TYPE_WRITE 0x1 +#define DR_TYPE_IO 0x2 +#define DR_TYPE_RW 0x3 + +#define get_dr(regnum, val) \ + __asm__("movl %%db" #regnum ", %0" \ + :"=r" (val)) +static inline unsigned long read_dr(int regnum) +{ + unsigned long val = 0; + switch (regnum) { + case 0: get_dr(0, val); break; + case 1: get_dr(1, val); break; + case 2: get_dr(2, val); break; + case 3: get_dr(3, val); break; + case 6: get_dr(6, val); break; + case 7: get_dr(7, val); break; + } + return val; +} +#undef get_dr + +#define set_dr(regnum, val) \ + __asm__("movl %0,%%db" #regnum \ + : /* no output */ \ + :"r" (val)) +static inline void write_dr(int regnum, unsigned long val) +{ + switch (regnum) { + case 0: set_dr(0, val); break; + case 1: set_dr(1, val); break; + case 2: set_dr(2, val); break; + case 3: set_dr(3, val); break; + case 7: set_dr(7, val); break; + } + return; +} +#undef set_dr + +/* + * Given the debug status register, returns the debug register number + * which caused the debug trap. + */ +static inline int dr_trap(unsigned int condition) +{ + int i, reg_shift = 1UL; + for (i = 0; i < DR_MAX; i++, reg_shift <<= 1) + if ((condition & reg_shift)) + return i; + return -1; +} + +/* + * Given the debug status register, returns the address due to which + * the debug trap occured. + */ +static inline unsigned long dr_trap_addr(unsigned int condition) +{ + int regnum = dr_trap(condition); + + if (regnum == -1) + return -1; + return read_dr(regnum); +} + +/* + * Given the debug status register, returns the type of debug trap: + * execute, read/write, write or io. + */ +static inline int dr_trap_type(unsigned int condition) +{ + int regnum = dr_trap(condition); + + if (regnum == -1) + return -1; + return DR7_RW_VAL(read_dr(7), regnum); +} + +/* Function declarations */ + +#ifdef CONFIG_DEBUGREG +extern int dr_alloc(int regnum, int flag); +extern int dr_free(int regnum); +extern void dr_inc_use_count(unsigned long mask); +extern void dr_dec_use_count(unsigned long mask); +extern struct debugreg dr_list[DR_MAX]; +extern unsigned long dr7_global_mask; +extern int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7); + +static inline void load_process_dr7(unsigned long curr_dr7) +{ + write_dr(7, (read_dr(7) & dr7_global_mask) | curr_dr7); +} +#else +static inline int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) { return 0; } +static inline void void load_process_dr7(unsigned long curr_dr7) +{ + write_dr(7, curr_dr7); +} + +static void dr_inc_use_count(unsigned long mask) { } +static void dr_dec_use_count(unsigned long mask) { } + +#endif /* CONFIG_DEBUGREG */ #endif diff -Nur -X /root/dontdiff 47/include/asm-i386/kprobes.h 47-kp/include/asm-i386/kprobes.h --- 47/include/asm-i386/kprobes.h Thu Jan 1 08:00:00 1970 +++ 47-kp/include/asm-i386/kprobes.h Thu Nov 14 15:22:14 2002 @@ -0,0 +1,34 @@ +#ifndef _ASM_KPROBES_H +#define _ASM_KPROBES_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 u8 kprobe_opcode_t; +#define BREAKPOINT_INSTRUCTION 0xcc + +/* trap3/1 are intr gates for kprobes. So, restore the status of IF, + * if necessary, before executing the original int3/1 (trap) handler. + */ +static inline void restore_interrupts(struct pt_regs *regs) +{ + if (regs->eflags & IF_MASK) + __asm__ __volatile__ ("sti"); +} + +#ifdef CONFIG_KPROBES +extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +extern int post_kprobe_handler(struct pt_regs *regs); +extern int kprobe_handler(struct pt_regs *regs); +#else /* !CONFIG_KPROBES */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { return 0; } +static inline int post_kprobe_handler(struct pt_regs *regs) { return 0; } +static inline int kprobe_handler(struct pt_regs *regs) { return 0; } +#endif +#endif /* _ASM_KPROBES_H */ diff -Nur -X /root/dontdiff 47/include/asm-i386/kwatch.h 47-kp/include/asm-i386/kwatch.h --- 47/include/asm-i386/kwatch.h Thu Jan 1 08:00:00 1970 +++ 47-kp/include/asm-i386/kwatch.h Fri Nov 15 17:20:45 2002 @@ -0,0 +1,31 @@ +#ifndef _ASM_KWATCH_H +#define _ASM_KWATCH_H +/* + * Dynamic Probes (kwatch points) support + * Vamsi Krishna S <vam...@in...>, Oct, 2002 + */ +#include <linux/types.h> +#include <linux/ptrace.h> + +struct kwatch; +typedef void (*kwatch_handler_t)(struct kwatch *, struct pt_regs *); + +struct kwatch { + unsigned long addr; /* location of watchpoint */ + u8 length; /* range of address */ + u8 type; /* type of watchpoint */ + kwatch_handler_t handler; +}; + +#define RF_MASK 0x00010000 + +#ifdef CONFIG_KWATCH +extern int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler); +extern void unregister_kwatch(int debugreg); +extern int kwatch_handler(unsigned long condition, struct pt_regs *regs); +#else +static inline int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler) { return -ENOSYS; } +static inline void unregister_kwatch(int debugreg) { } +static inline int kwatch_handler(unsigned long condition, struct pt_regs *regs) { return 0; } +#endif +#endif /* _ASM_KWATCH_H */ diff -Nur -X /root/dontdiff 47/include/linux/kprobes.h 47-kp/include/linux/kprobes.h --- 47/include/linux/kprobes.h Thu Jan 1 08:00:00 1970 +++ 47-kp/include/linux/kprobes.h Fri Nov 15 17:21:23 2002 @@ -0,0 +1,66 @@ +#ifndef _LINUX_KPROBES_H +#define _LINUX_KPROBES_H +#include <linux/config.h> +#include <linux/list.h> +#include <linux/fs.h> +#include <linux/notifier.h> +#include <linux/smp.h> +#include <asm/kprobes.h> + +struct kprobe; +struct pt_regs; + +typedef void (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *); +typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *, + unsigned long flags); +typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *, + int trapnr); +struct probe_at { + kprobe_opcode_t *addr; + struct inode *inode; /* for user space probes */ + unsigned long offset; /* for user space probes */ +}; + +struct kprobe { + struct list_head list; + + /* location of the probe point */ + struct probe_at at; + + /* Called before addr is executed. */ + kprobe_pre_handler_t pre_handler; + + /* Called after addr is executed, unless... */ + kprobe_post_handler_t post_handler; + + /* ... called if executing addr causes a fault (eg. page fault). + * Return 1 if it handled fault, otherwise kernel will see it. */ + kprobe_fault_handler_t fault_handler; + + /* Saved opcode (which has been replaced with breakpoint) */ + kprobe_opcode_t opcode; +}; + +#ifdef CONFIG_KPROBES +/* Locks kprobe: irq must be disabled */ +void lock_kprobes(void); +void unlock_kprobes(void); + +/* kprobe running now on this CPU? */ +static inline int kprobe_running(void) +{ + extern unsigned int kprobe_cpu; + return kprobe_cpu == smp_processor_id(); +} + +/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ +struct kprobe *get_kprobe(void *addr); + +int register_kprobe(struct kprobe *p); +void unregister_kprobe(struct kprobe *p); +#else +static inline int kprobe_running(void) { return 0; } +static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; } +static inline void unregister_kprobe(struct kprobe *p) { } +#endif +#endif /* _LINUX_KPROBES_H */ diff -Nur -X /root/dontdiff 47/kernel/Makefile 47-kp/kernel/Makefile --- 47/kernel/Makefile Mon Nov 11 11:28:06 2002 +++ 47-kp/kernel/Makefile Thu Nov 14 15:22:14 2002 @@ -4,7 +4,7 @@ export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ printk.o platform.o suspend.o dma.o module.o cpufreq.o \ - profile.o rcupdate.o + profile.o rcupdate.o kprobes.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ module.o exit.o itimer.o time.o softirq.o resource.o \ @@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o +obj-$(CONFIG_KPROBES) += kprobes.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <al...@li...>, the -fno-omit-frame-pointer is diff -Nur -X /root/dontdiff 47/kernel/kprobes.c 47-kp/kernel/kprobes.c --- 47/kernel/kprobes.c Thu Jan 1 08:00:00 1970 +++ 47-kp/kernel/kprobes.c Fri Nov 15 17:21:23 2002 @@ -0,0 +1,157 @@ +/* Support for kernel probes. + (C) 2002 Vamsi Krishna S <vam...@in...>. +*/ +#include <linux/kprobes.h> +#include <linux/spinlock.h> +#include <linux/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/cacheflush.h> +#include <asm/errno.h> + +#define KPROBE_HASH_BITS 6 +#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) + +static struct list_head kprobe_table[KPROBE_TABLE_SIZE]; + +unsigned int kprobe_cpu = NR_CPUS; +static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED; + +/* Locks kprobe: irqs must be disabled */ +void lock_kprobes(void) +{ + spin_lock(&kprobe_lock); + kprobe_cpu = smp_processor_id(); +} + +void unlock_kprobes(void) +{ + kprobe_cpu = NR_CPUS; + spin_unlock(&kprobe_lock); +} + +/* + * We need to look up the inode and offset from the vma. We can't depend on + * the page->(mapping, index) as that would be incorrect if we ever swap this + * page out (possible for pages which are dirtied by GDB breakpoints etc) + * + * We acquire page_table_lock here to ensure that: + * - current page doesn't go away from under us (kswapd) + * - mm->mmap consistancy (vma are always added under this lock) + * + * We will never deadlock on page_table_lock, we always come here due to a + * probe in user space, no kernel code could have executed to take the + * page_table_lock. + */ +static struct kprobe *get_uprobe_at(struct inode *inode, unsigned long offset) +{ + struct list_head *head; + struct kprobe *p; + + head = &kprobe_table[hash_long((unsigned long)inode*offset, + KPROBE_HASH_BITS)]; + list_for_each_entry(p, head, list) { + if (p->at.inode == inode && p->at.offset == offset) + return p; + } + return NULL; +} + +static struct kprobe *get_uprobe(void *addr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct inode *inode; + unsigned long offset; + + spin_lock(&mm->page_table_lock); + vma = find_vma(mm, (unsigned long)addr); + offset = (unsigned long)addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); + if (!vma->vm_file) { + spin_unlock(&mm->page_table_lock); + return NULL; + } + inode = vma->vm_file->f_dentry->d_inode; + spin_unlock(&mm->page_table_lock); + + return get_uprobe_at(inode, offset); +} + +/* You have to be holding the kprobe_lock */ +struct kprobe *get_kprobe(void *addr) +{ + struct list_head *head, *tmp; + + if ((unsigned long)addr < PAGE_OFFSET) + return get_uprobe(addr); + + head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)]; + list_for_each(tmp, head) { + struct kprobe *p = list_entry(tmp, struct kprobe, list); + if (p->at.addr == addr) + return p; + } + return NULL; +} + +/* + * p->at.addr has to be writeable address for uspace probes. + */ +int register_kprobe(struct kprobe *p) +{ + int ret = 0; + kprobe_opcode_t *addr = p->at.addr; + + spin_lock_irq(&kprobe_lock); + if (!p->at.inode) { + if (get_kprobe(addr)) { + ret = -EEXIST; + goto out; + } + list_add(&p->list, &kprobe_table[hash_ptr(addr, + KPROBE_HASH_BITS)]); + } else { + if (get_uprobe_at(p->at.inode, p->at.offset)) { + ret = -EEXIST; + goto out; + } + list_add(&p->list, + &kprobe_table[hash_long( + (unsigned long)p->at.inode * p->at.offset, + KPROBE_HASH_BITS)]); + } + + p->opcode = *addr; + *addr = BREAKPOINT_INSTRUCTION; + flush_icache_range(addr, addr + sizeof(kprobe_opcode_t)); + out: + spin_unlock_irq(&kprobe_lock); + return ret; +} + +void unregister_kprobe(struct kprobe *p) +{ + kprobe_opcode_t *addr = p->at.addr; + + spin_lock_irq(&kprobe_lock); + *addr = p->opcode; + list_del(&p->list); + flush_icache_range(addr, addr + sizeof(kprobe_opcode_t)); + spin_unlock_irq(&kprobe_lock); +} + +static int __init init_kprobes(void) +{ + int i; + + /* FIXME allocate the probe table, currently defined statically */ + /* initialize all list heads */ + for (i = 0; i < KPROBE_TABLE_SIZE; i++) + INIT_LIST_HEAD(&kprobe_table[i]); + + return 0; +} +__initcall(init_kprobes); + +EXPORT_SYMBOL_GPL(register_kprobe); +EXPORT_SYMBOL_GPL(unregister_kprobe); |
From: Gao, K. <kev...@in...> - 2002-11-15 07:07:39
|
E100 is a pretty good target driver, how about net_link_down example? Kevin -----Original Message----- From: Zhuang, Louis=20 Sent: 2002=C4=EA11=D4=C215=C8=D5 15:02 To: Wang, Frank; Wang, Stanley; 'fau...@li...' Cc: Gao, Kevin Subject: RE: [Fault-injection-developer] FITH minimal feature set = (proposal) Impl. suit for the minimal feature set: 1. a moderate kernel patch against lastest 2.5.x kernel 2. page-fault kernel module code 3. decision-make kernel module code 4. utility tool 5. a simple demonstrate examples Comments? - Louis > -----Original Message----- > From: Wang, Frank=20 > Sent: Friday, November 15, 2002 2:47 PM > To: Wang, Stanley; Zhuang, Louis; > fau...@li... > Cc: Gao, Kevin > Subject: RE: [Fault-injection-developer] FITH minimal feature set > (proposal) >=20 >=20 > one example should be ready to inject fault into existing=20 > common drivers. >=20 > fw >=20 > -----Original Message----- > From: Wang, Stanley=20 > Sent: 2002=C4=EA11=D4=C215=C8=D5 14:23 > To: Zhuang, Louis; = fau...@li... > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley > Subject: RE: [Fault-injection-developer] FITH minimal feature set > (proposal) >=20 >=20 > How about adding the feature of intercepting IRQ :) >=20 > > -----Original Message----- > > From: Zhuang, Louis [mailto:lou...@in...] > > Sent: 2002=C4=EA11=D4=C215=C8=D5 10:39 > > To: fau...@li... > > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis > > Subject: [Fault-injection-developer] FITH minimal feature set=20 > > (proposal) > >=20 > >=20 > > Hi all, > > We'd like to submit following feature set to LKML for=20 > > comments. The > > feature set emphasizes the feature which FITH is good at but=20 > > kprobes isn't. > > Any comments? -Louis > >=20 > > -------------------------------------------------- > > FITH Minimal feature set > > 1. Data orientation Interceptor > > To be different with kprobes, FITH focus on=20 > intercepting data > > access. We can intercept data accesses in any addresses=20 > without the > > limitation of the number of debugger register. (Page=20 > fault method is > > proposed) > > 2. Decision Maker > > FITH can process intercepted data accesses with=20 > many pre-defined > > methods, such as logical/arithmetical operation on the access=20 > > results. (This > > feature can simulate the hardware reading/writing error)=20 > > 3. XML-based utility > > FITH can have a utility to describe intercepted=20 > address and > > corresponding operation in a XML format. > >=20 > >=20 > > ------------------------------------------------------- > > This sf.net email is sponsored by: To learn the basics=20 > of securing=20 > > your web site with SSL, click here to get a FREE TRIAL=20 > of a Thawte=20 > > Server Certificate: http://www.gothawte.com/rd524.html > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 > https://lists.sourceforge.net/lists/listinfo/fault-injecti on-developer >=20 |
From: Zhuang, L. <lou...@in...> - 2002-11-15 07:04:28
|
Impl. suit for the minimal feature set: 1. a moderate kernel patch against lastest 2.5.x kernel 2. page-fault kernel module code 3. decision-make kernel module code 4. utility tool 5. a simple demonstrate examples Comments? - Louis > -----Original Message----- > From: Wang, Frank=20 > Sent: Friday, November 15, 2002 2:47 PM > To: Wang, Stanley; Zhuang, Louis; > fau...@li... > Cc: Gao, Kevin > Subject: RE: [Fault-injection-developer] FITH minimal feature set > (proposal) >=20 >=20 > one example should be ready to inject fault into existing=20 > common drivers. >=20 > fw >=20 > -----Original Message----- > From: Wang, Stanley=20 > Sent: 2002=C4=EA11=D4=C215=C8=D5 14:23 > To: Zhuang, Louis; = fau...@li... > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley > Subject: RE: [Fault-injection-developer] FITH minimal feature set > (proposal) >=20 >=20 > How about adding the feature of intercepting IRQ :) >=20 > > -----Original Message----- > > From: Zhuang, Louis [mailto:lou...@in...] > > Sent: 2002=C4=EA11=D4=C215=C8=D5 10:39 > > To: fau...@li... > > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis > > Subject: [Fault-injection-developer] FITH minimal feature set=20 > > (proposal) > >=20 > >=20 > > Hi all, > > We'd like to submit following feature set to LKML for=20 > > comments. The > > feature set emphasizes the feature which FITH is good at but=20 > > kprobes isn't. > > Any comments? -Louis > >=20 > > -------------------------------------------------- > > FITH Minimal feature set > > 1. Data orientation Interceptor > > To be different with kprobes, FITH focus on=20 > intercepting data > > access. We can intercept data accesses in any addresses=20 > without the > > limitation of the number of debugger register. (Page=20 > fault method is > > proposed) > > 2. Decision Maker > > FITH can process intercepted data accesses with=20 > many pre-defined > > methods, such as logical/arithmetical operation on the access=20 > > results. (This > > feature can simulate the hardware reading/writing error)=20 > > 3. XML-based utility > > FITH can have a utility to describe intercepted=20 > address and > > corresponding operation in a XML format. > >=20 > >=20 > > ------------------------------------------------------- > > This sf.net email is sponsored by: To learn the basics=20 > of securing=20 > > your web site with SSL, click here to get a FREE TRIAL=20 > of a Thawte=20 > > Server Certificate: http://www.gothawte.com/rd524.html > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 > https://lists.sourceforge.net/lists/listinfo/fault-injecti on-developer >=20 |
From: Wang, F. <fra...@in...> - 2002-11-15 06:48:48
|
one example should be ready to inject fault into existing common = drivers. fw -----Original Message----- From: Wang, Stanley=20 Sent: 2002=C4=EA11=D4=C215=C8=D5 14:23 To: Zhuang, Louis; fau...@li... Cc: Gao, Kevin; Wang, Frank; Wang, Stanley Subject: RE: [Fault-injection-developer] FITH minimal feature set (proposal) How about adding the feature of intercepting IRQ :) > -----Original Message----- > From: Zhuang, Louis [mailto:lou...@in...] > Sent: 2002=C4=EA11=D4=C215=C8=D5 10:39 > To: fau...@li... > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis > Subject: [Fault-injection-developer] FITH minimal feature set=20 > (proposal) >=20 >=20 > Hi all, > We'd like to submit following feature set to LKML for=20 > comments. The > feature set emphasizes the feature which FITH is good at but=20 > kprobes isn't. > Any comments? -Louis >=20 > -------------------------------------------------- > FITH Minimal feature set > 1. Data orientation Interceptor > To be different with kprobes, FITH focus on intercepting data > access. We can intercept data accesses in any addresses without the > limitation of the number of debugger register. (Page fault method is > proposed) > 2. Decision Maker > FITH can process intercepted data accesses with many pre-defined > methods, such as logical/arithmetical operation on the access=20 > results. (This > feature can simulate the hardware reading/writing error)=20 > 3. XML-based utility > FITH can have a utility to describe intercepted address and > corresponding operation in a XML format. >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: To learn the basics of securing=20 > your web site with SSL, click here to get a FREE TRIAL of a Thawte=20 > Server Certificate: http://www.gothawte.com/rd524.html > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Wang, S. <sta...@in...> - 2002-11-15 06:25:23
|
How about adding the feature of intercepting IRQ :) > -----Original Message----- > From: Zhuang, Louis [mailto:lou...@in...] > Sent: 2002=C4=EA11=D4=C215=C8=D5 10:39 > To: fau...@li... > Cc: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis > Subject: [Fault-injection-developer] FITH minimal feature set=20 > (proposal) >=20 >=20 > Hi all, > We'd like to submit following feature set to LKML for=20 > comments. The > feature set emphasizes the feature which FITH is good at but=20 > kprobes isn't. > Any comments? -Louis >=20 > -------------------------------------------------- > FITH Minimal feature set > 1. Data orientation Interceptor > To be different with kprobes, FITH focus on intercepting data > access. We can intercept data accesses in any addresses without the > limitation of the number of debugger register. (Page fault method is > proposed) > 2. Decision Maker > FITH can process intercepted data accesses with many pre-defined > methods, such as logical/arithmetical operation on the access=20 > results. (This > feature can simulate the hardware reading/writing error)=20 > 3. XML-based utility > FITH can have a utility to describe intercepted address and > corresponding operation in a XML format. >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: To learn the basics of securing=20 > your web site with SSL, click here to get a FREE TRIAL of a Thawte=20 > Server Certificate: http://www.gothawte.com/rd524.html > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Zhuang, L. <lou...@in...> - 2002-11-15 06:11:38
|
Hi all, We'd like to submit following feature set to LKML for comments. The feature set emphasizes the feature which FITH is good at but kprobes isn't. Any comments? -Louis -------------------------------------------------- FITH Minimal feature set 1. Data orientation Interceptor To be different with kprobes, FITH focus on intercepting data access. We can intercept data accesses in any addresses without the limitation of the number of debugger register. (Page fault method is proposed) 2. Decision Maker FITH can process intercepted data accesses with many pre-defined methods, such as logical/arithmetical operation on the access results. (This feature can simulate the hardware reading/writing error) 3. XML-based utility FITH can have a utility to describe intercepted address and corresponding operation in a XML format. |
From: Rusty L. <ru...@li...> - 2002-11-14 07:12:47
|
s/practive/practice/ As in it is good "practice" to use a spell checker if your name is Rusty Lynch. -rusty ----- Original Message ----- From: "Lynch, Rusty" <rus...@in...> To: "Zhuang, Louis" <lou...@in...>; "'Rusty Lynch'" <ru...@li...>; "Gao, Kevin" <kev...@in...>; "Wang, Frank" <fra...@in...>; "Wang, Stanley" <sta...@in...> Cc: <fau...@li...> Sent: Wednesday, November 13, 2002 11:06 PM Subject: RE: [Fault-injection-developer] RE: [PATCH] 2.5.44-kp2-fi1 > Actually, it's good practive to reply on each of the points, and argue > when you do not agree. > > -rusty > > -----Original Message----- > From: Zhuang, Louis [mailto:lou...@in...] > Sent: Wednesday, November 13, 2002 10:59 PM > To: 'Rusty Lynch'; Gao, Kevin; Wang, Frank; Wang, Stanley > Cc: fau...@li... > Subject: [Fault-injection-developer] RE: [PATCH] 2.5.44-kp2-fi1 > > > As you wish, I am learning to speak rightly in a huge maillist. So I use the > maillist as a playground to practise. ;-) I'll refine my announcement when > the next patch. -Louis > > > -----Original Message----- > > From: Rusty Lynch [mailto:ru...@li...] > > Sent: Thursday, November 14, 2002 2:48 PM > > To: Zhuang, Louis; Gao, Kevin; Wang, Frank; Wang, Stanley > > Cc: fau...@li... > > Subject: Re: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > > > > > ----- Original Message ----- > > From: "Zhuang, Louis" <lou...@in...> > > To: "Gao, Kevin" <kev...@in...>; "Wang, Frank" > > <fra...@in...>; "Wang, Stanley" > > <sta...@in...>; "Zhuang, > > Louis" <lou...@in...> > > Cc: <fau...@li...> > > Sent: Wednesday, November 13, 2002 6:51 PM > > Subject: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > > > > Dear all, > > > Following is the first fault injection patch against > > 2.5.x sserials > > > kernel. > > 2.5.x is way to vauge. State exactly which version and any > > patches you depend on. It looks like you implemented on > > 2.5.44 with the kprobes patch applied. > > > > >kernel module part is ongoing. > > Everything is ongoing... unless you think this code is perfect :-> > > > Please review it and give us > > > feedback. > > > > Check out some of the other patches submitted to LKML for some > > more hints on what to describe in your intro. For example: > > > > State which files are touched and why. Keep in mind that this > > patch will need to be submitted to lkml, where most people have > > never heard of FITH and almost everyone will look at this patch as > > yet another something else to break or slow down their server. > > > > > - Louis > > > > > > diff -Nur -X /root/dontdiff 44-kp/Makefile 44-kp-fi/Makefile > > > --- 44-kp/Makefile Sat Oct 19 12:01:12 2002 > > > +++ 44-kp-fi/Makefile Wed Nov 13 16:28:48 2002 > > > @@ -1,7 +1,7 @@ > > > VERSION = 2 > > > PATCHLEVEL = 5 > > > SUBLEVEL = 44 > > > -EXTRAVERSION = > > > +EXTRAVERSION =kp-fi > > Take this out. > > > > > > > > # *DOCUMENTATION* > > > # To see a list of typical targets execute "make help" > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/Config.help > > > 44-kp-fi/arch/i386/Config.help > > > --- 44-kp/arch/i386/Config.help Wed Nov 13 16:24:41 2002 > > > +++ 44-kp-fi/arch/i386/Config.help Thu Nov 14 09:43:55 2002 > > > > All fo the config stuff has been replaced in 2.5.46. Please > > update with the new Kconfig format. > > > > > @@ -1108,3 +1108,6 @@ > > > register_kprobe(), and providing a callback > > function. This is useful > > > for kernel debugging, non-intrusive instrumentation > > and testing. If > > > in doubt, say "N". > > > + CONFIG_FI > > > + Say Y here if you want to enable Fault Injection > > (FI) mechanism. The FI > > > + can monitor MMIO/IO access in kernel. > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/config.in > > > 44-kp-fi/arch/i386/config.in > > > --- 44-kp/arch/i386/config.in Wed Nov 13 16:25:00 2002 > > > +++ 44-kp-fi/arch/i386/config.in Thu Nov 14 09:46:44 2002 > > > @@ -469,6 +469,9 @@ > > > fi > > > bool ' Load all symbols for debugging/kksymoops' > > CONFIG_KALLSYMS > > > bool ' Kprobes' CONFIG_KPROBES > > > + if [ "$CONFIG_KPROBES" = "y" ]; then > > > + bool ' Fault Injection' CONFIG_FI > > > + fi > > > fi > > > > > > if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/i386_ksyms.c > > > 44-kp-fi/arch/i386/kernel/i386_ksyms.c > > > --- 44-kp/arch/i386/kernel/i386_ksyms.c Sat Oct 19 12:02:34 2002 > > > +++ 44-kp-fi/arch/i386/kernel/i386_ksyms.c Thu Nov 14 > > 10:25:53 2002 > > > @@ -32,6 +32,7 @@ > > > #include <asm/tlbflush.h> > > > #include <asm/nmi.h> > > > #include <asm/edd.h> > > > +#include <asm/fi.h> > > > > > > extern void dump_thread(struct pt_regs *, struct user *); > > > extern spinlock_t rtc_lock; > > > @@ -207,3 +208,9 @@ > > > EXPORT_SYMBOL(edd); > > > EXPORT_SYMBOL(eddnr); > > > #endif > > > + > > > +#ifdef CONFIG_FI > > > +EXPORT_SYMBOL(irq_desc); > > > +EXPORT_SYMBOL(fi_page_fault); > > > +EXPORT_SYMBOL(fi_post_page_fault); > > > +#endif > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/traps.c > > > 44-kp-fi/arch/i386/kernel/traps.c > > > --- 44-kp/arch/i386/kernel/traps.c Wed Nov 13 16:25:00 2002 > > > +++ 44-kp-fi/arch/i386/kernel/traps.c Thu Nov 14 09:34:36 2002 > > > @@ -47,6 +47,7 @@ > > > #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> > > > @@ -559,6 +560,9 @@ > > > return 0; > > > } > > > > > > +int (*fi_post_page_fault) (unsigned long condition, > > > + struct pt_regs *reg); > > > + > > > /* > > > * Our handling of the processor debug registers is > > non-trivial. > > > * We do not clear them on entry and exit from the > > kernel. Therefore > > > @@ -595,6 +599,9 @@ > > > if (kwatch_handler(condition, regs)) > > > return 1; > > > > > > + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) > > > + return 1; > > > + > > > /* Interrupts not disabled for normal trap handling. */ > > > restore_interrupts(regs); > > > > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/mm/fault.c > > > 44-kp-fi/arch/i386/mm/fault.c > > > --- 44-kp/arch/i386/mm/fault.c Wed Nov 13 16:24:41 2002 > > > +++ 44-kp-fi/arch/i386/mm/fault.c Thu Nov 14 09:33:35 2002 > > > @@ -26,6 +26,7 @@ > > > #include <asm/pgalloc.h> > > > #include <asm/hardirq.h> > > > #include <asm/desc.h> > > > +#include <asm/fi.h> > > > > > > extern void die(const char *,struct pt_regs *,long); > > > > > > @@ -127,6 +128,7 @@ > > > } > > > > > > asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); > > > +int (*fi_page_fault) ( struct pt_regs *regs, unsigned > > long address); > > > > > > /* > > > * This routine handles page faults. It determines > > the address, > > > @@ -154,7 +156,9 @@ > > > > > > if (kprobe_running() && kprobe_fault_handler(regs, 14)) > > > return; > > > - > > > + if (fi_page_fault && fi_page_fault(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 -X /root/dontdiff 44-kp/drivers/net/e100/e100.h > > > 44-kp-fi/drivers/net/e100/e100.h > > > --- 44-kp/drivers/net/e100/e100.h Sat Oct 19 12:01:20 2002 > > > +++ 44-kp-fi/drivers/net/e100/e100.h Wed Nov 13 17:15:28 2002 > > > @@ -100,7 +100,7 @@ > > > > > > #define E100_MAX_NIC 16 > > > > > > -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ > > > +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ > > > > Did you mean to include this? > > > > > #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in > > wait_cus_idle */ > > > > > > /* HWI feature related constant */ > > > diff -Nur -X /root/dontdiff 44-kp/include/asm-i386/fi.h > > > 44-kp-fi/include/asm-i386/fi.h > > > --- 44-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 > > > +++ 44-kp-fi/include/asm-i386/fi.h Thu Nov 14 09:26:53 2002 > > > @@ -0,0 +1,8 @@ > > > +#ifndef _ASM_FI_H > > > +#define _ASM_FI_H > > > +#ifdef CONFIG_FI > > > > We should us _I386_FI_H or _ASMI386_FI_H since other > > architectures could have a fi.h also. > > > > > +extern int (*fi_page_fault) ( struct pt_regs *regs, > > unsigned long > > address); > > > +extern int (*fi_post_page_fault) (unsigned long condition, > > > + struct pt_regs *reg); > > > +#endif > > > +#endif /* _ASM_FI_H */ > > > diff -Nur -X /root/dontdiff 44-kp/kernel/ksyms.c > > 44-kp-fi/kernel/ksyms.c > > > --- 44-kp/kernel/ksyms.c Sat Oct 19 12:01:08 2002 > > > +++ 44-kp-fi/kernel/ksyms.c Thu Nov 14 10:25:32 2002 > > > @@ -601,3 +601,7 @@ > > > > > > /* debug */ > > > EXPORT_SYMBOL(dump_stack); > > > + > > > +#ifdef CONFIG_FI > > > +EXPORT_SYMBOL(module_list); > > > +#endif > > > > > > > > > ------------------------------------------------------- > > > This sf.net email is sponsored by: Are you worried about > > > your web server security? Click here for a FREE Thawte > > > Apache SSL Guide and answer your Apache SSL security > > > needs: http://www.gothawte.com/rd523.html > > > _______________________________________________ > > > Fault-injection-developer mailing list > > > Fau...@li... > > > > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > > > ------------------------------------------------------- > This sf.net email is sponsored by: To learn the basics of securing > your web site with SSL, click here to get a FREE TRIAL of a Thawte > Server Certificate: http://www.gothawte.com/rd524.html > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > > > ------------------------------------------------------- > This sf.net email is sponsored by: To learn the basics of securing > your web site with SSL, click here to get a FREE TRIAL of a Thawte > Server Certificate: http://www.gothawte.com/rd524.html > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Lynch, R. <rus...@in...> - 2002-11-14 07:06:10
|
Actually, it's good practive to reply on each of the points, and argue when you do not agree. -rusty -----Original Message----- From: Zhuang, Louis [mailto:lou...@in...] Sent: Wednesday, November 13, 2002 10:59 PM To: 'Rusty Lynch'; Gao, Kevin; Wang, Frank; Wang, Stanley Cc: fau...@li... Subject: [Fault-injection-developer] RE: [PATCH] 2.5.44-kp2-fi1 As you wish, I am learning to speak rightly in a huge maillist. So I use the maillist as a playground to practise. ;-) I'll refine my announcement when the next patch. -Louis > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: Thursday, November 14, 2002 2:48 PM > To: Zhuang, Louis; Gao, Kevin; Wang, Frank; Wang, Stanley > Cc: fau...@li... > Subject: Re: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > ----- Original Message ----- > From: "Zhuang, Louis" <lou...@in...> > To: "Gao, Kevin" <kev...@in...>; "Wang, Frank" > <fra...@in...>; "Wang, Stanley" > <sta...@in...>; "Zhuang, > Louis" <lou...@in...> > Cc: <fau...@li...> > Sent: Wednesday, November 13, 2002 6:51 PM > Subject: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > Dear all, > > Following is the first fault injection patch against > 2.5.x sserials > > kernel. > 2.5.x is way to vauge. State exactly which version and any > patches you depend on. It looks like you implemented on > 2.5.44 with the kprobes patch applied. > > >kernel module part is ongoing. > Everything is ongoing... unless you think this code is perfect :-> > > Please review it and give us > > feedback. > > Check out some of the other patches submitted to LKML for some > more hints on what to describe in your intro. For example: > > State which files are touched and why. Keep in mind that this > patch will need to be submitted to lkml, where most people have > never heard of FITH and almost everyone will look at this patch as > yet another something else to break or slow down their server. > > > - Louis > > > > diff -Nur -X /root/dontdiff 44-kp/Makefile 44-kp-fi/Makefile > > --- 44-kp/Makefile Sat Oct 19 12:01:12 2002 > > +++ 44-kp-fi/Makefile Wed Nov 13 16:28:48 2002 > > @@ -1,7 +1,7 @@ > > VERSION = 2 > > PATCHLEVEL = 5 > > SUBLEVEL = 44 > > -EXTRAVERSION = > > +EXTRAVERSION =kp-fi > Take this out. > > > > > # *DOCUMENTATION* > > # To see a list of typical targets execute "make help" > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/Config.help > > 44-kp-fi/arch/i386/Config.help > > --- 44-kp/arch/i386/Config.help Wed Nov 13 16:24:41 2002 > > +++ 44-kp-fi/arch/i386/Config.help Thu Nov 14 09:43:55 2002 > > All fo the config stuff has been replaced in 2.5.46. Please > update with the new Kconfig format. > > > @@ -1108,3 +1108,6 @@ > > register_kprobe(), and providing a callback > function. This is useful > > for kernel debugging, non-intrusive instrumentation > and testing. If > > in doubt, say "N". > > + CONFIG_FI > > + Say Y here if you want to enable Fault Injection > (FI) mechanism. The FI > > + can monitor MMIO/IO access in kernel. > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/config.in > > 44-kp-fi/arch/i386/config.in > > --- 44-kp/arch/i386/config.in Wed Nov 13 16:25:00 2002 > > +++ 44-kp-fi/arch/i386/config.in Thu Nov 14 09:46:44 2002 > > @@ -469,6 +469,9 @@ > > fi > > bool ' Load all symbols for debugging/kksymoops' > CONFIG_KALLSYMS > > bool ' Kprobes' CONFIG_KPROBES > > + if [ "$CONFIG_KPROBES" = "y" ]; then > > + bool ' Fault Injection' CONFIG_FI > > + fi > > fi > > > > if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/i386_ksyms.c > > 44-kp-fi/arch/i386/kernel/i386_ksyms.c > > --- 44-kp/arch/i386/kernel/i386_ksyms.c Sat Oct 19 12:02:34 2002 > > +++ 44-kp-fi/arch/i386/kernel/i386_ksyms.c Thu Nov 14 > 10:25:53 2002 > > @@ -32,6 +32,7 @@ > > #include <asm/tlbflush.h> > > #include <asm/nmi.h> > > #include <asm/edd.h> > > +#include <asm/fi.h> > > > > extern void dump_thread(struct pt_regs *, struct user *); > > extern spinlock_t rtc_lock; > > @@ -207,3 +208,9 @@ > > EXPORT_SYMBOL(edd); > > EXPORT_SYMBOL(eddnr); > > #endif > > + > > +#ifdef CONFIG_FI > > +EXPORT_SYMBOL(irq_desc); > > +EXPORT_SYMBOL(fi_page_fault); > > +EXPORT_SYMBOL(fi_post_page_fault); > > +#endif > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/traps.c > > 44-kp-fi/arch/i386/kernel/traps.c > > --- 44-kp/arch/i386/kernel/traps.c Wed Nov 13 16:25:00 2002 > > +++ 44-kp-fi/arch/i386/kernel/traps.c Thu Nov 14 09:34:36 2002 > > @@ -47,6 +47,7 @@ > > #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> > > @@ -559,6 +560,9 @@ > > return 0; > > } > > > > +int (*fi_post_page_fault) (unsigned long condition, > > + struct pt_regs *reg); > > + > > /* > > * Our handling of the processor debug registers is > non-trivial. > > * We do not clear them on entry and exit from the > kernel. Therefore > > @@ -595,6 +599,9 @@ > > if (kwatch_handler(condition, regs)) > > return 1; > > > > + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) > > + return 1; > > + > > /* Interrupts not disabled for normal trap handling. */ > > restore_interrupts(regs); > > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/mm/fault.c > > 44-kp-fi/arch/i386/mm/fault.c > > --- 44-kp/arch/i386/mm/fault.c Wed Nov 13 16:24:41 2002 > > +++ 44-kp-fi/arch/i386/mm/fault.c Thu Nov 14 09:33:35 2002 > > @@ -26,6 +26,7 @@ > > #include <asm/pgalloc.h> > > #include <asm/hardirq.h> > > #include <asm/desc.h> > > +#include <asm/fi.h> > > > > extern void die(const char *,struct pt_regs *,long); > > > > @@ -127,6 +128,7 @@ > > } > > > > asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); > > +int (*fi_page_fault) ( struct pt_regs *regs, unsigned > long address); > > > > /* > > * This routine handles page faults. It determines > the address, > > @@ -154,7 +156,9 @@ > > > > if (kprobe_running() && kprobe_fault_handler(regs, 14)) > > return; > > - > > + if (fi_page_fault && fi_page_fault(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 -X /root/dontdiff 44-kp/drivers/net/e100/e100.h > > 44-kp-fi/drivers/net/e100/e100.h > > --- 44-kp/drivers/net/e100/e100.h Sat Oct 19 12:01:20 2002 > > +++ 44-kp-fi/drivers/net/e100/e100.h Wed Nov 13 17:15:28 2002 > > @@ -100,7 +100,7 @@ > > > > #define E100_MAX_NIC 16 > > > > -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ > > +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ > > Did you mean to include this? > > > #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in > wait_cus_idle */ > > > > /* HWI feature related constant */ > > diff -Nur -X /root/dontdiff 44-kp/include/asm-i386/fi.h > > 44-kp-fi/include/asm-i386/fi.h > > --- 44-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 > > +++ 44-kp-fi/include/asm-i386/fi.h Thu Nov 14 09:26:53 2002 > > @@ -0,0 +1,8 @@ > > +#ifndef _ASM_FI_H > > +#define _ASM_FI_H > > +#ifdef CONFIG_FI > > We should us _I386_FI_H or _ASMI386_FI_H since other > architectures could have a fi.h also. > > > +extern int (*fi_page_fault) ( struct pt_regs *regs, > unsigned long > address); > > +extern int (*fi_post_page_fault) (unsigned long condition, > > + struct pt_regs *reg); > > +#endif > > +#endif /* _ASM_FI_H */ > > diff -Nur -X /root/dontdiff 44-kp/kernel/ksyms.c > 44-kp-fi/kernel/ksyms.c > > --- 44-kp/kernel/ksyms.c Sat Oct 19 12:01:08 2002 > > +++ 44-kp-fi/kernel/ksyms.c Thu Nov 14 10:25:32 2002 > > @@ -601,3 +601,7 @@ > > > > /* debug */ > > EXPORT_SYMBOL(dump_stack); > > + > > +#ifdef CONFIG_FI > > +EXPORT_SYMBOL(module_list); > > +#endif > > > > > > ------------------------------------------------------- > > This sf.net email is sponsored by: Are you worried about > > your web server security? Click here for a FREE Thawte > > Apache SSL Guide and answer your Apache SSL security > > needs: http://www.gothawte.com/rd523.html > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer ------------------------------------------------------- This sf.net email is sponsored by: To learn the basics of securing your web site with SSL, click here to get a FREE TRIAL of a Thawte Server Certificate: http://www.gothawte.com/rd524.html _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Zhuang, L. <lou...@in...> - 2002-11-14 07:01:21
|
As you wish, I am learning to speak rightly in a huge maillist. So I use the maillist as a playground to practise. ;-) I'll refine my announcement when the next patch. -Louis > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: Thursday, November 14, 2002 2:48 PM > To: Zhuang, Louis; Gao, Kevin; Wang, Frank; Wang, Stanley > Cc: fau...@li... > Subject: Re: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > ----- Original Message ----- > From: "Zhuang, Louis" <lou...@in...> > To: "Gao, Kevin" <kev...@in...>; "Wang, Frank" > <fra...@in...>; "Wang, Stanley" > <sta...@in...>; "Zhuang, > Louis" <lou...@in...> > Cc: <fau...@li...> > Sent: Wednesday, November 13, 2002 6:51 PM > Subject: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > > > > Dear all, > > Following is the first fault injection patch against > 2.5.x sserials > > kernel. > 2.5.x is way to vauge. State exactly which version and any > patches you depend on. It looks like you implemented on > 2.5.44 with the kprobes patch applied. > > >kernel module part is ongoing. > Everything is ongoing... unless you think this code is perfect :-> > > Please review it and give us > > feedback. > > Check out some of the other patches submitted to LKML for some > more hints on what to describe in your intro. For example: > > State which files are touched and why. Keep in mind that this > patch will need to be submitted to lkml, where most people have > never heard of FITH and almost everyone will look at this patch as > yet another something else to break or slow down their server. > > > - Louis > > > > diff -Nur -X /root/dontdiff 44-kp/Makefile 44-kp-fi/Makefile > > --- 44-kp/Makefile Sat Oct 19 12:01:12 2002 > > +++ 44-kp-fi/Makefile Wed Nov 13 16:28:48 2002 > > @@ -1,7 +1,7 @@ > > VERSION = 2 > > PATCHLEVEL = 5 > > SUBLEVEL = 44 > > -EXTRAVERSION = > > +EXTRAVERSION =kp-fi > Take this out. > > > > > # *DOCUMENTATION* > > # To see a list of typical targets execute "make help" > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/Config.help > > 44-kp-fi/arch/i386/Config.help > > --- 44-kp/arch/i386/Config.help Wed Nov 13 16:24:41 2002 > > +++ 44-kp-fi/arch/i386/Config.help Thu Nov 14 09:43:55 2002 > > All fo the config stuff has been replaced in 2.5.46. Please > update with the new Kconfig format. > > > @@ -1108,3 +1108,6 @@ > > register_kprobe(), and providing a callback > function. This is useful > > for kernel debugging, non-intrusive instrumentation > and testing. If > > in doubt, say "N". > > + CONFIG_FI > > + Say Y here if you want to enable Fault Injection > (FI) mechanism. The FI > > + can monitor MMIO/IO access in kernel. > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/config.in > > 44-kp-fi/arch/i386/config.in > > --- 44-kp/arch/i386/config.in Wed Nov 13 16:25:00 2002 > > +++ 44-kp-fi/arch/i386/config.in Thu Nov 14 09:46:44 2002 > > @@ -469,6 +469,9 @@ > > fi > > bool ' Load all symbols for debugging/kksymoops' > CONFIG_KALLSYMS > > bool ' Kprobes' CONFIG_KPROBES > > + if [ "$CONFIG_KPROBES" = "y" ]; then > > + bool ' Fault Injection' CONFIG_FI > > + fi > > fi > > > > if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/i386_ksyms.c > > 44-kp-fi/arch/i386/kernel/i386_ksyms.c > > --- 44-kp/arch/i386/kernel/i386_ksyms.c Sat Oct 19 12:02:34 2002 > > +++ 44-kp-fi/arch/i386/kernel/i386_ksyms.c Thu Nov 14 > 10:25:53 2002 > > @@ -32,6 +32,7 @@ > > #include <asm/tlbflush.h> > > #include <asm/nmi.h> > > #include <asm/edd.h> > > +#include <asm/fi.h> > > > > extern void dump_thread(struct pt_regs *, struct user *); > > extern spinlock_t rtc_lock; > > @@ -207,3 +208,9 @@ > > EXPORT_SYMBOL(edd); > > EXPORT_SYMBOL(eddnr); > > #endif > > + > > +#ifdef CONFIG_FI > > +EXPORT_SYMBOL(irq_desc); > > +EXPORT_SYMBOL(fi_page_fault); > > +EXPORT_SYMBOL(fi_post_page_fault); > > +#endif > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/traps.c > > 44-kp-fi/arch/i386/kernel/traps.c > > --- 44-kp/arch/i386/kernel/traps.c Wed Nov 13 16:25:00 2002 > > +++ 44-kp-fi/arch/i386/kernel/traps.c Thu Nov 14 09:34:36 2002 > > @@ -47,6 +47,7 @@ > > #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> > > @@ -559,6 +560,9 @@ > > return 0; > > } > > > > +int (*fi_post_page_fault) (unsigned long condition, > > + struct pt_regs *reg); > > + > > /* > > * Our handling of the processor debug registers is > non-trivial. > > * We do not clear them on entry and exit from the > kernel. Therefore > > @@ -595,6 +599,9 @@ > > if (kwatch_handler(condition, regs)) > > return 1; > > > > + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) > > + return 1; > > + > > /* Interrupts not disabled for normal trap handling. */ > > restore_interrupts(regs); > > > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/mm/fault.c > > 44-kp-fi/arch/i386/mm/fault.c > > --- 44-kp/arch/i386/mm/fault.c Wed Nov 13 16:24:41 2002 > > +++ 44-kp-fi/arch/i386/mm/fault.c Thu Nov 14 09:33:35 2002 > > @@ -26,6 +26,7 @@ > > #include <asm/pgalloc.h> > > #include <asm/hardirq.h> > > #include <asm/desc.h> > > +#include <asm/fi.h> > > > > extern void die(const char *,struct pt_regs *,long); > > > > @@ -127,6 +128,7 @@ > > } > > > > asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); > > +int (*fi_page_fault) ( struct pt_regs *regs, unsigned > long address); > > > > /* > > * This routine handles page faults. It determines > the address, > > @@ -154,7 +156,9 @@ > > > > if (kprobe_running() && kprobe_fault_handler(regs, 14)) > > return; > > - > > + if (fi_page_fault && fi_page_fault(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 -X /root/dontdiff 44-kp/drivers/net/e100/e100.h > > 44-kp-fi/drivers/net/e100/e100.h > > --- 44-kp/drivers/net/e100/e100.h Sat Oct 19 12:01:20 2002 > > +++ 44-kp-fi/drivers/net/e100/e100.h Wed Nov 13 17:15:28 2002 > > @@ -100,7 +100,7 @@ > > > > #define E100_MAX_NIC 16 > > > > -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ > > +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ > > Did you mean to include this? > > > #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in > wait_cus_idle */ > > > > /* HWI feature related constant */ > > diff -Nur -X /root/dontdiff 44-kp/include/asm-i386/fi.h > > 44-kp-fi/include/asm-i386/fi.h > > --- 44-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 > > +++ 44-kp-fi/include/asm-i386/fi.h Thu Nov 14 09:26:53 2002 > > @@ -0,0 +1,8 @@ > > +#ifndef _ASM_FI_H > > +#define _ASM_FI_H > > +#ifdef CONFIG_FI > > We should us _I386_FI_H or _ASMI386_FI_H since other > architectures could have a fi.h also. > > > +extern int (*fi_page_fault) ( struct pt_regs *regs, > unsigned long > address); > > +extern int (*fi_post_page_fault) (unsigned long condition, > > + struct pt_regs *reg); > > +#endif > > +#endif /* _ASM_FI_H */ > > diff -Nur -X /root/dontdiff 44-kp/kernel/ksyms.c > 44-kp-fi/kernel/ksyms.c > > --- 44-kp/kernel/ksyms.c Sat Oct 19 12:01:08 2002 > > +++ 44-kp-fi/kernel/ksyms.c Thu Nov 14 10:25:32 2002 > > @@ -601,3 +601,7 @@ > > > > /* debug */ > > EXPORT_SYMBOL(dump_stack); > > + > > +#ifdef CONFIG_FI > > +EXPORT_SYMBOL(module_list); > > +#endif > > > > > > ------------------------------------------------------- > > This sf.net email is sponsored by: Are you worried about > > your web server security? Click here for a FREE Thawte > > Apache SSL Guide and answer your Apache SSL security > > needs: http://www.gothawte.com/rd523.html > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Rusty L. <ru...@li...> - 2002-11-14 06:48:09
|
----- Original Message ----- From: "Zhuang, Louis" <lou...@in...> To: "Gao, Kevin" <kev...@in...>; "Wang, Frank" <fra...@in...>; "Wang, Stanley" <sta...@in...>; "Zhuang, Louis" <lou...@in...> Cc: <fau...@li...> Sent: Wednesday, November 13, 2002 6:51 PM Subject: [Fault-injection-developer] [PATCH] 2.5.44-kp2-fi1 > Dear all, > Following is the first fault injection patch against 2.5.x sserials > kernel. 2.5.x is way to vauge. State exactly which version and any patches you depend on. It looks like you implemented on 2.5.44 with the kprobes patch applied. >kernel module part is ongoing. Everything is ongoing... unless you think this code is perfect :-> > Please review it and give us > feedback. Check out some of the other patches submitted to LKML for some more hints on what to describe in your intro. For example: State which files are touched and why. Keep in mind that this patch will need to be submitted to lkml, where most people have never heard of FITH and almost everyone will look at this patch as yet another something else to break or slow down their server. > - Louis > > diff -Nur -X /root/dontdiff 44-kp/Makefile 44-kp-fi/Makefile > --- 44-kp/Makefile Sat Oct 19 12:01:12 2002 > +++ 44-kp-fi/Makefile Wed Nov 13 16:28:48 2002 > @@ -1,7 +1,7 @@ > VERSION = 2 > PATCHLEVEL = 5 > SUBLEVEL = 44 > -EXTRAVERSION = > +EXTRAVERSION =kp-fi Take this out. > > # *DOCUMENTATION* > # To see a list of typical targets execute "make help" > diff -Nur -X /root/dontdiff 44-kp/arch/i386/Config.help > 44-kp-fi/arch/i386/Config.help > --- 44-kp/arch/i386/Config.help Wed Nov 13 16:24:41 2002 > +++ 44-kp-fi/arch/i386/Config.help Thu Nov 14 09:43:55 2002 All fo the config stuff has been replaced in 2.5.46. Please update with the new Kconfig format. > @@ -1108,3 +1108,6 @@ > register_kprobe(), and providing a callback function. This is useful > for kernel debugging, non-intrusive instrumentation and testing. If > in doubt, say "N". > + CONFIG_FI > + Say Y here if you want to enable Fault Injection (FI) mechanism. The FI > + can monitor MMIO/IO access in kernel. > diff -Nur -X /root/dontdiff 44-kp/arch/i386/config.in > 44-kp-fi/arch/i386/config.in > --- 44-kp/arch/i386/config.in Wed Nov 13 16:25:00 2002 > +++ 44-kp-fi/arch/i386/config.in Thu Nov 14 09:46:44 2002 > @@ -469,6 +469,9 @@ > fi > bool ' Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS > bool ' Kprobes' CONFIG_KPROBES > + if [ "$CONFIG_KPROBES" = "y" ]; then > + bool ' Fault Injection' CONFIG_FI > + fi > fi > > if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/i386_ksyms.c > 44-kp-fi/arch/i386/kernel/i386_ksyms.c > --- 44-kp/arch/i386/kernel/i386_ksyms.c Sat Oct 19 12:02:34 2002 > +++ 44-kp-fi/arch/i386/kernel/i386_ksyms.c Thu Nov 14 10:25:53 2002 > @@ -32,6 +32,7 @@ > #include <asm/tlbflush.h> > #include <asm/nmi.h> > #include <asm/edd.h> > +#include <asm/fi.h> > > extern void dump_thread(struct pt_regs *, struct user *); > extern spinlock_t rtc_lock; > @@ -207,3 +208,9 @@ > EXPORT_SYMBOL(edd); > EXPORT_SYMBOL(eddnr); > #endif > + > +#ifdef CONFIG_FI > +EXPORT_SYMBOL(irq_desc); > +EXPORT_SYMBOL(fi_page_fault); > +EXPORT_SYMBOL(fi_post_page_fault); > +#endif > diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/traps.c > 44-kp-fi/arch/i386/kernel/traps.c > --- 44-kp/arch/i386/kernel/traps.c Wed Nov 13 16:25:00 2002 > +++ 44-kp-fi/arch/i386/kernel/traps.c Thu Nov 14 09:34:36 2002 > @@ -47,6 +47,7 @@ > #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> > @@ -559,6 +560,9 @@ > return 0; > } > > +int (*fi_post_page_fault) (unsigned long condition, > + struct pt_regs *reg); > + > /* > * Our handling of the processor debug registers is non-trivial. > * We do not clear them on entry and exit from the kernel. Therefore > @@ -595,6 +599,9 @@ > if (kwatch_handler(condition, regs)) > return 1; > > + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) > + return 1; > + > /* Interrupts not disabled for normal trap handling. */ > restore_interrupts(regs); > > diff -Nur -X /root/dontdiff 44-kp/arch/i386/mm/fault.c > 44-kp-fi/arch/i386/mm/fault.c > --- 44-kp/arch/i386/mm/fault.c Wed Nov 13 16:24:41 2002 > +++ 44-kp-fi/arch/i386/mm/fault.c Thu Nov 14 09:33:35 2002 > @@ -26,6 +26,7 @@ > #include <asm/pgalloc.h> > #include <asm/hardirq.h> > #include <asm/desc.h> > +#include <asm/fi.h> > > extern void die(const char *,struct pt_regs *,long); > > @@ -127,6 +128,7 @@ > } > > asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); > +int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); > > /* > * This routine handles page faults. It determines the address, > @@ -154,7 +156,9 @@ > > if (kprobe_running() && kprobe_fault_handler(regs, 14)) > return; > - > + if (fi_page_fault && fi_page_fault(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 -X /root/dontdiff 44-kp/drivers/net/e100/e100.h > 44-kp-fi/drivers/net/e100/e100.h > --- 44-kp/drivers/net/e100/e100.h Sat Oct 19 12:01:20 2002 > +++ 44-kp-fi/drivers/net/e100/e100.h Wed Nov 13 17:15:28 2002 > @@ -100,7 +100,7 @@ > > #define E100_MAX_NIC 16 > > -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ > +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ Did you mean to include this? > #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ > > /* HWI feature related constant */ > diff -Nur -X /root/dontdiff 44-kp/include/asm-i386/fi.h > 44-kp-fi/include/asm-i386/fi.h > --- 44-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 > +++ 44-kp-fi/include/asm-i386/fi.h Thu Nov 14 09:26:53 2002 > @@ -0,0 +1,8 @@ > +#ifndef _ASM_FI_H > +#define _ASM_FI_H > +#ifdef CONFIG_FI We should us _I386_FI_H or _ASMI386_FI_H since other architectures could have a fi.h also. > +extern int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); > +extern int (*fi_post_page_fault) (unsigned long condition, > + struct pt_regs *reg); > +#endif > +#endif /* _ASM_FI_H */ > diff -Nur -X /root/dontdiff 44-kp/kernel/ksyms.c 44-kp-fi/kernel/ksyms.c > --- 44-kp/kernel/ksyms.c Sat Oct 19 12:01:08 2002 > +++ 44-kp-fi/kernel/ksyms.c Thu Nov 14 10:25:32 2002 > @@ -601,3 +601,7 @@ > > /* debug */ > EXPORT_SYMBOL(dump_stack); > + > +#ifdef CONFIG_FI > +EXPORT_SYMBOL(module_list); > +#endif > > > ------------------------------------------------------- > This sf.net email is sponsored by: Are you worried about > your web server security? Click here for a FREE Thawte > Apache SSL Guide and answer your Apache SSL security > needs: http://www.gothawte.com/rd523.html > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Lynch, R. <rus...@in...> - 2002-11-14 05:56:32
|
But wasn't this a patch to make FI work with 2.5.45? That's what your title says. -rusty -----Original Message----- From: Zhuang, Louis Sent: Wednesday, November 13, 2002 9:53 PM To: Lynch, Rusty Cc: 'fau...@li...' Subject: RE: [Fault-injection-developer] [PATCH] fi_pf patch against 2.5.45 kernel These code is in-progress, so it is not finished. When we reach an end, we will refine it againt current 2.5 kernel. > -----Original Message----- > From: Lynch, Rusty > Sent: Thursday, November 14, 2002 1:44 PM > To: Zhuang, Louis; Gao, Kevin; Wang, Frank; Wang, Stanley > Cc: 'fau...@li...' > Subject: RE: [Fault-injection-developer] [PATCH] fi_pf > patch against 2.5.45 kernel > > > Actually, I like the idea of following lkml practices to > get the fault injection > code ready for submission. That helps shed some light on > what we need > to do for our kernel code. > > We should really start working directly on the latest > development kernel > (currently 2.5.47), with the code available as patch > files on the sourceforge > site. > > Please submit the kernel side fault injection code as a > patch to 2.5.47 as > if we were submitting to LKML. That means follow > patching and coding guidelines > documented in > linux/Documentation/SubmittingPatches,SubmittingDrivers > > -rusty |
From: Zhuang, L. <lou...@in...> - 2002-11-14 05:54:48
|
These code is in-progress, so it is not finished. When we reach an end, we will refine it againt current 2.5 kernel. > -----Original Message----- > From: Lynch, Rusty > Sent: Thursday, November 14, 2002 1:44 PM > To: Zhuang, Louis; Gao, Kevin; Wang, Frank; Wang, Stanley > Cc: 'fau...@li...' > Subject: RE: [Fault-injection-developer] [PATCH] fi_pf > patch against 2.5.45 kernel > > > Actually, I like the idea of following lkml practices to > get the fault injection > code ready for submission. That helps shed some light on > what we need > to do for our kernel code. > > We should really start working directly on the latest > development kernel > (currently 2.5.47), with the code available as patch > files on the sourceforge > site. > > Please submit the kernel side fault injection code as a > patch to 2.5.47 as > if we were submitting to LKML. That means follow > patching and coding guidelines > documented in > linux/Documentation/SubmittingPatches,SubmittingDrivers > > -rusty |
From: Lynch, R. <rus...@in...> - 2002-11-14 05:44:07
|
Actually, I like the idea of following lkml practices to get the fault injection code ready for submission. That helps shed some light on what we need to do for our kernel code. We should really start working directly on the latest development kernel (currently 2.5.47), with the code available as patch files on the sourceforge site. Please submit the kernel side fault injection code as a patch to 2.5.47 as if we were submitting to LKML. That means follow patching and coding guidelines documented in linux/Documentation/SubmittingPatches,SubmittingDrivers -rusty -----Original Message----- From: Zhuang, Louis [mailto:lou...@in...] Sent: Wednesday, November 13, 2002 9:05 PM To: Gao, Kevin; Wang, Frank; Wang, Stanley; Zhuang, Louis Cc: 'fau...@li...' Subject: [Fault-injection-developer] [PATCH] fi_pf patch against 2.5.45 kernel Any comments? Index: src/fi_intcpt/fi_pf/Makefile.am =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/Makefile.am,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Makefile.am --- src/fi_intcpt/fi_pf/Makefile.am 12 Nov 2002 05:56:32 -0000 1.1. 1.1 +++ src/fi_intcpt/fi_pf/Makefile.am 14 Nov 2002 04:21:15 -0000 @@ -5,7 +5,7 @@ include $(top_srcdir)/rules.mk -INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/include -I$(KERNEL)/include +INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/include -I$(KERNEL)/include -I$(KERNEL)/arch/i386/mach-generic if DEBUG DEBUG= -DFI_DEBUG else @@ -16,7 +16,7 @@ -mpreferred-stack-boundary=2 -march=i686 -DMODULE -DMODVERSIONS \ -c -include $(KERNEL)/include/linux/modversions.h \ $(INCLUDE) $(DEBUG) -fi_pf_o_SOURCES = pf.c pf_hooks.c pf_interface.c pf_region.c pf_in.c +fi_pf_o_SOURCES = pf.c pf_interface.c pf_region.c pf_in.c fi_pf.o$(EXEEXT): $(fi_pf_o_OBJECTS) $(LD) -r -o $@ $^ Index: src/fi_intcpt/fi_pf/fi_pf.h =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/fi_pf.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 fi_pf.h --- src/fi_intcpt/fi_pf/fi_pf.h 12 Nov 2002 05:56:32 -0000 1.1.1.1 +++ src/fi_intcpt/fi_pf/fi_pf.h 14 Nov 2002 04:21:15 -0000 @@ -41,17 +41,6 @@ }; /* - * Declare functions in pf_hooks.h - */ -int initialize_pf_hooks(void); -int terminate_pf_hooks(void); -int register_pf_hooks(void); -int deregister_pf_hooks(void); -int arm_pf_hooks(void); -int disarm_pf_hooks(void); - - -/* * Declare functions in pf_interface.c */ void register_pf_interface(void); @@ -85,8 +74,6 @@ /* * Declare functions in pf.c */ -int pf_do_debug(struct pt_regs * regs, unsigned long condition); -int pf_do_page_fault(struct pt_regs * regs); int pf_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname); int pf_unregister(int id, char *modname); int pf_corrupt(int id, __u32 dirty, void *data); Index: src/fi_intcpt/fi_pf/pf.c =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/pf.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 pf.c --- src/fi_intcpt/fi_pf/pf.c 12 Nov 2002 05:56:31 -0000 1.1.1.1 +++ src/fi_intcpt/fi_pf/pf.c 14 Nov 2002 04:21:15 -0000 @@ -50,8 +50,9 @@ #include <linux/slab.h> #include <asm/pgalloc.h> #include <asm/io.h> +#include <asm/tlbflush.h> -#include <linux/dprobes.h> +#include <asm/fi.h> #define PREFIX_NAME "FI_PF" #include <linux/fi/fi.h> @@ -237,19 +238,12 @@ static unsigned long crpt_mask[] = { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF}; -int pf_do_page_fault(struct pt_regs * regs) { - unsigned long address; +int pf_do_page_fault(struct pt_regs * regs, unsigned long address) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int i; int ins_len, crpt_len; - /* - * gets the address, does not need to disallow irq, because our hook - * is before do_page_fault allows irq - */ - __asm__("movl %%cr2,%0":"=r" (address)); - pf_lock_region(); //lock it! if (pf_find_region(address)<0) { if (pf_is_removed_regions(address)) { @@ -335,7 +329,7 @@ out: /* set TF */ - regs->eflags |= EF_TF; + regs->eflags |= X86_EFLAGS_TF; /* clean page fault and tlb ONLY on this cpu */ pf_set_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); @@ -350,7 +344,7 @@ return 0; }; -int pf_do_debug(struct pt_regs * regs, unsigned long condition) { +int pf_do_debug(unsigned long condition, struct pt_regs * regs) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int ins_len, crpt_len; @@ -412,7 +406,7 @@ exit: /* clear TF */ - regs->eflags &= ~EF_TF; + regs->eflags &= ~X86_EFLAGS_TF; /* clean page fault and tlb ONLY on this cpu */ pf_clr_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); @@ -431,40 +425,25 @@ * Initialize/Uninitialize modules */ static int __init fi_pf_init(void) { - int rv=0; - - if ((rv = initialize_pf_hooks())) { - goto err1; - } - if ((rv = register_pf_hooks())) { - goto err2; - } - if ((rv = arm_pf_hooks())) { - goto err3; - } + int rv=0; - register_pf_interface(); - - PINFO("FI Pagefault interceptor v%d.%d.%d loaded.\n", PF_MAJOR, PF_MINOR, PF_PATCH); - EXPORT_NO_SYMBOLS; - return 0; - -err3: - deregister_pf_hooks(); -err2: - terminate_pf_hooks(); -err1: - return rv; + register_pf_interface(); + fi_post_page_fault=pf_do_debug; + fi_page_fault=pf_do_page_fault; + + PINFO("FI Pagefault interceptor v%d.%d.%d loaded.\n", PF_MAJOR, PF_MINOR, PF_PATCH); + EXPORT_NO_SYMBOLS; + return 0; }; static void __exit fi_pf_cleanup(void) { - unregister_pf_interface(); - disarm_pf_hooks(); - deregister_pf_hooks(); - terminate_pf_hooks(); + fi_page_fault=NULL; + fi_post_page_fault=NULL; + unregister_pf_interface(); }; module_init(fi_pf_init); module_exit(fi_pf_cleanup); MODULE_AUTHOR("Louis Zhuang"); MODULE_DESCRIPTION("Pagefault interceptor component for FI"); +MODULE_LICENSE("GPL"); Index: src/fi_intcpt/fi_pf/pf_region.c =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/pf_region.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 pf_region.c --- src/fi_intcpt/fi_pf/pf_region.c 12 Nov 2002 05:56:32 -0000 1.1. 1.1 +++ src/fi_intcpt/fi_pf/pf_region.c 14 Nov 2002 04:21:15 -0000 @@ -84,16 +84,12 @@ } }; -static pte_t *get_pte(unsigned long addr) { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - /* we need to change page table */ - pgd = pgd_offset_k( addr ); - pmd = pmd_offset(pgd, addr ); - pte = pte_offset(pmd, addr ); - return pte; +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); }; /** ------------------------------------------------------- This sf.net email is sponsored by: Are you worried about your web server security? Click here for a FREE Thawte Apache SSL Guide and answer your Apache SSL security needs: http://www.gothawte.com/rd523.html _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Zhuang, L. <lou...@in...> - 2002-11-14 05:07:40
|
Any comments? Index: src/fi_intcpt/fi_pf/Makefile.am =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/Makefile.am,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Makefile.am --- src/fi_intcpt/fi_pf/Makefile.am 12 Nov 2002 05:56:32 -0000 1.1. 1.1 +++ src/fi_intcpt/fi_pf/Makefile.am 14 Nov 2002 04:21:15 -0000 @@ -5,7 +5,7 @@ include $(top_srcdir)/rules.mk -INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/include -I$(KERNEL)/include +INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/include -I$(KERNEL)/include -I$(KERNEL)/arch/i386/mach-generic if DEBUG DEBUG= -DFI_DEBUG else @@ -16,7 +16,7 @@ -mpreferred-stack-boundary=2 -march=i686 -DMODULE -DMODVERSIONS \ -c -include $(KERNEL)/include/linux/modversions.h \ $(INCLUDE) $(DEBUG) -fi_pf_o_SOURCES = pf.c pf_hooks.c pf_interface.c pf_region.c pf_in.c +fi_pf_o_SOURCES = pf.c pf_interface.c pf_region.c pf_in.c fi_pf.o$(EXEEXT): $(fi_pf_o_OBJECTS) $(LD) -r -o $@ $^ Index: src/fi_intcpt/fi_pf/fi_pf.h =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/fi_pf.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 fi_pf.h --- src/fi_intcpt/fi_pf/fi_pf.h 12 Nov 2002 05:56:32 -0000 1.1.1.1 +++ src/fi_intcpt/fi_pf/fi_pf.h 14 Nov 2002 04:21:15 -0000 @@ -41,17 +41,6 @@ }; /* - * Declare functions in pf_hooks.h - */ -int initialize_pf_hooks(void); -int terminate_pf_hooks(void); -int register_pf_hooks(void); -int deregister_pf_hooks(void); -int arm_pf_hooks(void); -int disarm_pf_hooks(void); - - -/* * Declare functions in pf_interface.c */ void register_pf_interface(void); @@ -85,8 +74,6 @@ /* * Declare functions in pf.c */ -int pf_do_debug(struct pt_regs * regs, unsigned long condition); -int pf_do_page_fault(struct pt_regs * regs); int pf_register(struct watchpoint wp, int id, struct iInterceptHook *hook, char *modname); int pf_unregister(int id, char *modname); int pf_corrupt(int id, __u32 dirty, void *data); Index: src/fi_intcpt/fi_pf/pf.c =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/pf.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 pf.c --- src/fi_intcpt/fi_pf/pf.c 12 Nov 2002 05:56:31 -0000 1.1.1.1 +++ src/fi_intcpt/fi_pf/pf.c 14 Nov 2002 04:21:15 -0000 @@ -50,8 +50,9 @@ #include <linux/slab.h> #include <asm/pgalloc.h> #include <asm/io.h> +#include <asm/tlbflush.h> -#include <linux/dprobes.h> +#include <asm/fi.h> #define PREFIX_NAME "FI_PF" #include <linux/fi/fi.h> @@ -237,19 +238,12 @@ static unsigned long crpt_mask[] = { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF}; -int pf_do_page_fault(struct pt_regs * regs) { - unsigned long address; +int pf_do_page_fault(struct pt_regs * regs, unsigned long address) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int i; int ins_len, crpt_len; - /* - * gets the address, does not need to disallow irq, because our hook - * is before do_page_fault allows irq - */ - __asm__("movl %%cr2,%0":"=r" (address)); - pf_lock_region(); //lock it! if (pf_find_region(address)<0) { if (pf_is_removed_regions(address)) { @@ -335,7 +329,7 @@ out: /* set TF */ - regs->eflags |= EF_TF; + regs->eflags |= X86_EFLAGS_TF; /* clean page fault and tlb ONLY on this cpu */ pf_set_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); @@ -350,7 +344,7 @@ return 0; }; -int pf_do_debug(struct pt_regs * regs, unsigned long condition) { +int pf_do_debug(unsigned long condition, struct pt_regs * regs) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int ins_len, crpt_len; @@ -412,7 +406,7 @@ exit: /* clear TF */ - regs->eflags &= ~EF_TF; + regs->eflags &= ~X86_EFLAGS_TF; /* clean page fault and tlb ONLY on this cpu */ pf_clr_pte_bits(pf_reason[cpu].addr, _PAGE_PRESENT); @@ -431,40 +425,25 @@ * Initialize/Uninitialize modules */ static int __init fi_pf_init(void) { - int rv=0; - - if ((rv = initialize_pf_hooks())) { - goto err1; - } - if ((rv = register_pf_hooks())) { - goto err2; - } - if ((rv = arm_pf_hooks())) { - goto err3; - } + int rv=0; - register_pf_interface(); - - PINFO("FI Pagefault interceptor v%d.%d.%d loaded.\n", PF_MAJOR, PF_MINOR, PF_PATCH); - EXPORT_NO_SYMBOLS; - return 0; - -err3: - deregister_pf_hooks(); -err2: - terminate_pf_hooks(); -err1: - return rv; + register_pf_interface(); + fi_post_page_fault=pf_do_debug; + fi_page_fault=pf_do_page_fault; + + PINFO("FI Pagefault interceptor v%d.%d.%d loaded.\n", PF_MAJOR, PF_MINOR, PF_PATCH); + EXPORT_NO_SYMBOLS; + return 0; }; static void __exit fi_pf_cleanup(void) { - unregister_pf_interface(); - disarm_pf_hooks(); - deregister_pf_hooks(); - terminate_pf_hooks(); + fi_page_fault=NULL; + fi_post_page_fault=NULL; + unregister_pf_interface(); }; module_init(fi_pf_init); module_exit(fi_pf_cleanup); MODULE_AUTHOR("Louis Zhuang"); MODULE_DESCRIPTION("Pagefault interceptor component for FI"); +MODULE_LICENSE("GPL"); Index: src/fi_intcpt/fi_pf/pf_region.c =================================================================== RCS file: /cvsroot/fault-injection/fith_core/src/fi_intcpt/fi_pf/pf_region.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 pf_region.c --- src/fi_intcpt/fi_pf/pf_region.c 12 Nov 2002 05:56:32 -0000 1.1. 1.1 +++ src/fi_intcpt/fi_pf/pf_region.c 14 Nov 2002 04:21:15 -0000 @@ -84,16 +84,12 @@ } }; -static pte_t *get_pte(unsigned long addr) { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - /* we need to change page table */ - pgd = pgd_offset_k( addr ); - pmd = pmd_offset(pgd, addr ); - pte = pte_offset(pmd, addr ); - return pte; +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); }; /** |
From: Zhuang, L. <lou...@in...> - 2002-11-14 02:54:08
|
Dear all, Following is the first fault injection patch against 2.5.x sserials kernel. kernel module part is ongoing. Please review it and give us feedback. - Louis diff -Nur -X /root/dontdiff 44-kp/Makefile 44-kp-fi/Makefile --- 44-kp/Makefile Sat Oct 19 12:01:12 2002 +++ 44-kp-fi/Makefile Wed Nov 13 16:28:48 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 44 -EXTRAVERSION = +EXTRAVERSION =kp-fi # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -Nur -X /root/dontdiff 44-kp/arch/i386/Config.help 44-kp-fi/arch/i386/Config.help --- 44-kp/arch/i386/Config.help Wed Nov 13 16:24:41 2002 +++ 44-kp-fi/arch/i386/Config.help Thu Nov 14 09:43:55 2002 @@ -1108,3 +1108,6 @@ register_kprobe(), and providing a callback function. This is useful for kernel debugging, non-intrusive instrumentation and testing. If in doubt, say "N". + CONFIG_FI + Say Y here if you want to enable Fault Injection (FI) mechanism. The FI + can monitor MMIO/IO access in kernel. diff -Nur -X /root/dontdiff 44-kp/arch/i386/config.in 44-kp-fi/arch/i386/config.in --- 44-kp/arch/i386/config.in Wed Nov 13 16:25:00 2002 +++ 44-kp-fi/arch/i386/config.in Thu Nov 14 09:46:44 2002 @@ -469,6 +469,9 @@ fi bool ' Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS bool ' Kprobes' CONFIG_KPROBES + if [ "$CONFIG_KPROBES" = "y" ]; then + bool ' Fault Injection' CONFIG_FI + fi fi if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/i386_ksyms.c 44-kp-fi/arch/i386/kernel/i386_ksyms.c --- 44-kp/arch/i386/kernel/i386_ksyms.c Sat Oct 19 12:02:34 2002 +++ 44-kp-fi/arch/i386/kernel/i386_ksyms.c Thu Nov 14 10:25:53 2002 @@ -32,6 +32,7 @@ #include <asm/tlbflush.h> #include <asm/nmi.h> #include <asm/edd.h> +#include <asm/fi.h> extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -207,3 +208,9 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif + +#ifdef CONFIG_FI +EXPORT_SYMBOL(irq_desc); +EXPORT_SYMBOL(fi_page_fault); +EXPORT_SYMBOL(fi_post_page_fault); +#endif diff -Nur -X /root/dontdiff 44-kp/arch/i386/kernel/traps.c 44-kp-fi/arch/i386/kernel/traps.c --- 44-kp/arch/i386/kernel/traps.c Wed Nov 13 16:25:00 2002 +++ 44-kp-fi/arch/i386/kernel/traps.c Thu Nov 14 09:34:36 2002 @@ -47,6 +47,7 @@ #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> @@ -559,6 +560,9 @@ return 0; } +int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -595,6 +599,9 @@ if (kwatch_handler(condition, regs)) return 1; + if (fi_post_page_fault && fi_post_page_fault(condition, regs)) + return 1; + /* Interrupts not disabled for normal trap handling. */ restore_interrupts(regs); diff -Nur -X /root/dontdiff 44-kp/arch/i386/mm/fault.c 44-kp-fi/arch/i386/mm/fault.c --- 44-kp/arch/i386/mm/fault.c Wed Nov 13 16:24:41 2002 +++ 44-kp-fi/arch/i386/mm/fault.c Thu Nov 14 09:33:35 2002 @@ -26,6 +26,7 @@ #include <asm/pgalloc.h> #include <asm/hardirq.h> #include <asm/desc.h> +#include <asm/fi.h> extern void die(const char *,struct pt_regs *,long); @@ -127,6 +128,7 @@ } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); +int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); /* * This routine handles page faults. It determines the address, @@ -154,7 +156,9 @@ if (kprobe_running() && kprobe_fault_handler(regs, 14)) return; - + if (fi_page_fault && fi_page_fault(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 -X /root/dontdiff 44-kp/drivers/net/e100/e100.h 44-kp-fi/drivers/net/e100/e100.h --- 44-kp/drivers/net/e100/e100.h Sat Oct 19 12:01:20 2002 +++ 44-kp-fi/drivers/net/e100/e100.h Wed Nov 13 17:15:28 2002 @@ -100,7 +100,7 @@ #define E100_MAX_NIC 16 -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ +#define E100_MAX_SCB_WAIT 5000 /* Max udelays in wait_scb */ #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ /* HWI feature related constant */ diff -Nur -X /root/dontdiff 44-kp/include/asm-i386/fi.h 44-kp-fi/include/asm-i386/fi.h --- 44-kp/include/asm-i386/fi.h Thu Jan 1 08:00:00 1970 +++ 44-kp-fi/include/asm-i386/fi.h Thu Nov 14 09:26:53 2002 @@ -0,0 +1,8 @@ +#ifndef _ASM_FI_H +#define _ASM_FI_H +#ifdef CONFIG_FI +extern int (*fi_page_fault) ( struct pt_regs *regs, unsigned long address); +extern int (*fi_post_page_fault) (unsigned long condition, + struct pt_regs *reg); +#endif +#endif /* _ASM_FI_H */ diff -Nur -X /root/dontdiff 44-kp/kernel/ksyms.c 44-kp-fi/kernel/ksyms.c --- 44-kp/kernel/ksyms.c Sat Oct 19 12:01:08 2002 +++ 44-kp-fi/kernel/ksyms.c Thu Nov 14 10:25:32 2002 @@ -601,3 +601,7 @@ /* debug */ EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_FI +EXPORT_SYMBOL(module_list); +#endif |