Whamcloud - gitweb
add kgdb_eth patch
authorwangdi <wangdi>
Tue, 2 Sep 2003 13:47:23 +0000 (13:47 +0000)
committerwangdi <wangdi>
Tue, 2 Sep 2003 13:47:23 +0000 (13:47 +0000)
lustre/kernel_patches/patches/kgdb_eth.patch [new file with mode: 0644]

diff --git a/lustre/kernel_patches/patches/kgdb_eth.patch b/lustre/kernel_patches/patches/kgdb_eth.patch
new file mode 100644 (file)
index 0000000..5c8eaa2
--- /dev/null
@@ -0,0 +1,1185 @@
+Index: linux-2.6.0-test1/arch/i386/kernel/kgdb_stub.c
+===================================================================
+--- linux-2.6.0-test1.orig/arch/i386/kernel/kgdb_stub.c        2003-09-02 14:16:10.000000000 +0800
++++ linux-2.6.0-test1/arch/i386/kernel/kgdb_stub.c     2003-09-02 14:32:02.000000000 +0800
+@@ -30,6 +30,7 @@
+  *
+  *  Written by:            Glenn Engel $
+  *  Updated by:            David Grothe <dave@gcom.com>
++ *  Updated by:            Robert Walsh <rjwalsh@durables.org>
+  *  ModuleState:     Experimental $
+  *
+  *  NOTES:         See Below $
+@@ -112,6 +113,7 @@
+ #include <asm/processor.h>
+ #include <linux/irq.h>
+ #include <asm/desc.h>
++#include <linux/inet.h>
+ /************************************************************************
+  *
+@@ -122,8 +124,16 @@
+ /* Thread reference */
+ typedef unsigned char threadref[8];
+-extern void putDebugChar(int);        /* write a single character      */
+-extern int getDebugChar(void);        /* read and return a single char */
++extern int tty_putDebugChar(int);     /* write a single character      */
++extern int tty_getDebugChar(void);    /* read and return a single char */
++extern void tty_flushDebugChar(void); /* flush pending characters      */
++extern int eth_putDebugChar(int);     /* write a single character      */
++extern int eth_getDebugChar(void);    /* read and return a single char */
++extern void eth_flushDebugChar(void); /* flush pending characters      */
++extern void gdb_eth_set_trapmode(int);
++extern void gdb_eth_reply_arp(void);   /*send arp request */
++extern int gdb_eth_is_initializing;
++
+ /************************************************************************/
+ /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+@@ -264,6 +274,35 @@
+ }
+ /*
++ * I/O dispatch functions...
++ * Based upon gdb_eth, either call the ethernet
++ * handler or the serial one..
++ */
++void putDebugChar(int c)
++{
++  if (gdb_eth == -1)
++      tty_putDebugChar(c);
++  else
++      eth_putDebugChar(c);
++}
++
++int getDebugChar(void)
++{
++  if (gdb_eth == -1)
++      return tty_getDebugChar();
++  else
++      return eth_getDebugChar();
++}
++
++void flushDebugChar(void)
++{
++    if (gdb_eth == -1)
++      tty_flushDebugChar();
++    else
++      eth_flushDebugChar();
++}
++
++/*
+  * Gdb calls functions by pushing agruments, including a return address 
+  * on the stack and the adjusting EIP to point to the function.        The 
+  * whole assumption in GDB is that we are on a different stack than the
+@@ -389,7 +428,6 @@
+               xmitcsum = -1;
+               count = 0;
+-
+               /* now, read until a # or end of buffer is found */
+               while (count < BUFMAX) {
+                       ch = getDebugChar() & 0x7f;
+@@ -429,6 +467,7 @@
+       if (remote_debug)
+               printk("R:%s\n", buffer);
++      flushDebugChar();
+ }
+ /* send the packet in buffer.  */
+@@ -441,25 +480,64 @@
+       char ch;
+       /*  $<packet info>#<checksum>. */
+-      do {
+-              if (remote_debug)
+-                      printk("T:%s\n", buffer);
+-              putDebugChar('$');
+-              checksum = 0;
+-              count = 0;
+-
+-              while ((ch = buffer[count])) {
+-                      putDebugChar(ch);
+-                      checksum += ch;
+-                      count += 1;
+-              }
+-              putDebugChar('#');
+-              putDebugChar(hexchars[checksum >> 4]);
+-              putDebugChar(hexchars[checksum % 16]);
+-
+-      } while ((getDebugChar() & 0x7f) != '+');
++      if (gdb_eth == -1){
++              do {
++                      if (remote_debug)
++                              printk("T:%s\n", buffer);
++                      putDebugChar('$');
++                      checksum = 0;
++                      count = 0;
++
++                      while ((ch = buffer[count])) {
++                              putDebugChar(ch);
++                              checksum += ch;
++                              count += 1;
++                      }
++                      
++                      putDebugChar('#');
++                      putDebugChar(hexchars[checksum >> 4]);
++                      putDebugChar(hexchars[checksum % 16]);
++                      flushDebugChar();
++
++              } while ((getDebugChar() & 0x7f) != '+');
++      }else{
++      
++              /*for udp, we can not transfer too much bytes once */
++              /*we only transfer MAX_SEND_COUNT size byts each time */
++#define MAX_SEND_COUNT 30     
++              int send_count=0, i=0;
++              char send_buf[30];
++              do {
++                      if (remote_debug)
++                              printk("T:%s\n", buffer);
++                      putDebugChar('$');
++                      checksum = 0;
++                      count = 0;
++                      send_count = 0; 
++                      while ((ch = buffer[count])) {
++                              if (send_count >= MAX_SEND_COUNT){
++                                      for(i=0; i < MAX_SEND_COUNT; i++){
++                                              putDebugChar(send_buf[i]);
++                                      }               
++                                      flushDebugChar();
++                                      send_count = 0;
++                              }else{
++                                      send_buf[send_count] = ch;
++                                      checksum += ch;
++                                      count ++;
++                                      send_count++;
++                              }
++                      }
++                      for(i=0; i < send_count; i++)
++                              putDebugChar(send_buf[i]);
++                      putDebugChar('#');
++                      putDebugChar(hexchars[checksum >> 4]);
++                      putDebugChar(hexchars[checksum % 16]);
++                      flushDebugChar();
++              } while ((getDebugChar() & 0x7f) != '+');
++      }
+ }
+ static char remcomInBuffer[BUFMAX];
+@@ -1143,6 +1221,13 @@
+               print_regs(&regs);
+               return (0);
+       }
++      /*
++       * If we're using eth mode, set the 'mode' in the netdevice.
++       */
++
++      if(gdb_eth != -1) {
++              gdb_eth_set_trapmode(1);
++      }
+       kgdb_local_irq_save(flags);
+@@ -1156,8 +1241,8 @@
+        * NMI and will wait there for the following spin locks to be 
+        * released.
+        */
++      
+ #ifdef CONFIG_SMP
+-
+ #if 0
+       if (cpu_callout_map & ~MAX_CPU_MASK) {
+               printk("kgdb : too many cpus, possibly not mapped"
+@@ -1372,6 +1457,7 @@
+       gdb_i386vector = exceptionVector;
+       gdb_i386errcode = err_code;
+       kgdb_info.called_from = __builtin_return_address(0);
++
+ #ifdef CONFIG_SMP
+       /*
+        * OK, we can now communicate, lets tell gdb about the sync.
+@@ -1400,8 +1486,13 @@
+       remcomOutBuffer[2] = hexchars[signo % 16];
+       remcomOutBuffer[3] = 0;
+-      putpacket(remcomOutBuffer);
++      if (gdb_eth_is_initializing) {
++              gdb_eth_is_initializing = 0;
++      } else {
++              putpacket(remcomOutBuffer);
++      }
++      gdb_eth_reply_arp();
+       while (1 == 1) {
+               error = 0;
+               remcomOutBuffer[0] = 0;
+@@ -1419,7 +1510,9 @@
+                              remote_debug ? "on" : "off");
+                       break;
+               case 'g':       /* return the value of the CPU registers */
++                      
+                       get_gdb_regs(usethread, &regs, gdb_regs);
++                      
+                       mem2hex((char *) gdb_regs,
+                               remcomOutBuffer, NUMREGBYTES, 0);
+                       break;
+@@ -1536,6 +1629,10 @@
+                       newPC = regs.eip;
++                      if (gdb_eth != -1) {
++                              gdb_eth_set_trapmode(0);
++                      }
++
+                       /* clear the trace bit */
+                       regs.eflags &= 0xfffffeff;
+@@ -1856,9 +1953,7 @@
+               kgdb_local_irq_restore(flags);
+               return (0);
+       }
+-#if 0
+-exit_just_unlock:
+-#endif
++      exit_just_unlock:
+ #endif
+       /* Release kgdb spinlock */
+       KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+@@ -2213,3 +2308,72 @@
+ typedef int gdb_debug_hook(int exceptionVector,
+                          int signo, int err_code, struct pt_regs *linux_regs);
+ gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;    /* histerical reasons... */
++
++static int __init kgdb_opt_gdbeth(char *str)
++{
++      gdb_eth = simple_strtoul(str,NULL,10);
++      return 1;
++}
++
++static int __init kgdb_opt_gdbeth_remote(char *str)
++{
++      gdb_ethremote = in_aton(str);
++      return 1;
++}
++
++static int __init kgdb_opt_gdbeth_listen(char *str)
++{
++      gdb_listenport = simple_strtoul(str,NULL,10);
++      return 1;
++}
++
++static int __init kgdb_opt_gdbeth_hwaddr(char *str)
++{
++      int  i;
++      char *p;
++
++      p = str;
++      i = 0;
++      while(1)
++      {
++              unsigned int c;
++              sscanf(p, "%x:", &c);
++              gdb_sendhwaddr[i++] = c;
++              while((*p != 0) && (*p != ':'))
++                      p++;
++              if (*p == 0)
++                      break;
++              p++;
++      }
++
++      return 1;
++}
++static int __init kgdb_opt_gdbeth_rchwaddr(char *str)
++{
++      int  i;
++      char *p;
++
++      p = str;
++      i = 0;
++      while(1)
++      {
++              unsigned int c;
++              sscanf(p, "%x:", &c);
++              gdb_receivehwaddr[i++] = c;
++              while((*p != 0) && (*p != ':'))
++                      p++;
++              if (*p == 0)
++                      break;
++              p++;
++      }
++
++      return 1;
++}
++
++
++__setup("gdbeth=", kgdb_opt_gdbeth);
++__setup("gdbeth_remote=", kgdb_opt_gdbeth_remote);
++__setup("gdbeth_listenport=", kgdb_opt_gdbeth_listen);
++__setup("gdbeth_sendhwaddr=", kgdb_opt_gdbeth_hwaddr);
++__setup("gdbeth_receivehwaddr=", kgdb_opt_gdbeth_rchwaddr);
++
+Index: linux-2.6.0-test1/arch/i386/lib/kgdb_serial.c
+===================================================================
+--- linux-2.6.0-test1.orig/arch/i386/lib/kgdb_serial.c 2003-09-02 14:16:11.000000000 +0800
++++ linux-2.6.0-test1/arch/i386/lib/kgdb_serial.c      2003-09-02 14:32:02.000000000 +0800
+@@ -155,12 +155,12 @@
+  * It will receive a limited number of characters of input
+  * from the gdb  host machine and save them up in a buffer.
+  *
+- * When the gdb stub routine getDebugChar() is called it
++ * When the gdb stub routine tty_getDebugChar() is called it
+  * draws characters out of the buffer until it is empty and
+  * then reads directly from the serial port.
+  *
+  * We do not attempt to write chars from the interrupt routine
+- * since the stubs do all of that via putDebugChar() which
++ * since the stubs do all of that via tty_putDebugChar() which
+  * writes one byte after waiting for the interface to become
+  * ready.
+  *
+@@ -226,7 +226,7 @@
+ /*
+  * Hook an IRQ for KGDB.
+  *
+- * This routine is called from putDebugChar, below.
++ * This routine is called from tty_putDebugChar, below.
+  */
+ static int ints_disabled = 1;
+ int
+@@ -331,7 +331,7 @@
+ }
+ /*
+- * getDebugChar
++ * tty_getDebugChar
+  *
+  * This is a GDB stub routine.        It waits for a character from the
+  * serial interface and then returns it.  If there is no serial
+@@ -345,11 +345,11 @@
+ /* Caller takes needed protections */
+ int
+-getDebugChar(void)
++tty_getDebugChar(void)
+ {
+       volatile int chr, dum, time, end_time;
+-      dbprintk(("getDebugChar(port %x): ", gdb_async_info->port));
++      dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+       if (gdb_async_info == NULL) {
+               gdb_hook_interrupt(&local_info, 0);
+@@ -375,7 +375,7 @@
+       dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+       return (chr);
+-}                             /* getDebugChar */
++}                             /* tty_getDebugChar */
+ static int count = 3;
+ static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+@@ -383,6 +383,9 @@
+ static int __init
+ kgdb_enable_ints(void)
+ {
++      if (gdb_eth != -1) {
++              return 0;
++      }
+       if (gdb_async_info == NULL) {
+               gdb_hook_interrupt(&local_info, 1);
+       }
+@@ -444,7 +447,7 @@
+ }
+ /*
+- * putDebugChar
++ * tty_putDebugChar
+  *
+  * This is a GDB stub routine.        It waits until the interface is ready
+  * to transmit a char and then sends it.  If there is no serial
+@@ -452,9 +455,9 @@
+  * pretended to send the char.        Caller takes needed protections.
+  */
+ void
+-putDebugChar(int chr)
++tty_putDebugChar(int chr)
+ {
+-      dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
++      dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+                 gdb_async_info->port,
+                 chr,
+                 chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+@@ -480,6 +483,14 @@
+               }
+       }
+-}                             /* putDebugChar */
++}                             /* tty_putDebugChar */
++
++/*
++ * This does nothing for the serial port, since it doesn't buffer.
++ */
++
++void tty_flushDebugChar(void)
++{
++}
+ module_init(kgdb_enable_ints);
+Index: linux-2.6.0-test1/include/linux/netdevice.h
+===================================================================
+--- linux-2.6.0-test1.orig/include/linux/netdevice.h   2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/include/linux/netdevice.h        2003-09-02 14:32:02.000000000 +0800
+@@ -469,6 +469,11 @@
+       /* statistics sub-directory */
+       struct kobject          stats_kobj;
++
++#ifdef CONFIG_KGDB
++      int                     kgdb_is_trapped;
++      void                    (*kgdb_net_poll_rx)(struct net_device *);
++#endif
+ };
+ #define SET_MODULE_OWNER(dev) do { } while (0)
+@@ -524,6 +529,11 @@
+ extern struct net_device      *dev_get_by_index(int ifindex);
+ extern struct net_device      *__dev_get_by_index(int ifindex);
+ extern int            dev_restart(struct net_device *dev);
++#ifdef CONFIG_KGDB
++int           gdb_eth_is_trapped(void);
++int           gdb_net_interrupt(struct sk_buff *skb);
++void          gdb_send_arp_request(void);
++#endif
+ typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len);
+ extern int            register_gifconf(unsigned int family, gifconf_func_t * gifconf);
+@@ -582,12 +592,20 @@
+ static inline void netif_wake_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++      if (gdb_eth_is_trapped())
++              return;
++#endif
+       if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+               __netif_schedule(dev);
+ }
+ static inline void netif_stop_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++      if (gdb_eth_is_trapped())
++              return;
++#endif
+       set_bit(__LINK_STATE_XOFF, &dev->state);
+ }
+Index: linux-2.6.0-test1/include/asm-i386/kgdb.h
+===================================================================
+--- linux-2.6.0-test1.orig/include/asm-i386/kgdb.h     2003-09-02 14:16:20.000000000 +0800
++++ linux-2.6.0-test1/include/asm-i386/kgdb.h  2003-09-02 14:32:03.000000000 +0800
+@@ -18,6 +18,16 @@
+ #ifndef BREAKPOINT
+ #define BREAKPOINT   asm("   int $3")
+ #endif
++
++extern int gdb_eth;
++extern unsigned gdb_ethremote;
++extern unsigned short gdb_listenport;
++extern unsigned char gdb_sendhwaddr[6];
++extern unsigned char gdb_receivehwaddr[6];
++
++extern int gdb_tty_hook(void);
++extern int gdb_eth_hook(void);
++
+ /*
+  * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+  * pointer to its routine and it will be entered as the first thing
+@@ -34,6 +44,7 @@
+ extern int kgdb_handle_exception(int trapno,
+                                int signo, int err_code, struct pt_regs *regs);
+ extern int in_kgdb(struct pt_regs *regs);
++extern void kgdb_null(void);
+ #ifdef CONFIG_KGDB_TS
+ void kgdb_tstamp(int line, char *source, int data0, int data1);
+Index: linux-2.6.0-test1/drivers/net/e100/e100_main.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/e100/e100_main.c        2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/e100/e100_main.c     2003-09-02 14:32:03.000000000 +0800
+@@ -567,6 +567,15 @@
+ }
+ #endif
++#ifdef CONFIG_KGDB
++static void e100_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      e100intr(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++#endif
++
+ static int __devinit
+ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+ {
+@@ -662,7 +671,9 @@
+       dev->set_multicast_list = &e100_set_multi;
+       dev->set_mac_address = &e100_set_mac;
+       dev->do_ioctl = &e100_ioctl;
+-
++#ifdef CONFIG_KGDB
++      dev->kgdb_net_poll_rx = e100_rx_poll;
++#endif
+       if (bdp->flags & USE_IPCB)
+       dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+                       NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+Index: linux-2.6.0-test1/drivers/net/3c59x.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/3c59x.c 2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/3c59x.c      2003-09-02 14:32:03.000000000 +0800
+@@ -1063,6 +1063,22 @@
+       return rc;
+ }
++#ifdef CONFIG_KGDB
++static void vortex_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      vortex_interrupt(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++
++static void boomerang_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      boomerang_interrupt(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++#endif
++
+ /*
+  * Start up the PCI/EISA device which is described by *gendev.
+  * Return 0 on success.
+@@ -1449,6 +1465,14 @@
+       dev->set_multicast_list = set_rx_mode;
+       dev->tx_timeout = vortex_tx_timeout;
+       dev->watchdog_timeo = (watchdog * HZ) / 1000;
++#ifdef CONFIG_KGDB
++      if (vp->full_bus_master_tx) {
++              dev->kgdb_net_poll_rx = boomerang_rx_poll;
++      } else {
++              dev->kgdb_net_poll_rx = vortex_rx_poll;
++      }
++#endif
++
+ #ifdef HAVE_POLL_CONTROLLER
+       dev->poll_controller = &vorboom_poll;
+ #endif
+Index: linux-2.6.0-test1/drivers/net/Makefile
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/Makefile        2003-07-14 11:32:32.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/Makefile     2003-09-02 14:32:03.000000000 +0800
+@@ -32,6 +32,8 @@
+ obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
++obj-$(CONFIG_KGDB) += kgdb_eth.o
++
+ obj-$(CONFIG_DGRS) += dgrs.o
+ obj-$(CONFIG_RCPCI) += rcpci.o
+ obj-$(CONFIG_VORTEX) += 3c59x.o
+Index: linux-2.6.0-test1/drivers/net/kgdb_eth.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/kgdb_eth.c      2003-09-02 14:32:02.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/kgdb_eth.c   2003-09-02 21:41:42.000000000 +0800
+@@ -0,0 +1,547 @@
++/*
++ * Network interface GDB stub
++ *
++ * Written by San Mehat (nettwerk@biodome.org)
++ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
++ * and Scott Foehner (sfoehner@engr.sgi.com)
++ *
++ * Twiddled for 2.5 by Robert Walsh (rjwalsh@durables.org)
++ *
++ */
++ 
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/config.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <linux/workqueue.h>
++#include <asm/kgdb.h>
++#include <linux/if_ether.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/delay.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/bitops.h>
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/atomic.h>
++
++#undef        PRNT                            /* define for debug printing */
++
++#define       GDB_BUF_SIZE    512             /* power of 2, please */
++
++static char   gdb_buf[GDB_BUF_SIZE] ;
++static int    gdb_buf_in_inx ;
++static atomic_t       gdb_buf_in_cnt ;
++static int    gdb_buf_out_inx ;
++
++extern void   set_debug_traps(void) ;         /* GDB routine */
++extern void     breakpoint(void);
++
++unsigned int    gdb_ethremote = 0;
++unsigned short  gdb_listenport = 6443;
++unsigned short  gdb_sendport= 6442;
++int             gdb_eth = -1; /* Default tty mode */
++unsigned char   gdb_sendhwaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++unsigned char   gdb_receivehwaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++int             gdb_eth_is_initializing = 0;
++int           gdb_eth_debug = 0;
++
++struct net_device *gdb_netdevice = NULL;
++
++//static int      initialized = -1;
++//static struct work_struct irq_bp;
++
++static void bpwork_func(void *p)
++{
++    udelay(500);
++    BREAKPOINT;
++}
++
++static struct workqueue_struct *irq_bp;
++DECLARE_WORK(bpwork, bpwork_func, NULL);
++
++/*
++ * Get a char if available, return -1 if nothing available.
++ * Empty the receive buffer first, then look at the interface hardware.
++ */
++static int read_char(void)
++{
++    
++    if (atomic_read(&gdb_buf_in_cnt) != 0) /* intr routine has q'd chars */
++    {
++      int chr ;
++
++      chr = gdb_buf[gdb_buf_out_inx++] ;
++      gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
++      atomic_dec(&gdb_buf_in_cnt) ;
++      return chr;
++    }
++    return -1; // no data
++} /* read_char */
++
++//static unsigned char daddr[6] = {0x00,0x06,0x25,0xA9,0x9F,0x6A};
++//static unsigned char daddr[6] = {0x00,0x50,0xFC,0xB8,0x22,0x03};
++//static unsigned char daddr[6] = {0x00,0x08,0x74,0x96,0x6D,0x9B};
++//static unsigned char daddr[6] = {0x00,0x07,0xE9,0xD4,0xBE,0x85};
++//static unsigned char daddr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
++
++/*
++ * Wait until the interface can accept a char, then write it.
++ */
++static void write_buffer(char *buf, int len)
++{
++    int              total_len, eth_len, ip_len, udp_len;
++    struct in_device *in_dev;
++    struct sk_buff   *skb;
++    struct udphdr    *udph;
++    struct iphdr     *iph;
++    struct ethhdr    *eth;
++
++    if (!(in_dev = (struct in_device *) gdb_netdevice->ip_ptr)) 
++      panic("No in_device available for interface!\n");
++    if (!(in_dev->ifa_list))
++      panic("No interface address set for interface!\n");
++    udp_len = len + sizeof(struct udphdr);
++    ip_len = eth_len = udp_len + sizeof(struct iphdr);
++    total_len = eth_len + ETH_HLEN;
++
++    if (!(skb = alloc_skb(total_len, GFP_ATOMIC)))
++      return;
++
++    atomic_set(&skb->users, 1);
++    skb_reserve(skb, total_len - 1);
++
++    memcpy(skb->data , (unsigned char *) buf, len);
++    skb->len += len;
++
++    udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++    udph->source = htons(gdb_listenport);
++    udph->dest   = htons(gdb_sendport);
++    udph->len    = htons(udp_len);
++    udph->check  = 0;
++  
++    iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++    iph->version = 4;
++    iph->ihl     = 5;
++    iph->tos     = 0;
++    iph->tot_len = htons(ip_len);
++    iph->id      = 0;
++    iph->frag_off= 0;
++    iph->ttl     = 64;
++    iph->protocol= IPPROTO_UDP;
++    iph->check   = 0;
++    iph->saddr   = in_dev->ifa_list->ifa_address;
++    iph->daddr   = gdb_ethremote;
++    iph->check   = ip_fast_csum((unsigned char *)iph, iph->ihl);
++
++    eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
++    eth->h_proto = htons(ETH_P_IP);
++    memcpy(eth->h_source, gdb_sendhwaddr, gdb_netdevice->addr_len);
++//    memcpy(eth->h_dest, daddr, gdb_netdevice->addr_len);
++    memcpy(eth->h_dest, gdb_receivehwaddr, gdb_netdevice->addr_len);
++
++#if 0 
++repeat_poll:
++#endif
++    spin_lock(&gdb_netdevice->xmit_lock);
++    gdb_netdevice->xmit_lock_owner = smp_processor_id();
++#if 0 
++    if (netif_queue_stopped(gdb_netdevice))
++    {
++      gdb_netdevice->xmit_lock_owner = -1;
++      spin_unlock(&gdb_netdevice->xmit_lock);
++      gdb_netdevice->poll_controller(gdb_netdevice);
++      zap_completion_queue();
++      goto repeat_poll;
++    }
++#endif
++    gdb_netdevice->hard_start_xmit(skb, gdb_netdevice);
++    gdb_netdevice->xmit_lock_owner = -1;
++    spin_unlock(&gdb_netdevice->xmit_lock);
++
++   // kfree_skb(skb);
++} /* write_char */
++/* in interrupt state the target machine will not response the arp request */ 
++
++static struct sk_buff *send_skb = NULL;
++void gdb_eth_reply_arp(void)
++{
++      if (send_skb){
++#if 0 
++repeat_poll:
++#endif
++              spin_lock(&gdb_netdevice->xmit_lock);
++              gdb_netdevice->xmit_lock_owner = smp_processor_id();
++#if 0 
++              if (netif_queue_stopped(gdb_netdevice)){
++                      gdb_netdevice->xmit_lock_owner = -1;
++                      spin_unlock(&gdb_netdevice->xmit_lock);
++                      gdb_netdevice->poll_controller(gdb_netdevice);
++                      zap_completion_queue();
++                      goto repeat_poll;
++              }
++#endif
++              gdb_netdevice->hard_start_xmit(send_skb, gdb_netdevice);
++              gdb_netdevice->xmit_lock_owner = -1;
++              spin_unlock(&gdb_netdevice->xmit_lock);
++              send_skb = NULL;        
++      
++      }
++}
++static int make_arp_request( struct sk_buff *skb)
++{
++      struct arphdr *arp;
++      unsigned char *arp_ptr;
++      int type = ARPOP_REPLY;
++      int ptype = ETH_P_ARP;
++      u32 sip, tip;
++      unsigned char *sha, *tha;
++      struct in_device *in_dev = (struct in_device *) gdb_netdevice->ip_ptr; 
++      /*
++       *      No arp on this interface.
++       */
++      if (gdb_netdevice->flags &IFF_NOARP)
++              return 0;
++      if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
++                               (2 * gdb_netdevice->addr_len) +
++                               (2 * sizeof(u32)))))
++              return 0;
++      
++      skb->h.raw = skb->nh.raw = skb->data;
++      arp = skb->nh.arph;
++
++      if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
++           arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
++          arp->ar_pro != htons(ETH_P_IP))
++              return 0;
++
++/* Understand only these message types */
++
++      if (arp->ar_op != htons(ARPOP_REQUEST))
++              return 0;
++/*
++ *    Extract fields
++ */
++      arp_ptr= (unsigned char *)(arp+1);
++      sha     = arp_ptr;
++      arp_ptr += gdb_netdevice->addr_len;
++      memcpy(&sip, arp_ptr, 4);
++      arp_ptr += 4;
++      tha     = arp_ptr;
++      arp_ptr += gdb_netdevice->addr_len;
++      memcpy(&tip, arp_ptr, 4);
++      if (tip != in_dev->ifa_list->ifa_address){
++              return 0;
++      } 
++      if (gdb_ethremote != sip){
++              return 0;       
++      }
++/* 
++ *    Check for bad requests for 127.x.x.x and requests for multicast
++ *    addresses.  If this is one such, delete it.
++ */
++      
++      if (LOOPBACK(tip) || MULTICAST(tip))
++              return 0;
++
++/*
++ *      reply the arp request
++ */   
++      send_skb = alloc_skb(sizeof(struct arphdr)+ 2*(gdb_netdevice->addr_len+4)
++                              + LL_RESERVED_SPACE(gdb_netdevice), GFP_ATOMIC);
++      if (send_skb == NULL)
++              return 0;
++
++      skb_reserve(send_skb, LL_RESERVED_SPACE(gdb_netdevice));
++      send_skb->nh.raw = send_skb->data;
++      arp = (struct arphdr *) skb_put(send_skb,sizeof(struct arphdr) + 2*(gdb_netdevice->addr_len+4));
++      send_skb->dev = gdb_netdevice;
++      send_skb->protocol = htons(ETH_P_ARP);
++      
++      /*
++       *      Fill the device header for the ARP frame
++       */
++      if (gdb_netdevice->hard_header &&
++          gdb_netdevice->hard_header(send_skb,  gdb_netdevice,  ptype, gdb_receivehwaddr, gdb_sendhwaddr, send_skb->len) < 0){
++              kfree_skb(send_skb);
++              return 0;
++      }
++      /*
++       * Fill out the arp protocol part.
++       *
++       * we only support ethernet device type, 
++       * which (according to RFC 1390) should always equal 1 (Ethernet).
++       */
++      arp->ar_hrd = htons(gdb_netdevice->type);
++      arp->ar_pro = htons(ETH_P_IP);
++
++      arp->ar_hln = gdb_netdevice->addr_len;
++      arp->ar_pln = 4;
++      arp->ar_op = htons(type);
++
++      arp_ptr=(unsigned char *)(arp+1);
++
++      memcpy(arp_ptr, gdb_netdevice->dev_addr, gdb_netdevice->addr_len); 
++      arp_ptr += gdb_netdevice->addr_len;
++      memcpy(arp_ptr, &tip, 4);
++      arp_ptr += 4;
++        memcpy(arp_ptr, gdb_sendhwaddr, gdb_netdevice->addr_len);
++      arp_ptr+=gdb_netdevice->addr_len;
++      memcpy(arp_ptr, &sip, 4);
++      return 0;
++}
++/*
++ * Accept an skbuff from net_device layer and 
++ * add the payload onto gdb buffer
++ *
++ * When the gdb stub routine getDebugChar() is called it
++ * draws characters out of the buffer until it is empty and
++ * then reads directly from the serial port.
++ *
++ * We do not attempt to write chars from the interrupt routine
++ * since the stubs do all of that via putDebugChar() which
++ * writes one byte after waiting for the interface to become
++ * ready.
++ *
++ * The debug stubs like to run with interrupts disabled since,
++ * after all, they run as a consequence of a breakpoint in
++ * the kernel.
++ *
++ * NOTE: Return value of 1 means it was for us and is an
++ * indication to the calling driver to destroy the sk_buff
++ * and not send it up the stack
++ */
++
++int gdb_net_interrupt(struct sk_buff *skb)
++{
++    unsigned char  chr;
++    struct iphdr   *iph = (struct iphdr*)skb->data;
++    struct udphdr  *udph= (struct udphdr*)(skb->data+(iph->ihl<<2));
++    unsigned char  *data = (unsigned char *) udph + sizeof(struct udphdr);
++    int            len;
++    int            i;
++
++    if ((gdb_eth != -1) && (!gdb_netdevice) &&
++      (iph->protocol == IPPROTO_UDP) &&
++      (be16_to_cpu(udph->dest) == gdb_listenport)) {
++      gdb_sendport = be16_to_cpu(udph->source);
++      
++        while(gdb_eth_is_initializing);
++      if(!gdb_netdevice)
++          gdb_eth_hook();
++      if (!gdb_netdevice) {
++          /* Lets not even try again. */
++          gdb_eth = -1;
++          return 0;
++      }
++    }
++    if (!gdb_netdevice) {
++      return 0;
++    }
++    if (skb->protocol == __constant_htons(ETH_P_ARP) && !send_skb){
++      make_arp_request(skb);
++      return 0;
++    }
++    if (iph->protocol != IPPROTO_UDP)
++      return 0;
++
++    if (be16_to_cpu(udph->dest) != gdb_listenport)
++      return 0;
++
++    len = be16_to_cpu(iph->tot_len) - (sizeof(struct udphdr) +
++                                     sizeof(struct iphdr));
++    for (i = 0; i < len; i++)
++    {
++      chr = *data++;
++      if (chr == 3)
++      {
++          queue_work(irq_bp, &bpwork);
++//        flush_workqueue(irq_bp);
++          continue;
++/*
++          if (!in_interrupt())
++          {
++              breakpoint();
++          }
++          else
++          {
++              schedule_work(&irq_bp); // XXX: is this really necessary??
++          }
++          continue;
++*/
++      }
++      if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE)
++      {                               /* buffer overflow, clear it */
++          gdb_buf_in_inx = 0 ;
++          atomic_set(&gdb_buf_in_cnt, 0) ;
++          gdb_buf_out_inx = 0 ;
++          break ;
++      }
++      gdb_buf[gdb_buf_in_inx++] = chr ;
++      gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
++      atomic_inc(&gdb_buf_in_cnt) ;
++    }
++
++    return 1;
++} /* gdb_interrupt */
++
++
++int gdb_eth_hook(void)
++{
++    char gdb_netdev[16];
++    extern void kgdb_respond_ok(void);
++
++    if (gdb_sendhwaddr[0] == 0xff)
++      panic("ERROR! 'gdbeth_sendhwaddr' option not set!\n");
++    if (gdb_receivehwaddr[0] == 0xff)
++      panic("ERROR! 'gdbeth_receivehwaddr' option not set!\n");
++    if (gdb_ethremote == 0)
++      panic("ERROR! 'gdbeth_remote' option not set!\n");
++
++    sprintf(gdb_netdev,"eth%d",gdb_eth);
++
++#ifdef CONFIG_SMP
++    if (num_online_cpus() > CONFIG_NO_KGDB_CPUS){ 
++      printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
++      return -1;
++    }
++#endif
++    for (gdb_netdevice = dev_base;
++       gdb_netdevice != NULL; 
++       gdb_netdevice = gdb_netdevice->next){
++      if (strncmp(gdb_netdevice->name, gdb_netdev, IFNAMSIZ) == 0)
++          break;
++    }
++    if (!gdb_netdevice){
++      printk("KGDB NET : Unable to find interface %s\n",gdb_netdev);
++      return -ENODEV;
++    }
++
++    /*
++     * Call GDB routine to setup the exception vectors for the debugger
++     */
++    set_debug_traps() ;
++
++    /*
++     * Call the breakpoint() routine in GDB to start the debugging
++     * session.
++     */
++     if (gdb_eth_debug){
++          printk(KERN_INFO "Waiting for remote gdb connection from %x on local port %d\n",
++                 gdb_ethremote, gdb_listenport);
++          printk(KERN_INFO "We are sending on port %d to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++                 gdb_sendport,
++                 gdb_sendhwaddr[0],
++                 gdb_sendhwaddr[1],
++                 gdb_sendhwaddr[2],
++                 gdb_sendhwaddr[3],
++                 gdb_sendhwaddr[4],
++                 gdb_sendhwaddr[5]);
++          printk("Connected.\n");
++    }
++    gdb_eth_is_initializing = 1;
++    queue_work(irq_bp, &bpwork);
++    return 0;
++} /* gdb_hook_interrupt2 */
++
++/*
++ * getDebugChar
++ *
++ * This is a GDB stub routine.  It waits for a character from the
++ * serial interface and then returns it.  If there is no serial
++ * interface connection then it returns a bogus value which will
++ * almost certainly cause the system to hang.
++ */
++int eth_getDebugChar(void)
++{
++    volatile int      chr ;
++
++    while((chr = read_char()) < 0)
++    {
++      if (send_skb){
++              gdb_eth_reply_arp();    
++        }
++      if (gdb_netdevice->kgdb_net_poll_rx)
++          gdb_netdevice->kgdb_net_poll_rx(gdb_netdevice);
++      else
++        {
++          printk("KGDB NET: Error - Device %s is not supported!\n",
++                 gdb_netdevice->name);
++          panic("Please add support for kgdb net to this driver");
++        }
++    }
++    return chr;
++
++} /* eth_getDebugChar */
++
++#define ETH_QUEUE_SIZE 256
++static char eth_queue[ETH_QUEUE_SIZE];
++static int outgoing_queue;
++
++void eth_flushDebugChar(void)
++{
++    if(outgoing_queue) {
++      write_buffer(eth_queue, outgoing_queue);
++
++      outgoing_queue = 0;
++    }
++}
++
++static void put_char_on_queue(int chr)
++{
++    eth_queue[outgoing_queue++] = chr;
++    if(outgoing_queue == ETH_QUEUE_SIZE)
++    {
++      eth_flushDebugChar();
++    }
++}
++
++/*
++ * eth_putDebugChar
++ *
++ * This is a GDB stub routine.  It waits until the interface is ready
++ * to transmit a char and then sends it.
++ */
++void eth_putDebugChar(int chr)
++{
++    if (gdb_eth_debug)
++      printk(KERN_INFO "eth_putDebugChar: chr=%02x '%c'\n", chr,
++              chr > ' ' && chr < 0x7F ? chr : ' ') ;
++    put_char_on_queue(chr) ;  /* this routine will wait */
++} /* putDebugChar */
++
++void gdb_eth_set_trapmode(int mode)
++{
++    if (!gdb_netdevice)
++      return;
++    gdb_netdevice->kgdb_is_trapped = mode;
++}
++
++int gdb_eth_is_trapped()
++{
++    if (!gdb_netdevice)
++      return 0;
++    return gdb_netdevice->kgdb_is_trapped;
++}
++
++static int __init
++kgdb_eth_init(void)
++{
++    irq_bp = create_workqueue("kgdb");
++    return 0;
++}
++
++module_init(kgdb_eth_init);
+Index: linux-2.6.0-test1/net/core/dev.c
+===================================================================
+--- linux-2.6.0-test1.orig/net/core/dev.c      2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/net/core/dev.c   2003-09-02 14:32:03.000000000 +0800
+@@ -188,7 +188,9 @@
+ extern int netdev_sysfs_init(void);
+ extern int netdev_register_sysfs(struct net_device *);
+ extern void netdev_unregister_sysfs(struct net_device *);
+-
++#ifdef CONFIG_KGDB
++extern int gdb_net_interrupt(struct sk_buff *skb);
++#endif
+ /*******************************************************************************
+@@ -1349,6 +1351,21 @@
+       struct softnet_data *queue;
+       unsigned long flags;
++#ifdef CONFIG_KGDB
++      /* See if kgdb_eth wants this packet */
++      if (!gdb_net_interrupt(skb)) {
++              /* No.. if we're 'trapped' then junk it */
++              if (gdb_eth_is_trapped()) {
++                      kfree_skb(skb);
++                      return NET_RX_DROP;
++              }
++      } else {
++              /* kgdb_eth ate the packet... drop it silently */
++              kfree_skb(skb);
++              return NET_RX_DROP;
++      }
++#endif
++
+       /*
+        * The code is rearranged so that the path is the most