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 + * Updated by: Robert Walsh * ModuleState: Experimental $ * * NOTES: See Below $ @@ -112,6 +113,7 @@ #include #include #include +#include /************************************************************************ * @@ -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; /* $#. */ - 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(®s); 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, ®s, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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