diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/Documentation/DocBook/Makefile linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/Makefile --- linux-2.6.18-53.1.14/Documentation/DocBook/Makefile 2008-03-06 05:54:50.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/Makefile 2008-06-10 15:37:25.000000000 +0400 @@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mc procfs-guide.xml writing_usb_driver.xml \ kernel-api.xml journal-api.xml lsm.xml utrace.xml usb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ - genericirq.xml + genericirq.xml kgdb.xml ### # The build process is as follows (targets): diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/Documentation/DocBook/kgdb.tmpl linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/kgdb.tmpl --- linux-2.6.18-53.1.14/Documentation/DocBook/kgdb.tmpl 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/kgdb.tmpl 2008-06-10 15:38:50.000000000 +0400 @@ -0,0 +1,250 @@ + + + + + + KGDB Internals + + + + Tom + Rini + +
+ trini@kernel.crashing.org +
+
+
+
+ + + + Amit S. + Kale + +
+ amitkale@linsyssoft.com +
+
+
+
+ + + 2004-2005 + MontaVista Software, Inc. + + + 2004 + Amit S. Kale + + + + + This file is licensed under the terms of the GNU General Public License + version 2. This program is licensed "as is" without any warranty of any + kind, whether express or implied. + + + +
+ + + + Introduction + + kgdb is a source level debugger for linux kernel. It is used along + with gdb to debug a linux kernel. Kernel developers can debug a kernel + similar to application programs with the use of kgdb. It makes it + possible to place breakpoints in kernel code, step through the code + and observe variables. + + + Two machines are required for using kgdb. One of these machines is a + development machine and the other is a test machine. The machines are + typically connected through a serial line, a null-modem cable which + connects their serial ports. It is also possible however, to use an + ethernet connection between the machines. The kernel to be debugged + runs on the test machine. gdb runs on the development machine. The + serial line or ethernet connection is used by gdb to communicate to + the kernel being debugged. + + + + Compiling a kernel + + To enable CONFIG_KGDB, look under the "Kernel debugging" + and then select "KGDB: kernel debugging with remote gdb". + + + The first choice for I/O is CONFIG_KGDB_ONLY_MODULES. + This means that you will only be able to use KGDB after loading a + kernel module that defines how you want to be able to talk with + KGDB. There are two other choices (more on some architectures) that + can be enabled as modules later, if not picked here. + + The first of these is CONFIG_KGDB_8250_NOMODULE. + This has sub-options such as CONFIG_KGDB_SIMPLE_SERIAL + which toggles choosing the serial port by ttyS number or by specifying + a port and IRQ number. + + + The second of these choices on most systems for I/O is + CONFIG_KGDBOE. This requires that the machine to be + debugged has an ethernet card which supports the netpoll API, such as + the cards supported by CONFIG_E100. There are no + sub-options for this, but a kernel command line option is required. + + + + Booting the kernel + + The Kernel command line option kgdbwait makes kgdb + wait for gdb connection during booting of a kernel. If the + CONFIG_KGDB_8250 driver is used (or if applicable, + another serial driver) this breakpoint will happen very early on, before + console output. If you wish to change serial port information and you + have enabled both CONFIG_KGDB_8250 and + CONFIG_KGDB_SIMPLE_SERIAL then you must pass the option + kgdb8250=<io or mmio>,<address>,<baud + rate>,<irq> before kgdbwait. + The values io or mmio refer to + if the address being passed next needs to be memory mapped + (mmio) or not. The address must + be passed in hex and is the hardware address and will be remapped if + passed as mmio. The value + baud rate and irq are base-10. + The supported values for baud rate are + 9600, 19200, + 38400, 57600, and + 115200. + + + To have KGDB stop the kernel and wait, with the compiled values for the + serial driver, pass in: kgdbwait. + + + To specify the values of the SH SCI(F) serial port at boot: + kgdbsci=0,115200. + + + To specify the values of the serial port at boot: + kgdb8250=io,3f8,115200,3. + On IA64 this could also be: + kgdb8250=mmio,0xff5e0000,115200,74 + And to have KGDB also stop the kernel and wait for GDB to connect, pass in + kgdbwait after this arguement. + + + To configure the CONFIG_KGDBOE driver, pass in + kgdboe=[src-port]@<src-ip>/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr] + where: + + src-port (optional): source for UDP packets (defaults to 6443) + src-ip: source IP to use (interface address) + dev (optional): network interface (eth0) + tgt-port (optional): port GDB will use (defaults to 6442) + tgt-ip: IP address GDB will be connecting from + tgt-macaddr (optional): ethernet MAC address for logging agent (default is broadcast) + + + + The CONFIG_KGDBOE driver can be reconfigured at run + time, if CONFIG_SYSFS and + CONFIG_MODULES by echo'ing a new config string to + /sys/module/kgdboe/parameter/kgdboe. The + driver can be unconfigured with the special string + not_configured. + + + + Connecting gdb + + If you have used any of the methods to have KGDB stop and create + an initial breakpoint described in the previous chapter, kgdb prints + the message "Waiting for connection from remote gdb..." on the console + and waits for connection from gdb. At this point you connect gdb to kgdb. + + + Example (serial): + + + % gdb ./vmlinux + (gdb) set remotebaud 115200 + (gdb) target remote /dev/ttyS0 + + + Example (ethernet): + + + % gdb ./vmlinux + (gdb) target remote udp:192.168.2.2:6443 + + + Once connected, you can debug a kernel the way you would debug an + application program. + + + + Architecture specific notes + + SuperH: The NMI switch found on some boards can be used to trigger an + initial breakpoint. Subsequent triggers do nothing. If console + is enabled on the SCI(F) serial port, and that is the port being used + for KGDB, then you must trigger a breakpoint via sysrq, NMI, or + some other method prior to connecting, or echo a control-c to the + serial port. Also, to use the SCI(F) port for KGDB, the + CONFIG_SERIAL_SH_SCI driver must be enabled. + + + + The common backend (required) + + There are a few flags which must be set on every architecture in + their <asm/kgdb.h> file. These are: + + + + NUMREGBYTES: The size in bytes of all of the registers, so + that we can ensure they will all fit into a packet. + + + BUFMAX: The size in bytes of the buffer GDB will read into. + This must be larger than NUMREGBYTES. + + + CACHE_FLUSH_IS_SAFE: Set to one if it always safe to call + flush_cache_range or flush_icache_range. On some architectures, + these functions may not be safe to call on SMP since we keep other + CPUs in a holding pattern. + + + + + + There are also the following functions for the common backend, + found in kernel/kgdb.c that must be supplied by the + architecture-specific backend. No weak version of these is provided. + +!Iinclude/linux/kgdb.h + + + The common backend (optional) + + These functions are part of the common backend, found in kernel/kgdb.c + and are optionally implemented. Some functions (with _hw_ in the name) + end up being required on arches which use hardware breakpoints. + +!Ikernel/kgdb.c + + + Driver-Specific Functions + + Some of the I/O drivers have additional functions that can be + called, that are specific to the driver. Calls from other places + to these functions must be wrapped in #ifdefs for the driver in + question. + +!Idrivers/serial/8250_kgdb.c + +
diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/MAINTAINERS linux-2.6.18-53.1.14.kgdb/MAINTAINERS --- linux-2.6.18-53.1.14/MAINTAINERS 2008-03-06 05:54:49.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/MAINTAINERS 2008-06-10 15:37:25.000000000 +0400 @@ -1715,6 +1715,15 @@ L: linux-kernel@vger.kernel.org L: fastboot@osdl.org S: Maintained +KGDB +P: Tom Rini +P: Amit S. Kale +M: trini@kernel.crashing.org +M: amitkale@linsyssoft.com +W: http://sourceforge.net/projects/kgdb +L: kgdb-bugreport@lists.sourceforge.net +S: Maintained + KPROBES P: Prasanna S Panchamukhi M: prasanna@in.ibm.com diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/Makefile linux-2.6.18-53.1.14.kgdb/Makefile --- linux-2.6.18-53.1.14/Makefile 2008-03-06 05:55:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/Makefile 2008-06-10 15:39:01.000000000 +0400 @@ -992,6 +992,7 @@ MRPROPER_DIRS += include/config include MRPROPER_FILES += .config .config.old include/asm .version .old_version \ include/linux/autoconf.h include/linux/version.h \ include/linux/utsrelease.h \ + include/linux/dwarf2-defs.h \ Module.symvers tags TAGS cscope* # clean - Delete most, but leave enough to build external modules @@ -1422,7 +1423,11 @@ clean := -f $(if $(KBUILD_SRC),$(srctree endif # skip-makefile PHONY += FORCE -FORCE: +include/linux/dwarf2-defs.h: $(srctree)/include/linux/dwarf2.h $(srctree)/scripts/dwarfh.awk + mkdir -p include/linux/ + awk -f $(srctree)/scripts/dwarfh.awk $(srctree)/include/linux/dwarf2.h > include/linux/dwarf2-defs.h + +FORCE: include/linux/dwarf2-defs.h # Declare the contents of the .PHONY variable as phony. We keep that diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/Makefile --- linux-2.6.18-53.1.14/arch/arm/kernel/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/Makefile 2008-06-10 15:38:56.000000000 +0400 @@ -20,6 +20,7 @@ obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/entry-armv.S linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/entry-armv.S --- linux-2.6.18-53.1.14/arch/arm/kernel/entry-armv.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/entry-armv.S 2008-06-10 15:39:01.000000000 +0400 @@ -15,6 +15,7 @@ * it to save wrong values... Be aware! */ +#include #include #include #include @@ -232,6 +233,7 @@ svc_preempt: beq preempt_return @ go again b 1b #endif + CFI_END_FRAME(__irq_svc) .align 5 __und_svc: diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/kgdb-jmp.S linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/kgdb-jmp.S --- linux-2.6.18-53.1.14/arch/arm/kernel/kgdb-jmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/kgdb-jmp.S 2008-06-10 15:38:56.000000000 +0400 @@ -0,0 +1,32 @@ +/* + * arch/arm/kernel/kgdb-jmp.S + * + * Trivial setjmp and longjmp procedures to support bus error recovery + * which may occur during kgdb memory read/write operations. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-2005 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program as licensed + * "as is" without any warranty of any kind, whether express or implied. + */ +#include + +ENTRY (kgdb_fault_setjmp) + /* Save registers */ + stmia r0, {r0-r14} + str lr,[r0, #60] + mrs r1,cpsr + str r1,[r0,#64] + ldr r1,[r0,#4] + mov r0, #0 + mov pc,lr + +ENTRY (kgdb_fault_longjmp) + /* Restore registers */ + mov r1,#1 + str r1,[r0] + ldr r1,[r0, #64] + msr spsr,r1 + ldmia r0,{r0-pc}^ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/arm/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/kgdb.c 2008-06-10 15:38:56.000000000 +0400 @@ -0,0 +1,208 @@ +/* + * arch/arm/kernel/kgdb.c + * + * ARM KGDB support + * + * Copyright (c) 2002-2004 MontaVista Software, Inc + * + * Authors: George Davis + * Deepak Saxena + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Make a local copy of the registers passed into the handler (bletch) */ +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +{ + int regno; + + /* Initialize all to zero (??) */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + gdb_regs[_R0] = kernel_regs->ARM_r0; + gdb_regs[_R1] = kernel_regs->ARM_r1; + gdb_regs[_R2] = kernel_regs->ARM_r2; + gdb_regs[_R3] = kernel_regs->ARM_r3; + gdb_regs[_R4] = kernel_regs->ARM_r4; + gdb_regs[_R5] = kernel_regs->ARM_r5; + gdb_regs[_R6] = kernel_regs->ARM_r6; + gdb_regs[_R7] = kernel_regs->ARM_r7; + gdb_regs[_R8] = kernel_regs->ARM_r8; + gdb_regs[_R9] = kernel_regs->ARM_r9; + gdb_regs[_R10] = kernel_regs->ARM_r10; + gdb_regs[_FP] = kernel_regs->ARM_fp; + gdb_regs[_IP] = kernel_regs->ARM_ip; + gdb_regs[_SP] = kernel_regs->ARM_sp; + gdb_regs[_LR] = kernel_regs->ARM_lr; + gdb_regs[_PC] = kernel_regs->ARM_pc; + gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; +} + +/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +{ + kernel_regs->ARM_r0 = gdb_regs[_R0]; + kernel_regs->ARM_r1 = gdb_regs[_R1]; + kernel_regs->ARM_r2 = gdb_regs[_R2]; + kernel_regs->ARM_r3 = gdb_regs[_R3]; + kernel_regs->ARM_r4 = gdb_regs[_R4]; + kernel_regs->ARM_r5 = gdb_regs[_R5]; + kernel_regs->ARM_r6 = gdb_regs[_R6]; + kernel_regs->ARM_r7 = gdb_regs[_R7]; + kernel_regs->ARM_r8 = gdb_regs[_R8]; + kernel_regs->ARM_r9 = gdb_regs[_R9]; + kernel_regs->ARM_r10 = gdb_regs[_R10]; + kernel_regs->ARM_fp = gdb_regs[_FP]; + kernel_regs->ARM_ip = gdb_regs[_IP]; + kernel_regs->ARM_sp = gdb_regs[_SP]; + kernel_regs->ARM_lr = gdb_regs[_LR]; + kernel_regs->ARM_pc = gdb_regs[_PC]; + kernel_regs->ARM_cpsr = gdb_regs[GDB_MAX_REGS - 1]; +} + +static inline struct pt_regs *kgdb_get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task->thread_info + THREAD_SIZE - + 8 - sizeof(struct pt_regs)); +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, + struct task_struct *task) +{ + int regno; + struct pt_regs *thread_regs; + + /* Just making sure... */ + if (task == NULL) + return; + + /* Initialize to zero */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + /* Otherwise, we have only some registers from switch_to() */ + thread_regs = kgdb_get_user_regs(task); + gdb_regs[_R0] = thread_regs->ARM_r0; /* Not really valid? */ + gdb_regs[_R1] = thread_regs->ARM_r1; /* " " */ + gdb_regs[_R2] = thread_regs->ARM_r2; /* " " */ + gdb_regs[_R3] = thread_regs->ARM_r3; /* " " */ + gdb_regs[_R4] = thread_regs->ARM_r4; + gdb_regs[_R5] = thread_regs->ARM_r5; + gdb_regs[_R6] = thread_regs->ARM_r6; + gdb_regs[_R7] = thread_regs->ARM_r7; + gdb_regs[_R8] = thread_regs->ARM_r8; + gdb_regs[_R9] = thread_regs->ARM_r9; + gdb_regs[_R10] = thread_regs->ARM_r10; + gdb_regs[_FP] = thread_regs->ARM_fp; + gdb_regs[_IP] = thread_regs->ARM_ip; + gdb_regs[_SP] = thread_regs->ARM_sp; + gdb_regs[_LR] = thread_regs->ARM_lr; + gdb_regs[_PC] = thread_regs->ARM_pc; + gdb_regs[_CPSR] = thread_regs->ARM_cpsr; +} + +static int compiled_break; + +int kgdb_arch_handle_exception(int exception_vector, int signo, + int err_code, char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + long addr; + char *ptr; + + switch (remcom_in_buffer[0]) { + case 'c': + kgdb_contthread = NULL; + + /* + * Try to read optional parameter, pc unchanged if no parm. + * If this was a compiled breakpoint, we need to move + * to the next instruction or we will just breakpoint + * over and over again. + */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr)) { + linux_regs->ARM_pc = addr; + } else if (compiled_break == 1) { + linux_regs->ARM_pc += 4; + } + + compiled_break = 0; + + return 0; + } + + return -1; +} + +static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr) +{ + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return 0; +} + +static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr) +{ + compiled_break = 1; + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return 0; +} + +static struct undef_hook kgdb_brkpt_hook = { + .instr_mask = 0xffffffff, + .instr_val = KGDB_BREAKINST, + .fn = kgdb_brk_fn +}; + +static struct undef_hook kgdb_compiled_brkpt_hook = { + .instr_mask = 0xffffffff, + .instr_val = KGDB_COMPILED_BREAK, + .fn = kgdb_compiled_brk_fn +}; + +/* + * Register our undef instruction hooks with ARM undef core. + * We regsiter a hook specifically looking for the KGB break inst + * and we handle the normal undef case within the do_undefinstr + * handler. + */ +int kgdb_arch_init(void) +{ + register_undef_hook(&kgdb_brkpt_hook); + register_undef_hook(&kgdb_compiled_brkpt_hook); + + return 0; +} + +struct kgdb_arch arch_kgdb_ops = { +#ifndef __ARMEB__ + .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} +#else + .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe} +#endif +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/setup.c linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/setup.c --- linux-2.6.18-53.1.14/arch/arm/kernel/setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/setup.c 2008-06-10 15:38:56.000000000 +0400 @@ -829,6 +829,11 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif #endif + +#if defined(CONFIG_KGDB) + extern void __init early_trap_init(void); + early_trap_init(); +#endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/kernel/traps.c linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/traps.c --- linux-2.6.18-53.1.14/arch/arm/kernel/traps.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/kernel/traps.c 2008-06-10 15:38:56.000000000 +0400 @@ -278,6 +278,7 @@ asmlinkage void do_undefinstr(struct pt_ unsigned int instr; struct undef_hook *hook; siginfo_t info; + mm_segment_t fs; void __user *pc; /* @@ -287,12 +288,15 @@ asmlinkage void do_undefinstr(struct pt_ */ regs->ARM_pc -= correction; + fs = get_fs(); + set_fs(KERNEL_DS); pc = (void __user *)instruction_pointer(regs); if (thumb_mode(regs)) { get_user(instr, (u16 __user *)pc); } else { get_user(instr, (u32 __user *)pc); } + set_fs(fs); spin_lock_irq(&undef_lock); list_for_each_entry(hook, &undef_hook, node) { @@ -684,6 +688,13 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { +#if defined(CONFIG_KGDB) + return; +} + +void __init early_trap_init(void) +{ +#endif unsigned long vectors = CONFIG_VECTORS_BASE; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-ixp2000/core.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp2000/core.c --- linux-2.6.18-53.1.14/arch/arm/mach-ixp2000/core.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp2000/core.c 2008-06-10 15:38:56.000000000 +0400 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -184,6 +185,9 @@ static struct platform_device ixp2000_se void __init ixp2000_uart_init(void) { platform_device_register(&ixp2000_serial_device); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixp2000_serial_port); +#endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-ixp2000/ixdp2x01.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp2000/ixdp2x01.c --- linux-2.6.18-53.1.14/arch/arm/mach-ixp2000/ixdp2x01.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp2000/ixdp2x01.c 2008-06-10 15:38:56.000000000 +0400 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -413,6 +414,11 @@ static void __init ixdp2x01_init_machine platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); ixp2000_uart_init(); ixdp2x01_uart_init(); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixdp425_serial_ports[0]); + kgdb8250_add_port(1, &ixdp425_serial_ports[1]); +#endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-ixp4xx/coyote-setup.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp4xx/coyote-setup.c --- linux-2.6.18-53.1.14/arch/arm/mach-ixp4xx/coyote-setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp4xx/coyote-setup.c 2008-06-10 15:38:56.000000000 +0400 @@ -96,6 +96,10 @@ static void __init coyote_init(void) } platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices)); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &coyote_serial_port); +#endif } #ifdef CONFIG_ARCH_ADI_COYOTE diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-ixp4xx/ixdp425-setup.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp4xx/ixdp425-setup.c --- linux-2.6.18-53.1.14/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-ixp4xx/ixdp425-setup.c 2008-06-10 15:38:56.000000000 +0400 @@ -24,6 +24,7 @@ #include #include #include +#include static struct flash_platform_data ixdp425_flash_data = { .map_name = "cfi_probe", @@ -76,7 +77,8 @@ static struct plat_serial8250_port ixdp4 .mapbase = IXP4XX_UART1_BASE_PHYS, .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, .irq = IRQ_IXP4XX_UART1, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_SHARE_IRQ, .iotype = UPIO_MEM, .regshift = 2, .uartclk = IXP4XX_UART_XTAL, @@ -85,7 +87,8 @@ static struct plat_serial8250_port ixdp4 .mapbase = IXP4XX_UART2_BASE_PHYS, .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, .irq = IRQ_IXP4XX_UART2, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_SHARE_IRQ, .iotype = UPIO_MEM, .regshift = 2, .uartclk = IXP4XX_UART_XTAL, @@ -116,6 +119,11 @@ static void __init ixdp425_init(void) IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixdp425_serial_ports[0]); + kgdb8250_add_port(1, &ixdp425_serial_ports[1]); +#endif } #ifdef CONFIG_ARCH_IXDP425 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-omap1/serial.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-omap1/serial.c --- linux-2.6.18-53.1.14/arch/arm/mach-omap1/serial.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-omap1/serial.c 2008-06-10 15:38:56.000000000 +0400 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -199,6 +200,9 @@ void __init omap_serial_init(void) break; } omap_serial_reset(&serial_platform_data[i]); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_platform_port(i, &serial_platform_data[i]); +#endif } } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-pxa/Makefile linux-2.6.18-53.1.14.kgdb/arch/arm/mach-pxa/Makefile --- linux-2.6.18-53.1.14/arch/arm/mach-pxa/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-pxa/Makefile 2008-06-10 15:38:56.000000000 +0400 @@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS) += $(led-y) # Misc features obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PXA_SSP) += ssp.o +obj-$(CONFIG_KGDB_PXA_SERIAL) += kgdb-serial.o ifeq ($(CONFIG_PXA27x),y) obj-$(CONFIG_PM) += standby.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-pxa/kgdb-serial.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-pxa/kgdb-serial.c --- linux-2.6.18-53.1.14/arch/arm/mach-pxa/kgdb-serial.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-pxa/kgdb-serial.c 2008-06-10 15:38:56.000000000 +0400 @@ -0,0 +1,98 @@ +/* + * linux/arch/arm/mach-pxa/kgdb-serial.c + * + * Provides low level kgdb serial support hooks for PXA2xx boards + * + * Author: Nicolas Pitre + * Copyright: (C) 2002-2005 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_KGDB_PXA_FFUART) + +#define UART FFUART +#define CKEN_UART CKEN6_FFUART +#define GPIO_RX_MD GPIO34_FFRXD_MD +#define GPIO_TX_MD GPIO39_FFTXD_MD + +#elif defined(CONFIG_KGDB_PXA_BTUART) + +#define UART BTUART +#define CKEN_UART CKEN7_BTUART +#define GPIO_RX_MD GPIO42_BTRXD_MD +#define GPIO_TX_MD GPIO43_BTTXD_MD + +#elif defined(CONFIG_KGDB_PXA_STUART) + +#define UART STUART +#define CKEN_UART CKEN5_STUART +#define GPIO_RX_MD GPIO46_STRXD_MD +#define GPIO_TX_MD GPIO47_STTXD_MD + +#endif + +#define UART_BAUDRATE (CONFIG_KGDB_BAUDRATE) + +static volatile unsigned long *port = (unsigned long *)&UART; + +static int kgdb_serial_init(void) +{ + pxa_set_cken(CKEN_UART, 1); + pxa_gpio_mode(GPIO_RX_MD); + pxa_gpio_mode(GPIO_TX_MD); + + port[UART_IER] = 0; + port[UART_LCR] = LCR_DLAB; + port[UART_DLL] = ((921600 / UART_BAUDRATE) & 0xff); + port[UART_DLM] = ((921600 / UART_BAUDRATE) >> 8); + port[UART_LCR] = LCR_WLS1 | LCR_WLS0; + port[UART_MCR] = 0; + port[UART_IER] = IER_UUE; + port[UART_FCR] = FCR_ITL_16; + + return 0; +} + +static void kgdb_serial_putchar(int c) +{ + if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE) + kgdb_serial_init(); + while (!(port[UART_LSR] & LSR_TDRQ)) + cpu_relax(); + port[UART_TX] = c; +} + +static void kgdb_serial_flush(void) +{ + if ((CKEN & CKEN_UART) && (port[UART_IER] & IER_UUE)) + while (!(port[UART_LSR] & LSR_TEMT)) + cpu_relax(); +} + +static int kgdb_serial_getchar(void) +{ + unsigned char c; + if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE) + kgdb_serial_init(); + while (!(port[UART_LSR] & UART_LSR_DR)) + cpu_relax(); + c = port[UART_RX]; + return c; +} + +struct kgdb_io kgdb_io_ops = { + .init = kgdb_serial_init, + .write_char = kgdb_serial_putchar, + .flush = kgdb_serial_flush, + .read_char = kgdb_serial_getchar, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mach-versatile/kgdb_serial.c linux-2.6.18-53.1.14.kgdb/arch/arm/mach-versatile/kgdb_serial.c --- linux-2.6.18-53.1.14/arch/arm/mach-versatile/kgdb_serial.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mach-versatile/kgdb_serial.c 2008-06-10 15:38:56.000000000 +0400 @@ -0,0 +1,121 @@ +/* + * arch/arm/mach-versatile/kgdb_serial.c + * + * Author: Manish Lachwani, mlachwani@mvista.com + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for KGDB on ARM Versatile. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARM_BAUD_38400 23 +/* + * Functions that will be used later + */ +#define UART_GET_INT_STATUS(p) readb((p) + UART010_IIR) +#define UART_GET_MIS(p) readw((p) + UART011_MIS) +#define UART_PUT_ICR(p, c) writel((c), (p) + UART010_ICR) +#define UART_GET_FR(p) readb((p) + UART01x_FR) +#define UART_GET_CHAR(p) readb((p) + UART01x_DR) +#define UART_PUT_CHAR(p, c) writel((c), (p) + UART01x_DR) +#define UART_GET_RSR(p) readb((p) + UART01x_RSR) +#define UART_GET_CR(p) readb((p) + UART010_CR) +#define UART_PUT_CR(p,c) writel((c), (p) + UART010_CR) +#define UART_GET_LCRL(p) readb((p) + UART010_LCRL) +#define UART_PUT_LCRL(p,c) writel((c), (p) + UART010_LCRL) +#define UART_GET_LCRM(p) readb((p) + UART010_LCRM) +#define UART_PUT_LCRM(p,c) writel((c), (p) + UART010_LCRM) +#define UART_GET_LCRH(p) readb((p) + UART010_LCRH) +#define UART_PUT_LCRH(p,c) writel((c), (p) + UART010_LCRH) +#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART01x_FR_TMSK) == 0) + +/* + * KGDB IRQ + */ +static int kgdb_irq = 12; +static volatile unsigned char *port = NULL; + +static int kgdb_serial_init(void) +{ + int rate = ARM_BAUD_38400; + + port = IO_ADDRESS(0x101F1000); + UART_PUT_CR(port, 0); + + /* Set baud rate */ + UART_PUT_LCRM(port, ((rate & 0xf00) >> 8)); + UART_PUT_LCRL(port, (rate & 0xff)); + UART_PUT_LCRH(port, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN); + UART_PUT_CR(port, UART01x_CR_UARTEN); + + return 0; +} + +static void kgdb_serial_putchar(int ch) +{ + unsigned int status; + + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + + UART_PUT_CHAR(port, ch); +} + +static int kgdb_serial_getchar(void) +{ + unsigned int status; + int ch; + + do { + status = UART_GET_FR(port); + } while (!UART_RX_DATA(status)); + ch = UART_GET_CHAR(port); + return ch; +} + +static struct uart_port kgdb_amba_port = { + .irq = 12, + .iobase = 0, + .iotype = UPIO_MEM, + .membase = (unsigned char *)IO_ADDRESS(0x101F1000), +}; + +static irqreturn_t kgdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status = UART_GET_MIS(port); + + if (irq != kgdb_irq) + return IRQ_NONE; + + if (status & 0x40) + breakpoint(); + + return IRQ_HANDLED; +} + +static void __init kgdb_hookup_irq(void) +{ + request_irq(kgdb_irq, kgdb_interrupt, SA_SHIRQ, "GDB-stub", + &kgdb_amba_port); +} + +struct kgdb_io kgdb_io_ops = { + .init = kgdb_serial_init, + .write_char = kgdb_serial_putchar, + .read_char = kgdb_serial_getchar, + .late_init = kgdb_hookup_irq, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/arm/mm/extable.c linux-2.6.18-53.1.14.kgdb/arch/arm/mm/extable.c --- linux-2.6.18-53.1.14/arch/arm/mm/extable.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/arm/mm/extable.c 2008-06-10 15:38:56.000000000 +0400 @@ -2,6 +2,7 @@ * linux/arch/arm/mm/extable.c */ #include +#include #include int fixup_exception(struct pt_regs *regs) @@ -11,6 +12,12 @@ int fixup_exception(struct pt_regs *regs fixup = search_exception_tables(instruction_pointer(regs)); if (fixup) regs->ARM_pc = fixup->fixup; +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ +#endif return fixup != NULL; } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/Makefile --- linux-2.6.18-53.1.14/arch/i386/kernel/Makefile 2008-03-06 05:54:14.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/Makefile 2008-06-10 15:38:03.000000000 +0400 @@ -39,6 +39,7 @@ obj-$(CONFIG_VM86) += vm86.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o EXTRA_AFLAGS := -traditional diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/entry.S linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/entry.S --- linux-2.6.18-53.1.14/arch/i386/kernel/entry.S 2008-03-06 05:55:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/entry.S 2008-06-10 15:39:01.000000000 +0400 @@ -201,7 +201,7 @@ VM_MASK = 0x00020000 CFI_OFFSET ecx, ECX-OLDESP;\ CFI_OFFSET ebx, EBX-OLDESP -ENTRY(ret_from_fork) +KPROBE_ENTRY(ret_from_fork) CFI_STARTPROC pushl %eax CFI_ADJUST_CFA_OFFSET 4 @@ -659,7 +659,7 @@ ENTRY(simd_coprocessor_error) jmp error_code CFI_ENDPROC -ENTRY(device_not_available) +KPROBE_ENTRY(device_not_available) RING0_INT_FRAME pushl $-1 # mark this as an int CFI_ADJUST_CFA_OFFSET 4 @@ -916,7 +916,7 @@ ENTRY(machine_check) CFI_ENDPROC #endif -ENTRY(spurious_interrupt_bug) +KPROBE_ENTRY(spurious_interrupt_bug) RING0_INT_FRAME pushl $0 CFI_ADJUST_CFA_OFFSET 4 @@ -942,3 +942,108 @@ ENDPROC(kernel_thread_helper) #include "syscall_table.S" syscall_table_size=(.-sys_call_table) + +# Here we do call frames. We cheat a bit as we only really need +# correct frames at locations we can actually look at from a +# debugger. Since the break instruction trap actually goes thru +# some of this code, we don't really need info on those areas, but +# only after the fact. I.e. if we can not step or break in a +# location or end up with a return address pointing at the +# location, we don't need a correct call frame for it. + +#ifdef CONFIG_KGDB + +#include +/* + * The register numbers as known by gdb + */ + +#define _EAX 0 +#define _ECX 1 +#define _EDX 2 +#define _EBX 3 +#define _ESP 4 +#define _EBP 5 +#define _ESI 6 +#define _EDI 7 +#define _PC 8 +#define _EIP 8 +#define _PS 9 +#define _EFLAGS 9 +#define _CS 10 +#define _SS 11 +#define _DS 12 +#define _ES 13 +#define _FS 14 +#define _GS 15 + /* + * This code uses macros defined in linux/dwarf2-lang.h + * They attempt to follow the dwarf2 naming conventions... sort of.. + */ +ENTRY(end_of_stack_stop_unwind_function) + .long end_of_stack_stop_unwind_function+1 + + .text + + CFI_preamble(c1,_PC,1,1) + CFA_define_reference(_ESP,OLDESP) /* Stack pointer */ + CFA_expression(_EIP) + CFA_exp_OP_dup /* copy old esp */ + CFA_exp_OP_consts(CS-OLDESP) /* offset to CS address */ + CFA_exp_OP_plus /* should be CS address */ + CFA_exp_OP_deref /* get the CS */ + CFA_exp_OP_const4s(VM_MASK|3) /* prepare to mask it */ + CFA_exp_OP_and /* mask it, zero means kernel */ + CFA_exp_OP_bra(eip_user_rtn) /* branch if user */ + CFA_exp_OP_const4s(EIP-OLDESP) /* offset to return address */ + CFA_exp_OP_plus /* add that in */ + CFA_exp_OP_skip(eip_end) /* done if kernel, skip out */ +eip_user_rtn: + CFA_exp_OP_addr(end_of_stack_stop_unwind_function)/*dummy function */ +eip_end: + CFA_expression_end + CFA_define_offset(_EBX,EBX-OLDESP) + CFA_define_offset(_ECX,ECX-OLDESP) + CFA_define_offset(_EDX,EDX-OLDESP) + CFA_define_offset(_ESI,ESI-OLDESP) + CFA_define_offset(_EDI,EDI-OLDESP) + CFA_define_offset(_EBP,EBP-OLDESP) + CFA_define_offset(_EAX,EAX-OLDESP) + CFA_define_offset(_EFLAGS,EFLAGS-OLDESP) + CFI_postamble() + +/* + * This provides an uwind for our dummy end of unwind function. + * Current convention is to provied an undefined return address. + */ + CFI_preamble(c2,_PC,1,1) + CFA_define_reference(_ESP,0) /* Stack pointer */ + CFA_undefine_reg(_EIP) + CFI_postamble() + + FDE_preamble(c2,end_of_stack_stop_unwind_function, \ + end_of_stack_stop_unwind_function+5) + FDE_postamble() + /* + * This is VERY sloppy. At this point all we want to do is get + * the frame right for back tracing. It will not be good if + * you try to single step. We use already defined labels. + * We want to cover all call outs. + * We could also recode this as just one FDE, but this works and + * I want to get it out. + */ + FDE_preamble(c1,ret_from_fork,ret_from_exception) + CFA_define_cfa_offset(4) /* one extra word on stack */ + FDE_postamble() + + FDE_preamble(c1,ret_from_exception,device_not_available_emulate) + FDE_postamble() + + FDE_preamble(c1,device_not_available_emulate,debug) + CFA_define_cfa_offset(4) /* one extra word on stack */ + FDE_postamble() + + FDE_preamble(c1, debug,spurious_interrupt_bug) + FDE_postamble() + +#endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/head.S linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/head.S --- linux-2.6.18-53.1.14/arch/i386/kernel/head.S 2008-03-06 05:54:34.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/head.S 2008-06-10 15:39:01.000000000 +0400 @@ -10,6 +10,7 @@ .text #include #include +#include #include #include #include @@ -336,6 +337,10 @@ is386: movl $2,%ecx # set MP #endif /* CONFIG_SMP */ jmp start_kernel + /* This dwarf code tells gdb that this is the end of the unwind */ + /* This uses the CFA set up for pc=1 located in entry.S */ + CFI_END_FRAME(is386) + /* * We depend on ET to be correct. This checks for 287/387. */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/kgdb-jmp.S linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/kgdb-jmp.S --- linux-2.6.18-53.1.14/arch/i386/kernel/kgdb-jmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/kgdb-jmp.S 2008-06-10 15:38:03.000000000 +0400 @@ -0,0 +1,74 @@ +/* + * arch/i386/kernel/kgdb-jmp.S + * + * Save and restore system registers so that within a limited frame we + * may have a fault and "jump back" to a known safe location. + * + * Author: George Anzinger + * + * Cribbed from glibc, which carries the following: + * Copyright (C) 1996, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + * Copyright (C) 2005 by MontaVista Software. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of + * any kind, whether express or implied. + */ + +#include + +#define PCOFF 0 +#define LINKAGE 4 /* just the return address */ +#define PTR_SIZE 4 +#define PARMS LINKAGE /* no space for saved regs */ +#define JMPBUF PARMS +#define VAL JMPBUF+PTR_SIZE + +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + +/* This must be called prior to kgdb_fault_longjmp and + * kgdb_fault_longjmp must not be called outside of the context of the + * last call to kgdb_fault_setjmp. + * kgdb_fault_setjmp(int *jmp_buf[6]) + */ +ENTRY(kgdb_fault_setjmp) + movl JMPBUF(%esp), %eax + + /* Save registers. */ + movl %ebx, (JB_BX*4)(%eax) + movl %esi, (JB_SI*4)(%eax) + movl %edi, (JB_DI*4)(%eax) + /* Save SP as it will be after we return. */ + leal JMPBUF(%esp), %ecx + movl %ecx, (JB_SP*4)(%eax) + movl PCOFF(%esp), %ecx /* Save PC we are returning to now. */ + movl %ecx, (JB_PC*4)(%eax) + movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */ + + /* Restore state so we can now try the access. */ + movl JMPBUF(%esp), %ecx /* User's jmp_buf in %ecx. */ + /* Save the return address now. */ + movl (JB_PC*4)(%ecx), %edx + /* Restore registers. */ + movl $0, %eax + movl (JB_SP*4)(%ecx), %esp + jmp *%edx /* Jump to saved PC. */ + +/* kgdb_fault_longjmp(int *jmp_buf[6]) */ +ENTRY(kgdb_fault_longjmp) + movl JMPBUF(%esp), %ecx /* User's jmp_buf in %ecx. */ + /* Save the return address now. */ + movl (JB_PC*4)(%ecx), %edx + /* Restore registers. */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + movl $1, %eax + movl (JB_SP*4)(%ecx), %esp + jmp *%edx /* Jump to saved PC. */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/i386/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/kgdb.c 2008-06-10 15:39:27.000000000 +0400 @@ -0,0 +1,363 @@ +/* + * + * 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, 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. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale + * Updated by: Tom Rini + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by + * David Grothe + * Additional support from Tigran Aivazian + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include + +#include "mach_ipi.h" + +/* Put the error code here just in case the user cares. */ +int gdb_i386errcode; +/* Likewise, the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_i386vector = -1; + +extern atomic_t cpu_doing_single_step; + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_EAX] = regs->eax; + gdb_regs[_EBX] = regs->ebx; + gdb_regs[_ECX] = regs->ecx; + gdb_regs[_EDX] = regs->edx; + gdb_regs[_ESI] = regs->esi; + gdb_regs[_EDI] = regs->edi; + gdb_regs[_EBP] = regs->ebp; + gdb_regs[_DS] = regs->xds; + gdb_regs[_ES] = regs->xes; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_CS] = regs->xcs; + gdb_regs[_PC] = regs->eip; + gdb_regs[_ESP] = (int)(®s->esp); + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} + +/* + * Extracts ebp, esp and eip values understandable by gdb from the values + * saved by switch_to. + * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp + * prior to entering switch_to is 8 greater then the value that is saved. + * If switch_to changes, change following code appropriately. + */ +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + gdb_regs[_EAX] = 0; + gdb_regs[_EBX] = 0; + gdb_regs[_ECX] = 0; + gdb_regs[_EDX] = 0; + gdb_regs[_ESI] = 0; + gdb_regs[_EDI] = 0; + gdb_regs[_EBP] = *(unsigned long *)p->thread.esp; + gdb_regs[_DS] = __KERNEL_DS; + gdb_regs[_ES] = __KERNEL_DS; + gdb_regs[_PS] = 0; + gdb_regs[_CS] = __KERNEL_CS; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_ESP] = p->thread.esp; + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + regs->eax = gdb_regs[_EAX]; + regs->ebx = gdb_regs[_EBX]; + regs->ecx = gdb_regs[_ECX]; + regs->edx = gdb_regs[_EDX]; + regs->esi = gdb_regs[_ESI]; + regs->edi = gdb_regs[_EDI]; + regs->ebp = gdb_regs[_EBP]; + regs->xds = gdb_regs[_DS]; + regs->xes = gdb_regs[_ES]; + regs->eflags = gdb_regs[_PS]; + regs->xcs = gdb_regs[_CS]; + regs->eip = gdb_regs[_PC]; +} + +static struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned addr; +} breakinfo[4] = { + { .enabled = 0 }, + { .enabled = 0 }, + { .enabled = 0 }, + { .enabled = 0 }, +}; + +void kgdb_correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned dr7; + + asm volatile ("movl %%db7, %0\n":"=r" (dr7) + :); + do { + unsigned addr0, addr1, addr2, addr3; + asm volatile ("movl %%db0, %0\n" + "movl %%db1, %1\n" + "movl %%db2, %2\n" + "movl %%db3, %3\n":"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3):); + } while (0); + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movl %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movl %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movl %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movl %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) + asm volatile ("movl %0, %%db7\n"::"r" (dr7)); +} + +int kgdb_remove_hw_break(unsigned long addr) +{ + int i, idx = -1; + for (i = 0; i < 4; i++) { + if (breakinfo[i].addr == addr && breakinfo[i].enabled) { + idx = i; + break; + } + } + if (idx == -1) + return -1; + + breakinfo[idx].enabled = 0; + return 0; +} + +void kgdb_remove_all_hw_break(void) +{ + int i; + + for (i = 0; i < 4; i++) { + if (breakinfo[i].enabled) { + /* Do what? */ + ; + } + memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); + } +} + +int kgdb_set_hw_break(unsigned long addr) +{ + int i, idx = -1; + for (i = 0; i < 4; i++) { + if (!breakinfo[i].enabled) { + idx = i; + break; + } + } + if (idx == -1) + return -1; + + breakinfo[idx].enabled = 1; + breakinfo[idx].type = 1; + breakinfo[idx].len = 1; + breakinfo[idx].addr = addr; + return 0; +} + +void kgdb_disable_hw_debug(struct pt_regs *regs) +{ + /* Disable hardware debugging while we are in kgdb */ + asm volatile ("movl %0,%%db7": /* no output */ :"r" (0)); +} + +void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code) +{ + /* Master processor is completely in the debugger */ + gdb_i386vector = e_vector; + gdb_i386errcode = err_code; +} + +void kgdb_roundup_cpus(unsigned long flags) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + +int kgdb_arch_handle_exception(int e_vector, int signo, + int err_code, char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + long addr; + char *ptr; + int newPC, dr6; + + switch (remcom_in_buffer[0]) { + case 'c': + case 's': + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->eip = addr; + newPC = linux_regs->eip; + + /* clear the trace bit */ + linux_regs->eflags &= ~TF_MASK; + atomic_set(&cpu_doing_single_step, -1); + + /* set the trace bit if we're stepping */ + if (remcom_in_buffer[0] == 's') { + linux_regs->eflags |= TF_MASK; + debugger_step = 1; + atomic_set(&cpu_doing_single_step,smp_processor_id()); + } + + asm volatile ("movl %%db6, %0\n":"=r" (dr6)); + if (!(dr6 & 0x4000)) { + long breakno; + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + breakinfo[breakno].type == 0) { + /* Set restore flag */ + linux_regs->eflags |= X86_EFLAGS_RF; + break; + } + } + } + kgdb_correct_hw_break(); + asm volatile ("movl %0, %%db6\n"::"r" (0)); + + return (0); + } /* switch */ + /* this means that we do not want to exit from the handler */ + return -1; +} + +/* Register KGDB with the i386die_chain so that we hook into all of the right + * spots. */ +static int kgdb_notify(struct notifier_block *self, unsigned long cmd, + void *ptr) +{ + struct die_args *args = ptr; + struct pt_regs *regs = args->regs; + + /* Bad memory access? */ + if (cmd == DIE_PAGE_FAULT_NO_CONTEXT && atomic_read(&debugger_active) + && kgdb_may_fault) { + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + return NOTIFY_STOP; + } else if (cmd == DIE_PAGE_FAULT) + /* A normal page fault, ignore. */ + return NOTIFY_DONE; + else if ((cmd == DIE_NMI || cmd == DIE_NMI_IPI || + cmd == DIE_NMIWATCHDOG) && atomic_read(&debugger_active)) { + /* CPU roundup */ + kgdb_nmihook(smp_processor_id(), regs); + return NOTIFY_STOP; + } else if (cmd == DIE_NMI_IPI || cmd == DIE_NMI || user_mode(regs) || + (cmd == DIE_DEBUG && atomic_read(&debugger_active))) + /* Normal watchdog event or userspace debugging, or spurious + * debug exception, ignore. */ + return NOTIFY_DONE; + + kgdb_handle_exception(args->trapnr, args->signr, args->err, regs); + + return NOTIFY_STOP; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, +}; + +int kgdb_arch_init(void) +{ + atomic_notifier_chain_register(&i386die_chain, &kgdb_notifier); + return 0; +} + +/* + * Skip an int3 exception when it occurs after a breakpoint has been + * removed. Backtrack eip by 1 since the int3 would have caused it to + * increment by 1. + */ + +int kgdb_skipexception(int exception, struct pt_regs *regs) +{ + if (exception == 3 && kgdb_isremovedbreak(regs->eip - 1)) { + regs->eip -= 1; + return 1; + } + return 0; +} + +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0xcc}, + .flags = KGDB_HW_BREAKPOINT, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/setup.c linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/setup.c --- linux-2.6.18-53.1.14/arch/i386/kernel/setup.c 2008-03-06 05:54:58.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/setup.c 2008-06-10 15:38:03.000000000 +0400 @@ -148,6 +148,7 @@ EXPORT_SYMBOL(ist_info); struct e820map e820; extern void early_cpu_init(void); +extern void early_trap_init(void); extern void generic_apic_probe(char *); extern int root_mountflags; @@ -1470,6 +1471,7 @@ void __init setup_arch(char **cmdline_p) memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); pre_setup_arch_hook(); early_cpu_init(); + early_trap_init(); /* * FIXME: This isn't an official loader_type right @@ -1526,6 +1528,7 @@ void __init setup_arch(char **cmdline_p) data_resource.end = virt_to_phys(_edata)-1; parse_cmdline_early(cmdline_p); + parse_early_param(); #ifdef CONFIG_EARLY_PRINTK { diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/smpboot.c linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/smpboot.c --- linux-2.6.18-53.1.14/arch/i386/kernel/smpboot.c 2008-03-06 05:54:34.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/smpboot.c 2008-06-10 15:39:01.000000000 +0400 @@ -592,6 +592,9 @@ void __devinit initialize_secondary(void asm volatile( "movl %0,%%esp\n\t" +#ifdef CONFIG_KGDB + "pushl end_of_stack_stop_unwind_function\n\t" +#endif "jmp *%1" : :"r" (current->thread.esp),"r" (current->thread.eip)); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/kernel/traps.c linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/traps.c --- linux-2.6.18-53.1.14/arch/i386/kernel/traps.c 2008-03-06 05:55:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/kernel/traps.c 2008-06-10 15:38:03.000000000 +0400 @@ -964,6 +964,7 @@ fastcall void __kprobes do_debug(struct */ clear_dr7: set_debugreg(0, 7); + notify_die(DIE_DEBUG, "debug2", regs, condition, error_code, SIGTRAP); return; debug_vm86: @@ -1268,6 +1269,12 @@ static void __init set_task_gate(unsigne _set_gate(idt_table+n,5,0,0,(gdt_entry<<3)); } +/* Some traps need to be set early. */ +void __init early_trap_init(void) { + set_intr_gate(1,&debug); + set_system_intr_gate(3, &int3); /* int3 can be called from all */ + set_intr_gate(14,&page_fault); +} void __init trap_init(void) { @@ -1284,10 +1291,8 @@ void __init trap_init(void) #endif set_trap_gate(0,÷_error); - set_intr_gate(1,&debug); set_intr_gate(2,&nmi); - set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ - set_system_gate(4,&overflow); + set_system_gate(4,&overflow); /* int4/5 can be called from all */ set_trap_gate(5,&bounds); set_trap_gate(6,&invalid_op); set_trap_gate(7,&device_not_available); @@ -1297,7 +1302,6 @@ void __init trap_init(void) set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); - set_intr_gate(14,&page_fault); set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/i386/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/i386/mm/fault.c --- linux-2.6.18-53.1.14/arch/i386/mm/fault.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/i386/mm/fault.c 2008-06-10 15:38:03.000000000 +0400 @@ -539,6 +539,10 @@ no_context: if (is_prefetch(regs, address, error_code)) return; + if (notify_die(DIE_PAGE_FAULT_NO_CONTEXT, "no context", regs, + error_code, 14, SIGSEGV) == NOTIFY_STOP) + return; + /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/Makefile --- linux-2.6.18-53.1.14/arch/ia64/kernel/Makefile 2008-03-06 05:54:11.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/Makefile 2008-06-10 15:38:32.000000000 +0400 @@ -32,6 +32,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_AUDIT) += audit.o mca_recovery-y += mca_drv.o mca_drv_asm.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/entry.S linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/entry.S --- linux-2.6.18-53.1.14/arch/ia64/kernel/entry.S 2008-03-06 05:54:43.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/entry.S 2008-06-10 15:39:39.000000000 +0400 @@ -959,9 +959,9 @@ GLOBAL_ENTRY(__ia64_leave_kernel) shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; mov r16=ar.bsp // get existing backing store pointer - addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 +(pUStk) addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; - ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 +(pUStk) ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 (pKStk) br.cond.dpnt skip_rbs_switch /* diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/ivt.S linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/ivt.S --- linux-2.6.18-53.1.14/arch/ia64/kernel/ivt.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/ivt.S 2008-06-10 15:39:39.000000000 +0400 @@ -52,6 +52,14 @@ #include #include +#ifdef CONFIG_KGDB +#define KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; \ + or r31=r31,r30;; \ + mov psr.l=r31;; srlz.i;; +#else +#define KGDB_ENABLE_PSR_DB +#endif + #if 1 # define PSR_DEFAULT_BITS psr.ac #else @@ -519,6 +527,7 @@ ENTRY(page_fault) movl r14=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r14 ;; adds out2=16,r12 // out2 = pointer to pt_regs @@ -863,6 +872,7 @@ ENTRY(interrupt) srlz.i // ensure everybody knows psr.ic is back on ;; SAVE_REST + KGDB_ENABLE_PSR_DB ;; MCA_RECOVER_RANGE(interrupt) alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group @@ -1110,6 +1120,7 @@ ENTRY(non_syscall) movl r15=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r15 ;; br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr @@ -1143,6 +1154,7 @@ ENTRY(dispatch_unaligned_handler) adds r3=8,r2 // set up second base pointer ;; SAVE_REST + KGDB_ENABLE_PSR_DB movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -1185,6 +1197,10 @@ ENTRY(dispatch_to_fault_handler) adds r3=8,r2 // set up second base pointer for SAVE_REST ;; SAVE_REST + cmp.eq p6,p0=29,out0 +(p6) br.cond.spnt 1f;; // debug_vector + KGDB_ENABLE_PSR_DB +1: movl r14=ia64_leave_kernel ;; mov rp=r14 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/kgdb-jmp.S linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/kgdb-jmp.S --- linux-2.6.18-53.1.14/arch/ia64/kernel/kgdb-jmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/kgdb-jmp.S 2008-06-10 15:38:32.000000000 +0400 @@ -0,0 +1,238 @@ +/* setjmp() and longjmp() assembler support for kdb on ia64. + + This code was copied from glibc CVS as of 2001-06-27 and modified where + necessary to fit the kernel. + Keith Owens 2001-06-27 + */ + +/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +GLOBAL_ENTRY(kgdb_fault_setjmp) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc loc1=ar.pfs,2,2,2,0 + mov r16=ar.unat + ;; + mov r17=ar.fpsr + mov r2=in0 + add r3=8,in0 + ;; +.mem.offset 0,0; + st8.spill.nta [r2]=sp,16 // r12 (sp) +.mem.offset 8,0; + st8.spill.nta [r3]=gp,16 // r1 (gp) + ;; + st8.nta [r2]=r16,16 // save caller's unat + st8.nta [r3]=r17,16 // save fpsr + add r8=0xa0,in0 + ;; +.mem.offset 160,0; + st8.spill.nta [r2]=r4,16 // r4 +.mem.offset 168,0; + st8.spill.nta [r3]=r5,16 // r5 + add r9=0xb0,in0 + ;; + stf.spill.nta [r8]=f2,32 + stf.spill.nta [r9]=f3,32 + mov loc0=rp + .body + ;; + stf.spill.nta [r8]=f4,32 + stf.spill.nta [r9]=f5,32 + mov r17=b1 + ;; + stf.spill.nta [r8]=f16,32 + stf.spill.nta [r9]=f17,32 + mov r18=b2 + ;; + stf.spill.nta [r8]=f18,32 + stf.spill.nta [r9]=f19,32 + mov r19=b3 + ;; + stf.spill.nta [r8]=f20,32 + stf.spill.nta [r9]=f21,32 + mov r20=b4 + ;; + stf.spill.nta [r8]=f22,32 + stf.spill.nta [r9]=f23,32 + mov r21=b5 + ;; + stf.spill.nta [r8]=f24,32 + stf.spill.nta [r9]=f25,32 + mov r22=ar.lc + ;; + stf.spill.nta [r8]=f26,32 + stf.spill.nta [r9]=f27,32 + mov r24=pr + ;; + stf.spill.nta [r8]=f28,32 + stf.spill.nta [r9]=f29,32 + ;; + stf.spill.nta [r8]=f30 + stf.spill.nta [r9]=f31 + +.mem.offset 0,0; + st8.spill.nta [r2]=r6,16 // r6 +.mem.offset 8,0; + st8.spill.nta [r3]=r7,16 // r7 + ;; + mov r23=ar.bsp + mov r25=ar.unat + st8.nta [r2]=loc0,16 // b0 + st8.nta [r3]=r17,16 // b1 + ;; + st8.nta [r2]=r18,16 // b2 + st8.nta [r3]=r19,16 // b3 + ;; + st8.nta [r2]=r20,16 // b4 + st8.nta [r3]=r21,16 // b5 + ;; + st8.nta [r2]=loc1,16 // ar.pfs + st8.nta [r3]=r22,16 // ar.lc + ;; + st8.nta [r2]=r24,16 // pr + st8.nta [r3]=r23,16 // ar.bsp + ;; + st8.nta [r2]=r25 // ar.unat + st8.nta [r3]=in0 // &__jmp_buf + mov r8=0 + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.few rp +END(kdba_setjmp) +#define pPos p6 /* is rotate count positive? */ +#define pNeg p7 /* is rotate count negative? */ +GLOBAL_ENTRY(kgdb_fault_longjmp) + alloc r8=ar.pfs,2,1,0,0 + mov r27=ar.rsc + add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr + ;; + ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr + mov r10=ar.bsp + and r11=~0x3,r27 // clear ar.rsc.mode + ;; + flushrs // flush dirty regs to backing store (must be first in insn grp) + ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp + sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf + ;; + ld8 r25=[r2] // r25 <- jmpbuf.ar_unat + extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f + ;; + cmp.lt pNeg,pPos=r8,r0 + mov r2=in0 + ;; +(pPos) mov r16=r8 +(pNeg) add r16=64,r8 +(pPos) sub r17=64,r8 +(pNeg) sub r17=r0,r8 + ;; + mov ar.rsc=r11 // put RSE in enforced lazy mode + shr.u r8=r25,r16 + add r3=8,in0 // r3 <- &jmpbuf.r1 + shl r9=r25,r17 + ;; + or r25=r8,r9 + ;; + mov r26=ar.rnat + mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12) + ;; + ld8.fill.nta sp=[r2],16 // r12 (sp) + ld8.fill.nta gp=[r3],16 // r1 (gp) + dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp) + ;; + ld8.nta r16=[r2],16 // caller's unat + ld8.nta r17=[r3],16 // fpsr + ;; + ld8.fill.nta r4=[r2],16 // r4 + ld8.fill.nta r5=[r3],16 // r5 (gp) + cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp) + ;; + ld8.fill.nta r6=[r2],16 // r6 + ld8.fill.nta r7=[r3],16 // r7 + ;; + mov ar.unat=r16 // restore caller's unat + mov ar.fpsr=r17 // restore fpsr + ;; + ld8.nta r16=[r2],16 // b0 + ld8.nta r17=[r3],16 // b1 + ;; +(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp) + mov ar.bspstore=r23 // restore ar.bspstore + ;; + ld8.nta r18=[r2],16 // b2 + ld8.nta r19=[r3],16 // b3 + ;; + ld8.nta r20=[r2],16 // b4 + ld8.nta r21=[r3],16 // b5 + ;; + ld8.nta r11=[r2],16 // ar.pfs + ld8.nta r22=[r3],56 // ar.lc + ;; + ld8.nta r24=[r2],32 // pr + mov b0=r16 + ;; + ldf.fill.nta f2=[r2],32 + ldf.fill.nta f3=[r3],32 + mov b1=r17 + ;; + ldf.fill.nta f4=[r2],32 + ldf.fill.nta f5=[r3],32 + mov b2=r18 + ;; + ldf.fill.nta f16=[r2],32 + ldf.fill.nta f17=[r3],32 + mov b3=r19 + ;; + ldf.fill.nta f18=[r2],32 + ldf.fill.nta f19=[r3],32 + mov b4=r20 + ;; + ldf.fill.nta f20=[r2],32 + ldf.fill.nta f21=[r3],32 + mov b5=r21 + ;; + ldf.fill.nta f22=[r2],32 + ldf.fill.nta f23=[r3],32 + mov ar.lc=r22 + ;; + ldf.fill.nta f24=[r2],32 + ldf.fill.nta f25=[r3],32 + cmp.eq p8,p9=0,in1 + ;; + ldf.fill.nta f26=[r2],32 + ldf.fill.nta f27=[r3],32 + mov ar.pfs=r11 + ;; + ldf.fill.nta f28=[r2],32 + ldf.fill.nta f29=[r3],32 + ;; + ldf.fill.nta f30=[r2] + ldf.fill.nta f31=[r3] +(p8) mov r8=1 + + mov ar.rnat=r26 // restore ar.rnat + ;; + mov ar.rsc=r27 // restore ar.rsc +(p9) mov r8=in1 + + invala // virt. -> phys. regnum mapping may change + mov pr=r24,-1 + br.ret.sptk.few rp +END(kgdb_fault_longjmp) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/ia64/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/kgdb.c 2008-06-10 15:38:32.000000000 +0400 @@ -0,0 +1,1131 @@ +/* + * + * 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, 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. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * (c) Copyright 2005 Hewlett-Packard Development Company, L.P. + * Bob Picco + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include + +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) \ + + ((N) <= IA64_FR0_REGNUM ? \ + 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) \ + (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#define REGISTER_INDEX(N) (REGISTER_BYTE(N) / sizeof (unsigned long)) +#define BREAK_INSTR_ALIGN (~0xfULL) + +#define ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V) +struct reg_to_ptreg_index { + unsigned int reg; + unsigned int ptregoff; +}; + +static struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = { + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, +}; + +static struct reg_to_ptreg_index br_reg_to_ptreg_index[] = { + {IA64_BR0_REGNUM, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; + +static struct reg_to_ptreg_index ar_reg_to_ptreg_index[] = { + {IA64_PFS_REGNUM, ptoff(ar_pfs)}, + {IA64_UNAT_REGNUM, ptoff(ar_unat)}, + {IA64_RNAT_REGNUM, ptoff(ar_rnat)}, + {IA64_BSPSTORE_REGNUM, ptoff(ar_bspstore)}, + {IA64_RSC_REGNUM, ptoff(ar_rsc)}, + {IA64_CSD_REGNUM, ptoff(ar_csd)}, + {IA64_SSD_REGNUM, ptoff(ar_ssd)}, + {IA64_FPSR_REGNUM, ptoff(ar_fpsr)}, + {IA64_CCV_REGNUM, ptoff(ar_ccv)}, +}; + +extern atomic_t cpu_doing_single_step; + +static int kgdb_gr_reg(int regnum, struct unw_frame_info *info, + unsigned long *reg, int rw) +{ + char nat; + + if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) || + (regnum >= (IA64_GR0_REGNUM + 4) && + regnum <= (IA64_GR0_REGNUM + 7))) + return !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + else + return 0; +} +static int kgdb_gr_ptreg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + char nat; + + if (!((regnum >= (IA64_GR0_REGNUM + 2) && + regnum <= (IA64_GR0_REGNUM + 3)) || + (regnum >= (IA64_GR0_REGNUM + 8) && + regnum <= (IA64_GR0_REGNUM + 15)) || + (regnum >= (IA64_GR0_REGNUM + 16) && + regnum <= (IA64_GR0_REGNUM + 31)))) + return 0; + else if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *)(((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)) = *reg; + break; + } + } else if (!rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)); + break; + } + } else + result = !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + return result; +} + +static int kgdb_br_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + + if (!(regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7))) + return 0; + + switch (regnum) { + case IA64_BR0_REGNUM: + case IA64_BR0_REGNUM + 6: + case IA64_BR0_REGNUM + 7: + if (rw) { + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i].ptregoff)) = + *reg; + break; + } + } else + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i]. + ptregoff)); + break; + } + break; + case IA64_BR0_REGNUM + 1: + case IA64_BR0_REGNUM + 2: + case IA64_BR0_REGNUM + 3: + case IA64_BR0_REGNUM + 4: + case IA64_BR0_REGNUM + 5: + result = !unw_access_br(info, regnum - IA64_BR0_REGNUM, + reg, rw); + break; + } + + return result; +} + +static int kgdb_fr_reg(int regnum, char *inbuffer, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, + struct ia64_fpreg *freg, int rw) +{ + int result = 1; + + if (!(regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127))) + return 0; + + switch (regnum) { + case IA64_FR0_REGNUM + 6: + case IA64_FR0_REGNUM + 7: + case IA64_FR0_REGNUM + 8: + case IA64_FR0_REGNUM + 9: + case IA64_FR0_REGNUM + 10: + case IA64_FR0_REGNUM + 11: + case IA64_FR0_REGNUM + 12: + if (rw) { + char *ptr = inbuffer; + + freg->u.bits[0] = *reg; + kgdb_hex2long(&ptr, &freg->u.bits[1]); + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))) = + *freg; + break; + } else if (!ptregs) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else + *freg = + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))); + break; + default: + if (!rw) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else + result = 0; + break; + } + + return result; +} + +static int kgdb_ar_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int result = 0, i; + + if (!(regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM)) + return 0; + + if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)) = + *reg; + result = 1; + break; + } + } else if (ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)); + result = 1; + break; + } + } + + if (result) + return result; + + result = 1; + + switch (regnum) { + case IA64_CSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_CSD, reg, rw); + break; + case IA64_SSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_SSD, reg, rw); + break; + case IA64_UNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_RNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_BSPSTORE_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_PFS_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_LC_REGNUM: + result = !unw_access_ar(info, UNW_AR_LC, reg, rw); + break; + case IA64_EC_REGNUM: + result = !unw_access_ar(info, UNW_AR_EC, reg, rw); + break; + case IA64_FPSR_REGNUM: + result = !unw_access_ar(info, UNW_AR_FPSR, reg, rw); + break; + case IA64_RSC_REGNUM: + result = !unw_access_ar(info, UNW_AR_RSC, reg, rw); + break; + case IA64_CCV_REGNUM: + result = !unw_access_ar(info, UNW_AR_CCV, reg, rw); + break; + default: + result = 0; + } + + return result; +} + +void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, + struct pt_regs *ptregs) +{ + unsigned long reg, size = 0, *mem = ® + struct ia64_fpreg freg; + + if (kgdb_gr_reg(regnum, info, ®, 0) || + kgdb_gr_ptreg(regnum, ptregs, info, ®, 0) || + kgdb_br_reg(regnum, ptregs, info, ®, 0) || + kgdb_ar_reg(regnum, ptregs, info, ®, 0)) + size = sizeof(reg); + else if (kgdb_fr_reg(regnum, NULL, ptregs, info, ®, &freg, 0)) { + size = sizeof(freg); + mem = (unsigned long *)&freg; + } else if (regnum == IA64_IP_REGNUM) { + if (!ptregs) { + unw_get_ip(info, ®); + size = sizeof(reg); + } else { + reg = ptregs->cr_iip; + size = sizeof(reg); + } + } else if (regnum == IA64_CFM_REGNUM) { + if (!ptregs) + unw_get_cfm(info, ®); + else + reg = ptregs->cr_ifs; + size = sizeof(reg); + } else if (regnum == IA64_PSR_REGNUM) { + if (!ptregs && kgdb_usethread) + ptregs = (struct pt_regs *) + ((unsigned long)kgdb_usethread + + IA64_STK_OFFSET) - 1; + if (ptregs) + reg = ptregs->cr_ipsr; + size = sizeof(reg); + } else if (regnum == IA64_PR_REGNUM) { + if (ptregs) + reg = ptregs->pr; + else + unw_access_pr(info, ®, 0); + size = sizeof(reg); + } else if (regnum == IA64_BSP_REGNUM) { + unw_get_bsp(info, ®); + size = sizeof(reg); + } + + if (size) { + kgdb_mem2hex((char *) mem, outbuffer, size); + outbuffer[size*2] = 0; + } + else + strcpy(outbuffer, "E0"); + + return; +} + +void kgdb_put_reg(char *inbuffer, char *outbuffer, int regnum, + struct unw_frame_info *info, struct pt_regs *ptregs) +{ + unsigned long reg; + struct ia64_fpreg freg; + char *ptr = inbuffer; + + kgdb_hex2long(&ptr, ®); + strcpy(outbuffer, "OK"); + + if (kgdb_gr_reg(regnum, info, ®, 1) || + kgdb_gr_ptreg(regnum, ptregs, info, ®, 1) || + kgdb_br_reg(regnum, ptregs, info, ®, 1) || + kgdb_fr_reg(regnum, inbuffer, ptregs, info, ®, &freg, 1) || + kgdb_ar_reg(regnum, ptregs, info, ®, 1)) ; + else if (regnum == IA64_IP_REGNUM) + ptregs->cr_iip = reg; + else if (regnum == IA64_CFM_REGNUM) + ptregs->cr_ifs = reg; + else if (regnum == IA64_PSR_REGNUM) + ptregs->cr_ipsr = reg; + else if (regnum == IA64_PR_REGNUM) + ptregs->pr = reg; + else + strcpy(outbuffer, "E01"); + return; +} + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + +} + +#define MAX_HW_BREAKPOINT (20) +long hw_break_total_dbr, hw_break_total_ibr; +#define HW_BREAKPOINT (hw_break_total_dbr + hw_break_total_ibr) +#define WATCH_INSTRUCTION 0x0 +#define WATCH_WRITE 0x1 +#define WATCH_READ 0x2 +#define WATCH_ACCESS 0x3 + +#define HWCAP_DBR ((1 << WATCH_WRITE) | (1 << WATCH_READ)) +#define HWCAP_IBR (1 << WATCH_INSTRUCTION) +struct hw_breakpoint { + unsigned enabled; + unsigned long capable; + unsigned long type; + unsigned long mask; + unsigned long addr; +} *breakinfo; + +static struct hw_breakpoint hwbreaks[MAX_HW_BREAKPOINT]; + +enum instruction_type { A, I, M, F, B, L, X, u }; + +static enum instruction_type bundle_encoding[32][3] = { + {M, I, I}, /* 00 */ + {M, I, I}, /* 01 */ + {M, I, I}, /* 02 */ + {M, I, I}, /* 03 */ + {M, L, X}, /* 04 */ + {M, L, X}, /* 05 */ + {u, u, u}, /* 06 */ + {u, u, u}, /* 07 */ + {M, M, I}, /* 08 */ + {M, M, I}, /* 09 */ + {M, M, I}, /* 0A */ + {M, M, I}, /* 0B */ + {M, F, I}, /* 0C */ + {M, F, I}, /* 0D */ + {M, M, F}, /* 0E */ + {M, M, F}, /* 0F */ + {M, I, B}, /* 10 */ + {M, I, B}, /* 11 */ + {M, B, B}, /* 12 */ + {M, B, B}, /* 13 */ + {u, u, u}, /* 14 */ + {u, u, u}, /* 15 */ + {B, B, B}, /* 16 */ + {B, B, B}, /* 17 */ + {M, M, B}, /* 18 */ + {M, M, B}, /* 19 */ + {u, u, u}, /* 1A */ + {u, u, u}, /* 1B */ + {M, F, B}, /* 1C */ + {M, F, B}, /* 1D */ + {u, u, u}, /* 1E */ + {u, u, u}, /* 1F */ +}; + +int kgdb_validate_break_address(unsigned long addr) +{ + int error; + char tmp_variable[BREAK_INSTR_SIZE]; + error = kgdb_get_mem((char *)(addr & BREAK_INSTR_ALIGN), tmp_variable, + BREAK_INSTR_SIZE); + return error; +} + +int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) +{ + extern unsigned long _start[]; + unsigned long slot = addr & BREAK_INSTR_ALIGN, bundle_addr; + unsigned long template; + struct bundle { + struct { + unsigned long long template:5; + unsigned long long slot0:41; + unsigned long long slot1_p0:64 - 46; + } quad0; + struct { + unsigned long long slot1_p1:41 - (64 - 46); + unsigned long long slot2:41; + } quad1; + } bundle; + int ret; + + bundle_addr = addr & ~0xFULL; + + if (bundle_addr == (unsigned long)_start) + return 0; + + ret = kgdb_get_mem((char *)bundle_addr, (char *)&bundle, + BREAK_INSTR_SIZE); + if (ret < 0) + return ret; + + if (slot > 2) + slot = 0; + + memcpy(saved_instr, &bundle, BREAK_INSTR_SIZE); + template = bundle.quad0.template; + + if (slot == 1 && bundle_encoding[template][1] == L) + slot = 2; + + switch (slot) { + case 0: + bundle.quad0.slot0 = BREAKNUM; + break; + case 1: + bundle.quad0.slot1_p0 = BREAKNUM; + bundle.quad1.slot1_p1 = (BREAKNUM >> (64 - 46)); + break; + case 2: + bundle.quad1.slot2 = BREAKNUM; + break; + } + + return kgdb_set_mem((char *)bundle_addr, (char *)&bundle, + BREAK_INSTR_SIZE); +} + +int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) +{ + extern unsigned long _start[]; + + addr = addr & BREAK_INSTR_ALIGN; + if (addr == (unsigned long)_start) + return 0; + return kgdb_set_mem((char *)addr, (char *)bundle, BREAK_INSTR_SIZE); +} + +static int hw_breakpoint_init; + +void do_init_hw_break(void) +{ + s64 status; + int i; + + hw_breakpoint_init = 1; + +#ifdef CONFIG_IA64_HP_SIM + hw_break_total_ibr = 8; + hw_break_total_dbr = 8; + status = 0; +#else + status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr); +#endif + + if (status) { + printk(KERN_INFO "do_init_hw_break: pal call failed %d\n", + (int)status); + return; + } + + if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) { + printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n", + (int)HW_BREAKPOINT, (int)MAX_HW_BREAKPOINT); + + while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT) + && hw_break_total_ibr != 1) + hw_break_total_ibr--; + while (HW_BREAKPOINT > MAX_HW_BREAKPOINT) + hw_break_total_dbr--; + } + + breakinfo = hwbreaks; + + memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint)); + + for (i = 0; i < hw_break_total_dbr; i++) + breakinfo[i].capable = HWCAP_DBR; + + for (; i < HW_BREAKPOINT; i++) + breakinfo[i].capable = HWCAP_IBR; + + return; +} + +void kgdb_correct_hw_break(void) +{ + int breakno; + + if (!breakinfo) + return; + + for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) { + if (breakinfo[breakno].enabled) { + if (breakinfo[breakno].capable & HWCAP_IBR) { + int ibreakno = breakno - hw_break_total_dbr; + ia64_set_ibr(ibreakno << 1, + breakinfo[breakno].addr); + ia64_set_ibr((ibreakno << 1) + 1, + (~breakinfo[breakno].mask & + ((1UL << 56UL) - 1)) | + (1UL << 56UL) | (1UL << 63UL)); + } else { + ia64_set_dbr(breakno << 1, + breakinfo[breakno].addr); + ia64_set_dbr((breakno << 1) + 1, + (~breakinfo[breakno]. + mask & ((1UL << 56UL) - 1)) | + (1UL << 56UL) | + (breakinfo[breakno].type << 62UL)); + } + } else { + if (breakinfo[breakno].capable & HWCAP_IBR) + ia64_set_ibr(((breakno - + hw_break_total_dbr) << 1) + 1, + 0); + else + ia64_set_dbr((breakno << 1) + 1, 0); + } + } + + return; +} + +int hardware_breakpoint(unsigned long addr, int length, int type, int action) +{ + int breakno, found, watch; + unsigned long mask; + extern unsigned long _start[]; + + if (!hw_breakpoint_init) + do_init_hw_break(); + + if (!breakinfo) + return 0; + else if (addr == (unsigned long)_start) + return 1; + + if (type == WATCH_ACCESS) + mask = HWCAP_DBR; + else + mask = 1UL << type; + + for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT; + breakno++) { + if (action) { + if (breakinfo[breakno].enabled + || !(breakinfo[breakno].capable & mask)) + continue; + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].mask = length - 1; + breakinfo[breakno].addr = addr; + watch = breakno; + } else if (breakinfo[breakno].enabled && + ((length < 0 && breakinfo[breakno].addr == addr) || + ((breakinfo[breakno].capable & mask) && + (breakinfo[breakno].mask == (length - 1)) && + (breakinfo[breakno].addr == addr)))) { + breakinfo[breakno].enabled = 0; + breakinfo[breakno].type = 0UL; + } else + continue; + found++; + if (type != WATCH_ACCESS) + break; + else if (found == 2) + break; + else + mask = HWCAP_IBR; + } + + if (type == WATCH_ACCESS && found == 1) { + breakinfo[watch].enabled = 0; + found = 0; + } + + mb(); + return found; +} + +int kgdb_arch_set_hw_breakpoint(unsigned long addr, int len, + enum kgdb_bptype type) +{ + return hardware_breakpoint(addr, len, type - '1', 1); +} + +int kgdb_arch_remove_hw_breakpoint(unsigned long addr, int len, + enum kgdb_bptype type) +{ + return hardware_breakpoint(addr, len, type - '1', 0); +} + +int kgdb_remove_hw_break(unsigned long addr) +{ + return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 0); + +} + +void kgdb_remove_all_hw_break(void) +{ + int i; + + for (i = 0; i < HW_BREAKPOINT; i++) + memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); +} + +int kgdb_set_hw_break(unsigned long addr) +{ + return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 1); +} + +void kgdb_disable_hw_debug(struct pt_regs *regs) +{ + unsigned long hw_breakpoint_status; + + hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR); + if (hw_breakpoint_status & IA64_PSR_DB) + ia64_setreg(_IA64_REG_PSR_L, + hw_breakpoint_status ^ IA64_PSR_DB); +} + +volatile static struct smp_unw { + struct unw_frame_info *unw; + struct task_struct *task; +} smp_unw[NR_CPUS]; + +static int inline kgdb_get_blocked_state(struct task_struct *p, + struct unw_frame_info *unw) +{ + unsigned long ip; + int count = 0; + + unw_init_from_blocked_task(unw, p); + ip = 0UL; + do { + if (unw_unwind(unw) < 0) + return -1; + unw_get_ip(unw, &ip); + if (!in_sched_functions(ip)) + break; + } while (count++ < 16); + + if (!ip) + return -1; + else + return 0; +} + +static void inline kgdb_wait(struct pt_regs *regs) +{ + unsigned long hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR); + if (hw_breakpoint_status & IA64_PSR_DB) + ia64_setreg(_IA64_REG_PSR_L, + hw_breakpoint_status ^ IA64_PSR_DB); + kgdb_nmihook(smp_processor_id(), regs); + if (hw_breakpoint_status & IA64_PSR_DB) + ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status); + + return; +} + +static void inline normalize(struct unw_frame_info *running, + struct pt_regs *regs) +{ + unsigned long sp; + + do { + unw_get_sp(running, &sp); + if ((sp + 0x10) >= (unsigned long)regs) + break; + } while (unw_unwind(running) >= 0); + + return; +} + +static void kgdb_init_running(struct unw_frame_info *unw, void *data) +{ + struct pt_regs *regs; + + regs = data; + normalize(unw, regs); + smp_unw[smp_processor_id()].unw = unw; + kgdb_wait(regs); +} + +void kgdb_wait_ipi(struct pt_regs *regs) +{ + struct unw_frame_info unw; + + smp_unw[smp_processor_id()].task = current; + + if (user_mode(regs)) { + smp_unw[smp_processor_id()].unw = (struct unw_frame_info *)1; + kgdb_wait(regs); + } else { + if (current->state == TASK_RUNNING) + unw_init_running(kgdb_init_running, regs); + else { + if (kgdb_get_blocked_state(current, &unw)) + smp_unw[smp_processor_id()].unw = + (struct unw_frame_info *)1; + else + smp_unw[smp_processor_id()].unw = &unw; + kgdb_wait(regs); + } + } + + smp_unw[smp_processor_id()].unw = NULL; + return; +} + +void kgdb_roundup_cpus(unsigned long flags) +{ + if (num_online_cpus() > 1) + smp_send_nmi_allbutself(); +} + +static volatile int kgdb_hwbreak_sstep[NR_CPUS]; + +static int kgdb_notify(struct notifier_block *self, unsigned long cmd, + void *ptr) +{ + struct die_args *args = ptr; + struct pt_regs *regs = args->regs; + unsigned long err = args->err; + + switch (cmd) { + default: + return NOTIFY_DONE; + case DIE_PAGE_FAULT_NO_CONTEXT: + if (atomic_read(&debugger_active) && kgdb_may_fault) { + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + return NOTIFY_STOP; + } + break; + case DIE_BREAK: + if (user_mode(regs) || err == 0x80001) + return NOTIFY_DONE; + break; + case DIE_FAULT: + if (user_mode(regs)) + return NOTIFY_DONE; + else if (err == 36 && kgdb_hwbreak_sstep[smp_processor_id()]) { + kgdb_hwbreak_sstep[smp_processor_id()] = 0; + regs->cr_ipsr &= ~IA64_PSR_SS; + return NOTIFY_STOP; + } + case DIE_MCA_MONARCH_PROCESS: + case DIE_INIT_MONARCH_PROCESS: + break; + } + + kgdb_handle_exception(args->trapnr, args->signr, args->err, regs); + return NOTIFY_STOP; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, +}; + +int kgdb_arch_init(void) +{ + atomic_notifier_chain_register(&ia64die_chain, &kgdb_notifier); + return 0; +} + +static void do_kgdb_handle_exception(struct unw_frame_info *, void *data); + +struct kgdb_state { + int e_vector; + int signo; + unsigned long err_code; + struct pt_regs *regs; + struct unw_frame_info *unw; + char *inbuf; + char *outbuf; + int unwind; + int ret; +}; + +static void inline kgdb_pc(struct pt_regs *regs, unsigned long pc) +{ + regs->cr_iip = pc & ~0xf; + ia64_psr(regs)->ri = pc & 0x3; + return; +} + +int kgdb_arch_handle_exception(int e_vector, int signo, + int err_code, char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + struct kgdb_state info; + + info.e_vector = e_vector; + info.signo = signo; + info.err_code = err_code; + info.unw = (void *)0; + info.inbuf = remcom_in_buffer; + info.outbuf = remcom_out_buffer; + info.unwind = 0; + info.ret = -1; + + if (remcom_in_buffer[0] == 'c' || remcom_in_buffer[0] == 's') { + info.regs = linux_regs; + do_kgdb_handle_exception(NULL, &info); + } else if (kgdb_usethread == current) { + info.regs = linux_regs; + info.unwind = 1; + unw_init_running(do_kgdb_handle_exception, &info); + } else if (kgdb_usethread->state != TASK_RUNNING) { + struct unw_frame_info unw_info; + + if (kgdb_get_blocked_state(kgdb_usethread, &unw_info)) { + info.ret = 1; + goto bad; + } + info.regs = NULL; + do_kgdb_handle_exception(&unw_info, &info); + } else { + int i; + + for (i = 0; i < NR_CPUS; i++) + if (smp_unw[i].task == kgdb_usethread && smp_unw[i].unw + && smp_unw[i].unw != (struct unw_frame_info *)1) { + info.regs = NULL; + do_kgdb_handle_exception(smp_unw[i].unw, &info); + break; + } else { + info.ret = 1; + goto bad; + } + } + + bad: + if (info.ret != -1 && remcom_in_buffer[0] == 'p') { + unsigned long bad = 0xbad4badbadbadbadUL; + + printk("kgdb_arch_handle_exception: p packet bad (%s)\n", + remcom_in_buffer); + kgdb_mem2hex((char *)&bad, remcom_out_buffer, sizeof(bad)); + remcom_out_buffer[sizeof(bad) * 2] = 0; + info.ret = -1; + } + return info.ret; +} + +/* + * This is done because I evidently made an incorrect 'p' encoding + * when my patch for gdb was committed. It was later corrected. This + * check supports both my wrong encoding of the register number and + * the correct encoding. Eventually this should be eliminated and + * kgdb_hex2long should be demarshalling the regnum. + */ +static inline int check_packet(unsigned int regnum, char *packet) +{ + static int check_done, swap; + unsigned long reglong; + + if (likely(check_done)) { + if (swap) { + kgdb_hex2long(&packet, ®long); + regnum = (int) reglong; + } + + } else { + if (regnum > NUM_REGS) { + kgdb_hex2long(&packet, ®long); + regnum = (int) reglong; + swap = 1; + } + check_done = 1; + } + return regnum; +} + +static void do_kgdb_handle_exception(struct unw_frame_info *unw_info, + void *data) +{ + long addr; + char *ptr; + unsigned long newPC; + int e_vector, signo; + unsigned long err_code; + struct pt_regs *linux_regs; + struct kgdb_state *info; + char *remcom_in_buffer, *remcom_out_buffer; + + info = data; + info->unw = unw_info; + e_vector = info->e_vector; + signo = info->signo; + err_code = info->err_code; + remcom_in_buffer = info->inbuf; + remcom_out_buffer = info->outbuf; + linux_regs = info->regs; + + if (info->unwind) + normalize(unw_info, linux_regs); + + switch (remcom_in_buffer[0]) { + case 'p': + { + unsigned int regnum; + + kgdb_hex2mem(&remcom_in_buffer[1], (char *)®num, + sizeof(regnum)); + regnum = check_packet(regnum, &remcom_in_buffer[1]); + if (regnum >= NUM_REGS) { + remcom_out_buffer[0] = 'E'; + remcom_out_buffer[1] = 0; + } else + kgdb_get_reg(remcom_out_buffer, regnum, + unw_info, linux_regs); + break; + } + case 'P': + { + unsigned int regno; + long v; + char *ptr; + + ptr = &remcom_in_buffer[1]; + if ((!kgdb_usethread || kgdb_usethread == current) && + kgdb_hex2long(&ptr, &v) && + *ptr++ == '=' && (v >= 0)) { + regno = (unsigned int)v; + regno = (regno >= NUM_REGS ? 0 : regno); + kgdb_put_reg(ptr, remcom_out_buffer, regno, + unw_info, linux_regs); + } else + strcpy(remcom_out_buffer, "E01"); + break; + } + case 'c': + case 's': + if (e_vector == TRAP_BRKPT && err_code == KGDBBREAKNUM) { + if (ia64_psr(linux_regs)->ri < 2) + kgdb_pc(linux_regs, linux_regs->cr_iip + + ia64_psr(linux_regs)->ri + 1); + else + kgdb_pc(linux_regs, linux_regs->cr_iip + 16); + } + + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr)) { + linux_regs->cr_iip = addr; + } + newPC = linux_regs->cr_iip; + + /* clear the trace bit */ + linux_regs->cr_ipsr &= ~IA64_PSR_SS; + + atomic_set(&cpu_doing_single_step, -1); + + /* set the trace bit if we're stepping or took a hardware break */ + if (remcom_in_buffer[0] == 's' || e_vector == TRAP_HWBKPT) { + linux_regs->cr_ipsr |= IA64_PSR_SS; + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + + kgdb_correct_hw_break(); + + /* if not hardware breakpoint, then reenable them */ + if (e_vector != TRAP_HWBKPT) + linux_regs->cr_ipsr |= IA64_PSR_DB; + else { + kgdb_hwbreak_sstep[smp_processor_id()] = 1; + linux_regs->cr_ipsr &= ~IA64_PSR_DB; + } + + info->ret = 0; + break; + default: + break; + } + + return; +} + +struct kgdb_arch arch_kgdb_ops = { + .set_hw_breakpoint = kgdb_arch_set_hw_breakpoint, + .remove_hw_breakpoint = kgdb_arch_remove_hw_breakpoint, + .gdb_bpt_instr = {0xcc}, + .flags = KGDB_HW_BREAKPOINT, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/process.c linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/process.c --- linux-2.6.18-53.1.14/arch/ia64/kernel/process.c 2008-03-06 05:55:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/process.c 2008-06-10 15:39:39.000000000 +0400 @@ -463,6 +463,9 @@ copy_thread (int nr, unsigned long clone */ child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); +#ifdef CONFIG_KGDB + child_ptregs->cr_ipsr |= IA64_PSR_DB; +#endif /* * NOTE: The calling convention considers all floating point @@ -691,6 +694,9 @@ kernel_thread (int (*fn)(void *), void * regs.pt.r11 = (unsigned long) arg; /* 2nd argument */ /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */ regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; +#ifdef CONFIG_KGDB + regs.pt.cr_ipsr |= IA64_PSR_DB; +#endif regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/smp.c linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/smp.c --- linux-2.6.18-53.1.14/arch/ia64/kernel/smp.c 2008-03-06 05:54:27.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/smp.c 2008-06-10 15:38:32.000000000 +0400 @@ -48,6 +48,7 @@ #include #include #include +#include /* * Structure and data for smp_call_function(). This is designed to minimise static memory @@ -68,6 +69,9 @@ static volatile struct call_data_struct #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 #define IPI_KDUMP_CPU_STOP 3 +#ifdef CONFIG_KGDB +#define IPI_KGDB_INTERRUPT 2 +#endif /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; @@ -185,6 +189,11 @@ handle_IPI (int irq, void *dev_id, struc case IPI_CPU_STOP: stop_this_cpu(); break; +#ifdef CONFIG_KGDB + case IPI_KGDB_INTERRUPT: + kgdb_wait_ipi(regs); + break; +#endif #ifdef CONFIG_CRASH_DUMP case IPI_KDUMP_CPU_STOP: unw_init_running(kdump_cpu_freeze, NULL); @@ -359,6 +368,14 @@ smp_call_function_single (int cpuid, voi } EXPORT_SYMBOL(smp_call_function_single); +#ifdef CONFIG_KGDB +void +smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(IPI_KGDB_INTERRUPT); +} +#endif + /* * this function sends a 'generic call function' IPI to all other CPUs * in the system. diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/traps.c linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/traps.c --- linux-2.6.18-53.1.14/arch/ia64/kernel/traps.c 2008-03-06 05:54:44.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/traps.c 2008-06-10 15:38:32.000000000 +0400 @@ -200,8 +200,12 @@ __kprobes ia64_bad_break (unsigned long break; default: - if (break_num < 0x40000 || break_num > 0x100000) + if (break_num < 0x40000 || break_num > 0x100000) { + if (notify_die(DIE_BREAK, "bad break", regs, + break_num, TRAP_BRKPT, SIGTRAP) == NOTIFY_STOP) + return; die_if_kernel("Bad break", regs, break_num); + } if (break_num < 0x80000) { sig = SIGILL; code = __ILL_BREAK; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/kernel/unwind.c linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/unwind.c --- linux-2.6.18-53.1.14/arch/ia64/kernel/unwind.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/kernel/unwind.c 2008-06-10 15:39:39.000000000 +0400 @@ -72,10 +72,68 @@ # define STAT(x...) #endif +#ifdef CONFIG_KGDB +#define KGDB_EARLY_SIZE 100 +static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE]; +static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE]; +void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free; + +static void __init +kgdb_malloc_init(void) +{ + int i; + + kgdb_reg_state_free = kgdb_reg_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free; + kgdb_reg_state_free = &kgdb_reg_state[i]; + } + + kgdb_labeled_state_free = kgdb_labeled_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_labeled_state[i]) = + (unsigned long) kgdb_labeled_state_free; + kgdb_labeled_state_free = &kgdb_labeled_state[i]; + } + +} + +static void * __init +kgdb_malloc(void **mem) +{ + void *p; + + p = *mem; + *mem = *((void **) p); + return p; +} + +static void __init +kgdb_free(void **mem, void *p) +{ + *((void **)p) = *mem; + *mem = p; +} + +#define alloc_reg_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_reg_state_free) : \ + kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)) +#define free_reg_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_reg_state_free, usr) : \ + kfree(usr)) +#define alloc_labeled_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_labeled_state_free) : \ + kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)) +#define free_labeled_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_labeled_state_free, usr) : \ + kfree(usr)) + +#else #define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) +#endif typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; @@ -238,6 +296,24 @@ static struct { #endif }; +#ifdef CONFIG_KGDB +/* + * This makes it safe to call breakpoint() very early + * in setup_arch providing: + * 1) breakpoint isn't called between lines in cpu_init + * where init_mm.mm_count is incremented and ia64_mmu_init + * is called. Otherwise the test below is invalid. + * 2) the memory examined doesn't result in tlbmiss. + */ +static unsigned long inline kgdb_unimpl_va_mask(void) +{ + if (atomic_read(&init_mm.mm_count) > 1) + return local_cpu_data->unimpl_va_mask; + else + return 0UL; +} +#endif + static inline int read_only (void *addr) { @@ -1786,7 +1862,11 @@ run_script (struct unw_script *script, s case UNW_INSN_LOAD: #ifdef UNW_DEBUG +#ifdef CONFIG_KGDB + if ((s[val] & (kgdb_unimpl_va_mask() | 0x7)) != 0 +#else if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0 +#endif || s[val] < TASK_SIZE) { UNW_DPRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n", @@ -1821,7 +1901,11 @@ find_save_locs (struct unw_frame_info *i struct unw_script *scr; unsigned long flags = 0; +#ifdef CONFIG_KGDB + if ((info->ip & (kgdb_unimpl_va_mask() | 0xf)) || info->ip < TASK_SIZE) { +#else if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { +#endif /* don't let obviously bad addresses pollute the cache */ /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); @@ -2249,6 +2333,9 @@ unw_init (void) init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp, __start_unwind, __end_unwind); +#ifdef CONFIG_KGDB + kgdb_malloc_init(); +#endif } /* diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/mm/extable.c linux-2.6.18-53.1.14.kgdb/arch/ia64/mm/extable.c --- linux-2.6.18-53.1.14/arch/ia64/mm/extable.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/mm/extable.c 2008-06-10 15:38:32.000000000 +0400 @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -73,6 +74,11 @@ search_extable (const struct exception_t else last = mid - 1; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ +#endif return NULL; } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ia64/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/ia64/mm/fault.c --- linux-2.6.18-53.1.14/arch/ia64/mm/fault.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ia64/mm/fault.c 2008-06-10 15:38:32.000000000 +0400 @@ -266,6 +266,10 @@ ia64_do_page_fault (unsigned long addres */ bust_spinlocks(1); + if (notify_die(DIE_PAGE_FAULT_NO_CONTEXT, "no context", regs, + isr, 14, SIGSEGV) == NOTIFY_STOP) + return; + if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address); else diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/Kconfig.debug linux-2.6.18-53.1.14.kgdb/arch/mips/Kconfig.debug --- linux-2.6.18-53.1.14/arch/mips/Kconfig.debug 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/Kconfig.debug 2008-06-10 15:38:24.000000000 +0400 @@ -37,25 +37,6 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config KGDB - bool "Remote GDB kernel debugging" - depends on DEBUG_KERNEL - select DEBUG_INFO - help - If you say Y here, it will be possible to remotely debug the MIPS - kernel using gdb. This enlarges your kernel image disk size by - several megabytes and requires a machine with more than 16 MB, - better 32 MB RAM to avoid excessive linking time. This is only - useful for kernel hackers. If unsure, say N. - -config GDB_CONSOLE - bool "Console output to GDB" - depends on KGDB - help - If you are using GDB for remote debugging over a serial port and - would like kernel messages to be formatted into GDB $O packets so - that GDB prints them as program output, say 'Y'. - config SB1XXX_CORELIS bool "Corelis Debugger" depends on SIBYTE_SB1xxx_SOC diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/Makefile --- linux-2.6.18-53.1.14/arch/mips/kernel/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/Makefile 2008-06-10 15:38:24.000000000 +0400 @@ -59,7 +59,8 @@ obj-$(CONFIG_MIPS32_COMPAT) += linux32.o obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o ptrace32.o -obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o +obj-$(CONFIG_KGDB) += kgdb_handler.o kgdb.o kgdb-jmp.o \ + kgdb-setjmp.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/gdb-low.S linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/gdb-low.S --- linux-2.6.18-53.1.14/arch/mips/kernel/gdb-low.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/gdb-low.S 1970-01-01 03:00:00.000000000 +0300 @@ -1,394 +0,0 @@ -/* - * gdb-low.S contains the low-level trap handler for the GDB stub. - * - * Copyright (C) 1995 Andreas Busse - */ -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_32BIT -#define DMFC0 mfc0 -#define DMTC0 mtc0 -#define LDC1 lwc1 -#define SDC1 lwc1 -#endif -#ifdef CONFIG_64BIT -#define DMFC0 dmfc0 -#define DMTC0 dmtc0 -#define LDC1 ldc1 -#define SDC1 ldc1 -#endif - -/* - * [jsun] We reserves about 2x GDB_FR_SIZE in stack. The lower (addressed) - * part is used to store registers and passed to exception handler. - * The upper part is reserved for "call func" feature where gdb client - * saves some of the regs, setups call frame and passes args. - * - * A trace shows about 200 bytes are used to store about half of all regs. - * The rest should be big enough for frame setup and passing args. - */ - -/* - * The low level trap handler - */ - .align 5 - NESTED(trap_low, GDB_FR_SIZE, sp) - .set noat - .set noreorder - - mfc0 k0, CP0_STATUS - sll k0, 3 /* extract cu0 bit */ - bltz k0, 1f - move k1, sp - - /* - * Called from user mode, go somewhere else. - */ - mfc0 k0, CP0_CAUSE - andi k0, k0, 0x7c -#ifdef CONFIG_64BIT - dsll k0, k0, 1 -#endif - PTR_L k1, saved_vectors(k0) - jr k1 - nop -1: - move k0, sp - PTR_SUBU sp, k1, GDB_FR_SIZE*2 # see comment above - LONG_S k0, GDB_FR_REG29(sp) - LONG_S $2, GDB_FR_REG2(sp) - -/* - * First save the CP0 and special registers - */ - - mfc0 v0, CP0_STATUS - LONG_S v0, GDB_FR_STATUS(sp) - mfc0 v0, CP0_CAUSE - LONG_S v0, GDB_FR_CAUSE(sp) - DMFC0 v0, CP0_EPC - LONG_S v0, GDB_FR_EPC(sp) - DMFC0 v0, CP0_BADVADDR - LONG_S v0, GDB_FR_BADVADDR(sp) - mfhi v0 - LONG_S v0, GDB_FR_HI(sp) - mflo v0 - LONG_S v0, GDB_FR_LO(sp) - -/* - * Now the integer registers - */ - - LONG_S zero, GDB_FR_REG0(sp) /* I know... */ - LONG_S $1, GDB_FR_REG1(sp) - /* v0 already saved */ - LONG_S $3, GDB_FR_REG3(sp) - LONG_S $4, GDB_FR_REG4(sp) - LONG_S $5, GDB_FR_REG5(sp) - LONG_S $6, GDB_FR_REG6(sp) - LONG_S $7, GDB_FR_REG7(sp) - LONG_S $8, GDB_FR_REG8(sp) - LONG_S $9, GDB_FR_REG9(sp) - LONG_S $10, GDB_FR_REG10(sp) - LONG_S $11, GDB_FR_REG11(sp) - LONG_S $12, GDB_FR_REG12(sp) - LONG_S $13, GDB_FR_REG13(sp) - LONG_S $14, GDB_FR_REG14(sp) - LONG_S $15, GDB_FR_REG15(sp) - LONG_S $16, GDB_FR_REG16(sp) - LONG_S $17, GDB_FR_REG17(sp) - LONG_S $18, GDB_FR_REG18(sp) - LONG_S $19, GDB_FR_REG19(sp) - LONG_S $20, GDB_FR_REG20(sp) - LONG_S $21, GDB_FR_REG21(sp) - LONG_S $22, GDB_FR_REG22(sp) - LONG_S $23, GDB_FR_REG23(sp) - LONG_S $24, GDB_FR_REG24(sp) - LONG_S $25, GDB_FR_REG25(sp) - LONG_S $26, GDB_FR_REG26(sp) - LONG_S $27, GDB_FR_REG27(sp) - LONG_S $28, GDB_FR_REG28(sp) - /* sp already saved */ - LONG_S $30, GDB_FR_REG30(sp) - LONG_S $31, GDB_FR_REG31(sp) - - CLI /* disable interrupts */ - TRACE_IRQS_OFF - -/* - * Followed by the floating point registers - */ - mfc0 v0, CP0_STATUS /* FPU enabled? */ - srl v0, v0, 16 - andi v0, v0, (ST0_CU1 >> 16) - - beqz v0,2f /* disabled, skip */ - nop - - SDC1 $0, GDB_FR_FPR0(sp) - SDC1 $1, GDB_FR_FPR1(sp) - SDC1 $2, GDB_FR_FPR2(sp) - SDC1 $3, GDB_FR_FPR3(sp) - SDC1 $4, GDB_FR_FPR4(sp) - SDC1 $5, GDB_FR_FPR5(sp) - SDC1 $6, GDB_FR_FPR6(sp) - SDC1 $7, GDB_FR_FPR7(sp) - SDC1 $8, GDB_FR_FPR8(sp) - SDC1 $9, GDB_FR_FPR9(sp) - SDC1 $10, GDB_FR_FPR10(sp) - SDC1 $11, GDB_FR_FPR11(sp) - SDC1 $12, GDB_FR_FPR12(sp) - SDC1 $13, GDB_FR_FPR13(sp) - SDC1 $14, GDB_FR_FPR14(sp) - SDC1 $15, GDB_FR_FPR15(sp) - SDC1 $16, GDB_FR_FPR16(sp) - SDC1 $17, GDB_FR_FPR17(sp) - SDC1 $18, GDB_FR_FPR18(sp) - SDC1 $19, GDB_FR_FPR19(sp) - SDC1 $20, GDB_FR_FPR20(sp) - SDC1 $21, GDB_FR_FPR21(sp) - SDC1 $22, GDB_FR_FPR22(sp) - SDC1 $23, GDB_FR_FPR23(sp) - SDC1 $24, GDB_FR_FPR24(sp) - SDC1 $25, GDB_FR_FPR25(sp) - SDC1 $26, GDB_FR_FPR26(sp) - SDC1 $27, GDB_FR_FPR27(sp) - SDC1 $28, GDB_FR_FPR28(sp) - SDC1 $29, GDB_FR_FPR29(sp) - SDC1 $30, GDB_FR_FPR30(sp) - SDC1 $31, GDB_FR_FPR31(sp) - -/* - * FPU control registers - */ - - cfc1 v0, CP1_STATUS - LONG_S v0, GDB_FR_FSR(sp) - cfc1 v0, CP1_REVISION - LONG_S v0, GDB_FR_FIR(sp) - -/* - * Current stack frame ptr - */ - -2: - LONG_S sp, GDB_FR_FRP(sp) - -/* - * CP0 registers (R4000/R4400 unused registers skipped) - */ - - mfc0 v0, CP0_INDEX - LONG_S v0, GDB_FR_CP0_INDEX(sp) - mfc0 v0, CP0_RANDOM - LONG_S v0, GDB_FR_CP0_RANDOM(sp) - DMFC0 v0, CP0_ENTRYLO0 - LONG_S v0, GDB_FR_CP0_ENTRYLO0(sp) - DMFC0 v0, CP0_ENTRYLO1 - LONG_S v0, GDB_FR_CP0_ENTRYLO1(sp) - DMFC0 v0, CP0_CONTEXT - LONG_S v0, GDB_FR_CP0_CONTEXT(sp) - mfc0 v0, CP0_PAGEMASK - LONG_S v0, GDB_FR_CP0_PAGEMASK(sp) - mfc0 v0, CP0_WIRED - LONG_S v0, GDB_FR_CP0_WIRED(sp) - DMFC0 v0, CP0_ENTRYHI - LONG_S v0, GDB_FR_CP0_ENTRYHI(sp) - mfc0 v0, CP0_PRID - LONG_S v0, GDB_FR_CP0_PRID(sp) - - .set at - -/* - * Continue with the higher level handler - */ - - move a0,sp - - jal handle_exception - nop - -/* - * Restore all writable registers, in reverse order - */ - - .set noat - - LONG_L v0, GDB_FR_CP0_ENTRYHI(sp) - LONG_L v1, GDB_FR_CP0_WIRED(sp) - DMTC0 v0, CP0_ENTRYHI - mtc0 v1, CP0_WIRED - LONG_L v0, GDB_FR_CP0_PAGEMASK(sp) - LONG_L v1, GDB_FR_CP0_ENTRYLO1(sp) - mtc0 v0, CP0_PAGEMASK - DMTC0 v1, CP0_ENTRYLO1 - LONG_L v0, GDB_FR_CP0_ENTRYLO0(sp) - LONG_L v1, GDB_FR_CP0_INDEX(sp) - DMTC0 v0, CP0_ENTRYLO0 - LONG_L v0, GDB_FR_CP0_CONTEXT(sp) - mtc0 v1, CP0_INDEX - DMTC0 v0, CP0_CONTEXT - - -/* - * Next, the floating point registers - */ - mfc0 v0, CP0_STATUS /* check if the FPU is enabled */ - srl v0, v0, 16 - andi v0, v0, (ST0_CU1 >> 16) - - beqz v0, 3f /* disabled, skip */ - nop - - LDC1 $31, GDB_FR_FPR31(sp) - LDC1 $30, GDB_FR_FPR30(sp) - LDC1 $29, GDB_FR_FPR29(sp) - LDC1 $28, GDB_FR_FPR28(sp) - LDC1 $27, GDB_FR_FPR27(sp) - LDC1 $26, GDB_FR_FPR26(sp) - LDC1 $25, GDB_FR_FPR25(sp) - LDC1 $24, GDB_FR_FPR24(sp) - LDC1 $23, GDB_FR_FPR23(sp) - LDC1 $22, GDB_FR_FPR22(sp) - LDC1 $21, GDB_FR_FPR21(sp) - LDC1 $20, GDB_FR_FPR20(sp) - LDC1 $19, GDB_FR_FPR19(sp) - LDC1 $18, GDB_FR_FPR18(sp) - LDC1 $17, GDB_FR_FPR17(sp) - LDC1 $16, GDB_FR_FPR16(sp) - LDC1 $15, GDB_FR_FPR15(sp) - LDC1 $14, GDB_FR_FPR14(sp) - LDC1 $13, GDB_FR_FPR13(sp) - LDC1 $12, GDB_FR_FPR12(sp) - LDC1 $11, GDB_FR_FPR11(sp) - LDC1 $10, GDB_FR_FPR10(sp) - LDC1 $9, GDB_FR_FPR9(sp) - LDC1 $8, GDB_FR_FPR8(sp) - LDC1 $7, GDB_FR_FPR7(sp) - LDC1 $6, GDB_FR_FPR6(sp) - LDC1 $5, GDB_FR_FPR5(sp) - LDC1 $4, GDB_FR_FPR4(sp) - LDC1 $3, GDB_FR_FPR3(sp) - LDC1 $2, GDB_FR_FPR2(sp) - LDC1 $1, GDB_FR_FPR1(sp) - LDC1 $0, GDB_FR_FPR0(sp) - -/* - * Now the CP0 and integer registers - */ - -3: -#ifdef CONFIG_MIPS_MT_SMTC - /* Read-modify write of Status must be atomic */ - mfc0 t2, CP0_TCSTATUS - ori t1, t2, TCSTATUS_IXMT - mtc0 t1, CP0_TCSTATUS - andi t2, t2, TCSTATUS_IXMT - _ehb - DMT 9 # dmt t1 - jal mips_ihb - nop -#endif /* CONFIG_MIPS_MT_SMTC */ - mfc0 t0, CP0_STATUS - ori t0, 0x1f - xori t0, 0x1f - mtc0 t0, CP0_STATUS -#ifdef CONFIG_MIPS_MT_SMTC - andi t1, t1, VPECONTROL_TE - beqz t1, 9f - nop - EMT # emt -9: - mfc0 t1, CP0_TCSTATUS - xori t1, t1, TCSTATUS_IXMT - or t1, t1, t2 - mtc0 t1, CP0_TCSTATUS - _ehb -#endif /* CONFIG_MIPS_MT_SMTC */ - LONG_L v0, GDB_FR_STATUS(sp) - LONG_L v1, GDB_FR_EPC(sp) - mtc0 v0, CP0_STATUS - DMTC0 v1, CP0_EPC - LONG_L v0, GDB_FR_HI(sp) - LONG_L v1, GDB_FR_LO(sp) - mthi v0 - mtlo v1 - LONG_L $31, GDB_FR_REG31(sp) - LONG_L $30, GDB_FR_REG30(sp) - LONG_L $28, GDB_FR_REG28(sp) - LONG_L $27, GDB_FR_REG27(sp) - LONG_L $26, GDB_FR_REG26(sp) - LONG_L $25, GDB_FR_REG25(sp) - LONG_L $24, GDB_FR_REG24(sp) - LONG_L $23, GDB_FR_REG23(sp) - LONG_L $22, GDB_FR_REG22(sp) - LONG_L $21, GDB_FR_REG21(sp) - LONG_L $20, GDB_FR_REG20(sp) - LONG_L $19, GDB_FR_REG19(sp) - LONG_L $18, GDB_FR_REG18(sp) - LONG_L $17, GDB_FR_REG17(sp) - LONG_L $16, GDB_FR_REG16(sp) - LONG_L $15, GDB_FR_REG15(sp) - LONG_L $14, GDB_FR_REG14(sp) - LONG_L $13, GDB_FR_REG13(sp) - LONG_L $12, GDB_FR_REG12(sp) - LONG_L $11, GDB_FR_REG11(sp) - LONG_L $10, GDB_FR_REG10(sp) - LONG_L $9, GDB_FR_REG9(sp) - LONG_L $8, GDB_FR_REG8(sp) - LONG_L $7, GDB_FR_REG7(sp) - LONG_L $6, GDB_FR_REG6(sp) - LONG_L $5, GDB_FR_REG5(sp) - LONG_L $4, GDB_FR_REG4(sp) - LONG_L $3, GDB_FR_REG3(sp) - LONG_L $2, GDB_FR_REG2(sp) - LONG_L $1, GDB_FR_REG1(sp) -#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) - LONG_L k0, GDB_FR_EPC(sp) - LONG_L $29, GDB_FR_REG29(sp) /* Deallocate stack */ - jr k0 - rfe -#else - LONG_L sp, GDB_FR_REG29(sp) /* Deallocate stack */ - - .set mips3 - eret - .set mips0 -#endif - .set at - .set reorder - END(trap_low) - -LEAF(kgdb_read_byte) -4: lb t0, (a0) - sb t0, (a1) - li v0, 0 - jr ra - .section __ex_table,"a" - PTR 4b, kgdbfault - .previous - END(kgdb_read_byte) - -LEAF(kgdb_write_byte) -5: sb a0, (a1) - li v0, 0 - jr ra - .section __ex_table,"a" - PTR 5b, kgdbfault - .previous - END(kgdb_write_byte) - - .type kgdbfault@function - .ent kgdbfault - -kgdbfault: li v0, -EFAULT - jr ra - .end kgdbfault diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/gdb-stub.c linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/gdb-stub.c --- linux-2.6.18-53.1.14/arch/mips/kernel/gdb-stub.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/gdb-stub.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,1154 +0,0 @@ -/* - * arch/mips/kernel/gdb-stub.c - * - * Originally written by Glenn Engel, Lake Stevens Instrument Division - * - * Contributed by HP Systems - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse - * Send complaints, suggestions etc. to - * - * Copyright (C) 1995 Andreas Busse - * - * Copyright (C) 2003 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - */ - -/* - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a BREAK instruction. - * - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * bBB..BB Set baud rate to BB..BB OK or BNN, then sets - * baud rate - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $#. - * - * where - * :: - * :: < two hex digits computed as modulo 256 sum of > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - * - * ============== - * MORE EXAMPLES: - * ============== - * - * For reference -- the following are the steps that one - * company took (RidgeRun Inc) to get remote gdb debugging - * going. In this scenario the host machine was a PC and the - * target platform was a Galileo EVB64120A MIPS evaluation - * board. - * - * Step 1: - * First download gdb-5.0.tar.gz from the internet. - * and then build/install the package. - * - * Example: - * $ tar zxf gdb-5.0.tar.gz - * $ cd gdb-5.0 - * $ ./configure --target=mips-linux-elf - * $ make - * $ install - * $ which mips-linux-elf-gdb - * /usr/local/bin/mips-linux-elf-gdb - * - * Step 2: - * Configure linux for remote debugging and build it. - * - * Example: - * $ cd ~/linux - * $ make menuconfig - * $ make - * - * Step 3: - * Download the kernel to the remote target and start - * the kernel running. It will promptly halt and wait - * for the host gdb session to connect. It does this - * since the "Kernel Hacking" option has defined - * CONFIG_KGDB which in turn enables your calls - * to: - * set_debug_traps(); - * breakpoint(); - * - * Step 4: - * Start the gdb session on the host. - * - * Example: - * $ mips-linux-elf-gdb vmlinux - * (gdb) set remotebaud 115200 - * (gdb) target remote /dev/ttyS1 - * ...at this point you are connected to - * the remote target and can use gdb - * in the normal fasion. Setting - * breakpoints, single stepping, - * printing variables, etc. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * external low-level support routines - */ - -extern int putDebugChar(char c); /* write a single character */ -extern char getDebugChar(void); /* read and return a single char */ -extern void trap_low(void); - -/* - * breakpoint and test functions - */ -extern void breakpoint(void); -extern void breakinst(void); -extern void async_breakpoint(void); -extern void async_breakinst(void); -extern void adel(void); - -/* - * local prototypes - */ - -static void getpacket(char *buffer); -static void putpacket(char *buffer); -static int computeSignal(int tt); -static int hex(unsigned char ch); -static int hexToInt(char **ptr, int *intValue); -static int hexToLong(char **ptr, long *longValue); -static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault); -void handle_exception(struct gdb_regs *regs); - -int kgdb_enabled; - -/* - * spin locks for smp case - */ -static DEFINE_SPINLOCK(kgdb_lock); -static raw_spinlock_t kgdb_cpulock[NR_CPUS] = { - [0 ... NR_CPUS-1] = __RAW_SPIN_LOCK_UNLOCKED, -}; - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound buffers - * at least NUMREGBYTES*2 are needed for register packets - */ -#define BUFMAX 2048 - -static char input_buffer[BUFMAX]; -static char output_buffer[BUFMAX]; -static int initialized; /* !0 means we've been initialized */ -static int kgdb_started; -static const char hexchars[]="0123456789abcdef"; - -/* Used to prevent crashes in memory access. Note that they'll crash anyway if - we haven't set up fault handlers yet... */ -int kgdb_read_byte(unsigned char *address, unsigned char *dest); -int kgdb_write_byte(unsigned char val, unsigned char *dest); - -/* - * Convert ch from a hex digit to an int - */ -static int hex(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'f') - return ch-'a'+10; - if (ch >= '0' && ch <= '9') - return ch-'0'; - if (ch >= 'A' && ch <= 'F') - return ch-'A'+10; - return -1; -} - -/* - * scan for the sequence $# - */ -static void getpacket(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - unsigned char ch; - - do { - /* - * wait around for the start character, - * ignore all other characters - */ - while ((ch = (getDebugChar() & 0x7f)) != '$') ; - - checksum = 0; - xmitcsum = -1; - count = 0; - - /* - * now, read until a # or end of buffer is found - */ - while (count < BUFMAX) { - ch = getDebugChar(); - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - if (count >= BUFMAX) - continue; - - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex(getDebugChar() & 0x7f) << 4; - xmitcsum |= hex(getDebugChar() & 0x7f); - - if (checksum != xmitcsum) - putDebugChar('-'); /* failed checksum */ - else { - putDebugChar('+'); /* successful transfer */ - - /* - * if a sequence char is present, - * reply the sequence ID - */ - if (buffer[2] == ':') { - putDebugChar(buffer[0]); - putDebugChar(buffer[1]); - - /* - * remove sequence chars from buffer - */ - count = strlen(buffer); - for (i=3; i <= count; i++) - buffer[i-3] = buffer[i]; - } - } - } - } - while (checksum != xmitcsum); -} - -/* - * send the packet in buffer. - */ -static void putpacket(char *buffer) -{ - unsigned char checksum; - int count; - unsigned char ch; - - /* - * $#. - */ - - do { - putDebugChar('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count]) != 0) { - if (!(putDebugChar(ch))) - return; - checksum += ch; - count += 1; - } - - putDebugChar('#'); - putDebugChar(hexchars[checksum >> 4]); - putDebugChar(hexchars[checksum & 0xf]); - - } - while ((getDebugChar() & 0x7f) != '+'); -} - - -/* - * Convert the memory pointed to by mem into hex, placing result in buf. - * Return a pointer to the last char put in buf (null), in case of mem fault, - * return 0. - * may_fault is non-zero if we are reading from arbitrary memory, but is currently - * not used. - */ -static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault) -{ - unsigned char ch; - - while (count-- > 0) { - if (kgdb_read_byte(mem++, &ch) != 0) - return 0; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0xf]; - } - - *buf = 0; - - return buf; -} - -/* - * convert the hex array pointed to by buf into binary to be placed in mem - * return a pointer to the character AFTER the last byte written - * may_fault is non-zero if we are reading from arbitrary memory, but is currently - * not used. - */ -static char *hex2mem(char *buf, char *mem, int count, int binary, int may_fault) -{ - int i; - unsigned char ch; - - for (i=0; itt && ht->signo; ht++) - saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low); - - putDebugChar('+'); /* 'hello world' */ - /* - * In case GDB is started before us, ack any packets - * (presumably "$?#xx") sitting there. - */ - while((c = getDebugChar()) != '$'); - while((c = getDebugChar()) != '#'); - c = getDebugChar(); /* eat first csum byte */ - c = getDebugChar(); /* eat second csum byte */ - putDebugChar('+'); /* ack it */ - - initialized = 1; - local_irq_restore(flags); -} - -void restore_debug_traps(void) -{ - struct hard_trap_info *ht; - unsigned long flags; - - local_irq_save(flags); - for (ht = hard_trap_info; ht->tt && ht->signo; ht++) - set_except_vector(ht->tt, saved_vectors[ht->tt]); - local_irq_restore(flags); -} - -/* - * Convert the MIPS hardware trap type code to a Unix signal number. - */ -static int computeSignal(int tt) -{ - struct hard_trap_info *ht; - - for (ht = hard_trap_info; ht->tt && ht->signo; ht++) - if (ht->tt == tt) - return ht->signo; - - return SIGHUP; /* default for things we don't know about */ -} - -/* - * While we find nice hex chars, build an int. - * Return number of chars processed. - */ -static int hexToInt(char **ptr, int *intValue) -{ - int numChars = 0; - int hexValue; - - *intValue = 0; - - while (**ptr) { - hexValue = hex(**ptr); - if (hexValue < 0) - break; - - *intValue = (*intValue << 4) | hexValue; - numChars ++; - - (*ptr)++; - } - - return (numChars); -} - -static int hexToLong(char **ptr, long *longValue) -{ - int numChars = 0; - int hexValue; - - *longValue = 0; - - while (**ptr) { - hexValue = hex(**ptr); - if (hexValue < 0) - break; - - *longValue = (*longValue << 4) | hexValue; - numChars ++; - - (*ptr)++; - } - - return numChars; -} - - -#if 0 -/* - * Print registers (on target console) - * Used only to debug the stub... - */ -void show_gdbregs(struct gdb_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg0, regs->reg1, regs->reg2, regs->reg3, - regs->reg4, regs->reg5, regs->reg6, regs->reg7); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg8, regs->reg9, regs->reg10, regs->reg11, - regs->reg12, regs->reg13, regs->reg14, regs->reg15); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg16, regs->reg17, regs->reg18, regs->reg19, - regs->reg20, regs->reg21, regs->reg22, regs->reg23); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg24, regs->reg25, regs->reg26, regs->reg27, - regs->reg28, regs->reg29, regs->reg30, regs->reg31); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, regs->cp0_status, regs->cp0_cause); -} -#endif /* dead code */ - -/* - * We single-step by setting breakpoints. When an exception - * is handled, we need to restore the instructions hoisted - * when the breakpoints were set. - * - * This is where we save the original instructions. - */ -static struct gdb_bp_save { - unsigned long addr; - unsigned int val; -} step_bp[2]; - -#define BP 0x0000000d /* break opcode */ - -/* - * Set breakpoint instructions for single stepping. - */ -static void single_step(struct gdb_regs *regs) -{ - union mips_instruction insn; - unsigned long targ; - int is_branch, is_cond, i; - - targ = regs->cp0_epc; - insn.word = *(unsigned int *)targ; - is_branch = is_cond = 0; - - switch (insn.i_format.opcode) { - /* - * jr and jalr are in r_format format. - */ - case spec_op: - switch (insn.r_format.func) { - case jalr_op: - case jr_op: - targ = *(®s->reg0 + insn.r_format.rs); - is_branch = 1; - break; - } - break; - - /* - * This group contains: - * bltz_op, bgez_op, bltzl_op, bgezl_op, - * bltzal_op, bgezal_op, bltzall_op, bgezall_op. - */ - case bcond_op: - is_branch = is_cond = 1; - targ += 4 + (insn.i_format.simmediate << 2); - break; - - /* - * These are unconditional and in j_format. - */ - case jal_op: - case j_op: - is_branch = 1; - targ += 4; - targ >>= 28; - targ <<= 28; - targ |= (insn.j_format.target << 2); - break; - - /* - * These are conditional. - */ - case beq_op: - case beql_op: - case bne_op: - case bnel_op: - case blez_op: - case blezl_op: - case bgtz_op: - case bgtzl_op: - case cop0_op: - case cop1_op: - case cop2_op: - case cop1x_op: - is_branch = is_cond = 1; - targ += 4 + (insn.i_format.simmediate << 2); - break; - } - - if (is_branch) { - i = 0; - if (is_cond && targ != (regs->cp0_epc + 8)) { - step_bp[i].addr = regs->cp0_epc + 8; - step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8); - *(unsigned *)(regs->cp0_epc + 8) = BP; - } - step_bp[i].addr = targ; - step_bp[i].val = *(unsigned *)targ; - *(unsigned *)targ = BP; - } else { - step_bp[0].addr = regs->cp0_epc + 4; - step_bp[0].val = *(unsigned *)(regs->cp0_epc + 4); - *(unsigned *)(regs->cp0_epc + 4) = BP; - } -} - -/* - * If asynchronously interrupted by gdb, then we need to set a breakpoint - * at the interrupted instruction so that we wind up stopped with a - * reasonable stack frame. - */ -static struct gdb_bp_save async_bp; - -/* - * Swap the interrupted EPC with our asynchronous breakpoint routine. - * This is safer than stuffing the breakpoint in-place, since no cache - * flushes (or resulting smp_call_functions) are required. The - * assumption is that only one CPU will be handling asynchronous bp's, - * and only one can be active at a time. - */ -extern spinlock_t smp_call_lock; - -void set_async_breakpoint(unsigned long *epc) -{ - /* skip breaking into userland */ - if ((*epc & 0x80000000) == 0) - return; - -#ifdef CONFIG_SMP - /* avoid deadlock if someone is make IPC */ - if (spin_is_locked(&smp_call_lock)) - return; -#endif - - async_bp.addr = *epc; - *epc = (unsigned long)async_breakpoint; -} - -static void kgdb_wait(void *arg) -{ - unsigned flags; - int cpu = smp_processor_id(); - - local_irq_save(flags); - - __raw_spin_lock(&kgdb_cpulock[cpu]); - __raw_spin_unlock(&kgdb_cpulock[cpu]); - - local_irq_restore(flags); -} - -/* - * GDB stub needs to call kgdb_wait on all processor with interrupts - * disabled, so it uses it's own special variant. - */ -static int kgdb_smp_call_kgdb_wait(void) -{ -#ifdef CONFIG_SMP - struct call_data_struct data; - int i, cpus = num_online_cpus() - 1; - int cpu = smp_processor_id(); - - /* - * Can die spectacularly if this CPU isn't yet marked online - */ - BUG_ON(!cpu_online(cpu)); - - if (!cpus) - return 0; - - if (spin_is_locked(&smp_call_lock)) { - /* - * Some other processor is trying to make us do something - * but we're not going to respond... give up - */ - return -1; - } - - /* - * We will continue here, accepting the fact that - * the kernel may deadlock if another CPU attempts - * to call smp_call_function now... - */ - - data.func = kgdb_wait; - data.info = NULL; - atomic_set(&data.started, 0); - data.wait = 0; - - spin_lock(&smp_call_lock); - call_data = &data; - mb(); - - /* Send a message to all other CPUs and wait for them to respond */ - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i) && i != cpu) - core_send_ipi(i, SMP_CALL_FUNCTION); - - /* Wait for response */ - /* FIXME: lock-up detection, backtrace on lock-up */ - while (atomic_read(&data.started) != cpus) - barrier(); - - call_data = NULL; - spin_unlock(&smp_call_lock); -#endif - - return 0; -} - -/* - * This function does all command processing for interfacing to gdb. It - * returns 1 if you should skip the instruction at the trap address, 0 - * otherwise. - */ -void handle_exception (struct gdb_regs *regs) -{ - int trap; /* Trap type */ - int sigval; - long addr; - int length; - char *ptr; - unsigned long *stack; - int i; - int bflag = 0; - - kgdb_started = 1; - - /* - * acquire the big kgdb spinlock - */ - if (!spin_trylock(&kgdb_lock)) { - /* - * some other CPU has the lock, we should go back to - * receive the gdb_wait IPC - */ - return; - } - - /* - * If we're in async_breakpoint(), restore the real EPC from - * the breakpoint. - */ - if (regs->cp0_epc == (unsigned long)async_breakinst) { - regs->cp0_epc = async_bp.addr; - async_bp.addr = 0; - } - - /* - * acquire the CPU spinlocks - */ - for (i = num_online_cpus()-1; i >= 0; i--) - if (__raw_spin_trylock(&kgdb_cpulock[i]) == 0) - panic("kgdb: couldn't get cpulock %d\n", i); - - /* - * force other cpus to enter kgdb - */ - kgdb_smp_call_kgdb_wait(); - - /* - * If we're in breakpoint() increment the PC - */ - trap = (regs->cp0_cause & 0x7c) >> 2; - if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst) - regs->cp0_epc += 4; - - /* - * If we were single_stepping, restore the opcodes hoisted - * for the breakpoint[s]. - */ - if (step_bp[0].addr) { - *(unsigned *)step_bp[0].addr = step_bp[0].val; - step_bp[0].addr = 0; - - if (step_bp[1].addr) { - *(unsigned *)step_bp[1].addr = step_bp[1].val; - step_bp[1].addr = 0; - } - } - - stack = (long *)regs->reg29; /* stack ptr */ - sigval = computeSignal(trap); - - /* - * reply to host that an exception has occurred - */ - ptr = output_buffer; - - /* - * Send trap type (converted to signal) - */ - *ptr++ = 'T'; - *ptr++ = hexchars[sigval >> 4]; - *ptr++ = hexchars[sigval & 0xf]; - - /* - * Send Error PC - */ - *ptr++ = hexchars[REG_EPC >> 4]; - *ptr++ = hexchars[REG_EPC & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->cp0_epc, ptr, sizeof(long), 0); - *ptr++ = ';'; - - /* - * Send frame pointer - */ - *ptr++ = hexchars[REG_FP >> 4]; - *ptr++ = hexchars[REG_FP & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->reg30, ptr, sizeof(long), 0); - *ptr++ = ';'; - - /* - * Send stack pointer - */ - *ptr++ = hexchars[REG_SP >> 4]; - *ptr++ = hexchars[REG_SP & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->reg29, ptr, sizeof(long), 0); - *ptr++ = ';'; - - *ptr++ = 0; - putpacket(output_buffer); /* send it off... */ - - /* - * Wait for input from remote GDB - */ - while (1) { - output_buffer[0] = 0; - getpacket(input_buffer); - - switch (input_buffer[0]) - { - case '?': - output_buffer[0] = 'S'; - output_buffer[1] = hexchars[sigval >> 4]; - output_buffer[2] = hexchars[sigval & 0xf]; - output_buffer[3] = 0; - break; - - /* - * Detach debugger; let CPU run - */ - case 'D': - putpacket(output_buffer); - goto finish_kgdb; - break; - - case 'd': - /* toggle debug flag */ - break; - - /* - * Return the value of the CPU registers - */ - case 'g': - ptr = output_buffer; - ptr = mem2hex((char *)®s->reg0, ptr, 32*sizeof(long), 0); /* r0...r31 */ - ptr = mem2hex((char *)®s->cp0_status, ptr, 6*sizeof(long), 0); /* cp0 */ - ptr = mem2hex((char *)®s->fpr0, ptr, 32*sizeof(long), 0); /* f0...31 */ - ptr = mem2hex((char *)®s->cp1_fsr, ptr, 2*sizeof(long), 0); /* cp1 */ - ptr = mem2hex((char *)®s->frame_ptr, ptr, 2*sizeof(long), 0); /* frp */ - ptr = mem2hex((char *)®s->cp0_index, ptr, 16*sizeof(long), 0); /* cp0 */ - break; - - /* - * set the value of the CPU registers - return OK - */ - case 'G': - { - ptr = &input_buffer[1]; - hex2mem(ptr, (char *)®s->reg0, 32*sizeof(long), 0, 0); - ptr += 32*(2*sizeof(long)); - hex2mem(ptr, (char *)®s->cp0_status, 6*sizeof(long), 0, 0); - ptr += 6*(2*sizeof(long)); - hex2mem(ptr, (char *)®s->fpr0, 32*sizeof(long), 0, 0); - ptr += 32*(2*sizeof(long)); - hex2mem(ptr, (char *)®s->cp1_fsr, 2*sizeof(long), 0, 0); - ptr += 2*(2*sizeof(long)); - hex2mem(ptr, (char *)®s->frame_ptr, 2*sizeof(long), 0, 0); - ptr += 2*(2*sizeof(long)); - hex2mem(ptr, (char *)®s->cp0_index, 16*sizeof(long), 0, 0); - strcpy(output_buffer,"OK"); - } - break; - - /* - * mAA..AA,LLLL Read LLLL bytes at address AA..AA - */ - case 'm': - ptr = &input_buffer[1]; - - if (hexToLong(&ptr, &addr) - && *ptr++ == ',' - && hexToInt(&ptr, &length)) { - if (mem2hex((char *)addr, output_buffer, length, 1)) - break; - strcpy (output_buffer, "E03"); - } else - strcpy(output_buffer,"E01"); - break; - - /* - * XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA - */ - case 'X': - bflag = 1; - /* fall through */ - - /* - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK - */ - case 'M': - ptr = &input_buffer[1]; - - if (hexToLong(&ptr, &addr) - && *ptr++ == ',' - && hexToInt(&ptr, &length) - && *ptr++ == ':') { - if (hex2mem(ptr, (char *)addr, length, bflag, 1)) - strcpy(output_buffer, "OK"); - else - strcpy(output_buffer, "E03"); - } - else - strcpy(output_buffer, "E02"); - break; - - /* - * cAA..AA Continue at address AA..AA(optional) - */ - case 'c': - /* try to read optional parameter, pc unchanged if no parm */ - - ptr = &input_buffer[1]; - if (hexToLong(&ptr, &addr)) - regs->cp0_epc = addr; - - goto exit_kgdb_exception; - break; - - /* - * kill the program; let us try to restart the machine - * Reset the whole machine. - */ - case 'k': - case 'r': - machine_restart("kgdb restarts machine"); - break; - - /* - * Step to next instruction - */ - case 's': - /* - * There is no single step insn in the MIPS ISA, so we - * use breakpoints and continue, instead. - */ - single_step(regs); - goto exit_kgdb_exception; - /* NOTREACHED */ - break; - - /* - * Set baud rate (bBB) - * FIXME: Needs to be written - */ - case 'b': - { -#if 0 - int baudrate; - extern void set_timer_3(); - - ptr = &input_buffer[1]; - if (!hexToInt(&ptr, &baudrate)) - { - strcpy(output_buffer,"B01"); - break; - } - - /* Convert baud rate to uart clock divider */ - - switch (baudrate) - { - case 38400: - baudrate = 16; - break; - case 19200: - baudrate = 33; - break; - case 9600: - baudrate = 65; - break; - default: - baudrate = 0; - strcpy(output_buffer,"B02"); - goto x1; - } - - if (baudrate) { - putpacket("OK"); /* Ack before changing speed */ - set_timer_3(baudrate); /* Set it */ - } -#endif - } - break; - - } /* switch */ - - /* - * reply to the request - */ - - putpacket(output_buffer); - - } /* while */ - - return; - -finish_kgdb: - restore_debug_traps(); - -exit_kgdb_exception: - /* release locks so other CPUs can go */ - for (i = num_online_cpus()-1; i >= 0; i--) - __raw_spin_unlock(&kgdb_cpulock[i]); - spin_unlock(&kgdb_lock); - - __flush_cache_all(); - return; -} - -/* - * This function will generate a breakpoint exception. It is used at the - * beginning of a program to sync up with a debugger and can be used - * otherwise as a quick means to stop program execution and "break" into - * the debugger. - */ -void breakpoint(void) -{ - if (!initialized) - return; - - __asm__ __volatile__( - ".globl breakinst\n\t" - ".set\tnoreorder\n\t" - "nop\n" - "breakinst:\tbreak\n\t" - "nop\n\t" - ".set\treorder" - ); -} - -/* Nothing but the break; don't pollute any registers */ -void async_breakpoint(void) -{ - __asm__ __volatile__( - ".globl async_breakinst\n\t" - ".set\tnoreorder\n\t" - "nop\n" - "async_breakinst:\tbreak\n\t" - "nop\n\t" - ".set\treorder" - ); -} - -void adel(void) -{ - __asm__ __volatile__( - ".globl\tadel\n\t" - "lui\t$8,0x8000\n\t" - "lw\t$9,1($8)\n\t" - ); -} - -/* - * malloc is needed by gdb client in "call func()", even a private one - * will make gdb happy - */ -static void * __attribute_used__ malloc(size_t size) -{ - return kmalloc(size, GFP_ATOMIC); -} - -static void __attribute_used__ free (void *where) -{ - kfree(where); -} - -#ifdef CONFIG_GDB_CONSOLE - -void gdb_putsn(const char *str, int l) -{ - char outbuf[18]; - - if (!kgdb_started) - return; - - outbuf[0]='O'; - - while(l) { - int i = (l>8)?8:l; - mem2hex((char *)str, &outbuf[1], i, 0); - outbuf[(i*2)+1]=0; - putpacket(outbuf); - str += i; - l -= i; - } -} - -static void gdb_console_write(struct console *con, const char *s, unsigned n) -{ - gdb_putsn(s, n); -} - -static struct console gdb_console = { - .name = "gdb", - .write = gdb_console_write, - .flags = CON_PRINTBUFFER, - .index = -1 -}; - -static int __init register_gdb_console(void) -{ - register_console(&gdb_console); - - return 0; -} - -console_initcall(register_gdb_console); - -#endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/irq.c linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/irq.c --- linux-2.6.18-53.1.14/arch/mips/kernel/irq.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/irq.c 2008-06-10 15:38:24.000000000 +0400 @@ -25,6 +25,10 @@ #include #include #include +#include + +/* Keep track of if we've done certain initialization already or not. */ +int kgdb_early_setup; /* * 'what should we do if we get a hw irq event on an illegal vector'. @@ -115,23 +119,13 @@ asmlinkage void spurious_interrupt(struc atomic_inc(&irq_err_count); } -#ifdef CONFIG_KGDB -extern void breakpoint(void); -extern void set_debug_traps(void); - -static int kgdb_flag = 1; -static int __init nokgdb(char *str) -{ - kgdb_flag = 0; - return 1; -} -__setup("nokgdb", nokgdb); -#endif - void __init init_IRQ(void) { int i; + if (kgdb_early_setup) + return; + for (i = 0; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; @@ -144,12 +138,12 @@ void __init init_IRQ(void) } arch_init_irq(); - #ifdef CONFIG_KGDB - if (kgdb_flag) { - printk("Wait for gdb client connection ...\n"); - set_debug_traps(); - breakpoint(); - } + /* + * We have been called before kgdb_arch_init(). Hence, + * we dont want the traps to be reinitialized + */ + if (kgdb_early_setup == 0) + kgdb_early_setup = 1; #endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/kgdb-jmp.c linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb-jmp.c --- linux-2.6.18-53.1.14/arch/mips/kernel/kgdb-jmp.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb-jmp.c 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,116 @@ +/* + * arch/mips/kernel/kgdb-jmp.c + * + * Save and restore system registers so that within a limited frame we + * may have a fault and "jump back" to a known safe location. + * + * Author: Tom Rini + * Author: Manish Lachwani + * + * Cribbed from glibc, which carries the following: + * Copyright (C) 1996, 1997, 2000, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2005 by MontaVista Software. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of + * any kind, whether express or implied. + */ + +#include +#include + +#ifdef CONFIG_MIPS64 +/* + * MIPS 64-bit + */ + +int kgdb_fault_setjmp_aux(unsigned long *curr_context, int sp, int fp) +{ + __asm__ __volatile__ ("sd $gp, %0" : : "m" (curr_context[0])); + __asm__ __volatile__ ("sd $16, %0" : : "m" (curr_context[1])); + __asm__ __volatile__ ("sd $17, %0" : : "m" (curr_context[2])); + __asm__ __volatile__ ("sd $18, %0" : : "m" (curr_context[3])); + __asm__ __volatile__ ("sd $19, %0" : : "m" (curr_context[4])); + __asm__ __volatile__ ("sd $20, %0" : : "m" (curr_context[5])); + __asm__ __volatile__ ("sd $21, %0" : : "m" (curr_context[6])); + __asm__ __volatile__ ("sd $22, %0" : : "m" (curr_context[7])); + __asm__ __volatile__ ("sd $23, %0" : : "m" (curr_context[8])); + __asm__ __volatile__ ("sd $31, %0" : : "m" (curr_context[9])); + curr_context[10] = (long *)sp; + curr_context[11] = (long *)fp; + + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ + unsigned long sp_val, fp_val; + + __asm__ __volatile__ ("ld $gp, %0" : : "m" (curr_context[0])); + __asm__ __volatile__ ("ld $16, %0" : : "m" (curr_context[1])); + __asm__ __volatile__ ("ld $17, %0" : : "m" (curr_context[2])); + __asm__ __volatile__ ("ld $18, %0" : : "m" (curr_context[3])); + __asm__ __volatile__ ("ld $19, %0" : : "m" (curr_context[4])); + __asm__ __volatile__ ("ld $20, %0" : : "m" (curr_context[5])); + __asm__ __volatile__ ("ld $21, %0" : : "m" (curr_context[6])); + __asm__ __volatile__ ("ld $22, %0" : : "m" (curr_context[7])); + __asm__ __volatile__ ("ld $23, %0" : : "m" (curr_context[8])); + __asm__ __volatile__ ("ld $25, %0" : : "m" (curr_context[9])); + sp_val = curr_context[10]; + fp_val = curr_context[11]; + __asm__ __volatile__ ("ld $29, %0\n\t" + "ld $30, %1\n\t" : : "m" (sp_val), "m" (fp_val)); + + __asm__ __volatile__ ("dli $2, 1"); + __asm__ __volatile__ ("j $25"); + + for (;;); +} +#else +/* + * MIPS 32-bit + */ + +int kgdb_fault_setjmp_aux(unsigned long *curr_context, int sp, int fp) +{ + __asm__ __volatile__("sw $gp, %0" : : "m" (curr_context[0])); + __asm__ __volatile__("sw $16, %0" : : "m" (curr_context[1])); + __asm__ __volatile__("sw $17, %0" : : "m" (curr_context[2])); + __asm__ __volatile__("sw $18, %0" : : "m" (curr_context[3])); + __asm__ __volatile__("sw $19, %0" : : "m" (curr_context[4])); + __asm__ __volatile__("sw $20, %0" : : "m" (curr_context[5])); + __asm__ __volatile__("sw $21, %0" : : "m" (curr_context[6])); + __asm__ __volatile__("sw $22, %0" : : "m" (curr_context[7])); + __asm__ __volatile__("sw $23, %0" : : "m" (curr_context[8])); + __asm__ __volatile__("sw $31, %0" : : "m" (curr_context[9])); + curr_context[10] = (long *)sp; + curr_context[11] = (long *)fp; + + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ + unsigned long sp_val, fp_val; + + __asm__ __volatile__("lw $gp, %0" : : "m" (curr_context[0])); + __asm__ __volatile__("lw $16, %0" : : "m" (curr_context[1])); + __asm__ __volatile__("lw $17, %0" : : "m" (curr_context[2])); + __asm__ __volatile__("lw $18, %0" : : "m" (curr_context[3])); + __asm__ __volatile__("lw $19, %0" : : "m" (curr_context[4])); + __asm__ __volatile__("lw $20, %0" : : "m" (curr_context[5])); + __asm__ __volatile__("lw $21, %0" : : "m" (curr_context[6])); + __asm__ __volatile__("lw $22, %0" : : "m" (curr_context[7])); + __asm__ __volatile__("lw $23, %0" : : "m" (curr_context[8])); + __asm__ __volatile__("lw $25, %0" : : "m" (curr_context[9])); + sp_val = curr_context[10]; + fp_val = curr_context[11]; + __asm__ __volatile__("lw $29, %0\n\t" + "lw $30, %1\n\t" : : "m" (sp_val), "m" (fp_val)); + + __asm__ __volatile__("li $2, 1"); + __asm__ __volatile__("jr $25"); + + for (;;); +} +#endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/kgdb-setjmp.S linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb-setjmp.S --- linux-2.6.18-53.1.14/arch/mips/kernel/kgdb-setjmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb-setjmp.S 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,28 @@ +/* + * arch/mips/kernel/kgdb-jmp.c + * + * Save and restore system registers so that within a limited frame we + * may have a fault and "jump back" to a known safe location. + * + * Copyright (C) 2005 by MontaVista Software. + * Author: Manish Lachwani (mlachwani@mvista.com) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of + * any kind, whether express or implied. + */ + +#include +#include +#include +#include + + .ent kgdb_fault_setjmp,0 +ENTRY (kgdb_fault_setjmp) + move a1, sp + move a2, fp +#ifdef CONFIG_MIPS64 + nop +#endif + j kgdb_fault_setjmp_aux + .end kgdb_fault_setjmp diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/mips/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb.c 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,297 @@ +/* + * arch/mips/kernel/kgdb.c + * + * Originally written by Glenn Engel, Lake Stevens Instrument Division + * + * Contributed by HP Systems + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse + * Send complaints, suggestions etc. to + * + * Copyright (C) 1995 Andreas Busse + * + * Copyright (C) 2003 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * Copyright (C) 2004-2005 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include + +static struct hard_trap_info { + unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + { 6, SIGBUS }, /* instruction bus error */ + { 7, SIGBUS }, /* data bus error */ + { 9, SIGTRAP }, /* break */ +/* { 11, SIGILL }, */ /* CPU unusable */ + { 12, SIGFPE }, /* overflow */ + { 13, SIGTRAP }, /* trap */ + { 14, SIGSEGV }, /* virtual instruction cache coherency */ + { 15, SIGFPE }, /* floating point exception */ + { 23, SIGSEGV }, /* watch */ + { 31, SIGSEGV }, /* virtual data cache coherency */ + { 0, 0} /* Must be last */ +}; + +/* Save the normal trap handlers for user-mode traps. */ +void *saved_vectors[32]; + +extern void trap_low(void); +extern void breakinst(void); +extern void init_IRQ(void); + +void kgdb_call_nmi_hook(void *ignored) +{ + kgdb_nmihook(smp_processor_id(), (void *)0); +} + +void kgdb_roundup_cpus(unsigned long flags) +{ + local_irq_restore(flags); + smp_call_function(kgdb_call_nmi_hook, 0, 0, 0); + local_irq_save(flags); +} + +static int compute_signal(int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* + * Set up exception handlers for tracing and breakpoints + */ +void handle_exception(struct pt_regs *regs) +{ + int trap = (regs->cp0_cause & 0x7c) >> 2; + + if (fixup_exception(regs)) { + return; + } + + if (atomic_read(&debugger_active)) + kgdb_nmihook(smp_processor_id(), regs); + + if (atomic_read(&kgdb_setting_breakpoint)) + if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst)) + regs->cp0_epc += 4; + + kgdb_handle_exception(0, compute_signal(trap), 0, regs); + + /* In SMP mode, __flush_cache_all does IPI */ + __flush_cache_all(); +} + +void set_debug_traps(void) +{ + struct hard_trap_info *ht; + unsigned long flags; + + local_irq_save(flags); + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low); + + local_irq_restore(flags); +} + +#if 0 +/* This should be called before we exit kgdb_handle_exception() I believe. + * -- Tom + */ +void restore_debug_traps(void) +{ + struct hard_trap_info *ht; + unsigned long flags; + + local_irq_save(flags); + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + set_except_vector(ht->tt, saved_vectors[ht->tt]); + local_irq_restore(flags); +} +#endif + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + gdb_reg_t *ptr = (gdb_reg_t*)gdb_regs; + + for (reg = 0; reg < 32; reg++) + *(ptr++) = regs->regs[reg]; + + *(ptr++) = regs->cp0_status; + *(ptr++) = regs->lo; + *(ptr++) = regs->hi; + *(ptr++) = regs->cp0_badvaddr; + *(ptr++) = regs->cp0_cause; + *(ptr++) = regs->cp0_epc; + + return; +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + + int reg; + const gdb_reg_t *ptr = (gdb_reg_t*)gdb_regs; + + for (reg = 0; reg < 32; reg++) + regs->regs[reg] = *(ptr++); + + regs->cp0_status = *(ptr++); + regs->lo = *(ptr++); + regs->hi = *(ptr++); + regs->cp0_badvaddr = *(ptr++); + regs->cp0_cause = *(ptr++); + regs->cp0_epc = *(ptr++); + + return; +} + +/* + * Similar to regs_to_gdb_regs() except that process is sleeping and so + * we may not be able to get all the info. + */ +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + int reg; + struct thread_info *ti = p->thread_info; + unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; + struct pt_regs *regs = (struct pt_regs *)ksp - 1; + gdb_reg_t *ptr = (gdb_reg_t*)gdb_regs; + + for (reg = 0; reg < 16; reg++) + *(ptr++) = regs->regs[reg]; + + /* S0 - S7 */ + for (reg = 16; reg < 24; reg++) + *(ptr++) = regs->regs[reg]; + + for (reg = 24; reg < 28; reg++) + *(ptr++) = 0; + + /* GP, SP, FP, RA */ + for (reg = 28; reg < 32; reg++) + *(ptr++) = regs->regs[reg]; + + *(ptr++) = regs->cp0_status; + *(ptr++) = regs->lo; + *(ptr++) = regs->hi; + *(ptr++) = regs->cp0_badvaddr; + *(ptr++) = regs->cp0_cause; + *(ptr++) = regs->cp0_epc; + + return; +} + +/* + * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, + * then try to fall into the debugger + */ +static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, + void *ptr) +{ + struct die_args *args = (struct die_args *)ptr; + struct pt_regs *regs = args->regs; + int trap = (regs->cp0_cause & 0x7c) >> 2; + + /* See if KGDB is interested. */ + if (user_mode(regs)) + /* Userpace events, ignore. */ + return NOTIFY_DONE; + + kgdb_handle_exception(trap, compute_signal(trap), 0, regs); + return NOTIFY_OK; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_mips_notify, +}; + +/* + * Handle the 's' and 'c' commands + */ +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *regs) +{ + char *ptr; + unsigned long address; + int cpu = smp_processor_id(); + + switch (remcom_in_buffer[0]) { + case 's': + case 'c': + /* handle the optional parameter */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &address)) + regs->cp0_epc = address; + + atomic_set(&cpu_doing_single_step, -1); + if (remcom_in_buffer[0] == 's') + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, cpu); + + return 0; + } + + return -1; +} + +struct kgdb_arch arch_kgdb_ops = { +#ifdef CONFIG_CPU_LITTLE_ENDIAN + .gdb_bpt_instr = {0xd}, +#else + .gdb_bpt_instr = {0x00, 0x00, 0x00, 0x0d}, +#endif +}; + +/* + * We use kgdb_early_setup so that functions we need to call now don't + * cause trouble when called again later. + */ +int kgdb_arch_init(void) +{ + /* Board-specifics. */ + /* Force some calls to happen earlier. */ + if (kgdb_early_setup == 0) { + trap_init(); + init_IRQ(); + kgdb_early_setup = 1; + } + + /* Set our traps. */ + /* This needs to be done more finely grained again, paired in + * a before/after in kgdb_handle_exception(...) -- Tom */ + set_debug_traps(); + notifier_chain_register(&mips_die_chain, &kgdb_notifier); + + return 0; +} diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/kgdb_handler.S linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb_handler.S --- linux-2.6.18-53.1.14/arch/mips/kernel/kgdb_handler.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/kgdb_handler.S 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,57 @@ +/* + * arch/mips/kernel/kgdb_handler.S + * + * Copyright (C) 2004-2005 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com + * + * This file is licensed under the terms of the GNU General Public + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/* + * Trap Handler for the new KGDB framework. The main KGDB handler is + * handle_exception that will be called from here + * + */ + +#include +#include + +#include +#include +#include +#include +#include + + .align 5 + NESTED(trap_low, PT_SIZE, sp) + .set noat + .set noreorder + + /* + * Check for privileged instructions in user mode. For + * this, check the cu0 bit in the CPU status register. + */ + mfc0 k0, CP0_STATUS + sll k0, 3 + bltz k0, 1f + move k1, sp + + /* + * GDB userland from within KGDB. If a user mode address + * then jump to the saved exception handler + */ + mfc0 k1, CP0_CAUSE + andi k1, k1, 0x7c + PTR_L k0, saved_vectors(k1) + jr k0 + nop +1: + SAVE_ALL + .set at + .set reorder + move a0, sp + jal handle_exception + j ret_from_exception + END(trap_low) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/kernel/traps.c linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/traps.c --- linux-2.6.18-53.1.14/arch/mips/kernel/traps.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/kernel/traps.c 2008-06-10 15:38:24.000000000 +0400 @@ -10,6 +10,8 @@ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000, 01 MIPS Technologies, Inc. * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki + * + * KGDB specific changes - Manish Lachwani (mlachwani@mvista.com) */ #include #include @@ -20,6 +22,7 @@ #include #include #include +#include #include #include @@ -40,6 +43,7 @@ #include #include #include +#include extern asmlinkage void handle_int(void); extern asmlinkage void handle_tlbm(void); @@ -78,6 +82,21 @@ void (*board_bind_eic_interrupt)(int irq */ #define MODULE_RANGE (8*1024*1024) +struct notifier_block *mips_die_chain; +static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED; + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&mips_die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + + return err; +} + /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... @@ -1387,6 +1406,11 @@ void __init trap_init(void) extern char except_vec4; unsigned long i; +#if defined(CONFIG_KGDB) + if (kgdb_early_setup) + return; /* Already done */ +#endif + if (cpu_has_veic || cpu_has_vint) ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64); else diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/mips-boards/generic/Makefile linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/generic/Makefile --- linux-2.6.18-53.1.14/arch/mips/mips-boards/generic/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/generic/Makefile 2008-06-10 15:38:24.000000000 +0400 @@ -21,6 +21,5 @@ obj-y := reset.o display.o init.o memory.o printf.o \ cmdline.o time.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_KGDB) += gdb_hook.o EXTRA_AFLAGS := $(CFLAGS) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/mips-boards/generic/init.c linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/generic/init.c --- linux-2.6.18-53.1.14/arch/mips/mips-boards/generic/init.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/generic/init.c 2008-06-10 15:38:24.000000000 +0400 @@ -37,15 +37,6 @@ #include -#ifdef CONFIG_KGDB -extern int rs_kgdb_hook(int, int); -extern int rs_putDebugChar(char); -extern char rs_getDebugChar(void); -extern int saa9730_kgdb_hook(int); -extern int saa9730_putDebugChar(char); -extern char saa9730_getDebugChar(void); -#endif - int prom_argc; int *_prom_argv, *_prom_envp; @@ -172,58 +163,6 @@ static void __init console_config(void) } #endif -#ifdef CONFIG_KGDB -void __init kgdb_config (void) -{ - extern int (*generic_putDebugChar)(char); - extern char (*generic_getDebugChar)(void); - char *argptr; - int line, speed; - - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { - argptr += strlen("kgdb=ttyS"); - if (*argptr != '0' && *argptr != '1') - printk("KGDB: Unknown serial line /dev/ttyS%c, " - "falling back to /dev/ttyS1\n", *argptr); - line = *argptr == '0' ? 0 : 1; - printk("KGDB: Using serial line /dev/ttyS%d for session\n", line); - - speed = 0; - if (*++argptr == ',') - { - int c; - while ((c = *++argptr) && ('0' <= c && c <= '9')) - speed = speed * 10 + c - '0'; - } -#ifdef CONFIG_MIPS_ATLAS - if (line == 1) { - speed = saa9730_kgdb_hook(speed); - generic_putDebugChar = saa9730_putDebugChar; - generic_getDebugChar = saa9730_getDebugChar; - } - else -#endif - { - speed = rs_kgdb_hook(line, speed); - generic_putDebugChar = rs_putDebugChar; - generic_getDebugChar = rs_getDebugChar; - } - - prom_printf("KGDB: Using serial line /dev/ttyS%d at %d for session, " - "please connect your debugger\n", line ? 1 : 0, speed); - - { - char *s; - for (s = "Please connect GDB to this port\r\n"; *s; ) - generic_putDebugChar (*s++); - } - - /* Breakpoint is invoked after interrupts are initialised */ - } -} -#endif - void __init mips_nmi_setup (void) { void *base; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/mips-boards/malta/malta_setup.c linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/malta/malta_setup.c --- linux-2.6.18-53.1.14/arch/mips/mips-boards/malta/malta_setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/mips-boards/malta/malta_setup.c 2008-06-10 15:38:24.000000000 +0400 @@ -46,10 +46,6 @@ extern void mips_reboot_setup(void); extern void mips_time_init(void); extern unsigned long mips_rtc_get_time(void); -#ifdef CONFIG_KGDB -extern void kgdb_config(void); -#endif - struct resource standard_io_resources[] = { { .name = "dma1", .start = 0x00, .end = 0x1f, .flags = IORESOURCE_BUSY }, { .name = "timer", .start = 0x40, .end = 0x5f, .flags = IORESOURCE_BUSY }, @@ -124,10 +120,6 @@ void __init plat_mem_setup(void) */ enable_dma(4); -#ifdef CONFIG_KGDB - kgdb_config (); -#endif - if ((mips_revision_corid == MIPS_REVISION_CORID_BONITO64) || (mips_revision_corid == MIPS_REVISION_CORID_CORE_20K) || (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL_BON)) { diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/mm/extable.c linux-2.6.18-53.1.14.kgdb/arch/mips/mm/extable.c --- linux-2.6.18-53.1.14/arch/mips/mm/extable.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/mm/extable.c 2008-06-10 15:38:24.000000000 +0400 @@ -3,6 +3,7 @@ */ #include #include +#include #include #include @@ -16,6 +17,12 @@ int fixup_exception(struct pt_regs *regs return 1; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ +#endif return 0; } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/cfe/setup.c linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/cfe/setup.c --- linux-2.6.18-53.1.14/arch/mips/sibyte/cfe/setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/cfe/setup.c 2008-06-10 15:38:24.000000000 +0400 @@ -58,10 +58,6 @@ int cfe_cons_handle; extern unsigned long initrd_start, initrd_end; #endif -#ifdef CONFIG_KGDB -extern int kgdb_port; -#endif - static void ATTRIB_NORET cfe_linux_exit(void *arg) { int warm = *(int *)arg; @@ -242,9 +238,6 @@ void __init prom_init(void) int argc = fw_arg0; char **envp = (char **) fw_arg2; int *prom_vec = (int *) fw_arg3; -#ifdef CONFIG_KGDB - char *arg; -#endif _machine_restart = cfe_linux_restart; _machine_halt = cfe_linux_halt; @@ -308,13 +301,6 @@ void __init prom_init(void) } } -#ifdef CONFIG_KGDB - if ((arg = strstr(arcs_cmdline,"kgdb=duart")) != NULL) - kgdb_port = (arg[10] == '0') ? 0 : 1; - else - kgdb_port = 1; -#endif - #ifdef CONFIG_BLK_DEV_INITRD { char *ptr; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/Makefile linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/Makefile --- linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/Makefile 2008-06-10 15:38:24.000000000 +0400 @@ -4,5 +4,6 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o obj-$(CONFIG_SIBYTE_STANDALONE) += prom.o obj-$(CONFIG_SIBYTE_BUS_WATCHER) += bus_watcher.o +obj-$(CONFIG_KGDB_SIBYTE) += kgdb_sibyte.o EXTRA_AFLAGS := $(CFLAGS) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/irq.c linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/irq.c --- linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/irq.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/irq.c 2008-06-10 15:38:24.000000000 +0400 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -59,16 +60,6 @@ static void sb1250_set_affinity(unsigned extern unsigned long ldt_eoi_space; #endif -#ifdef CONFIG_KGDB -static int kgdb_irq; - -/* Default to UART1 */ -int kgdb_port = 1; -#ifdef CONFIG_SIBYTE_SB1250_DUART -extern char sb1250_duart_present[]; -#endif -#endif - static struct irq_chip sb1250_irq_type = { .typename = "SB1250-IMR", .startup = startup_sb1250_irq, @@ -324,6 +315,11 @@ void __init arch_init_irq(void) unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | STATUSF_IP1 | STATUSF_IP0; +#ifdef CONFIG_KGDB + if (kgdb_early_setup) + return; +#endif + /* Default everything to IP2 */ for (i = 0; i < SB1250_NR_IRQS; i++) { /* was I0 */ __raw_writeq(IMR_IP2_VAL, @@ -375,50 +371,6 @@ void __init arch_init_irq(void) /* Enable necessary IPs, disable the rest */ change_c0_status(ST0_IM, imask); -#ifdef CONFIG_KGDB - if (kgdb_flag) { - kgdb_irq = K_INT_UART_0 + kgdb_port; - -#ifdef CONFIG_SIBYTE_SB1250_DUART - sb1250_duart_present[kgdb_port] = 0; -#endif - /* Setup uart 1 settings, mapper */ - __raw_writeq(M_DUART_IMR_BRK, - IOADDR(A_DUART_IMRREG(kgdb_port))); - - sb1250_steal_irq(kgdb_irq); - __raw_writeq(IMR_IP6_VAL, - IOADDR(A_IMR_REGISTER(0, - R_IMR_INTERRUPT_MAP_BASE) + - (kgdb_irq << 3))); - sb1250_unmask_irq(0, kgdb_irq); - } -#endif -} - -#ifdef CONFIG_KGDB - -#include - -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) - -static void sb1250_kgdb_interrupt(struct pt_regs *regs) -{ - /* - * Clear break-change status (allow some time for the remote - * host to stop the break, since we would see another - * interrupt on the end-of-break too) - */ - kstat_this_cpu.irqs[kgdb_irq]++; - mdelay(500); - duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | - M_DUART_RX_EN | M_DUART_TX_EN); - set_async_breakpoint(®s->cp0_epc); -} - -#endif /* CONFIG_KGDB */ - static inline int dclz(unsigned long long x) { int lz; @@ -473,7 +425,7 @@ asmlinkage void plat_irq_dispatch(struct sb1250_mailbox_interrupt(regs); #endif -#ifdef CONFIG_KGDB +#ifdef CONFIG_KGDB_SIBYTE else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ sb1250_kgdb_interrupt(regs); #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/kgdb_sibyte.c linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/kgdb_sibyte.c --- linux-2.6.18-53.1.14/arch/mips/sibyte/sb1250/kgdb_sibyte.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/sb1250/kgdb_sibyte.c 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,164 @@ +/* + * arch/mips/sibyte/sb1250/kgdb_sibyte.c + * + * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com + * + * 2004 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +/* + * Support for KGDB on the Broadcom Sibyte. The SWARM board + * for example does not have a 8250/16550 compatible serial + * port. Hence, we need to have a driver for the serial + * ports to handle KGDB. This board needs nothing in addition + * to what is normally provided by the gdb portion of the stub. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int kgdb_port = 1; +static int kgdb_irq; + +extern char sb1250_duart_present[]; +extern int sb1250_steal_irq(int irq); + +/* Forward declarations. */ +static void kgdbsibyte_init_duart(void); +static int kgdb_init_io(void); + +#define IMR_IP6_VAL K_INT_MAP_I4 +#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) +#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) + +static void kgdb_swarm_write_char(int c) +{ + while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0) ; + duart_out(R_DUART_TX_HOLD, c); +} + +static int kgdb_swarm_read_char(void) +{ + int ret_char; + unsigned int status; + + status = duart_in(R_DUART_STATUS); + while ((status & M_DUART_RX_RDY) == 0) { + status = duart_in(R_DUART_STATUS); + } + + /* + * Check for framing error + */ + if (status & M_DUART_FRM_ERR) { + kgdbsibyte_init_duart(); + kgdb_swarm_write_char('-'); + return '-'; + } + + ret_char = duart_in(R_DUART_RX_HOLD); + + return ret_char; +} + +void sb1250_kgdb_interrupt(struct pt_regs *regs) +{ + int kgdb_irq = K_INT_UART_0 + kgdb_port; + /* + * Clear break-change status (allow some time for the remote + * host to stop the break, since we would see another + * interrupt on the end-of-break too) + */ + kstat_this_cpu.irqs[kgdb_irq]++; + mdelay(500); + duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | + M_DUART_RX_EN | M_DUART_TX_EN); + if (kgdb_io_ops.init != kgdb_init_io) { + /* Throw away the data if another I/O routine is + * active. + */ + unsigned int status; + + status = duart_in(R_DUART_STATUS); + while ((status & M_DUART_RX_RDY) == 0) { + status = duart_in(R_DUART_STATUS); + } + /* + * Check for framing error + */ + if (status & M_DUART_FRM_ERR) { + kgdbsibyte_init_duart(); + } + duart_in(R_DUART_RX_HOLD); + } else + breakpoint(); + +} + +/* + * We use port #1 and we set it for 115200 BAUD, 8n1. + */ +static void kgdbsibyte_init_duart(void) +{ + /* Set 8n1. */ + duart_out(R_DUART_MODE_REG_1, + V_DUART_BITS_PER_CHAR_8 | V_DUART_PARITY_MODE_NONE); + duart_out(R_DUART_MODE_REG_2, M_DUART_STOP_BIT_LEN_1); + /* Set baud rate of 115200. */ + duart_out(R_DUART_CLK_SEL, V_DUART_BAUD_RATE(115200)); + /* Enable rx and tx */ + duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN); +} + +static int kgdb_init_io(void) +{ +#ifdef CONFIG_SIBYTE_SB1250_DUART + sb1250_duart_present[kgdb_port] = 0; +#endif + + kgdbsibyte_init_duart(); + + return 0; +} + +/* + * Hookup our IRQ line. We will already have been initialized a + * this point. + */ +static void __init kgdbsibyte_hookup_irq(void) +{ + /* Steal the IRQ. */ + kgdb_irq = K_INT_UART_0 + kgdb_port; + + /* Setup uart 1 settings, mapper */ + __raw_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port))); + + sb1250_steal_irq(kgdb_irq); + + __raw_writeq(IMR_IP6_VAL, + IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + + (kgdb_irq << 3))); + + sb1250_unmask_irq(0, kgdb_irq); +} + +struct kgdb_io kgdb_io_ops = { + .read_char = kgdb_swarm_read_char, + .write_char = kgdb_swarm_write_char, + .init = kgdb_init_io, + .late_init = kgdbsibyte_hookup_irq, + .pre_exception = NULL, + .post_exception = NULL +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/swarm/Makefile linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/swarm/Makefile --- linux-2.6.18-53.1.14/arch/mips/sibyte/swarm/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/swarm/Makefile 2008-06-10 15:38:24.000000000 +0400 @@ -1,3 +1 @@ lib-y = setup.o rtc_xicor1241.o rtc_m41t81.o - -lib-$(CONFIG_KGDB) += dbg_io.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/sibyte/swarm/dbg_io.c linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/swarm/dbg_io.c --- linux-2.6.18-53.1.14/arch/mips/sibyte/swarm/dbg_io.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/sibyte/swarm/dbg_io.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,76 +0,0 @@ -/* - * kgdb debug routines for SiByte boards. - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * 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. - * - */ - -/* -------------------- BEGINNING OF CONFIG --------------------- */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * We use the second serial port for kgdb traffic. - * 115200, 8, N, 1. - */ - -#define BAUD_RATE 115200 -#define CLK_DIVISOR V_DUART_BAUD_RATE(BAUD_RATE) -#define DATA_BITS V_DUART_BITS_PER_CHAR_8 /* or 7 */ -#define PARITY V_DUART_PARITY_MODE_NONE /* or even */ -#define STOP_BITS M_DUART_STOP_BIT_LEN_1 /* or 2 */ - -static int duart_initialized = 0; /* 0: need to be init'ed by kgdb */ - -/* -------------------- END OF CONFIG --------------------- */ -extern int kgdb_port; - -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) - -void putDebugChar(unsigned char c); -unsigned char getDebugChar(void); -static void -duart_init(int clk_divisor, int data, int parity, int stop) -{ - duart_out(R_DUART_MODE_REG_1, data | parity); - duart_out(R_DUART_MODE_REG_2, stop); - duart_out(R_DUART_CLK_SEL, clk_divisor); - - duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN); /* enable rx and tx */ -} - -void -putDebugChar(unsigned char c) -{ - if (!duart_initialized) { - duart_initialized = 1; - duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); - } - while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0); - duart_out(R_DUART_TX_HOLD, c); -} - -unsigned char -getDebugChar(void) -{ - if (!duart_initialized) { - duart_initialized = 1; - duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); - } - while ((duart_in(R_DUART_STATUS) & M_DUART_RX_RDY) == 0) ; - return duart_in(R_DUART_RX_HOLD); -} - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/mips/tx4938/common/Makefile linux-2.6.18-53.1.14.kgdb/arch/mips/tx4938/common/Makefile --- linux-2.6.18-53.1.14/arch/mips/tx4938/common/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/mips/tx4938/common/Makefile 2008-06-10 15:38:24.000000000 +0400 @@ -7,5 +7,5 @@ # obj-y += prom.o setup.o irq.o rtc_rx5c348.o -obj-$(CONFIG_KGDB) += dbgio.o +obj-$(CONFIG_KGDB_8250) += dbgio.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/Kconfig.debug linux-2.6.18-53.1.14.kgdb/arch/powerpc/Kconfig.debug --- linux-2.6.18-53.1.14/arch/powerpc/Kconfig.debug 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/Kconfig.debug 2008-06-10 15:38:14.000000000 +0400 @@ -18,52 +18,9 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config DEBUGGER - bool "Enable debugger hooks" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for kernel debuggers. Unless you are - intending to debug the kernel, say N here. - -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUGGER && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - config XMON bool "Include xmon kernel debugger" - depends on DEBUGGER && !PPC_ISERIES + depends on DEBUG_KERNEL && !PPC_ISERIES help Include in-kernel hooks for the xmon kernel monitor/debugger. Unless you are intending to debug the kernel, say N here. @@ -82,6 +39,11 @@ config XMON_DEFAULT xmon is normally disabled unless booted with 'xmon=on'. Use 'xmon=off' to disable xmon init during runtime. +config DEBUGGER + bool + depends on KGDB || XMON + default y + config IRQSTACKS bool "Use separate kernel stacks when processing interrupts" depends on PPC64 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/Makefile --- linux-2.6.18-53.1.14/arch/powerpc/kernel/Makefile 2008-03-06 05:54:47.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/Makefile 2008-06-10 15:38:14.000000000 +0400 @@ -59,6 +59,7 @@ obj-$(CONFIG_PPC64) += misc_64.o dma_64 obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o +obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/powerpc/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/kgdb.c 2008-06-10 15:38:14.000000000 +0400 @@ -0,0 +1,568 @@ +/* + * arch/powerpc/kernel/kgdb.c + * + * PowerPC backend to the KGDB stub. + * + * Maintainer: Tom Rini + * + * Copied from arch/ppc/kernel/kgdb.c, updated for ppc64 + * + * Copyright (C) 1996 Paul Mackerras (setjmp/longjmp) + * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) + * Copyright (C) 2003 Timesys Corporation. + * Copyright (C) 2004-2006 MontaVista Software, Inc. + * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) + * PPC32 support restored by Vitaly Wool and + * Sergei Shtylyov + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This table contains the mapping between PowerPC hardware trap types, and + * signals, which are primarily what GDB understands. GDB and the kernel + * don't always agree on values, so we use constants taken from gdb-6.2. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + { 0x0100, 0x02 /* SIGINT */ }, /* system reset */ + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* data access */ + { 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */ + { 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ + { 0x0700, 0x05 /* SIGTRAP */ }, /* program check */ + { 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */ + { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */ +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + { 0x2002, 0x05 /* SIGTRAP */ }, /* debug */ +#if defined(CONFIG_FSL_BOOKE) + { 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */ + { 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */ + { 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */ + { 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */ + { 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */ + { 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */ + { 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */ + { 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */ + { 0x3200, 0x02 /* SIGINT */ }, /* watchdog */ +#else + { 0x1000, 0x0e /* SIGALRM */ }, /* programmable interval timer */ + { 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */ + { 0x1020, 0x02 /* SIGINT */ }, /* watchdog */ + { 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */ + { 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */ +#endif +#else + { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */ +#if defined(CONFIG_8xx) + { 0x1000, 0x04 /* SIGILL */ }, /* software emulation */ +#else + { 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */ + { 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */ + { 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */ +#if defined(CONFIG_PPC64) + { 0x1200, 0x05 /* SIGILL */ }, /* system error */ + { 0x1500, 0x04 /* SIGILL */ }, /* soft patch */ + { 0x1600, 0x04 /* SIGILL */ }, /* maintenance */ + { 0x1700, 0x08 /* SIGFPE */ }, /* altivec assist */ + { 0x1800, 0x04 /* SIGILL */ }, /* thermal */ +#else + { 0x1400, 0x02 /* SIGINT */ }, /* SMI */ + { 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */ + { 0x1700, 0x04 /* SIGILL */ }, /* TAU */ + { 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */ +#endif +#endif +#endif + { 0x0000, 0x00 } /* Must be last */ +}; + +extern atomic_t cpu_doing_single_step; + +static int computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +static int kgdb_call_nmi_hook(struct pt_regs *regs) +{ + kgdb_nmihook(smp_processor_id(), regs); + return 0; +} + +#ifdef CONFIG_SMP +void kgdb_roundup_cpus(unsigned long flags) +{ + smp_send_debugger_break(MSG_ALL_BUT_SELF); +} +#endif + +/* KGDB functions to use existing PowerPC64 hooks. */ +static int kgdb_debugger(struct pt_regs *regs) +{ + return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); +} + +static int kgdb_breakpoint(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) + regs->nip += 4; + + return 1; +} + +static int kgdb_singlestep(struct pt_regs *regs) +{ + struct thread_info *thread_info, *exception_thread_info; + if (user_mode(regs)) + return 0; + /* + * On Book E and perhaps other processsors, singlestep is handled on + * the critical exception stack. This causes current_thread_info() + * to fail, since it it locates the thread_info by masking off + * the low bits of the current stack pointer. We work around + * this issue by copying the thread_info from the kernel stack + * before calling kgdb_handle_exception, and copying it back + * afterwards. On most processors the copy is avoided since + * exception_thread_info == thread_info. + */ + thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); + exception_thread_info = current_thread_info(); + + if (thread_info != exception_thread_info) + memcpy(exception_thread_info, thread_info, sizeof *thread_info); + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (thread_info != exception_thread_info) + memcpy(thread_info, exception_thread_info, sizeof *thread_info); + + return 1; +} + +int kgdb_iabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +int kgdb_dabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +#define PACK64(ptr,src) do { *(ptr++) = (src); } while(0) + +#define PACK32(ptr,src) do { \ + u32 *ptr32; \ + ptr32 = (u32 *)ptr; \ + *(ptr32++) = (src); \ + ptr = (unsigned long *)ptr32; \ + } while(0) + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + unsigned long *ptr = gdb_regs; + int reg; + + memset(gdb_regs, 0, NUMREGBYTES); + + for (reg = 0; reg < 32; reg++) + PACK64(ptr, regs->gpr[reg]); + +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + for (reg = 0; reg < 32; reg++) + PACK64(ptr, current->thread.evr[reg]); +#else + ptr += 32; +#endif +#else + /* fp registers not used by kernel, leave zero */ + ptr += 32 * 8 / sizeof(long); +#endif + + PACK64(ptr, regs->nip); + PACK64(ptr, regs->msr); + PACK32(ptr, regs->ccr); + PACK64(ptr, regs->link); + PACK64(ptr, regs->ctr); + PACK32(ptr, regs->xer); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + PACK32(ptr, current->thread->fpscr); + + /* vr registers not used by kernel, leave zero */ + ptr += 32 * 16 / sizeof(long); + +#ifdef CONFIG_ALTIVEC + PACK32(ptr, current->thread->vscr); + PACK32(ptr, current->thread->vrsave); +#else + ptr += 2 * 4 / sizeof(long); +#endif +#else +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + /* u64 acc */ + PACK32(ptr, current->thread.acc >> 32); + PACK32(ptr, current->thread.acc & 0xffffffff); + PACK64(ptr, current->thread.spefscr); +#else + ptr += 2 + 1; +#endif +#else + /* fpscr not used by kernel, leave zero */ + PACK32(ptr, 0); +#endif +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + + STACK_FRAME_OVERHEAD); + unsigned long *ptr = gdb_regs; + int reg; + + memset(gdb_regs, 0, NUMREGBYTES); + + /* Regs GPR0-2 */ + for (reg = 0; reg < 3; reg++) + PACK64(ptr, regs->gpr[reg]); + + /* Regs GPR3-13 are caller saved, not in regs->gpr[] */ + ptr += 11; + + /* Regs GPR14-31 */ + for (reg = 14; reg < 32; reg++) + PACK64(ptr, regs->gpr[reg]); + +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + for (reg = 0; reg < 32; reg++) + PACK64(ptr, p->thread.evr[reg]); +#else + ptr += 32; +#endif +#else + /* fp registers not used by kernel, leave zero */ + ptr += 32 * 8 / sizeof(long); +#endif + PACK64(ptr, regs->nip); + PACK64(ptr, regs->msr); + PACK32(ptr, regs->ccr); + PACK64(ptr, regs->link); + PACK64(ptr, regs->ctr); + PACK32(ptr, regs->xer); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + PACK32(ptr, p->thread->fpscr); + + /* vr registers not used by kernel, leave zero */ + ptr += 32 * 16 / sizeof(long); + +#ifdef CONFIG_ALTIVEC + PACK32(ptr, p->thread->vscr); + PACK32(ptr, p->thread->vrsave); +#else + ptr += 2 * 4 / sizeof(long); +#endif +#else +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + /* u64 acc */ + PACK32(ptr, p->thread.acc >> 32); + PACK32(ptr, p->thread.acc & 0xffffffff); + PACK64(ptr, p->thread.spefscr); +#else + ptr += 2 + 1; +#endif +#else + /* fpscr not used by kernel, leave zero */ + PACK32(ptr, 0); +#endif +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +#define UNPACK64(dest,ptr) do { dest = *(ptr++); } while(0) + +#define UNPACK32(dest,ptr) do { \ + u32 *ptr32; \ + ptr32 = (u32 *)ptr; \ + dest = *(ptr32++); \ + ptr = (unsigned long *)ptr32; \ + } while(0) + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + unsigned long *ptr = gdb_regs; + int reg; + +#ifdef CONFIG_SPE + union { + u32 v32[2]; + u64 v64; + } acc; +#endif + for (reg = 0; reg < 32; reg++) + UNPACK64(regs->gpr[reg], ptr); + +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + for (reg = 0; reg < 32; reg++) + UNPACK64(current->thread.evr[reg], ptr); +#else + ptr += 32; +#endif +#else + /* fp registers not used by kernel, leave zero */ + ptr += 32 * 8 / sizeof(int); +#endif + UNPACK64(regs->nip, ptr); + UNPACK64(regs->msr, ptr); + UNPACK32(regs->ccr, ptr); + UNPACK64(regs->link, ptr); + UNPACK64(regs->ctr, ptr); + UNPACK32(regs->xer, ptr); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + /* fpscr, vscr, vrsave not used by kernel, leave unchanged */ + + UNPACK32(current->thread->fpscr, ptr); + + /* vr registers not used by kernel, leave zero */ + ptr += 32 * 16 / sizeof(long); + + #ifdef CONFIG_ALTIVEC + UNPACK32(current->thread->vscr, ptr); + UNPACK32(current->thread->vrsave, ptr); +#else + ptr += 2 * 4 / sizeof(long); +#endif +#else +#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_SPE + /* u64 acc */ + UNPACK32(acc.v32[0], ptr); + UNPACK32(acc.v32[1], ptr); + current->thread.acc = acc.v64; + UNPACK64(current->thread.spefscr, ptr); +#else + ptr += 2 + 1; +#endif +#endif +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +/* + * This function does PowerPC specific procesing for interfacing to gdb. + */ +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + + switch (remcom_in_buffer[0]) { + /* + * sAA..AA Step one instruction from AA..AA + * This will return an error to gdb .. + */ + case 's': + case 'c': + /* handle the optional parameter */ + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->nip = addr; + + atomic_set(&cpu_doing_single_step, -1); + /* set the trace bit if we're stepping */ + if (remcom_in_buffer[0] == 's') { +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + mtspr(SPRN_DBCR0, + mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); + linux_regs->msr |= MSR_DE; +#else + linux_regs->msr |= MSR_SE; +#endif + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + return 0; + } + + return -1; +} + +int kgdb_fault_setjmp(unsigned long *curr_context) +{ +#ifdef CONFIG_PPC32 + __asm__ __volatile__("mflr 0; stw 0,0(%0);\n\ + stw 1,4(%0); stw 2,8(%0);\n\ + mfcr 0; stw 0,12(%0);\n\ + stmw 13,16(%0)\n" : : "r" (curr_context)); +#else + __asm__ __volatile__("mflr 0; std 0,0(%0)\n\ + std 1,8(%0)\n\ + std 2,16(%0)\n\ + mfcr 0; std 0,24(%0)\n\ + std 13,32(%0)\n\ + std 14,40(%0)\n\ + std 15,48(%0)\n\ + std 16,56(%0)\n\ + std 17,64(%0)\n\ + std 18,72(%0)\n\ + std 19,80(%0)\n\ + std 20,88(%0)\n\ + std 21,96(%0)\n\ + std 22,104(%0)\n\ + std 23,112(%0)\n\ + std 24,120(%0)\n\ + std 25,128(%0)\n\ + std 26,136(%0)\n\ + std 27,144(%0)\n\ + std 28,152(%0)\n\ + std 29,160(%0)\n\ + std 30,168(%0)\n\ + std 31,176(%0)\n" : : "r" (curr_context)); +#endif + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ +#ifdef CONFIG_PPC32 + __asm__ __volatile__("lmw 13,16(%0);\n\ + lwz 0,12(%0); mtcrf 0x38,0;\n\ + lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);\n\ + mtlr 0; mr 3,1\n" : : "r" (curr_context)); +#else + __asm__ __volatile__("ld 13,32(%0)\n\ + ld 14,40(%0)\n\ + ld 15,48(%0)\n\ + ld 16,56(%0)\n\ + ld 17,64(%0)\n\ + ld 18,72(%0)\n\ + ld 19,80(%0)\n\ + ld 20,88(%0)\n\ + ld 21,96(%0)\n\ + ld 22,104(%0)\n\ + ld 23,112(%0)\n\ + ld 24,120(%0)\n\ + ld 25,128(%0)\n\ + ld 26,136(%0)\n\ + ld 27,144(%0)\n\ + ld 28,152(%0)\n\ + ld 29,160(%0)\n\ + ld 30,168(%0)\n\ + ld 31,176(%0)\n\ + ld 0,24(%0)\n\ + mtcrf 0x38,0\n\ + ld 0,0(%0)\n\ + ld 1,8(%0)\n\ + ld 2,16(%0)\n\ + mtlr 0\n\ + mr 3,1\n" : : "r" (curr_context)); +#endif +} + +/* + * Global data + */ +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, +}; + +int kgdb_not_implemented(struct pt_regs *regs) +{ + return 0; +} + +int kgdb_arch_init(void) +{ +#ifdef CONFIG_XMON +#error Both XMON and KGDB selected in .config. Unselect one of them. +#endif + + __debugger_ipi = kgdb_call_nmi_hook; + __debugger = kgdb_debugger; + __debugger_bpt = kgdb_breakpoint; + __debugger_sstep = kgdb_singlestep; + __debugger_iabr_match = kgdb_iabr_match; + __debugger_dabr_match = kgdb_dabr_match; + __debugger_fault_handler = kgdb_not_implemented; + + return 0; +} + +arch_initcall(kgdb_arch_init); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/kernel/legacy_serial.c linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/legacy_serial.c --- linux-2.6.18-53.1.14/arch/powerpc/kernel/legacy_serial.c 2008-03-06 05:54:47.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/legacy_serial.c 2008-06-10 15:38:14.000000000 +0400 @@ -11,6 +11,9 @@ #include #include #include +#ifdef CONFIG_KGDB_8250 +#include +#endif #undef DEBUG @@ -485,6 +488,9 @@ static int __init serial_dev_init(void) fixup_port_pio(i, np, port); if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_TSI)) fixup_port_mmio(i, np, port); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_platform_port(i, port); +#endif } DBG("Registering platform serial ports\n"); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/kernel/setup_32.c linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/setup_32.c --- linux-2.6.18-53.1.14/arch/powerpc/kernel/setup_32.c 2008-03-06 05:54:45.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/kernel/setup_32.c 2008-06-10 15:38:14.000000000 +0400 @@ -45,10 +45,6 @@ #define DBG(fmt...) -#if defined CONFIG_KGDB -#include -#endif - extern void bootx_init(unsigned long r4, unsigned long phys); struct ide_machdep_calls ppc_ide_md; @@ -251,18 +247,6 @@ void __init setup_arch(char **cmdline_p) xmon_setup(); -#if defined(CONFIG_KGDB) - if (ppc_md.kgdb_map_scc) - ppc_md.kgdb_map_scc(); - set_debug_traps(); - if (strstr(cmd_line, "gdb")) { - if (ppc_md.progress) - ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); - printk("kgdb breakpoint activated\n"); - breakpoint(); - } -#endif - /* * Set cache line size based on type of cpu as a default. * Systems with OF can look in the properties on the cpu node(s) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/powerpc/mm/fault.c --- linux-2.6.18-53.1.14/arch/powerpc/mm/fault.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/mm/fault.c 2008-06-10 15:38:14.000000000 +0400 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -424,6 +425,13 @@ void bad_page_fault(struct pt_regs *regs return; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ +#endif + /* kernel has accessed a bad area */ printk(KERN_ALERT "Unable to handle kernel paging request for "); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/powerpc/platforms/powermac/setup.c linux-2.6.18-53.1.14.kgdb/arch/powerpc/platforms/powermac/setup.c --- linux-2.6.18-53.1.14/arch/powerpc/platforms/powermac/setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/powerpc/platforms/powermac/setup.c 2008-06-10 15:38:14.000000000 +0400 @@ -98,8 +98,6 @@ extern struct machdep_calls pmac_md; int sccdbg; #endif -extern void zs_kgdb_hook(int tty_num); - sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; EXPORT_SYMBOL(sys_ctrler); @@ -319,10 +317,6 @@ static void __init pmac_setup_arch(void) l2cr_init(); #endif /* CONFIG_PPC32 */ -#ifdef CONFIG_KGDB - zs_kgdb_hook(0); -#endif - find_via_cuda(); find_via_pmu(); smu_init(); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/Kconfig.debug linux-2.6.18-53.1.14.kgdb/arch/ppc/Kconfig.debug --- linux-2.6.18-53.1.14/arch/ppc/Kconfig.debug 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/Kconfig.debug 2008-06-10 15:38:14.000000000 +0400 @@ -2,42 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - config XMON bool "Include xmon kernel debugger" depends on DEBUG_KERNEL diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/ppc/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/kgdb.c 2008-06-10 15:39:34.000000000 +0400 @@ -0,0 +1,350 @@ +/* + * arch/ppc/kernel/kgdb.c + * + * PowerPC backend to the KGDB stub. + * + * Maintainer: Tom Rini + * + * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) + * Copyright (C) 2003 Timesys Corporation. + * 2004 (c) MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This table contains the mapping between PowerPC hardware trap types, and + * signals, which are primarily what GDB understands. GDB and the kernel + * don't always agree on values, so we use constants taken from gdb-6.2. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + { 0x0100, 0x02 /* SIGINT */ }, /* critical input interrupt */ + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* data storage */ + { 0x0400, 0x0a /* SIGBUS */ }, /* instruction storage */ + { 0x0500, 0x02 /* SIGINT */ }, /* interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ + { 0x0700, 0x04 /* SIGILL */ }, /* program */ + { 0x0800, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0900, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0a00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0b00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* syscall */ + { 0x0d00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0e00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0f00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x2002, 0x05 /* SIGTRAP */}, /* debug */ +#else + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* address error (store) */ + { 0x0400, 0x0a /* SIGBUS */ }, /* instruction bus error */ + { 0x0500, 0x02 /* SIGINT */ }, /* interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alingment */ + { 0x0700, 0x05 /* SIGTRAP */ }, /* breakpoint trap */ + { 0x0800, 0x08 /* SIGFPE */}, /* fpu unavail */ + { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ + { 0x0a00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0b00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* syscall */ + { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step/watch */ + { 0x0e00, 0x08 /* SIGFPE */ }, /* fp assist */ +#endif + { 0x0000, 0x000 } /* Must be last */ +}; + +extern atomic_t cpu_doing_single_step; + +static int computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* KGDB functions to use existing PowerPC hooks. */ +static void kgdb_debugger(struct pt_regs *regs) +{ + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); +} + +static int kgdb_breakpoint(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) + regs->nip += 4; + + return 1; +} + +static int kgdb_singlestep(struct pt_regs *regs) +{ + struct thread_info *thread_info, *exception_thread_info; + + if (user_mode(regs)) + return 0; + /* + * On Book E and perhaps other processsors, singlestep is handled on + * the critical exception stack. This causes current_thread_info() + * to fail, since it it locates the thread_info by masking off + * the low bits of the current stack pointer. We work around + * this issue by copying the thread_info from the kernel stack + * before calling kgdb_handle_exception, and copying it back + * afterwards. On most processors the copy is avoided since + * exception_thread_info == thread_info. + */ + thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); + exception_thread_info = current_thread_info(); + + if (thread_info != exception_thread_info) + memcpy(exception_thread_info, thread_info, sizeof *thread_info); + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (thread_info != exception_thread_info) + memcpy(thread_info, exception_thread_info, sizeof *thread_info); + + return 1; +} + +int kgdb_iabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +int kgdb_dabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, MAXREG * 4); + + for (reg = 0; reg < 32; reg++) + *(ptr++) = regs->gpr[reg]; + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + *(ptr++) = 0; +#else + for (reg = 0; reg < 32; reg++) + *(ptr++) = current->thread.evr[reg]; +#endif + + *(ptr++) = regs->nip; + *(ptr++) = regs->msr; + *(ptr++) = regs->ccr; + *(ptr++) = regs->link; + *(ptr++) = regs->ctr; + *(ptr++) = regs->xer; + +#ifdef CONFIG_SPE + /* u64 acc */ + *(ptr++) = (current->thread.acc >> 32); + *(ptr++) = (current->thread.acc & 0xffffffff); + *(ptr++) = current->thread.spefscr; +#endif +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + + STACK_FRAME_OVERHEAD); + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, MAXREG * 4); + + /* Regs GPR0-2 */ + for (reg = 0; reg < 3; reg++) + *(ptr++) = regs->gpr[reg]; + + /* Regs GPR3-13 are not saved */ + for (reg = 3; reg < 14; reg++) + *(ptr++) = 0; + + /* Regs GPR14-31 */ + for (reg = 14; reg < 32; reg++) + *(ptr++) = regs->gpr[reg]; + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + *(ptr++) = 0; +#else + for (reg = 0; reg < 32; reg++) + *(ptr++) = current->thread.evr[reg]; +#endif + + *(ptr++) = regs->nip; + *(ptr++) = regs->msr; + *(ptr++) = regs->ccr; + *(ptr++) = regs->link; + *(ptr++) = regs->ctr; + *(ptr++) = regs->xer; + +#ifdef CONFIG_SPE + /* u64 acc */ + *(ptr++) = (current->thread.acc >> 32); + *(ptr++) = (current->thread.acc & 0xffffffff); + *(ptr++) = current->thread.spefscr; +#endif +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; +#ifdef CONFIG_SPE + union { + u32 v32[2]; + u64 v64; + } u; +#endif + + for (reg = 0; reg < 32; reg++) + regs->gpr[reg] = *(ptr++); + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + ptr++; +#else + for (reg = 0; reg < 32; reg++) + current->thread.evr[reg] = *(ptr++); +#endif + + regs->nip = *(ptr++); + regs->msr = *(ptr++); + regs->ccr = *(ptr++); + regs->link = *(ptr++); + regs->ctr = *(ptr++); + regs->xer = *(ptr++); + +#ifdef CONFIG_SPE + /* u64 acc */ + u.v32[0] = *(ptr++); + u.v32[1] = *(ptr++); + current->thread.acc = u.v64; + current->thread.spefscr = *(ptr++); +#endif +} + +/* + * Save/restore state in case a memory access causes a fault. + */ +int kgdb_fault_setjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("mflr 0; stw 0,0(%0);" + "stw 1,4(%0); stw 2,8(%0);" + "mfcr 0; stw 0,12(%0);" + "stmw 13,16(%0)"::"r"(curr_context)); + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("lmw 13,16(%0);" + "lwz 0,12(%0); mtcrf 0x38,0;" + "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" + "mtlr 0; mr 3,1"::"r"(curr_context)); +} + +/* + * This function does PoerPC specific procesing for interfacing to gdb. + */ +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + + switch (remcom_in_buffer[0]) + { + /* + * sAA..AA Step one instruction from AA..AA + * This will return an error to gdb .. + */ + case 's': + case 'c': + /* handle the optional parameter */ + if (kgdb_hex2long (&ptr, &addr)) + linux_regs->nip = addr; + + atomic_set(&cpu_doing_single_step, -1); + /* set the trace bit if we're stepping */ + if (remcom_in_buffer[0] == 's') { +#if defined (CONFIG_40x) || defined(CONFIG_BOOKE) + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | + DBCR0_IC | DBCR0_IDM); + linux_regs->msr |= MSR_DE; +#else + linux_regs->msr |= MSR_SE; +#endif + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + return 0; + } + + return -1; +} + +/* + * Global data + */ +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, +}; + +int kgdb_arch_init(void) +{ + debugger = kgdb_debugger; + debugger_bpt = kgdb_breakpoint; + debugger_sstep = kgdb_singlestep; + debugger_iabr_match = kgdb_iabr_match; + debugger_dabr_match = kgdb_dabr_match; + + return 0; +} + +arch_initcall(kgdb_arch_init); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/kernel/ppc-stub.c linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/ppc-stub.c --- linux-2.6.18-53.1.14/arch/ppc/kernel/ppc-stub.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/ppc-stub.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,866 +0,0 @@ -/* - * ppc-stub.c: KGDB support for the Linux kernel. - * - * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC - * some stuff borrowed from Paul Mackerras' xmon - * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) - * - * Modifications to run under Linux - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * This file originally came from the gdb sources, and the - * copyright notices have been retained below. - */ - -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or its performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ - * - * Module name: remcom.c $ - * Revision: 1.34 $ - * Date: 91/03/09 12:29:49 $ - * Contributor: Lake Stevens Instrument Division$ - * - * Description: low level support for gdb debugger. $ - * - * Considerations: only works on target hardware $ - * - * Written by: Glenn Engel $ - * ModuleState: Experimental $ - * - * NOTES: See Below $ - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * This code has been extensively tested on the Fujitsu SPARClite demo board. - * - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a trap #1. - * - ************* - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * bBB..BB Set baud rate to BB..BB OK or BNN, then sets - * baud rate - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $#. - * - * where - * :: - * :: > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -void breakinst(void); - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound buffers - * at least NUMREGBYTES*2 are needed for register packets - */ -#define BUFMAX 2048 -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; - -static int initialized; -static int kgdb_active; -static int kgdb_started; -static u_int fault_jmp_buf[100]; -static int kdebug; - - -static const char hexchars[]="0123456789abcdef"; - -/* Place where we save old trap entries for restoration - sparc*/ -/* struct tt_entry kgdb_savettable[256]; */ -/* typedef void (*trapfunc_t)(void); */ - -static void kgdb_fault_handler(struct pt_regs *regs); -static int handle_exception (struct pt_regs *regs); - -#if 0 -/* Install an exception handler for kgdb */ -static void exceptionHandler(int tnum, unsigned int *tfunc) -{ - /* We are dorking with a live trap table, all irqs off */ -} -#endif - -int -kgdb_setjmp(long *buf) -{ - asm ("mflr 0; stw 0,0(%0);" - "stw 1,4(%0); stw 2,8(%0);" - "mfcr 0; stw 0,12(%0);" - "stmw 13,16(%0)" - : : "r" (buf)); - /* XXX should save fp regs as well */ - return 0; -} -void -kgdb_longjmp(long *buf, int val) -{ - if (val == 0) - val = 1; - asm ("lmw 13,16(%0);" - "lwz 0,12(%0); mtcrf 0x38,0;" - "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" - "mtlr 0; mr 3,%1" - : : "r" (buf), "r" (val)); -} -/* Convert ch from a hex digit to an int */ -static int -hex(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'f') - return ch-'a'+10; - if (ch >= '0' && ch <= '9') - return ch-'0'; - if (ch >= 'A' && ch <= 'F') - return ch-'A'+10; - return -1; -} - -/* Convert the memory pointed to by mem into hex, placing result in buf. - * Return a pointer to the last char put in buf (null), in case of mem fault, - * return 0. - */ -static unsigned char * -mem2hex(const char *mem, char *buf, int count) -{ - unsigned char ch; - unsigned short tmp_s; - unsigned long tmp_l; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** load instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = *(unsigned short *)mem; - mem += 2; - *buf++ = hexchars[(tmp_s >> 12) & 0xf]; - *buf++ = hexchars[(tmp_s >> 8) & 0xf]; - *buf++ = hexchars[(tmp_s >> 4) & 0xf]; - *buf++ = hexchars[tmp_s & 0xf]; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = *(unsigned int *)mem; - mem += 4; - *buf++ = hexchars[(tmp_l >> 28) & 0xf]; - *buf++ = hexchars[(tmp_l >> 24) & 0xf]; - *buf++ = hexchars[(tmp_l >> 20) & 0xf]; - *buf++ = hexchars[(tmp_l >> 16) & 0xf]; - *buf++ = hexchars[(tmp_l >> 12) & 0xf]; - *buf++ = hexchars[(tmp_l >> 8) & 0xf]; - *buf++ = hexchars[(tmp_l >> 4) & 0xf]; - *buf++ = hexchars[tmp_l & 0xf]; - - } else { - while (count-- > 0) { - ch = *mem++; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0xf]; - } - } - - } else { - /* error condition */ - } - debugger_fault_handler = NULL; - *buf = 0; - return buf; -} - -/* convert the hex array pointed to by buf into binary to be placed in mem - * return a pointer to the character AFTER the last byte written. -*/ -static char * -hex2mem(char *buf, char *mem, int count) -{ - unsigned char ch; - int i; - char *orig_mem; - unsigned short tmp_s; - unsigned long tmp_l; - - orig_mem = mem; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** store instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = hex(*buf++) << 12; - tmp_s |= hex(*buf++) << 8; - tmp_s |= hex(*buf++) << 4; - tmp_s |= hex(*buf++); - - *(unsigned short *)mem = tmp_s; - mem += 2; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = hex(*buf++) << 28; - tmp_l |= hex(*buf++) << 24; - tmp_l |= hex(*buf++) << 20; - tmp_l |= hex(*buf++) << 16; - tmp_l |= hex(*buf++) << 12; - tmp_l |= hex(*buf++) << 8; - tmp_l |= hex(*buf++) << 4; - tmp_l |= hex(*buf++); - - *(unsigned long *)mem = tmp_l; - mem += 4; - - } else { - for (i=0; i# */ -static void -getpacket(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - unsigned char ch; - - do { - /* wait around for the start character, ignore all other - * characters */ - while ((ch = (getDebugChar() & 0x7f)) != '$') ; - - checksum = 0; - xmitcsum = -1; - - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) { - ch = getDebugChar() & 0x7f; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - if (count >= BUFMAX) - continue; - - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex(getDebugChar() & 0x7f) << 4; - xmitcsum |= hex(getDebugChar() & 0x7f); - if (checksum != xmitcsum) - putDebugChar('-'); /* failed checksum */ - else { - putDebugChar('+'); /* successful transfer */ - /* if a sequence char is present, reply the ID */ - if (buffer[2] == ':') { - putDebugChar(buffer[0]); - putDebugChar(buffer[1]); - /* remove sequence chars from buffer */ - count = strlen(buffer); - for (i=3; i <= count; i++) - buffer[i-3] = buffer[i]; - } - } - } - } while (checksum != xmitcsum); -} - -/* send the packet in buffer. */ -static void putpacket(unsigned char *buffer) -{ - unsigned char checksum; - int count; - unsigned char ch, recv; - - /* $#. */ - do { - putDebugChar('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count])) { - putDebugChar(ch); - checksum += ch; - count += 1; - } - - putDebugChar('#'); - putDebugChar(hexchars[checksum >> 4]); - putDebugChar(hexchars[checksum & 0xf]); - recv = getDebugChar(); - } while ((recv & 0x7f) != '+'); -} - -static void kgdb_flush_cache_all(void) -{ - flush_instruction_cache(); -} - -/* Set up exception handlers for tracing and breakpoints - * [could be called kgdb_init()] - */ -void set_debug_traps(void) -{ -#if 0 - unsigned char c; - - save_and_cli(flags); - - /* In case GDB is started before us, ack any packets (presumably - * "$?#xx") sitting there. - * - * I've found this code causes more problems than it solves, - * so that's why it's commented out. GDB seems to work fine - * now starting either before or after the kernel -bwb - */ - - while((c = getDebugChar()) != '$'); - while((c = getDebugChar()) != '#'); - c = getDebugChar(); /* eat first csum byte */ - c = getDebugChar(); /* eat second csum byte */ - putDebugChar('+'); /* ack it */ -#endif - debugger = kgdb; - debugger_bpt = kgdb_bpt; - debugger_sstep = kgdb_sstep; - debugger_iabr_match = kgdb_iabr_match; - debugger_dabr_match = kgdb_dabr_match; - - initialized = 1; -} - -static void kgdb_fault_handler(struct pt_regs *regs) -{ - kgdb_longjmp((long*)fault_jmp_buf, 1); -} - -int kgdb_bpt(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -int kgdb_sstep(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -void kgdb(struct pt_regs *regs) -{ - handle_exception(regs); -} - -int kgdb_iabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); - return handle_exception(regs); -} - -int kgdb_dabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); - return handle_exception(regs); -} - -/* Convert the hardware trap type code to a unix signal number. */ -/* - * This table contains the mapping between PowerPC hardware trap types, and - * signals, which are primarily what GDB understands. - */ -static struct hard_trap_info -{ - unsigned int tt; /* Trap type code for powerpc */ - unsigned char signo; /* Signal that we map this trap into */ -} hard_trap_info[] = { -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - { 0x100, SIGINT }, /* critical input interrupt */ - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* data storage */ - { 0x400, SIGBUS }, /* instruction storage */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alignment */ - { 0x700, SIGILL }, /* program */ - { 0x800, SIGILL }, /* reserved */ - { 0x900, SIGILL }, /* reserved */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGILL }, /* reserved */ - { 0xe00, SIGILL }, /* reserved */ - { 0xf00, SIGILL }, /* reserved */ - /* - ** 0x1000 PIT - ** 0x1010 FIT - ** 0x1020 watchdog - ** 0x1100 data TLB miss - ** 0x1200 instruction TLB miss - */ - { 0x2002, SIGTRAP}, /* debug */ -#else - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* address error (store) */ - { 0x400, SIGBUS }, /* instruction bus error */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGTRAP }, /* breakpoint trap */ - { 0x800, SIGFPE }, /* fpu unavail */ - { 0x900, SIGALRM }, /* decrementer */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGTRAP }, /* single-step/watch */ - { 0xe00, SIGFPE }, /* fp assist */ -#endif - { 0, 0} /* Must be last */ - -}; - -static int computeSignal(unsigned int tt) -{ - struct hard_trap_info *ht; - - for (ht = hard_trap_info; ht->tt && ht->signo; ht++) - if (ht->tt == tt) - return ht->signo; - - return SIGHUP; /* default for things we don't know about */ -} - -#define PC_REGNUM 64 -#define SP_REGNUM 1 - -/* - * This function does all command processing for interfacing to gdb. - */ -static int -handle_exception (struct pt_regs *regs) -{ - int sigval; - int addr; - int length; - char *ptr; - unsigned int msr; - - /* We don't handle user-mode breakpoints. */ - if (user_mode(regs)) - return 0; - - if (debugger_fault_handler) { - debugger_fault_handler(regs); - panic("kgdb longjump failed!\n"); - } - if (kgdb_active) { - printk(KERN_ERR "interrupt while in kgdb, returning\n"); - return 0; - } - - kgdb_active = 1; - kgdb_started = 1; - -#ifdef KGDB_DEBUG - printk("kgdb: entering handle_exception; trap [0x%x]\n", - (unsigned int)regs->trap); -#endif - - kgdb_interruptible(0); - lock_kernel(); - msr = mfmsr(); - mtmsr(msr & ~MSR_EE); /* disable interrupts */ - - if (regs->nip == (unsigned long)breakinst) { - /* Skip over breakpoint trap insn */ - regs->nip += 4; - } - - /* reply to host that an exception has occurred */ - sigval = computeSignal(regs->trap); - ptr = remcomOutBuffer; - - *ptr++ = 'T'; - *ptr++ = hexchars[sigval >> 4]; - *ptr++ = hexchars[sigval & 0xf]; - *ptr++ = hexchars[PC_REGNUM >> 4]; - *ptr++ = hexchars[PC_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->nip, ptr, 4); - *ptr++ = ';'; - *ptr++ = hexchars[SP_REGNUM >> 4]; - *ptr++ = hexchars[SP_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); - *ptr++ = ';'; - *ptr++ = 0; - - putpacket(remcomOutBuffer); - if (kdebug) - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - - /* XXX We may want to add some features dealing with poking the - * XXX page tables, ... (look at sparc-stub.c for more info) - * XXX also required hacking to the gdb sources directly... - */ - - while (1) { - remcomOutBuffer[0] = 0; - - getpacket(remcomInBuffer); - switch (remcomInBuffer[0]) { - case '?': /* report most recent signal */ - remcomOutBuffer[0] = 'S'; - remcomOutBuffer[1] = hexchars[sigval >> 4]; - remcomOutBuffer[2] = hexchars[sigval & 0xf]; - remcomOutBuffer[3] = 0; - break; -#if 0 - case 'q': /* this screws up gdb for some reason...*/ - { - extern long _start, sdata, __bss_start; - - ptr = &remcomInBuffer[1]; - if (strncmp(ptr, "Offsets", 7) != 0) - break; - - ptr = remcomOutBuffer; - sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", - &_start, &sdata, &__bss_start); - break; - } -#endif - case 'd': - /* toggle debug flag */ - kdebug ^= 1; - break; - - case 'g': /* return the value of the CPU registers. - * some of them are non-PowerPC names :( - * they are stored in gdb like: - * struct { - * u32 gpr[32]; - * f64 fpr[32]; - * u32 pc, ps, cnd, lr; (ps=msr) - * u32 cnt, xer, mq; - * } - */ - { - int i; - ptr = remcomOutBuffer; - /* General Purpose Regs */ - ptr = mem2hex((char *)regs, ptr, 32 * 4); - /* Floating Point Regs - FIXME */ - /*ptr = mem2hex((char *), ptr, 32 * 8);*/ - for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ - ptr[i] = '0'; - } - ptr += 32*8*2; - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = mem2hex((char *)®s->nip, ptr, 4); - ptr = mem2hex((char *)®s->msr, ptr, 4); - ptr = mem2hex((char *)®s->ccr, ptr, 4); - ptr = mem2hex((char *)®s->link, ptr, 4); - ptr = mem2hex((char *)®s->ctr, ptr, 4); - ptr = mem2hex((char *)®s->xer, ptr, 4); - } - break; - - case 'G': /* set the value of the CPU registers */ - { - ptr = &remcomInBuffer[1]; - - /* - * If the stack pointer has moved, you should pray. - * (cause only god can help you). - */ - - /* General Purpose Regs */ - hex2mem(ptr, (char *)regs, 32 * 4); - - /* Floating Point Regs - FIXME?? */ - /*ptr = hex2mem(ptr, ??, 32 * 8);*/ - ptr += 32*8*2; - - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = hex2mem(ptr, (char *)®s->nip, 4); - ptr = hex2mem(ptr, (char *)®s->msr, 4); - ptr = hex2mem(ptr, (char *)®s->ccr, 4); - ptr = hex2mem(ptr, (char *)®s->link, 4); - ptr = hex2mem(ptr, (char *)®s->ctr, 4); - ptr = hex2mem(ptr, (char *)®s->xer, 4); - - strcpy(remcomOutBuffer,"OK"); - } - break; - case 'H': - /* don't do anything, yet, just acknowledge */ - hexToInt(&ptr, &addr); - strcpy(remcomOutBuffer,"OK"); - break; - - case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - /* Try to read %x,%x. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length)) { - if (mem2hex((char *)addr, remcomOutBuffer, - length)) - break; - strcpy(remcomOutBuffer, "E03"); - } else - strcpy(remcomOutBuffer, "E01"); - break; - - case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - /* Try to read '%x,%x:'. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length) - && *ptr++ == ':') { - if (hex2mem(ptr, (char *)addr, length)) - strcpy(remcomOutBuffer, "OK"); - else - strcpy(remcomOutBuffer, "E03"); - flush_icache_range(addr, addr+length); - } else - strcpy(remcomOutBuffer, "E02"); - break; - - - case 'k': /* kill the program, actually just continue */ - case 'c': /* cAA..AA Continue; address AA..AA optional */ - /* try to read optional parameter, pc unchanged if no parm */ - - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr)) - regs->nip = addr; - -/* Need to flush the instruction cache here, as we may have deposited a - * breakpoint, and the icache probably has no way of knowing that a data ref to - * some location may have changed something that is in the instruction cache. - */ - kgdb_flush_cache_all(); - mtmsr(msr); - - kgdb_interruptible(1); - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 's': - kgdb_flush_cache_all(); -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); - regs->msr |= MSR_DE; -#else - regs->msr |= MSR_SE; -#endif - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 'r': /* Reset (if user process..exit ???)*/ - panic("kgdb reset."); - break; - } /* switch */ - if (remcomOutBuffer[0] && kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - /* reply to the request */ - putpacket(remcomOutBuffer); - } /* while(1) */ -} - -/* This function will generate a breakpoint exception. It is used at the - beginning of a program to sync up with a debugger and can be used - otherwise as a quick means to stop program execution and "break" into - the debugger. */ - -void -breakpoint(void) -{ - if (!initialized) { - printk("breakpoint() called b4 kgdb init\n"); - return; - } - - asm(" .globl breakinst \n\ - breakinst: .long 0x7d821008"); -} - -#ifdef CONFIG_KGDB_CONSOLE -/* Output string in GDB O-packet format if GDB has connected. If nothing - output, returns 0 (caller must then handle output). */ -int -kgdb_output_string (const char* s, unsigned int count) -{ - char buffer[512]; - - if (!kgdb_started) - return 0; - - count = (count <= (sizeof(buffer) / 2 - 2)) - ? count : (sizeof(buffer) / 2 - 2); - - buffer[0] = 'O'; - mem2hex (s, &buffer[1], count); - putpacket(buffer); - - return 1; -} -#endif - -static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) -{ - printk("Entering GDB stub\n"); - breakpoint(); -} -static struct sysrq_key_op sysrq_gdb_op = { - .handler = sysrq_handle_gdb, - .help_msg = "Gdb", - .action_msg = "GDB", -}; - -static int gdb_register_sysrq(void) -{ - printk("Registering GDB sysrq handler\n"); - register_sysrq_key('g', &sysrq_gdb_op); - return 0; -} -module_init(gdb_register_sysrq); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/kernel/setup.c linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/setup.c --- linux-2.6.18-53.1.14/arch/ppc/kernel/setup.c 2008-03-06 05:54:43.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/kernel/setup.c 2008-06-10 15:38:14.000000000 +0400 @@ -48,10 +48,6 @@ #include #endif -#if defined CONFIG_KGDB -#include -#endif - extern void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); extern void reloc_got2(unsigned long offset); @@ -506,18 +502,6 @@ void __init setup_arch(char **cmdline_p) #endif /* CONFIG_XMON */ if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); -#if defined(CONFIG_KGDB) - if (ppc_md.kgdb_map_scc) - ppc_md.kgdb_map_scc(); - set_debug_traps(); - if (strstr(cmd_line, "gdb")) { - if (ppc_md.progress) - ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); - printk("kgdb breakpoint activated\n"); - breakpoint(); - } -#endif - /* * Set cache line size based on type of cpu as a default. * Systems with OF can look in the properties on the cpu node(s) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/ppc/mm/fault.c --- linux-2.6.18-53.1.14/arch/ppc/mm/fault.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/mm/fault.c 2008-06-10 15:38:14.000000000 +0400 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -329,6 +330,14 @@ bad_page_fault(struct pt_regs *regs, uns return; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) { + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ + } +#endif + /* kernel has accessed a bad area */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_kernel_faults) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/bubinga.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/bubinga.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/bubinga.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/bubinga.c 2008-06-10 15:38:14.000000000 +0400 @@ -4,7 +4,7 @@ * Author: SAW (IBM), derived from walnut.c. * Maintained by MontaVista Software * - * 2003 (c) MontaVista Softare Inc. This file is licensed under the + * 2003-2004 (c) MontaVista Softare Inc. This file is licensed under the * terms of the GNU General Public License version 2. This program is * licensed "as is" without any warranty of any kind, whether express * or implied. @@ -100,17 +100,26 @@ bubinga_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif port.membase = (void*)ACTING_UART1_IO_BASE; port.irq = ACTING_UART1_INT; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 1 failed\n"); - } +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } void __init @@ -255,8 +264,4 @@ platform_init(unsigned long r3, unsigned ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; #endif -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = bubinga_early_serial_map; -#endif } - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/ebony.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/ebony.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/ebony.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/ebony.c 2008-06-10 15:38:14.000000000 +0400 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -226,14 +227,20 @@ ebony_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(0, &port); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Purge TLB entry added in head_44x.S for early serial access */ _tlbie(UART0_IO_BASE); #endif @@ -243,14 +250,18 @@ ebony_early_serial_map(void) port.uartclk = clocks.uart1; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 1) printk("Early serial init of port 1 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(1, &port); #endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } static void __init @@ -327,8 +338,4 @@ void __init platform_init(unsigned long ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ebony_early_serial_map; -#endif } - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/ocotea.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/ocotea.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/ocotea.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/ocotea.c 2008-06-10 15:38:14.000000000 +0400 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -249,14 +250,20 @@ ocotea_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(0, &port); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Purge TLB entry added in head_44x.S for early serial access */ _tlbie(UART0_IO_BASE); #endif @@ -266,14 +273,18 @@ ocotea_early_serial_map(void) port.uartclk = clocks.uart1; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 1) printk("Early serial init of port 1 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(1, &port); #endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } static void __init @@ -343,8 +354,5 @@ void __init platform_init(unsigned long ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ocotea_early_serial_map; -#endif ppc_md.init = ocotea_init; } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/xilinx_ml300.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/xilinx_ml300.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/4xx/xilinx_ml300.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/4xx/xilinx_ml300.c 2008-06-10 15:38:14.000000000 +0400 @@ -41,9 +41,6 @@ * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c * start_kernel init/main.c * setup_arch arch/ppc/kernel/setup.c - * #if defined(CONFIG_KGDB) - * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc - * #endif * *ppc_md.setup_arch == ml300_setup_arch this file * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c @@ -117,7 +114,6 @@ ml300_early_serial_init(int num, struct void __init ml300_early_serial_map(void) { -#ifdef CONFIG_SERIAL_8250 struct plat_serial8250_port *pdata; int i = 0; @@ -129,7 +125,14 @@ ml300_early_serial_map(void) pdata++; i++; } -#endif /* CONFIG_SERIAL_8250 */ +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) + printk("Early serial init of port %d failed\n", i); +#endif + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(i, &port) +#endif } void __init @@ -165,9 +168,4 @@ platform_init(unsigned long r3, unsigned #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) ppc_md.power_off = xilinx_power_off; #endif - -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ml300_early_serial_map; -#endif } - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/85xx/sbc8560.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/85xx/sbc8560.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/85xx/sbc8560.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/85xx/sbc8560.c 2008-06-10 15:38:14.000000000 +0400 @@ -50,7 +50,6 @@ #include #include -#ifdef CONFIG_SERIAL_8250 static void __init sbc8560_early_serial_map(void) { @@ -66,12 +65,16 @@ sbc8560_early_serial_map(void) uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE); uart_req.type = PORT_16650; -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) - gen550_init(0, &uart_req); -#endif - +#ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&uart_req) != 0) printk("Early serial init of port 0 failed\n"); +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &uart_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &uart_req); +#endif /* Assume early_serial_setup() doesn't modify uart_req */ uart_req.line = 1; @@ -79,14 +82,17 @@ sbc8560_early_serial_map(void) uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE); uart_req.irq = MPC85xx_IRQ_EXT10; -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) - gen550_init(1, &uart_req); -#endif - +#ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&uart_req) != 0) - printk("Early serial init of port 1 failed\n"); -} + printk("Early serial init of port 0 failed\n"); #endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &uart_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &uart_req); +#endif +} /* ************************************************************************ * @@ -115,9 +121,7 @@ sbc8560_setup_arch(void) /* setup PCI host bridges */ mpc85xx_setup_hose(); #endif -#ifdef CONFIG_SERIAL_8250 sbc8560_early_serial_map(); -#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Invalidate the entry we stole earlier the serial ports * should be properly mapped */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/chestnut.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/chestnut.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/chestnut.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/chestnut.c 2008-06-10 15:38:14.000000000 +0400 @@ -492,7 +492,7 @@ chestnut_power_off(void) static void __init chestnut_map_io(void) { -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, _PAGE_IO); #endif @@ -566,9 +566,6 @@ platform_init(unsigned long r3, unsigned #if defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif -#if defined(CONFIG_KGDB) - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif if (ppc_md.progress) ppc_md.progress("chestnut_init(): exit", 0); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/pplus.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/pplus.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/pplus.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/pplus.c 2008-06-10 15:38:14.000000000 +0400 @@ -893,9 +893,6 @@ platform_init(unsigned long r3, unsigned #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif #ifdef CONFIG_SMP smp_ops = &pplus_smp_ops; #endif /* CONFIG_SMP */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/sandpoint.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/sandpoint.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/sandpoint.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/sandpoint.c 2008-06-10 15:38:14.000000000 +0400 @@ -730,9 +730,6 @@ platform_init(unsigned long r3, unsigned ppc_md.nvram_read_val = todc_mc146818_read_val; ppc_md.nvram_write_val = todc_mc146818_write_val; -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/platforms/spruce.c linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/spruce.c --- linux-2.6.18-53.1.14/arch/ppc/platforms/spruce.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/platforms/spruce.c 2008-06-10 15:38:14.000000000 +0400 @@ -178,26 +178,32 @@ spruce_early_serial_map(void) serial_req.membase = (u_char *)UART0_IO_BASE; serial_req.regshift = 0; -#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) - gen550_init(0, &serial_req); -#endif #ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&serial_req) != 0) printk("Early serial init of port 0 failed\n"); #endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &serial_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif /* Assume early_serial_setup() doesn't modify serial_req */ serial_req.line = 1; serial_req.irq = UART1_INT; serial_req.membase = (u_char *)UART1_IO_BASE; -#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) - gen550_init(1, &serial_req); -#endif #ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&serial_req) != 0) printk("Early serial init of port 1 failed\n"); #endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(1, &serial_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &serial_req); +#endif } TODC_ALLOC(); @@ -316,7 +322,4 @@ platform_init(unsigned long r3, unsigned #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/Makefile linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/Makefile --- linux-2.6.18-53.1.14/arch/ppc/syslib/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/Makefile 2008-06-10 15:38:14.000000000 +0400 @@ -76,7 +76,6 @@ obj-$(CONFIG_PCI_8260) += m82xx_pci.o p obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o ifeq ($(CONFIG_PPC_GEN550),y) -obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o endif ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/gen550.h linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/gen550.h --- linux-2.6.18-53.1.14/arch/ppc/syslib/gen550.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/gen550.h 2008-06-10 15:38:14.000000000 +0400 @@ -11,4 +11,3 @@ extern void gen550_progress(char *, unsigned short); extern void gen550_init(int, struct uart_port *); -extern void gen550_kgdb_map_scc(void); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/ibm44x_common.c linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/ibm44x_common.c --- linux-2.6.18-53.1.14/arch/ppc/syslib/ibm44x_common.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/ibm44x_common.c 2008-06-10 15:38:14.000000000 +0400 @@ -192,9 +192,6 @@ void __init ibm44x_platform_init(unsigne #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif /* * The Abatron BDI JTAG debugger does not tolerate others diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/mv64x60.c linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/mv64x60.c --- linux-2.6.18-53.1.14/arch/ppc/syslib/mv64x60.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/mv64x60.c 2008-06-10 15:38:14.000000000 +0400 @@ -241,6 +241,12 @@ static struct resource mv64x60_mpsc0_res .end = MV64x60_IRQ_SDMA_0, .flags = IORESOURCE_IRQ, }, + [4] = { + .name = "mpsc 0 irq", + .start = MV64x60_IRQ_MPSC_0, + .end = MV64x60_IRQ_MPSC_0, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device mpsc0_device = { @@ -298,6 +304,12 @@ static struct resource mv64x60_mpsc1_res .end = MV64360_IRQ_SDMA_1, .flags = IORESOURCE_IRQ, }, + [4] = { + .name = "mpsc 1 irq", + .start = MV64360_IRQ_MPSC_1, + .end = MV64360_IRQ_MPSC_1, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device mpsc1_device = { @@ -1426,12 +1438,46 @@ mv64x60_pd_fixup(struct mv64x60_handle * static int __init mv64x60_add_pds(void) { - return platform_add_devices(mv64x60_pd_devs, - ARRAY_SIZE(mv64x60_pd_devs)); + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(mv64x60_pd_devs); i++) { + if (mv64x60_pd_devs[i]) { + ret = platform_device_register(mv64x60_pd_devs[i]); + } + if (ret) { + while (--i >= 0) + platform_device_unregister(mv64x60_pd_devs[i]); + break; + } + } + return ret; } arch_initcall(mv64x60_add_pds); /* + * mv64x60_early_get_pdev_data() + * + * Get the data associated with a platform device by name and number. + */ +struct platform_device * __init +mv64x60_early_get_pdev_data(const char *name, int id, int remove) +{ + int i; + struct platform_device *pdev; + + for (i = 0; i id == id && + !strcmp(pdev->name, name)) { + if (remove) + mv64x60_pd_devs[i] = NULL; + return pdev; + } + } + return NULL; +} + +/* ***************************************************************************** * * GT64260-Specific Routines @@ -1764,6 +1810,11 @@ gt64260a_chip_specific_init(struct mv64x r->start = MV64x60_IRQ_SDMA_0; r->end = MV64x60_IRQ_SDMA_0; } + if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 1)) + != NULL) { + r->start = GT64260_IRQ_MPSC_1; + r->end = GT64260_IRQ_MPSC_1; + } #endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/mv64x60_dbg.c linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/mv64x60_dbg.c --- linux-2.6.18-53.1.14/arch/ppc/syslib/mv64x60_dbg.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/mv64x60_dbg.c 2008-06-10 15:38:14.000000000 +0400 @@ -34,7 +34,7 @@ static struct mv64x60_handle mv64x60_dbg void mv64x60_progress_init(u32 base) { - mv64x60_dbg_bh.v_base = base; + mv64x60_dbg_bh.v_base = (void*)base; return; } @@ -69,53 +69,3 @@ mv64x60_mpsc_progress(char *s, unsigned return; } #endif /* CONFIG_SERIAL_TEXT_DEBUG */ - - -#if defined(CONFIG_KGDB) - -#if defined(CONFIG_KGDB_TTYS0) -#define KGDB_PORT 0 -#elif defined(CONFIG_KGDB_TTYS1) -#define KGDB_PORT 1 -#else -#error "Invalid kgdb_tty port" -#endif - -void -putDebugChar(unsigned char c) -{ - mv64x60_polled_putc(KGDB_PORT, (char)c); -} - -int -getDebugChar(void) -{ - unsigned char c; - - while (!mv64x60_polled_getc(KGDB_PORT, &c)); - return (int)c; -} - -void -putDebugString(char* str) -{ - while (*str != '\0') { - putDebugChar(*str); - str++; - } - putDebugChar('\r'); - return; -} - -void -kgdb_interruptible(int enable) -{ -} - -void -kgdb_map_scc(void) -{ - if (ppc_md.early_serial_map) - ppc_md.early_serial_map(); -} -#endif /* CONFIG_KGDB */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/ppc/syslib/ppc85xx_setup.c linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/ppc85xx_setup.c --- linux-2.6.18-53.1.14/arch/ppc/syslib/ppc85xx_setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/ppc/syslib/ppc85xx_setup.c 2008-06-10 15:38:14.000000000 +0400 @@ -69,7 +69,6 @@ mpc85xx_calibrate_decr(void) mtspr(SPRN_TCR, TCR_DIE); } -#ifdef CONFIG_SERIAL_8250 void __init mpc85xx_early_serial_map(void) { @@ -85,7 +84,7 @@ mpc85xx_early_serial_map(void) pdata[0].mapbase += binfo->bi_immr_base; pdata[0].membase = ioremap(pdata[0].mapbase, MPC85xx_UART0_SIZE); -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) memset(&serial_req, 0, sizeof (serial_req)); serial_req.iotype = UPIO_MEM; serial_req.mapbase = pdata[0].mapbase; @@ -93,18 +92,24 @@ mpc85xx_early_serial_map(void) serial_req.regshift = 0; gen550_init(0, &serial_req); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &serial_req); +#endif #endif pdata[1].uartclk = binfo->bi_busfreq; pdata[1].mapbase += binfo->bi_immr_base; pdata[1].membase = ioremap(pdata[1].mapbase, MPC85xx_UART0_SIZE); -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Assume gen550_init() doesn't modify serial_req */ serial_req.mapbase = pdata[1].mapbase; serial_req.membase = pdata[1].membase; gen550_init(1, &serial_req); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &serial_req); +#endif #endif } #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/Kconfig.debug linux-2.6.18-53.1.14.kgdb/arch/sh/Kconfig.debug --- linux-2.6.18-53.1.14/arch/sh/Kconfig.debug 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/Kconfig.debug 2008-06-10 15:38:50.000000000 +0400 @@ -29,96 +29,4 @@ config EARLY_PRINTK This option is only useful porting the kernel to a new machine, when the kernel may crash or hang before the serial console is initialised. If unsure, say N. - -config KGDB - bool "Include KGDB kernel debugger" - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -menu "KGDB configuration options" - depends on KGDB - -config MORE_COMPILE_OPTIONS - bool "Add any additional compile options" - help - If you want to add additional CFLAGS to the kernel build, enable this - option and then enter what you would like to add in the next question. - Note however that -g is already appended with the selection of KGDB. - -config COMPILE_OPTIONS - string "Additional compile arguments" - depends on MORE_COMPILE_OPTIONS - -config KGDB_NMI - bool "Enter KGDB on NMI" - default n - -config KGDB_THREAD - bool "Include KGDB thread support" - default y - -config SH_KGDB_CONSOLE - bool "Console messages through GDB" - default n - -config KGDB_SYSRQ - bool "Allow SysRq 'G' to enter KGDB" - default y - -config KGDB_KERNEL_ASSERTS - bool "Include KGDB kernel assertions" - default n - -comment "Serial port setup" - -config KGDB_DEFPORT - int "Port number (ttySCn)" - default "1" - -config KGDB_DEFBAUD - int "Baud rate" - default "115200" - -choice - prompt "Parity" - depends on KGDB - default KGDB_DEFPARITY_N - -config KGDB_DEFPARITY_N - bool "None" - -config KGDB_DEFPARITY_E - bool "Even" - -config KGDB_DEFPARITY_O - bool "Odd" - -endchoice - -choice - prompt "Data bits" - depends on KGDB - default KGDB_DEFBITS_8 - -config KGDB_DEFBITS_8 - bool "8" - -config KGDB_DEFBITS_7 - bool "7" - -endchoice - -endmenu - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if KGDB - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - endmenu diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/Makefile linux-2.6.18-53.1.14.kgdb/arch/sh/Makefile --- linux-2.6.18-53.1.14/arch/sh/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/Makefile 2008-06-10 15:38:50.000000000 +0400 @@ -43,7 +43,6 @@ cflags-$(CONFIG_CPU_SH4) += -m4 \ cflags-$(CONFIG_CPU_SH4A) += $(call cc-option,-m4a-nofpu,) cflags-$(CONFIG_SH_DSP) += -Wa,-dsp -cflags-$(CONFIG_SH_KGDB) += -g cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \ $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g') diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/boards/se/7751/setup.c linux-2.6.18-53.1.14.kgdb/arch/sh/boards/se/7751/setup.c --- linux-2.6.18-53.1.14/arch/sh/boards/se/7751/setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/boards/se/7751/setup.c 2008-06-10 15:38:50.000000000 +0400 @@ -17,10 +17,6 @@ #include #include -#ifdef CONFIG_SH_KGDB -#include -#endif - /* * Configure the Super I/O chip */ @@ -82,12 +78,6 @@ const char *get_system_type(void) return "7751 SolutionEngine"; } -#ifdef CONFIG_SH_KGDB -static int kgdb_uart_setup(void); -static struct kgdb_sermap kgdb_uart_sermap = -{ "ttyS", 0, kgdb_uart_setup, NULL }; -#endif - /* * Initialize the board */ @@ -95,133 +85,4 @@ void __init platform_setup(void) { /* Call init_smsc() replacement to set up SuperIO. */ /* XXX: RTC setting comes here */ -#ifdef CONFIG_SH_KGDB - kgdb_register_sermap(&kgdb_uart_sermap); -#endif -} - -/********************************************************************* - * Currently a hack (e.g. does not interact well w/serial.c, lots of * - * hardcoded stuff) but may be useful if SCI/F needs debugging. * - * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and * - * arch/i386/lib/kgdb_serial.c). * - *********************************************************************/ - -#ifdef CONFIG_SH_KGDB -#include -#include -#include -#include - -#define COM1_PORT 0x3f8 /* Base I/O address */ -#define COM1_IRQ 4 /* IRQ not used yet */ -#define COM2_PORT 0x2f8 /* Base I/O address */ -#define COM2_IRQ 3 /* IRQ not used yet */ - -#define SB_CLOCK 1843200 /* Serial baud clock */ -#define SB_BASE (SB_CLOCK/16) -#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS - -struct uart_port { - int base; -}; -#define UART_NPORTS 2 -struct uart_port uart_ports[] = { - { COM1_PORT }, - { COM2_PORT }, -}; -struct uart_port *kgdb_uart_port; - -#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg) -#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg) - -/* Basic read/write functions for the UART */ -#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE) -static int kgdb_uart_getchar(void) -{ - int lsr; - int c = -1; - - while (c == -1) { - lsr = UART_IN(UART_LSR); - if (lsr & UART_LSR_DR) - c = UART_IN(UART_RX); - if ((lsr & UART_LSR_RXCERR)) - c = -1; - } - return c; -} - -static void kgdb_uart_putchar(int c) -{ - while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0) - ; - UART_OUT(UART_TX, c); -} - -/* - * Initialize UART to configured/requested values. - * (But we don't interrupts yet, or interact w/serial.c) - */ -static int kgdb_uart_setup(void) -{ - int port; - int lcr = 0; - int bdiv = 0; - - if (kgdb_portnum >= UART_NPORTS) { - KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum); - return -1; - } - - kgdb_uart_port = &uart_ports[kgdb_portnum]; - - /* Init sequence from gdb_hook_interrupt */ - UART_IN(UART_RX); - UART_OUT(UART_IER, 0); - - UART_IN(UART_RX); /* Serial driver comments say */ - UART_IN(UART_IIR); /* this clears interrupt regs */ - UART_IN(UART_MSR); - - /* Figure basic LCR values */ - switch (kgdb_bits) { - case '7': - lcr |= UART_LCR_WLEN7; - break; - default: case '8': - lcr |= UART_LCR_WLEN8; - break; - } - switch (kgdb_parity) { - case 'O': - lcr |= UART_LCR_PARITY; - break; - case 'E': - lcr |= (UART_LCR_PARITY | UART_LCR_EPAR); - break; - default: break; - } - - /* Figure the baud rate divisor */ - bdiv = (SB_BASE/kgdb_baud); - - /* Set the baud rate and LCR values */ - UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB)); - UART_OUT(UART_DLL, (bdiv & 0xff)); - UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff)); - UART_OUT(UART_LCR, lcr); - - /* Set the MCR */ - UART_OUT(UART_MCR, SB_MCR); - - /* Turn off FIFOs for now */ - UART_OUT(UART_FCR, 0); - - /* Setup complete: initialize function pointers */ - kgdb_getchar = kgdb_uart_getchar; - kgdb_putchar = kgdb_uart_putchar; - - return 0; } -#endif /* CONFIG_SH_KGDB */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/Makefile --- linux-2.6.18-53.1.14/arch/sh/kernel/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/Makefile 2008-06-10 15:38:50.000000000 +0400 @@ -13,7 +13,7 @@ obj-y += cpu/ timers/ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_CF_ENABLER) += cf-enabler.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o -obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/cpu/sh3/ex.S linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/cpu/sh3/ex.S --- linux-2.6.18-53.1.14/arch/sh/kernel/cpu/sh3/ex.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/cpu/sh3/ex.S 2008-06-10 15:38:50.000000000 +0400 @@ -42,7 +42,7 @@ ENTRY(exception_handling_table) .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ ENTRY(nmi_slot) -#if defined (CONFIG_KGDB_NMI) +#if defined (CONFIG_KGDB) .long debug_enter /* 1C0 */ ! Allow trap to debugger #else .long exception_none /* 1C0 */ ! Not implemented yet diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/cpu/sh4/ex.S linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/cpu/sh4/ex.S --- linux-2.6.18-53.1.14/arch/sh/kernel/cpu/sh4/ex.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/cpu/sh4/ex.S 2008-06-10 15:38:50.000000000 +0400 @@ -46,7 +46,7 @@ ENTRY(exception_handling_table) .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ ENTRY(nmi_slot) -#if defined (CONFIG_KGDB_NMI) +#if defined (CONFIG_KGDB) .long debug_enter /* 1C0 */ ! Allow trap to debugger #else .long exception_none /* 1C0 */ ! Not implemented yet diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/entry.S linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/entry.S --- linux-2.6.18-53.1.14/arch/sh/kernel/entry.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/entry.S 2008-06-10 15:38:50.000000000 +0400 @@ -75,7 +75,7 @@ ENOSYS = 38 EINVAL = 22 -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) NMI_VEC = 0x1c0 ! Must catch early for debounce #endif @@ -227,31 +227,33 @@ call_dae: 2: .long do_address_error #endif /* CONFIG_MMU */ -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB) ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. ! If both are configured, handle the debug traps (breakpoints) in SW, ! but still allow BIOS traps to FW. .align 2 debug_kernel: -#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) +#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_KGDB) /* Force BIOS call to FW (debug_trap put TRA in r8) */ mov r8,r0 shlr2 r0 cmp/eq #0x3f,r0 bt debug_kernel_fw -#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ +#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_KGDB */ + .align 2 + .globl debug_enter debug_enter: -#if defined(CONFIG_SH_KGDB) +#if defined(CONFIG_KGDB) /* Jump to kgdb, pass stacked regs as arg */ debug_kernel_sw: mov.l 3f, r0 jmp @r0 mov r15, r4 .align 2 -3: .long kgdb_handle_exception -#endif /* CONFIG_SH_KGDB */ +3: .long kgdb_exception_handler +#endif /* CONFIG_KGDB */ #if defined(CONFIG_SH_STANDARD_BIOS) /* Unwind the stack and jmp to the debug entry */ @@ -293,12 +295,12 @@ debug_kernel_fw: 2: .long gdb_vbr_vector #endif /* CONFIG_SH_STANDARD_BIOS */ -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB */ .align 2 debug_trap: -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB) mov #OFF_SR, r0 mov.l @(r0,r15), r0 ! get status register shll r0 @@ -642,7 +644,7 @@ skip_restore: 6: or k0, k2 ! Set the IMASK-bits ldc k2, ssr ! -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) ! Clear in_nmi mov.l 4f, k0 mov #0, k1 @@ -694,7 +696,7 @@ tlb_miss: interrupt: mov.l 2f, k2 mov.l 3f, k3 -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) ! Debounce (filter nested NMI) mov.l @k2, k0 mov.l 5f, k1 @@ -709,7 +711,7 @@ interrupt: 5: .long NMI_VEC 6: .long in_nmi 0: -#endif /* defined(CONFIG_KGDB_NMI) */ +#endif /* defined(CONFIG_KGDB) */ bra handle_exception mov.l @k2, k2 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/kgdb-jmp.S linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb-jmp.S --- linux-2.6.18-53.1.14/arch/sh/kernel/kgdb-jmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb-jmp.S 2008-06-10 15:38:50.000000000 +0400 @@ -0,0 +1,32 @@ +#include + +ENTRY(kgdb_fault_setjmp) + add #(9*4), r4 + sts.l pr, @-r4 + mov.l r15, @-r4 + mov.l r14, @-r4 + mov.l r13, @-r4 + mov.l r12, @-r4 + mov.l r11, @-r4 + mov.l r10, @-r4 + mov.l r9, @-r4 + mov.l r8, @-r4 + rts + mov #0, r0 + +ENTRY(kgdb_fault_longjmp) + mov.l @r4+, r8 + mov.l @r4+, r9 + mov.l @r4+, r10 + mov.l @r4+, r11 + mov.l @r4+, r12 + mov.l @r4+, r13 + mov.l @r4+, r14 + mov.l @r4+, r15 + lds.l @r4+, pr + mov r5, r0 + tst r0, r0 + bf 1f + mov #1, r0 +1: rts + nop diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/sh/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb.c 2008-06-10 15:38:50.000000000 +0400 @@ -0,0 +1,363 @@ +/* + * arch/sh/kernel/kgdb.c + * + * Contains SH-specific low-level support for KGDB. + * + * Containes extracts from code by Glenn Engel, Jim Kingdon, + * David Grothe , Tigran Aivazian , + * Amit S. Kale , William Gatliff , + * Ben Lee, Steve Chamberlain and Benoit Miller , + * Henry Bell and Jeremy Siegel + * + * Maintainer: Tom Rini + * + * 2004 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void per_cpu_trap_init(void); +extern atomic_t cpu_doing_single_step; + +/* Function pointers for linkage */ +static struct kgdb_regs trap_registers; + +/* Globals. */ +char in_nmi; /* Set during NMI to prevent reentry */ + +/* TRA differs sh3/4 */ +#if defined(CONFIG_CPU_SH3) +#define TRA 0xffffffd0 +#elif defined(CONFIG_CPU_SH4) +#define TRA 0xff000020 +#endif + +/* Macros for single step instruction identification */ +#define OPCODE_BT(op) (((op) & 0xff00) == 0x8900) +#define OPCODE_BF(op) (((op) & 0xff00) == 0x8b00) +#define OPCODE_BTF_DISP(op) (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \ + (((op) & 0x7f ) << 1)) +#define OPCODE_BFS(op) (((op) & 0xff00) == 0x8f00) +#define OPCODE_BTS(op) (((op) & 0xff00) == 0x8d00) +#define OPCODE_BRA(op) (((op) & 0xf000) == 0xa000) +#define OPCODE_BRA_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ + (((op) & 0x7ff) << 1)) +#define OPCODE_BRAF(op) (((op) & 0xf0ff) == 0x0023) +#define OPCODE_BRAF_REG(op) (((op) & 0x0f00) >> 8) +#define OPCODE_BSR(op) (((op) & 0xf000) == 0xb000) +#define OPCODE_BSR_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ + (((op) & 0x7ff) << 1)) +#define OPCODE_BSRF(op) (((op) & 0xf0ff) == 0x0003) +#define OPCODE_BSRF_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_JMP(op) (((op) & 0xf0ff) == 0x402b) +#define OPCODE_JMP_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_JSR(op) (((op) & 0xf0ff) == 0x400b) +#define OPCODE_JSR_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_RTS(op) ((op) == 0xb) +#define OPCODE_RTE(op) ((op) == 0x2b) + +#define SR_T_BIT_MASK 0x1 +#define STEP_OPCODE 0xc320 +#define BIOS_CALL_TRAP 0x3f + +/* Exception codes as per SH-4 core manual */ +#define ADDRESS_ERROR_LOAD_VEC 7 +#define ADDRESS_ERROR_STORE_VEC 8 +#define TRAP_VEC 11 +#define INVALID_INSN_VEC 12 +#define INVALID_SLOT_VEC 13 +#define NMI_VEC 14 +#define SERIAL_BREAK_VEC 58 + +/* Misc static */ +static int stepped_address; +static short stepped_opcode; + +/* Translate SH-3/4 exception numbers to unix-like signal values */ +static int compute_signal(const int excep_code) +{ + switch (excep_code) { + case INVALID_INSN_VEC: + case INVALID_SLOT_VEC: + return SIGILL; + case ADDRESS_ERROR_LOAD_VEC: + case ADDRESS_ERROR_STORE_VEC: + return SIGSEGV; + case SERIAL_BREAK_VEC: + case NMI_VEC: + return SIGINT; + default: + /* Act like it was a break/trap. */ + return SIGTRAP; + } +} + +/* + * Translate the registers of the system into the format that GDB wants. Since + * we use a local structure to store things, instead of getting them out + * of pt_regs, we can just do a memcpy. + */ +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *ign) +{ + memcpy(gdb_regs, &trap_registers, sizeof(trap_registers)); +} + +/* + * On SH we save: r1 (prev->thread.sp) r2 (prev->thread.pc) r4 (prev) r5 (next) + * r6 (next->thread.sp) r7 (next->thread.pc) + */ +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + int count; + + for (count = 0; count < 16; count++) + *(gdb_regs++) = 0; + *(gdb_regs++) = p->thread.pc; + *(gdb_regs++) = 0; + *(gdb_regs++) = 0; + *(gdb_regs++) = 0; + *(gdb_regs++) = 0; + *(gdb_regs++) = 0; + *(gdb_regs++) = 0; +} + +/* + * Translate the registers values that GDB has given us back into the + * format of the system. See the comment above about memcpy. + */ +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *ign) +{ + memcpy(&trap_registers, gdb_regs, sizeof(trap_registers)); +} + +/* Calculate the new address for after a step */ +static short *get_step_address(void) +{ + short op = *(short *)trap_registers.pc; + long addr; + + /* BT */ + if (OPCODE_BT(op)) { + if (trap_registers.sr & SR_T_BIT_MASK) + addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); + else + addr = trap_registers.pc + 2; + } + + /* BTS */ + else if (OPCODE_BTS(op)) { + if (trap_registers.sr & SR_T_BIT_MASK) + addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); + else + addr = trap_registers.pc + 4; /* Not in delay slot */ + } + + /* BF */ + else if (OPCODE_BF(op)) { + if (!(trap_registers.sr & SR_T_BIT_MASK)) + addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); + else + addr = trap_registers.pc + 2; + } + + /* BFS */ + else if (OPCODE_BFS(op)) { + if (!(trap_registers.sr & SR_T_BIT_MASK)) + addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); + else + addr = trap_registers.pc + 4; /* Not in delay slot */ + } + + /* BRA */ + else if (OPCODE_BRA(op)) + addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op); + + /* BRAF */ + else if (OPCODE_BRAF(op)) + addr = trap_registers.pc + 4 + + trap_registers.regs[OPCODE_BRAF_REG(op)]; + + /* BSR */ + else if (OPCODE_BSR(op)) + addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op); + + /* BSRF */ + else if (OPCODE_BSRF(op)) + addr = trap_registers.pc + 4 + + trap_registers.regs[OPCODE_BSRF_REG(op)]; + + /* JMP */ + else if (OPCODE_JMP(op)) + addr = trap_registers.regs[OPCODE_JMP_REG(op)]; + + /* JSR */ + else if (OPCODE_JSR(op)) + addr = trap_registers.regs[OPCODE_JSR_REG(op)]; + + /* RTS */ + else if (OPCODE_RTS(op)) + addr = trap_registers.pr; + + /* RTE */ + else if (OPCODE_RTE(op)) + addr = trap_registers.regs[15]; + + /* Other */ + else + addr = trap_registers.pc + 2; + + kgdb_flush_icache_range(addr, addr + 2); + return (short *)addr; +} + +/* The command loop, read and act on requests */ +int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *ign) +{ + unsigned long addr; + char *ptr = &remcom_in_buffer[1]; + + /* Examine first char of buffer to see what we need to do */ + switch (remcom_in_buffer[0]) { + case 'c': /* Continue at address AA..AA (optional) */ + case 's': /* Step one instruction from AA..AA */ + /* Try to read optional parameter, PC unchanged if none */ + if (kgdb_hex2long(&ptr, &addr)) + trap_registers.pc = addr; + + atomic_set(&cpu_doing_single_step, -1); + if (remcom_in_buffer[0] == 's') { + /* Replace the instruction immediately after the + * current instruction (i.e. next in the expected + * flow of control) with a trap instruction, so that + * returning will cause only a single instruction to + * be executed. Note that this model is slightly + * broken for instructions with delay slots + * (e.g. B[TF]S, BSR, BRA etc), where both the branch + * and the instruction in the delay slot will be + * executed. + */ + /* Determine where the target instruction will send + * us to */ + unsigned short *next_addr = get_step_address(); + stepped_address = (int)next_addr; + + /* Replace it */ + stepped_opcode = *(short *)next_addr; + *next_addr = STEP_OPCODE; + + /* Flush and return */ + kgdb_flush_icache_range((long)next_addr, + (long)next_addr + 2); + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + return 0; + } + return -1; +} + +/* + * When an exception has occured, we are called. We need to set things + * up so that we can call kgdb_handle_exception to handle requests from + * the remote GDB. + */ +void kgdb_exception_handler(struct pt_regs *regs) +{ + int excep_code, vbr_val; + int count; + + /* Copy kernel regs (from stack) */ + for (count = 0; count < 16; count++) + trap_registers.regs[count] = regs->regs[count]; + trap_registers.pc = regs->pc; + trap_registers.pr = regs->pr; + trap_registers.sr = regs->sr; + trap_registers.gbr = regs->gbr; + trap_registers.mach = regs->mach; + trap_registers.macl = regs->macl; + + __asm__ __volatile__("stc vbr, %0":"=r"(vbr_val)); + trap_registers.vbr = vbr_val; + + /* Get the execption code. */ + __asm__ __volatile__("stc r2_bank, %0":"=r"(excep_code)); + + excep_code >>= 5; + + /* If we got an NMI, and KGDB is not yet initialized, call + * breakpoint() to try and initialize everything for us. */ + if (excep_code == NMI_VEC && !kgdb_initialized) { + breakpoint(); + return; + } + + /* TRAP_VEC exception indicates a software trap inserted in place of + * code by GDB so back up PC by one instruction, as this instruction + * will later be replaced by its original one. Do NOT do this for + * trap 0xff, since that indicates a compiled-in breakpoint which + * will not be replaced (and we would retake the trap forever) */ + if (excep_code == TRAP_VEC && + (*(volatile unsigned long *)TRA != (0xff << 2))) + trap_registers.pc -= 2; + + /* If we have been single-stepping, put back the old instruction. + * We use stepped_address in case we have stopped more than one + * instruction away. */ + if (stepped_opcode != 0) { + *(short *)stepped_address = stepped_opcode; + kgdb_flush_icache_range(stepped_address, stepped_address + 2); + } + stepped_opcode = 0; + + /* Call the stub to do the processing. Note that not everything we + * need to send back and forth lives in pt_regs. */ + kgdb_handle_exception(excep_code, compute_signal(excep_code), 0, regs); + + /* Copy back the (maybe modified) registers */ + for (count = 0; count < 16; count++) + regs->regs[count] = trap_registers.regs[count]; + regs->pc = trap_registers.pc; + regs->pr = trap_registers.pr; + regs->sr = trap_registers.sr; + regs->gbr = trap_registers.gbr; + regs->mach = trap_registers.mach; + regs->macl = trap_registers.macl; + + vbr_val = trap_registers.vbr; + __asm__ __volatile__("ldc %0, vbr": :"r"(vbr_val)); +} + +int __init kgdb_arch_init(void) +{ + per_cpu_trap_init(); + + return 0; +} + +struct kgdb_arch arch_kgdb_ops = { +#ifdef CONFIG_CPU_LITTLE_ENDIAN + .gdb_bpt_instr = {0xff, 0xc3}, +#else + .gdb_bpt_instr = {0xc3, 0xff}, +#endif +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/kgdb_jmp.S linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb_jmp.S --- linux-2.6.18-53.1.14/arch/sh/kernel/kgdb_jmp.S 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb_jmp.S 1970-01-01 03:00:00.000000000 +0300 @@ -1,33 +0,0 @@ -#include - -ENTRY(setjmp) - add #(9*4), r4 - sts.l pr, @-r4 - mov.l r15, @-r4 - mov.l r14, @-r4 - mov.l r13, @-r4 - mov.l r12, @-r4 - mov.l r11, @-r4 - mov.l r10, @-r4 - mov.l r9, @-r4 - mov.l r8, @-r4 - rts - mov #0, r0 - -ENTRY(longjmp) - mov.l @r4+, r8 - mov.l @r4+, r9 - mov.l @r4+, r10 - mov.l @r4+, r11 - mov.l @r4+, r12 - mov.l @r4+, r13 - mov.l @r4+, r14 - mov.l @r4+, r15 - lds.l @r4+, pr - mov r5, r0 - tst r0, r0 - bf 1f - mov #1, r0 ! in case val==0 -1: rts - nop - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/kgdb_stub.c linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb_stub.c --- linux-2.6.18-53.1.14/arch/sh/kernel/kgdb_stub.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/kgdb_stub.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,1491 +0,0 @@ -/* - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Containes extracts from code by Glenn Engel, Jim Kingdon, - * David Grothe , Tigran Aivazian , - * Amit S. Kale , William Gatliff , - * Ben Lee, Steve Chamberlain and Benoit Miller . - * - * This version by Henry Bell - * Minor modifications by Jeremy Siegel - * - * Contains low-level support for remote debug using GDB. - * - * To enable debugger support, two things need to happen. A call to - * set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * A breakpoint also needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint() which does - * a trapa if the initialisation phase has been successfully completed. - * - * In this case, set_debug_traps() is not used to "take over" exceptions; - * other kernel code is modified instead to enter the kgdb functions here - * when appropriate (see entry.S for breakpoint traps and NMI interrupts, - * see traps.c for kernel error exceptions). - * - * The following gdb commands are supported: - * - * Command Function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * XAA..AA,LLLL: Same, but data is binary (not hex) OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * CNN; Resume at current address with signal SNN - * CNN;AA..AA Resume at address AA..AA with signal SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * SNN; Step one instruction with signal SNN - * SNNAA..AA Step one instruction from AA..AA w/NN SNN - * - * k kill (Detach GDB) - * - * d Toggle debug flag - * D Detach GDB - * - * Hct Set thread t for operations, OK or ENN - * c = 'c' (step, cont), c = 'g' (other - * operations) - * - * qC Query current thread ID QCpid - * qfThreadInfo Get list of current threads (first) m - * qsThreadInfo " " " " " (subsequent) - * qOffsets Get section offsets Text=x;Data=y;Bss=z - * - * TXX Find if thread XX is alive OK or ENN - * ? What was the last sigval ? SNN (signal NN) - * O Output to GDB console - * - * Remote communication protocol. - * - * A debug packet whose contents are is encapsulated for - * transmission in the form: - * - * $ # CSUM1 CSUM2 - * - * must be ASCII alphanumeric and cannot include characters - * '$' or '#'. If starts with two characters followed by - * ':', then the existing stubs interpret this as a sequence number. - * - * CSUM1 and CSUM2 are ascii hex representation of an 8-bit - * checksum of , the most significant nibble is sent first. - * the hex digits 0-9,a-f are used. - * - * Receiver responds with: - * - * + - if CSUM is correct and ready for next packet - * - - if CSUM is incorrect - * - * Responses can be run-length encoded to save space. A '*' means that - * the next character is an ASCII encoding giving a repeat count which - * stands for that many repititions of the character preceding the '*'. - * The encoding is n+29, yielding a printable character where n >=3 - * (which is where RLE starts to win). Don't use an n > 126. - * - * So "0* " means the same as "0000". - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SH_KGDB_CONSOLE -#include -#endif - -/* Function pointers for linkage */ -kgdb_debug_hook_t *kgdb_debug_hook; -kgdb_bus_error_hook_t *kgdb_bus_err_hook; - -int (*kgdb_getchar)(void); -void (*kgdb_putchar)(int); - -static void put_debug_char(int c) -{ - if (!kgdb_putchar) - return; - (*kgdb_putchar)(c); -} -static int get_debug_char(void) -{ - if (!kgdb_getchar) - return -1; - return (*kgdb_getchar)(); -} - -/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */ -#define BUFMAX 1024 -#define NUMREGBYTES (MAXREG*4) -#define OUTBUFMAX (NUMREGBYTES*2+512) - -enum regs { - R0 = 0, R1, R2, R3, R4, R5, R6, R7, - R8, R9, R10, R11, R12, R13, R14, R15, - PC, PR, GBR, VBR, MACH, MACL, SR, - /* */ - MAXREG -}; - -static unsigned int registers[MAXREG]; -struct kgdb_regs trap_registers; - -char kgdb_in_gdb_mode; -char in_nmi; /* Set during NMI to prevent reentry */ -int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ -int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */ -int kgdb_halt; - -/* Exposed for user access */ -struct task_struct *kgdb_current; -unsigned int kgdb_g_imask; -int kgdb_trapa_val; -int kgdb_excode; - -/* Default values for SCI (can override via kernel args in setup.c) */ -#ifndef CONFIG_KGDB_DEFPORT -#define CONFIG_KGDB_DEFPORT 1 -#endif - -#ifndef CONFIG_KGDB_DEFBAUD -#define CONFIG_KGDB_DEFBAUD 115200 -#endif - -#if defined(CONFIG_KGDB_DEFPARITY_E) -#define CONFIG_KGDB_DEFPARITY 'E' -#elif defined(CONFIG_KGDB_DEFPARITY_O) -#define CONFIG_KGDB_DEFPARITY 'O' -#else /* CONFIG_KGDB_DEFPARITY_N */ -#define CONFIG_KGDB_DEFPARITY 'N' -#endif - -#ifdef CONFIG_KGDB_DEFBITS_7 -#define CONFIG_KGDB_DEFBITS '7' -#else /* CONFIG_KGDB_DEFBITS_8 */ -#define CONFIG_KGDB_DEFBITS '8' -#endif - -/* SCI/UART settings, used in kgdb_console_setup() */ -int kgdb_portnum = CONFIG_KGDB_DEFPORT; -int kgdb_baud = CONFIG_KGDB_DEFBAUD; -char kgdb_parity = CONFIG_KGDB_DEFPARITY; -char kgdb_bits = CONFIG_KGDB_DEFBITS; - -/* Jump buffer for setjmp/longjmp */ -static jmp_buf rem_com_env; - -/* TRA differs sh3/4 */ -#if defined(CONFIG_CPU_SH3) -#define TRA 0xffffffd0 -#elif defined(CONFIG_CPU_SH4) -#define TRA 0xff000020 -#endif - -/* Macros for single step instruction identification */ -#define OPCODE_BT(op) (((op) & 0xff00) == 0x8900) -#define OPCODE_BF(op) (((op) & 0xff00) == 0x8b00) -#define OPCODE_BTF_DISP(op) (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \ - (((op) & 0x7f ) << 1)) -#define OPCODE_BFS(op) (((op) & 0xff00) == 0x8f00) -#define OPCODE_BTS(op) (((op) & 0xff00) == 0x8d00) -#define OPCODE_BRA(op) (((op) & 0xf000) == 0xa000) -#define OPCODE_BRA_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ - (((op) & 0x7ff) << 1)) -#define OPCODE_BRAF(op) (((op) & 0xf0ff) == 0x0023) -#define OPCODE_BRAF_REG(op) (((op) & 0x0f00) >> 8) -#define OPCODE_BSR(op) (((op) & 0xf000) == 0xb000) -#define OPCODE_BSR_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ - (((op) & 0x7ff) << 1)) -#define OPCODE_BSRF(op) (((op) & 0xf0ff) == 0x0003) -#define OPCODE_BSRF_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_JMP(op) (((op) & 0xf0ff) == 0x402b) -#define OPCODE_JMP_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_JSR(op) (((op) & 0xf0ff) == 0x400b) -#define OPCODE_JSR_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_RTS(op) ((op) == 0xb) -#define OPCODE_RTE(op) ((op) == 0x2b) - -#define SR_T_BIT_MASK 0x1 -#define STEP_OPCODE 0xc320 -#define BIOS_CALL_TRAP 0x3f - -/* Exception codes as per SH-4 core manual */ -#define ADDRESS_ERROR_LOAD_VEC 7 -#define ADDRESS_ERROR_STORE_VEC 8 -#define TRAP_VEC 11 -#define INVALID_INSN_VEC 12 -#define INVALID_SLOT_VEC 13 -#define NMI_VEC 14 -#define USER_BREAK_VEC 15 -#define SERIAL_BREAK_VEC 58 - -/* Misc static */ -static int stepped_address; -static short stepped_opcode; -static const char hexchars[] = "0123456789abcdef"; -static char in_buffer[BUFMAX]; -static char out_buffer[OUTBUFMAX]; - -static void kgdb_to_gdb(const char *s); - -#ifdef CONFIG_KGDB_THREAD -static struct task_struct *trapped_thread; -static struct task_struct *current_thread; -typedef unsigned char threadref[8]; -#define BUF_THREAD_ID_SIZE 16 -#endif - -/* Return addr as a real volatile address */ -static inline unsigned int ctrl_inl(const unsigned long addr) -{ - return *(volatile unsigned long *) addr; -} - -/* Correctly set *addr using volatile */ -static inline void ctrl_outl(const unsigned int b, unsigned long addr) -{ - *(volatile unsigned long *) addr = b; -} - -/* Get high hex bits */ -static char highhex(const int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -/* Get low hex bits */ -static char lowhex(const int x) -{ - return hexchars[x & 0xf]; -} - -/* Convert ch to hex */ -static int hex(const char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return (-1); -} - -/* Convert the memory pointed to by mem into hex, placing result in buf. - Returns a pointer to the last char put in buf (null) */ -static char *mem_to_hex(const char *mem, char *buf, const int count) -{ - int i; - int ch; - unsigned short s_val; - unsigned long l_val; - - /* Check for 16 or 32 */ - if (count == 2 && ((long) mem & 1) == 0) { - s_val = *(unsigned short *) mem; - mem = (char *) &s_val; - } else if (count == 4 && ((long) mem & 3) == 0) { - l_val = *(unsigned long *) mem; - mem = (char *) &l_val; - } - for (i = 0; i < count; i++) { - ch = *mem++; - *buf++ = highhex(ch); - *buf++ = lowhex(ch); - } - *buf = 0; - return (buf); -} - -/* Convert the hex array pointed to by buf into binary, to be placed in mem. - Return a pointer to the character after the last byte written */ -static char *hex_to_mem(const char *buf, char *mem, const int count) -{ - int i; - unsigned char ch; - - for (i = 0; i < count; i++) { - ch = hex(*buf++) << 4; - ch = ch + hex(*buf++); - *mem++ = ch; - } - return (mem); -} - -/* While finding valid hex chars, convert to an integer, then return it */ -static int hex_to_int(char **ptr, int *int_value) -{ - int num_chars = 0; - int hex_value; - - *int_value = 0; - - while (**ptr) { - hex_value = hex(**ptr); - if (hex_value >= 0) { - *int_value = (*int_value << 4) | hex_value; - num_chars++; - } else - break; - (*ptr)++; - } - return num_chars; -} - -/* Copy the binary array pointed to by buf into mem. Fix $, #, - and 0x7d escaped with 0x7d. Return a pointer to the character - after the last byte written. */ -static char *ebin_to_mem(const char *buf, char *mem, int count) -{ - for (; count > 0; count--, buf++) { - if (*buf == 0x7d) - *mem++ = *(++buf) ^ 0x20; - else - *mem++ = *buf; - } - return mem; -} - -/* Pack a hex byte */ -static char *pack_hex_byte(char *pkt, int byte) -{ - *pkt++ = hexchars[(byte >> 4) & 0xf]; - *pkt++ = hexchars[(byte & 0xf)]; - return pkt; -} - -#ifdef CONFIG_KGDB_THREAD - -/* Pack a thread ID */ -static char *pack_threadid(char *pkt, threadref * id) -{ - char *limit; - unsigned char *altid; - - altid = (unsigned char *) id; - - limit = pkt + BUF_THREAD_ID_SIZE; - while (pkt < limit) - pkt = pack_hex_byte(pkt, *altid++); - return pkt; -} - -/* Convert an integer into our threadref */ -static void int_to_threadref(threadref * id, const int value) -{ - unsigned char *scan = (unsigned char *) id; - int i = 4; - - while (i--) - *scan++ = 0; - - *scan++ = (value >> 24) & 0xff; - *scan++ = (value >> 16) & 0xff; - *scan++ = (value >> 8) & 0xff; - *scan++ = (value & 0xff); -} - -/* Return a task structure ptr for a particular pid */ -static struct task_struct *get_thread(int pid) -{ - struct task_struct *thread; - - /* Use PID_MAX w/gdb for pid 0 */ - if (pid == PID_MAX) pid = 0; - - /* First check via PID */ - thread = find_task_by_pid(pid); - - if (thread) - return thread; - - /* Start at the start */ - thread = init_tasks[0]; - - /* Walk along the linked list of tasks */ - do { - if (thread->pid == pid) - return thread; - thread = thread->next_task; - } while (thread != init_tasks[0]); - - return NULL; -} - -#endif /* CONFIG_KGDB_THREAD */ - -/* Scan for the start char '$', read the packet and check the checksum */ -static void get_packet(char *buffer, int buflen) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - char ch; - - do { - /* Ignore everything until the start character */ - while ((ch = get_debug_char()) != '$'); - - checksum = 0; - xmitcsum = -1; - count = 0; - - /* Now, read until a # or end of buffer is found */ - while (count < (buflen - 1)) { - ch = get_debug_char(); - - if (ch == '#') - break; - - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - buffer[count] = 0; - - /* Continue to read checksum following # */ - if (ch == '#') { - xmitcsum = hex(get_debug_char()) << 4; - xmitcsum += hex(get_debug_char()); - - /* Checksum */ - if (checksum != xmitcsum) - put_debug_char('-'); /* Failed checksum */ - else { - /* Ack successful transfer */ - put_debug_char('+'); - - /* If a sequence char is present, reply - the sequence ID */ - if (buffer[2] == ':') { - put_debug_char(buffer[0]); - put_debug_char(buffer[1]); - - /* Remove sequence chars from buffer */ - count = strlen(buffer); - for (i = 3; i <= count; i++) - buffer[i - 3] = buffer[i]; - } - } - } - } - while (checksum != xmitcsum); /* Keep trying while we fail */ -} - -/* Send the packet in the buffer with run-length encoding */ -static void put_packet(char *buffer) -{ - int checksum; - char *src; - int runlen; - int encode; - - do { - src = buffer; - put_debug_char('$'); - checksum = 0; - - /* Continue while we still have chars left */ - while (*src) { - /* Check for runs up to 99 chars long */ - for (runlen = 1; runlen < 99; runlen++) { - if (src[0] != src[runlen]) - break; - } - - if (runlen > 3) { - /* Got a useful amount, send encoding */ - encode = runlen + ' ' - 4; - put_debug_char(*src); checksum += *src; - put_debug_char('*'); checksum += '*'; - put_debug_char(encode); checksum += encode; - src += runlen; - } else { - /* Otherwise just send the current char */ - put_debug_char(*src); checksum += *src; - src += 1; - } - } - - /* '#' Separator, put high and low components of checksum */ - put_debug_char('#'); - put_debug_char(highhex(checksum)); - put_debug_char(lowhex(checksum)); - } - while ((get_debug_char()) != '+'); /* While no ack */ -} - -/* A bus error has occurred - perform a longjmp to return execution and - allow handling of the error */ -static void kgdb_handle_bus_error(void) -{ - longjmp(rem_com_env, 1); -} - -/* Translate SH-3/4 exception numbers to unix-like signal values */ -static int compute_signal(const int excep_code) -{ - int sigval; - - switch (excep_code) { - - case INVALID_INSN_VEC: - case INVALID_SLOT_VEC: - sigval = SIGILL; - break; - case ADDRESS_ERROR_LOAD_VEC: - case ADDRESS_ERROR_STORE_VEC: - sigval = SIGSEGV; - break; - - case SERIAL_BREAK_VEC: - case NMI_VEC: - sigval = SIGINT; - break; - - case USER_BREAK_VEC: - case TRAP_VEC: - sigval = SIGTRAP; - break; - - default: - sigval = SIGBUS; /* "software generated" */ - break; - } - - return (sigval); -} - -/* Make a local copy of the registers passed into the handler (bletch) */ -static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs, - int *gdb_regs) -{ - gdb_regs[R0] = regs->regs[R0]; - gdb_regs[R1] = regs->regs[R1]; - gdb_regs[R2] = regs->regs[R2]; - gdb_regs[R3] = regs->regs[R3]; - gdb_regs[R4] = regs->regs[R4]; - gdb_regs[R5] = regs->regs[R5]; - gdb_regs[R6] = regs->regs[R6]; - gdb_regs[R7] = regs->regs[R7]; - gdb_regs[R8] = regs->regs[R8]; - gdb_regs[R9] = regs->regs[R9]; - gdb_regs[R10] = regs->regs[R10]; - gdb_regs[R11] = regs->regs[R11]; - gdb_regs[R12] = regs->regs[R12]; - gdb_regs[R13] = regs->regs[R13]; - gdb_regs[R14] = regs->regs[R14]; - gdb_regs[R15] = regs->regs[R15]; - gdb_regs[PC] = regs->pc; - gdb_regs[PR] = regs->pr; - gdb_regs[GBR] = regs->gbr; - gdb_regs[MACH] = regs->mach; - gdb_regs[MACL] = regs->macl; - gdb_regs[SR] = regs->sr; - gdb_regs[VBR] = regs->vbr; -} - -/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ -static void gdb_regs_to_kgdb_regs(const int *gdb_regs, - struct kgdb_regs *regs) -{ - regs->regs[R0] = gdb_regs[R0]; - regs->regs[R1] = gdb_regs[R1]; - regs->regs[R2] = gdb_regs[R2]; - regs->regs[R3] = gdb_regs[R3]; - regs->regs[R4] = gdb_regs[R4]; - regs->regs[R5] = gdb_regs[R5]; - regs->regs[R6] = gdb_regs[R6]; - regs->regs[R7] = gdb_regs[R7]; - regs->regs[R8] = gdb_regs[R8]; - regs->regs[R9] = gdb_regs[R9]; - regs->regs[R10] = gdb_regs[R10]; - regs->regs[R11] = gdb_regs[R11]; - regs->regs[R12] = gdb_regs[R12]; - regs->regs[R13] = gdb_regs[R13]; - regs->regs[R14] = gdb_regs[R14]; - regs->regs[R15] = gdb_regs[R15]; - regs->pc = gdb_regs[PC]; - regs->pr = gdb_regs[PR]; - regs->gbr = gdb_regs[GBR]; - regs->mach = gdb_regs[MACH]; - regs->macl = gdb_regs[MACL]; - regs->sr = gdb_regs[SR]; - regs->vbr = gdb_regs[VBR]; -} - -#ifdef CONFIG_KGDB_THREAD -/* Make a local copy of registers from the specified thread */ -asmlinkage void ret_from_fork(void); -static void thread_regs_to_gdb_regs(const struct task_struct *thread, - int *gdb_regs) -{ - int regno; - int *tregs; - - /* Initialize to zero */ - for (regno = 0; regno < MAXREG; regno++) - gdb_regs[regno] = 0; - - /* Just making sure... */ - if (thread == NULL) - return; - - /* A new fork has pt_regs on the stack from a fork() call */ - if (thread->thread.pc == (unsigned long)ret_from_fork) { - - int vbr_val; - struct pt_regs *kregs; - kregs = (struct pt_regs*)thread->thread.sp; - - gdb_regs[R0] = kregs->regs[R0]; - gdb_regs[R1] = kregs->regs[R1]; - gdb_regs[R2] = kregs->regs[R2]; - gdb_regs[R3] = kregs->regs[R3]; - gdb_regs[R4] = kregs->regs[R4]; - gdb_regs[R5] = kregs->regs[R5]; - gdb_regs[R6] = kregs->regs[R6]; - gdb_regs[R7] = kregs->regs[R7]; - gdb_regs[R8] = kregs->regs[R8]; - gdb_regs[R9] = kregs->regs[R9]; - gdb_regs[R10] = kregs->regs[R10]; - gdb_regs[R11] = kregs->regs[R11]; - gdb_regs[R12] = kregs->regs[R12]; - gdb_regs[R13] = kregs->regs[R13]; - gdb_regs[R14] = kregs->regs[R14]; - gdb_regs[R15] = kregs->regs[R15]; - gdb_regs[PC] = kregs->pc; - gdb_regs[PR] = kregs->pr; - gdb_regs[GBR] = kregs->gbr; - gdb_regs[MACH] = kregs->mach; - gdb_regs[MACL] = kregs->macl; - gdb_regs[SR] = kregs->sr; - - asm("stc vbr, %0":"=r"(vbr_val)); - gdb_regs[VBR] = vbr_val; - return; - } - - /* Otherwise, we have only some registers from switch_to() */ - tregs = (int *)thread->thread.sp; - gdb_regs[R15] = (int)tregs; - gdb_regs[R14] = *tregs++; - gdb_regs[R13] = *tregs++; - gdb_regs[R12] = *tregs++; - gdb_regs[R11] = *tregs++; - gdb_regs[R10] = *tregs++; - gdb_regs[R9] = *tregs++; - gdb_regs[R8] = *tregs++; - gdb_regs[PR] = *tregs++; - gdb_regs[GBR] = *tregs++; - gdb_regs[PC] = thread->thread.pc; -} -#endif /* CONFIG_KGDB_THREAD */ - -/* Calculate the new address for after a step */ -static short *get_step_address(void) -{ - short op = *(short *) trap_registers.pc; - long addr; - - /* BT */ - if (OPCODE_BT(op)) { - if (trap_registers.sr & SR_T_BIT_MASK) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 2; - } - - /* BTS */ - else if (OPCODE_BTS(op)) { - if (trap_registers.sr & SR_T_BIT_MASK) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 4; /* Not in delay slot */ - } - - /* BF */ - else if (OPCODE_BF(op)) { - if (!(trap_registers.sr & SR_T_BIT_MASK)) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 2; - } - - /* BFS */ - else if (OPCODE_BFS(op)) { - if (!(trap_registers.sr & SR_T_BIT_MASK)) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 4; /* Not in delay slot */ - } - - /* BRA */ - else if (OPCODE_BRA(op)) - addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op); - - /* BRAF */ - else if (OPCODE_BRAF(op)) - addr = trap_registers.pc + 4 - + trap_registers.regs[OPCODE_BRAF_REG(op)]; - - /* BSR */ - else if (OPCODE_BSR(op)) - addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op); - - /* BSRF */ - else if (OPCODE_BSRF(op)) - addr = trap_registers.pc + 4 - + trap_registers.regs[OPCODE_BSRF_REG(op)]; - - /* JMP */ - else if (OPCODE_JMP(op)) - addr = trap_registers.regs[OPCODE_JMP_REG(op)]; - - /* JSR */ - else if (OPCODE_JSR(op)) - addr = trap_registers.regs[OPCODE_JSR_REG(op)]; - - /* RTS */ - else if (OPCODE_RTS(op)) - addr = trap_registers.pr; - - /* RTE */ - else if (OPCODE_RTE(op)) - addr = trap_registers.regs[15]; - - /* Other */ - else - addr = trap_registers.pc + 2; - - kgdb_flush_icache_range(addr, addr + 2); - return (short *) addr; -} - -/* Set up a single-step. Replace the instruction immediately after the - current instruction (i.e. next in the expected flow of control) with a - trap instruction, so that returning will cause only a single instruction - to be executed. Note that this model is slightly broken for instructions - with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch - and the instruction in the delay slot will be executed. */ -static void do_single_step(void) -{ - unsigned short *addr = 0; - - /* Determine where the target instruction will send us to */ - addr = get_step_address(); - stepped_address = (int)addr; - - /* Replace it */ - stepped_opcode = *(short *)addr; - *addr = STEP_OPCODE; - - /* Flush and return */ - kgdb_flush_icache_range((long) addr, (long) addr + 2); - return; -} - -/* Undo a single step */ -static void undo_single_step(void) -{ - /* If we have stepped, put back the old instruction */ - /* Use stepped_address in case we stopped elsewhere */ - if (stepped_opcode != 0) { - *(short*)stepped_address = stepped_opcode; - kgdb_flush_icache_range(stepped_address, stepped_address + 2); - } - stepped_opcode = 0; -} - -/* Send a signal message */ -static void send_signal_msg(const int signum) -{ -#ifndef CONFIG_KGDB_THREAD - out_buffer[0] = 'S'; - out_buffer[1] = highhex(signum); - out_buffer[2] = lowhex(signum); - out_buffer[3] = 0; - put_packet(out_buffer); -#else /* CONFIG_KGDB_THREAD */ - int threadid; - threadref thref; - char *out = out_buffer; - const char *tstring = "thread"; - - *out++ = 'T'; - *out++ = highhex(signum); - *out++ = lowhex(signum); - - while (*tstring) { - *out++ = *tstring++; - } - *out++ = ':'; - - threadid = trapped_thread->pid; - if (threadid == 0) threadid = PID_MAX; - int_to_threadref(&thref, threadid); - pack_threadid(out, &thref); - out += BUF_THREAD_ID_SIZE; - *out++ = ';'; - - *out = 0; - put_packet(out_buffer); -#endif /* CONFIG_KGDB_THREAD */ -} - -/* Reply that all was well */ -static void send_ok_msg(void) -{ - strcpy(out_buffer, "OK"); - put_packet(out_buffer); -} - -/* Reply that an error occurred */ -static void send_err_msg(void) -{ - strcpy(out_buffer, "E01"); - put_packet(out_buffer); -} - -/* Empty message indicates unrecognised command */ -static void send_empty_msg(void) -{ - put_packet(""); -} - -/* Read memory due to 'm' message */ -static void read_mem_msg(void) -{ - char *ptr; - int addr; - int length; - - /* Jmp, disable bus error handler */ - if (setjmp(rem_com_env) == 0) { - - kgdb_nofault = 1; - - /* Walk through, have m, */ - ptr = &in_buffer[1]; - if (hex_to_int(&ptr, &addr) && (*ptr++ == ',')) - if (hex_to_int(&ptr, &length)) { - ptr = 0; - if (length * 2 > OUTBUFMAX) - length = OUTBUFMAX / 2; - mem_to_hex((char *) addr, out_buffer, length); - } - if (ptr) - send_err_msg(); - else - put_packet(out_buffer); - } else - send_err_msg(); - - /* Restore bus error handler */ - kgdb_nofault = 0; -} - -/* Write memory due to 'M' or 'X' message */ -static void write_mem_msg(int binary) -{ - char *ptr; - int addr; - int length; - - if (setjmp(rem_com_env) == 0) { - - kgdb_nofault = 1; - - /* Walk through, have M,: */ - ptr = &in_buffer[1]; - if (hex_to_int(&ptr, &addr) && (*ptr++ == ',')) - if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) { - if (binary) - ebin_to_mem(ptr, (char*)addr, length); - else - hex_to_mem(ptr, (char*)addr, length); - kgdb_flush_icache_range(addr, addr + length); - ptr = 0; - send_ok_msg(); - } - if (ptr) - send_err_msg(); - } else - send_err_msg(); - - /* Restore bus error handler */ - kgdb_nofault = 0; -} - -/* Continue message */ -static void continue_msg(void) -{ - /* Try to read optional parameter, PC unchanged if none */ - char *ptr = &in_buffer[1]; - int addr; - - if (hex_to_int(&ptr, &addr)) - trap_registers.pc = addr; -} - -/* Continue message with signal */ -static void continue_with_sig_msg(void) -{ - int signal; - char *ptr = &in_buffer[1]; - int addr; - - /* Report limitation */ - kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n"); - - /* Signal */ - hex_to_int(&ptr, &signal); - if (*ptr == ';') - ptr++; - - /* Optional address */ - if (hex_to_int(&ptr, &addr)) - trap_registers.pc = addr; -} - -/* Step message */ -static void step_msg(void) -{ - continue_msg(); - do_single_step(); -} - -/* Step message with signal */ -static void step_with_sig_msg(void) -{ - continue_with_sig_msg(); - do_single_step(); -} - -/* Send register contents */ -static void send_regs_msg(void) -{ -#ifdef CONFIG_KGDB_THREAD - if (!current_thread) - kgdb_regs_to_gdb_regs(&trap_registers, registers); - else - thread_regs_to_gdb_regs(current_thread, registers); -#else - kgdb_regs_to_gdb_regs(&trap_registers, registers); -#endif - - mem_to_hex((char *) registers, out_buffer, NUMREGBYTES); - put_packet(out_buffer); -} - -/* Set register contents - currently can't set other thread's registers */ -static void set_regs_msg(void) -{ -#ifdef CONFIG_KGDB_THREAD - if (!current_thread) { -#endif - kgdb_regs_to_gdb_regs(&trap_registers, registers); - hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); - gdb_regs_to_kgdb_regs(registers, &trap_registers); - send_ok_msg(); -#ifdef CONFIG_KGDB_THREAD - } else - send_err_msg(); -#endif -} - - -#ifdef CONFIG_KGDB_THREAD - -/* Set the status for a thread */ -void set_thread_msg(void) -{ - int threadid; - struct task_struct *thread = NULL; - char *ptr; - - switch (in_buffer[1]) { - - /* To select which thread for gG etc messages, i.e. supported */ - case 'g': - - ptr = &in_buffer[2]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - - /* If we haven't found it */ - if (!thread) { - send_err_msg(); - break; - } - - /* Set current_thread (or not) */ - if (thread == trapped_thread) - current_thread = NULL; - else - current_thread = thread; - send_ok_msg(); - break; - - /* To select which thread for cCsS messages, i.e. unsupported */ - case 'c': - send_ok_msg(); - break; - - default: - send_empty_msg(); - break; - } -} - -/* Is a thread alive? */ -static void thread_status_msg(void) -{ - char *ptr; - int threadid; - struct task_struct *thread = NULL; - - ptr = &in_buffer[1]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - if (thread) - send_ok_msg(); - else - send_err_msg(); -} -/* Send the current thread ID */ -static void thread_id_msg(void) -{ - int threadid; - threadref thref; - - out_buffer[0] = 'Q'; - out_buffer[1] = 'C'; - - if (current_thread) - threadid = current_thread->pid; - else if (trapped_thread) - threadid = trapped_thread->pid; - else /* Impossible, but just in case! */ - { - send_err_msg(); - return; - } - - /* Translate pid 0 to PID_MAX for gdb */ - if (threadid == 0) threadid = PID_MAX; - - int_to_threadref(&thref, threadid); - pack_threadid(out_buffer + 2, &thref); - out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0'; - put_packet(out_buffer); -} - -/* Send thread info */ -static void thread_info_msg(void) -{ - struct task_struct *thread = NULL; - int threadid; - char *pos; - threadref thref; - - /* Start with 'm' */ - out_buffer[0] = 'm'; - pos = &out_buffer[1]; - - /* For all possible thread IDs - this will overrun if > 44 threads! */ - /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */ - for (threadid = 1; threadid <= PID_MAX; threadid++) { - - read_lock(&tasklist_lock); - thread = get_thread(threadid); - read_unlock(&tasklist_lock); - - /* If it's a valid thread */ - if (thread) { - int_to_threadref(&thref, threadid); - pack_threadid(pos, &thref); - pos += BUF_THREAD_ID_SIZE; - *pos++ = ','; - } - } - *--pos = 0; /* Lose final comma */ - put_packet(out_buffer); - -} - -/* Return printable info for gdb's 'info threads' command */ -static void thread_extra_info_msg(void) -{ - int threadid; - struct task_struct *thread = NULL; - char buffer[20], *ptr; - int i; - - /* Extract thread ID */ - ptr = &in_buffer[17]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - - /* If we don't recognise it, say so */ - if (thread == NULL) - strcpy(buffer, "(unknown)"); - else - strcpy(buffer, thread->comm); - - /* Construct packet */ - for (i = 0, ptr = out_buffer; buffer[i]; i++) - ptr = pack_hex_byte(ptr, buffer[i]); - - if (thread->thread.pc == (unsigned long)ret_from_fork) { - strcpy(buffer, ""); - for (i = 0; buffer[i]; i++) - ptr = pack_hex_byte(ptr, buffer[i]); - } - - *ptr = '\0'; - put_packet(out_buffer); -} - -/* Handle all qFooBarBaz messages - have to use an if statement as - opposed to a switch because q messages can have > 1 char id. */ -static void query_msg(void) -{ - const char *q_start = &in_buffer[1]; - - /* qC = return current thread ID */ - if (strncmp(q_start, "C", 1) == 0) - thread_id_msg(); - - /* qfThreadInfo = query all threads (first) */ - else if (strncmp(q_start, "fThreadInfo", 11) == 0) - thread_info_msg(); - - /* qsThreadInfo = query all threads (subsequent). We know we have sent - them all after the qfThreadInfo message, so there are no to send */ - else if (strncmp(q_start, "sThreadInfo", 11) == 0) - put_packet("l"); /* el = last */ - - /* qThreadExtraInfo = supply printable information per thread */ - else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0) - thread_extra_info_msg(); - - /* Unsupported - empty message as per spec */ - else - send_empty_msg(); -} -#endif /* CONFIG_KGDB_THREAD */ - -/* - * Bring up the ports.. - */ -static int kgdb_serial_setup(void) -{ - extern int kgdb_console_setup(struct console *co, char *options); - struct console dummy; - - kgdb_console_setup(&dummy, 0); - - return 0; -} - -/* The command loop, read and act on requests */ -static void kgdb_command_loop(const int excep_code, const int trapa_value) -{ - int sigval; - - if (excep_code == NMI_VEC) { -#ifndef CONFIG_KGDB_NMI - KGDB_PRINTK("Ignoring unexpected NMI?\n"); - return; -#else /* CONFIG_KGDB_NMI */ - if (!kgdb_enabled) { - kgdb_enabled = 1; - kgdb_init(); - } -#endif /* CONFIG_KGDB_NMI */ - } - - /* Ignore if we're disabled */ - if (!kgdb_enabled) - return; - -#ifdef CONFIG_KGDB_THREAD - /* Until GDB specifies a thread */ - current_thread = NULL; - trapped_thread = current; -#endif - - /* Enter GDB mode (e.g. after detach) */ - if (!kgdb_in_gdb_mode) { - /* Do serial setup, notify user, issue preemptive ack */ - kgdb_serial_setup(); - KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n", - (kgdb_porttype ? kgdb_porttype->name : ""), - kgdb_portnum, kgdb_baud); - kgdb_in_gdb_mode = 1; - put_debug_char('+'); - } - - /* Reply to host that an exception has occurred */ - sigval = compute_signal(excep_code); - send_signal_msg(sigval); - - /* TRAP_VEC exception indicates a software trap inserted in place of - code by GDB so back up PC by one instruction, as this instruction - will later be replaced by its original one. Do NOT do this for - trap 0xff, since that indicates a compiled-in breakpoint which - will not be replaced (and we would retake the trap forever) */ - if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) { - trap_registers.pc -= 2; - } - - /* Undo any stepping we may have done */ - undo_single_step(); - - while (1) { - - out_buffer[0] = 0; - get_packet(in_buffer, BUFMAX); - - /* Examine first char of buffer to see what we need to do */ - switch (in_buffer[0]) { - - case '?': /* Send which signal we've received */ - send_signal_msg(sigval); - break; - - case 'g': /* Return the values of the CPU registers */ - send_regs_msg(); - break; - - case 'G': /* Set the value of the CPU registers */ - set_regs_msg(); - break; - - case 'm': /* Read LLLL bytes address AA..AA */ - read_mem_msg(); - break; - - case 'M': /* Write LLLL bytes address AA..AA, ret OK */ - write_mem_msg(0); /* 0 = data in hex */ - break; - - case 'X': /* Write LLLL bytes esc bin address AA..AA */ - if (kgdb_bits == '8') - write_mem_msg(1); /* 1 = data in binary */ - else - send_empty_msg(); - break; - - case 'C': /* Continue, signum included, we ignore it */ - continue_with_sig_msg(); - return; - - case 'c': /* Continue at address AA..AA (optional) */ - continue_msg(); - return; - - case 'S': /* Step, signum included, we ignore it */ - step_with_sig_msg(); - return; - - case 's': /* Step one instruction from AA..AA */ - step_msg(); - return; - -#ifdef CONFIG_KGDB_THREAD - - case 'H': /* Task related */ - set_thread_msg(); - break; - - case 'T': /* Query thread status */ - thread_status_msg(); - break; - - case 'q': /* Handle query - currently thread-related */ - query_msg(); - break; -#endif - - case 'k': /* 'Kill the program' with a kernel ? */ - break; - - case 'D': /* Detach from program, send reply OK */ - kgdb_in_gdb_mode = 0; - send_ok_msg(); - get_debug_char(); - return; - - default: - send_empty_msg(); - break; - } - } -} - -/* There has been an exception, most likely a breakpoint. */ -void kgdb_handle_exception(struct pt_regs *regs) -{ - int excep_code, vbr_val; - int count; - int trapa_value = ctrl_inl(TRA); - - /* Copy kernel regs (from stack) */ - for (count = 0; count < 16; count++) - trap_registers.regs[count] = regs->regs[count]; - trap_registers.pc = regs->pc; - trap_registers.pr = regs->pr; - trap_registers.sr = regs->sr; - trap_registers.gbr = regs->gbr; - trap_registers.mach = regs->mach; - trap_registers.macl = regs->macl; - - asm("stc vbr, %0":"=r"(vbr_val)); - trap_registers.vbr = vbr_val; - - /* Get excode for command loop call, user access */ - asm("stc r2_bank, %0":"=r"(excep_code)); - kgdb_excode = excep_code; - - /* Other interesting environment items for reference */ - asm("stc r6_bank, %0":"=r"(kgdb_g_imask)); - kgdb_current = current; - kgdb_trapa_val = trapa_value; - - /* Act on the exception */ - kgdb_command_loop(excep_code >> 5, trapa_value); - - kgdb_current = NULL; - - /* Copy back the (maybe modified) registers */ - for (count = 0; count < 16; count++) - regs->regs[count] = trap_registers.regs[count]; - regs->pc = trap_registers.pc; - regs->pr = trap_registers.pr; - regs->sr = trap_registers.sr; - regs->gbr = trap_registers.gbr; - regs->mach = trap_registers.mach; - regs->macl = trap_registers.macl; - - vbr_val = trap_registers.vbr; - asm("ldc %0, vbr": :"r"(vbr_val)); - - return; -} - -/* Trigger a breakpoint by function */ -void breakpoint(void) -{ - if (!kgdb_enabled) { - kgdb_enabled = 1; - kgdb_init(); - } - BREAKPOINT(); -} - -/* Initialise the KGDB data structures and serial configuration */ -int kgdb_init(void) -{ - if (!kgdb_enabled) - return 1; - - in_nmi = 0; - kgdb_nofault = 0; - stepped_opcode = 0; - kgdb_in_gdb_mode = 0; - - if (kgdb_serial_setup() != 0) { - KGDB_PRINTK("serial setup error\n"); - return -1; - } - - /* Init ptr to exception handler */ - kgdb_debug_hook = kgdb_handle_exception; - kgdb_bus_err_hook = kgdb_handle_bus_error; - - /* Enter kgdb now if requested, or just report init done */ - if (kgdb_halt) { - kgdb_in_gdb_mode = 1; - put_debug_char('+'); - breakpoint(); - } - else - { - KGDB_PRINTK("stub is initialized.\n"); - } - - return 0; -} - -/* Make function available for "user messages"; console will use it too. */ - -char gdbmsgbuf[BUFMAX]; -#define MAXOUT ((BUFMAX-2)/2) - -static void kgdb_msg_write(const char *s, unsigned count) -{ - int i; - int wcount; - char *bufptr; - - /* 'O'utput */ - gdbmsgbuf[0] = 'O'; - - /* Fill and send buffers... */ - while (count > 0) { - bufptr = gdbmsgbuf + 1; - - /* Calculate how many this time */ - wcount = (count > MAXOUT) ? MAXOUT : count; - - /* Pack in hex chars */ - for (i = 0; i < wcount; i++) - bufptr = pack_hex_byte(bufptr, s[i]); - *bufptr = '\0'; - - /* Move up */ - s += wcount; - count -= wcount; - - /* Write packet */ - put_packet(gdbmsgbuf); - } -} - -static void kgdb_to_gdb(const char *s) -{ - kgdb_msg_write(s, strlen(s)); -} - -#ifdef CONFIG_SH_KGDB_CONSOLE -void kgdb_console_write(struct console *co, const char *s, unsigned count) -{ - /* Bail if we're not talking to GDB */ - if (!kgdb_in_gdb_mode) - return; - - kgdb_msg_write(s, count); -} -#endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/setup.c linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/setup.c --- linux-2.6.18-53.1.14/arch/sh/kernel/setup.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/setup.c 2008-06-10 15:38:50.000000000 +0400 @@ -28,10 +28,6 @@ #include #include -#ifdef CONFIG_SH_KGDB -#include -static int kgdb_parse_options(char *options); -#endif extern void * __rd_start, * __rd_end; /* * Machine setup.. @@ -528,93 +524,3 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; #endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_SH_KGDB -/* - * Parse command-line kgdb options. By default KGDB is enabled, - * entered on error (or other action) using default serial info. - * The command-line option can include a serial port specification - * and an action to override default or configured behavior. - */ -struct kgdb_sermap kgdb_sci_sermap = -{ "ttySC", 5, kgdb_sci_setup, NULL }; - -struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap; -struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap; - -void kgdb_register_sermap(struct kgdb_sermap *map) -{ - struct kgdb_sermap *last; - - for (last = kgdb_serlist; last->next; last = last->next) - ; - last->next = map; - if (!map->namelen) { - map->namelen = strlen(map->name); - } -} - -static int __init kgdb_parse_options(char *options) -{ - char c; - int baud; - - /* Check for port spec (or use default) */ - - /* Determine port type and instance */ - if (!memcmp(options, "tty", 3)) { - struct kgdb_sermap *map = kgdb_serlist; - - while (map && memcmp(options, map->name, map->namelen)) - map = map->next; - - if (!map) { - KGDB_PRINTK("unknown port spec in %s\n", options); - return -1; - } - - kgdb_porttype = map; - kgdb_serial_setup = map->setup_fn; - kgdb_portnum = options[map->namelen] - '0'; - options += map->namelen + 1; - - options = (*options == ',') ? options+1 : options; - - /* Read optional parameters (baud/parity/bits) */ - baud = simple_strtoul(options, &options, 10); - if (baud != 0) { - kgdb_baud = baud; - - c = toupper(*options); - if (c == 'E' || c == 'O' || c == 'N') { - kgdb_parity = c; - options++; - } - - c = *options; - if (c == '7' || c == '8') { - kgdb_bits = c; - options++; - } - options = (*options == ',') ? options+1 : options; - } - } - - /* Check for action specification */ - if (!memcmp(options, "halt", 4)) { - kgdb_halt = 1; - options += 4; - } else if (!memcmp(options, "disabled", 8)) { - kgdb_enabled = 0; - options += 8; - } - - if (*options) { - KGDB_PRINTK("ignored unknown options: %s\n", options); - return 0; - } - return 1; -} -__setup("kgdb=", kgdb_parse_options); -#endif /* CONFIG_SH_KGDB */ - diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/time.c linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/time.c --- linux-2.6.18-53.1.14/arch/sh/kernel/time.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/time.c 2008-06-10 15:38:50.000000000 +0400 @@ -184,12 +184,4 @@ void __init time_init(void) */ sys_timer = get_sys_timer(); printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); - -#if defined(CONFIG_SH_KGDB) - /* - * Set up kgdb as requested. We do it here because the serial - * init uses the timer vars we just set up for figuring baud. - */ - kgdb_init(); -#endif } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/kernel/traps.c linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/traps.c --- linux-2.6.18-53.1.14/arch/sh/kernel/traps.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/kernel/traps.c 2008-06-10 15:38:50.000000000 +0400 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -34,17 +35,8 @@ #include #include -#ifdef CONFIG_SH_KGDB -#include -#define CHK_REMOTE_DEBUG(regs) \ -{ \ - if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \ - { \ - (*kgdb_debug_hook)(regs); \ - } \ -} -#else -#define CHK_REMOTE_DEBUG(regs) +#ifndef CONFIG_KGDB +#define kgdb_handle_exception(t, s, e, r) #endif #define DO_ERROR(trapnr, signr, str, name, tsk) \ @@ -65,7 +57,7 @@ asmlinkage void do_##name(unsigned long local_irq_enable(); \ tsk->thread.error_code = error_code; \ tsk->thread.trap_no = trapnr; \ - CHK_REMOTE_DEBUG(®s); \ + kgdb_handle_exception(trapnr, signr, error_code, ®s); \ force_sig(signr, tsk); \ die_if_no_fixup(str,®s,error_code); \ } @@ -92,10 +84,12 @@ void die(const char * str, struct pt_reg { static int die_counter; +#ifdef CONFIG_KGDB + kgdb_handle_exception(1, SIGTRAP, err, regs); +#endif console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); - CHK_REMOTE_DEBUG(regs); show_regs(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/mm/extable.c linux-2.6.18-53.1.14.kgdb/arch/sh/mm/extable.c --- linux-2.6.18-53.1.14/arch/sh/mm/extable.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/mm/extable.c 2008-06-10 15:38:50.000000000 +0400 @@ -5,6 +5,7 @@ */ #include +#include #include int fixup_exception(struct pt_regs *regs) @@ -16,6 +17,12 @@ int fixup_exception(struct pt_regs *regs regs->pc = fixup->fixup; return 1; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Never reached. */ +#endif return 0; } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/mm/fault-nommu.c linux-2.6.18-53.1.14.kgdb/arch/sh/mm/fault-nommu.c --- linux-2.6.18-53.1.14/arch/sh/mm/fault-nommu.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/mm/fault-nommu.c 2008-06-10 15:38:50.000000000 +0400 @@ -29,10 +29,6 @@ #include #include -#if defined(CONFIG_SH_KGDB) -#include -#endif - extern void die(const char *,struct pt_regs *,long); /* @@ -43,11 +39,6 @@ extern void die(const char *,struct pt_r asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, unsigned long address) { -#if defined(CONFIG_SH_KGDB) - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. @@ -69,11 +60,6 @@ asmlinkage void do_page_fault(struct pt_ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, unsigned long address) { -#if defined(CONFIG_SH_KGDB) - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - if (address >= TASK_SIZE) return 1; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/sh/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/sh/mm/fault.c --- linux-2.6.18-53.1.14/arch/sh/mm/fault.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/sh/mm/fault.c 2008-06-10 15:38:50.000000000 +0400 @@ -28,7 +28,6 @@ #include #include #include -#include extern void die(const char *,struct pt_regs *,long); @@ -45,11 +44,6 @@ asmlinkage void do_page_fault(struct pt_ struct vm_area_struct * vma; unsigned long page; -#ifdef CONFIG_SH_KGDB - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - tsk = current; mm = tsk->mm; @@ -153,6 +147,7 @@ no_context: } die("Oops", regs, writeaccess); do_exit(SIGKILL); + dump_stack(); /* * We ran out of memory, or some other thing happened to us that made @@ -202,11 +197,6 @@ asmlinkage int __do_page_fault(struct pt spinlock_t *ptl; int ret = 1; -#ifdef CONFIG_SH_KGDB - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - #ifdef CONFIG_SH_STORE_QUEUES addrmax = P4SEG_STORE_QUE + 0x04000000; #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/Kconfig.debug linux-2.6.18-53.1.14.kgdb/arch/x86_64/Kconfig.debug --- linux-2.6.18-53.1.14/arch/x86_64/Kconfig.debug 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/Kconfig.debug 2008-06-10 15:38:44.000000000 +0400 @@ -55,7 +55,4 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -#config X86_REMOTE_DEBUG -# bool "kgdb debugging stub" - endmenu diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/kernel/Makefile linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/Makefile --- linux-2.6.18-53.1.14/arch/x86_64/kernel/Makefile 2008-03-06 05:54:48.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/Makefile 2008-06-10 15:38:44.000000000 +0400 @@ -35,6 +35,7 @@ obj-$(CONFIG_IOMMU) += pci-gart.o apert obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o obj-$(CONFIG_X86_VSMP) += vsmp.o obj-$(CONFIG_K8_NB) += k8.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/kernel/entry.S linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/entry.S --- linux-2.6.18-53.1.14/arch/x86_64/kernel/entry.S 2008-03-06 05:54:50.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/entry.S 2008-06-10 15:39:01.000000000 +0400 @@ -42,6 +42,7 @@ #include #include #include +#include .code64 @@ -887,6 +888,7 @@ error_exit: RESTORE_ARGS 0,8,0 jmp iret_label CFI_ENDPROC + CFI_END_FRAME(kernel_thread) error_kernelspace: incl %ebx diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/kernel/kgdb-jmp.S linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/kgdb-jmp.S --- linux-2.6.18-53.1.14/arch/x86_64/kernel/kgdb-jmp.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/kgdb-jmp.S 2008-06-10 15:38:44.000000000 +0400 @@ -0,0 +1,65 @@ +/* + * arch/x86_64/kernel/kgdb-jmp.S + * + * Save and restore system registers so that within a limited frame we + * may have a fault and "jump back" to a known safe location. + * + * Author: Tom Rini + * + * Cribbed from glibc, which carries the following: + * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2005 by MontaVista Software. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of + * any kind, whether express or implied. + */ + +#include + +#define JB_RBX 0 +#define JB_RBP 1 +#define JB_R12 2 +#define JB_R13 3 +#define JB_R14 4 +#define JB_R15 5 +#define JB_RSP 6 +#define JB_PC 7 + + .code64 + +/* This must be called prior to kgdb_fault_longjmp and + * kgdb_fault_longjmp must not be called outside of the context of the + * last call to kgdb_fault_setjmp. + */ +ENTRY(kgdb_fault_setjmp) + /* Save registers. */ + movq %rbx, (JB_RBX*8)(%rdi) + movq %rbp, (JB_RBP*8)(%rdi) + movq %r12, (JB_R12*8)(%rdi) + movq %r13, (JB_R13*8)(%rdi) + movq %r14, (JB_R14*8)(%rdi) + movq %r15, (JB_R15*8)(%rdi) + leaq 8(%rsp), %rdx /* Save SP as it will be after we return. */ + movq %rdx, (JB_RSP*8)(%rdi) + movq (%rsp), %rax /* Save PC we are returning to now. */ + movq %rax, (JB_PC*8)(%rdi) + /* Set return value for setjmp. */ + mov $0,%eax + movq (JB_PC*8)(%rdi),%rdx + movq (JB_RSP*8)(%rdi),%rsp + jmpq *%rdx + +ENTRY(kgdb_fault_longjmp) + /* Restore registers. */ + movq (JB_RBX*8)(%rdi),%rbx + movq (JB_RBP*8)(%rdi),%rbp + movq (JB_R12*8)(%rdi),%r12 + movq (JB_R13*8)(%rdi),%r13 + movq (JB_R14*8)(%rdi),%r14 + movq (JB_R15*8)(%rdi),%r15 + /* Set return value for setjmp. */ + movq (JB_PC*8)(%rdi),%rdx + movq (JB_RSP*8)(%rdi),%rsp + mov $1,%eax + jmpq *%rdx diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/kgdb.c --- linux-2.6.18-53.1.14/arch/x86_64/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/kernel/kgdb.c 2008-06-10 15:38:44.000000000 +0400 @@ -0,0 +1,474 @@ +/* + * + * 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, 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. + * + */ + +/* + * Copyright (C) 2004 Amit S. Kale + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * Copyright (C) 2002 Andi Kleen, SuSE Labs + * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd. + */ +/**************************************************************************** + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by + * David Grothe + * Integrated into 2.2.5 kernel by Tigran Aivazian + * X86_64 changes from Andi Kleen's patch merged by Jim Houston + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include + +/* Put the error code here just in case the user cares. */ +int gdb_x86_64errcode; +/* Likewise, the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_x86_64vector = -1; + +extern atomic_t cpu_doing_single_step; + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_RAX] = regs->rax; + gdb_regs[_RBX] = regs->rbx; + gdb_regs[_RCX] = regs->rcx; + gdb_regs[_RDX] = regs->rdx; + gdb_regs[_RSI] = regs->rsi; + gdb_regs[_RDI] = regs->rdi; + gdb_regs[_RBP] = regs->rbp; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_PC] = regs->rip; + gdb_regs[_R8] = regs->r8; + gdb_regs[_R9] = regs->r9; + gdb_regs[_R10] = regs->r10; + gdb_regs[_R11] = regs->r11; + gdb_regs[_R12] = regs->r12; + gdb_regs[_R13] = regs->r13; + gdb_regs[_R14] = regs->r14; + gdb_regs[_R15] = regs->r15; + gdb_regs[_RSP] = regs->rsp; +} + +extern void thread_return(void); +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + gdb_regs[_RAX] = 0; + gdb_regs[_RBX] = 0; + gdb_regs[_RCX] = 0; + gdb_regs[_RDX] = 0; + gdb_regs[_RSI] = 0; + gdb_regs[_RDI] = 0; + gdb_regs[_RBP] = *(unsigned long *)p->thread.rsp; + gdb_regs[_PS] = *(unsigned long *)(p->thread.rsp + 8); + gdb_regs[_PC] = (unsigned long)&thread_return; + gdb_regs[_R8] = 0; + gdb_regs[_R9] = 0; + gdb_regs[_R10] = 0; + gdb_regs[_R11] = 0; + gdb_regs[_R12] = 0; + gdb_regs[_R13] = 0; + gdb_regs[_R14] = 0; + gdb_regs[_R15] = 0; + gdb_regs[_RSP] = p->thread.rsp; +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + regs->rax = gdb_regs[_RAX]; + regs->rbx = gdb_regs[_RBX]; + regs->rcx = gdb_regs[_RCX]; + regs->rdx = gdb_regs[_RDX]; + regs->rsi = gdb_regs[_RSI]; + regs->rdi = gdb_regs[_RDI]; + regs->rbp = gdb_regs[_RBP]; + regs->eflags = gdb_regs[_PS]; + regs->rip = gdb_regs[_PC]; + regs->r8 = gdb_regs[_R8]; + regs->r9 = gdb_regs[_R9]; + regs->r10 = gdb_regs[_R10]; + regs->r11 = gdb_regs[_R11]; + regs->r12 = gdb_regs[_R12]; + regs->r13 = gdb_regs[_R13]; + regs->r14 = gdb_regs[_R14]; + regs->r15 = gdb_regs[_R15]; +#if 0 /* can't change these */ + regs->rsp = gdb_regs[_RSP]; + regs->ss = gdb_regs[_SS]; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif + +} /* gdb_regs_to_regs */ + +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned long addr; +} breakinfo[4] = { { +enabled:0}, { +enabled:0}, { +enabled:0}, { +enabled:0}}; + +void kgdb_correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned long dr7; + + asm volatile ("movq %%db7, %0\n":"=r" (dr7):); + do { + unsigned long addr0, addr1, addr2, addr3; + asm volatile ("movq %%db0, %0\n" + "movq %%db1, %1\n" + "movq %%db2, %2\n" + "movq %%db3, %3\n":"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3):); + } while (0); + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movq %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movq %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movq %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movq %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movq %0, %%db7\n"::"r" (dr7)); + } +} + +int kgdb_remove_hw_break(unsigned long addr) +{ + int i, idx = -1; + for (i = 0; i < 4; i++) { + if (breakinfo[i].addr == addr && breakinfo[i].enabled) { + idx = i; + break; + } + } + if (idx == -1) + return -1; + + breakinfo[idx].enabled = 0; + return 0; +} + +int kgdb_set_hw_break(unsigned long addr) +{ + int i, idx = -1; + for (i = 0; i < 4; i++) { + if (!breakinfo[i].enabled) { + idx = i; + break; + } + } + if (idx == -1) + return -1; + + breakinfo[idx].enabled = 1; + breakinfo[idx].type = 1; + breakinfo[idx].len = 1; + breakinfo[idx].addr = addr; + return 0; +} + +int remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +void kgdb_disable_hw_debug(struct pt_regs *regs) +{ + /* Disable hardware debugging while we are in kgdb */ + asm volatile ("movq %0,%%db7": /* no output */ :"r" (0UL)); +} + +void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code) +{ + /* Master processor is completely in the debugger */ + gdb_x86_64vector = e_vector; + gdb_x86_64errcode = err_code; +} + +void kgdb_roundup_cpus(unsigned long flags) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + +int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + char *remcomInBuffer, char *remcomOutBuffer, + struct pt_regs *linux_regs) +{ + unsigned long addr, length; + unsigned long breakno, breaktype; + char *ptr; + int newPC; + unsigned long dr6; + + switch (remcomInBuffer[0]) { + case 'c': + case 's': + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->rip = addr; + newPC = linux_regs->rip; + + /* clear the trace bit */ + linux_regs->eflags &= ~TF_MASK; + + atomic_set(&cpu_doing_single_step, -1); + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') { + linux_regs->eflags |= TF_MASK; + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + + } + + asm volatile ("movq %%db6, %0\n":"=r" (dr6)); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno)) { + if (breakinfo[breakno].type == 0) { + /* Set restore flag */ + linux_regs->eflags |= + X86_EFLAGS_RF; + break; + } + } + } + } + kgdb_correct_hw_break(); + asm volatile ("movq %0, %%db6\n"::"r" (0UL)); + + return (0); + + case 'Y': + ptr = &remcomInBuffer[1]; + kgdb_hex2long(&ptr, &breakno); + ptr++; + kgdb_hex2long(&ptr, &breaktype); + ptr++; + kgdb_hex2long(&ptr, &length); + ptr++; + kgdb_hex2long(&ptr, &addr); + if (set_hw_break(breakno & 0x3, breaktype & 0x3, + length & 0x3, addr) == 0) + strcpy(remcomOutBuffer, "OK"); + else + strcpy(remcomOutBuffer, "ERROR"); + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + kgdb_hex2long(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) + strcpy(remcomOutBuffer, "OK"); + else + strcpy(remcomOutBuffer, "ERROR"); + break; + + } /* switch */ + return -1; +} + +static struct pt_regs *in_interrupt_stack(unsigned long rsp, int cpu) +{ + struct pt_regs *regs; + unsigned long end = (unsigned long)cpu_pda(cpu)->irqstackptr; + if (rsp <= end && rsp >= end - IRQSTACKSIZE + 8) { + regs = *(((struct pt_regs **)end) - 1); + return regs; + } + return NULL; +} + +static struct pt_regs *in_exception_stack(unsigned long rsp, int cpu) +{ + int i; + struct tss_struct *init_tss = &__get_cpu_var(init_tss); + for (i = 0; i < N_EXCEPTION_STACKS; i++) + if (rsp >= init_tss[cpu].ist[i] && + rsp <= init_tss[cpu].ist[i] + EXCEPTION_STKSZ) { + struct pt_regs *r = + (void *)init_tss[cpu].ist[i] + EXCEPTION_STKSZ; + return r - 1; + } + return NULL; +} + +void kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid) +{ + static char intr_desc[] = "Stack at interrupt entrypoint"; + static char exc_desc[] = "Stack at exception entrypoint"; + struct pt_regs *stregs; + int cpu = hard_smp_processor_id(); + + if ((stregs = in_interrupt_stack(regs->rsp, cpu))) + kgdb_mem2hex(intr_desc, buffer, strlen(intr_desc)); + else if ((stregs = in_exception_stack(regs->rsp, cpu))) + kgdb_mem2hex(exc_desc, buffer, strlen(exc_desc)); +} + +struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs, int threadid) +{ + struct pt_regs *stregs; + int cpu = hard_smp_processor_id(); + + if ((stregs = in_interrupt_stack(regs->rsp, cpu))) + return current; + else if ((stregs = in_exception_stack(regs->rsp, cpu))) + return current; + + return NULL; +} + +struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid) +{ + struct pt_regs *stregs; + int cpu = hard_smp_processor_id(); + + if ((stregs = in_interrupt_stack(regs->rsp, cpu))) + return stregs; + else if ((stregs = in_exception_stack(regs->rsp, cpu))) + return stregs; + + return NULL; +} + +/* Register KGDB with the die_chain so that we hook into all of the right + * spots. */ +static int kgdb_notify(struct notifier_block *self, unsigned long cmd, + void *ptr) +{ + struct die_args *args = ptr; + struct pt_regs *regs = args->regs; + + if (cmd == DIE_PAGE_FAULT_NO_CONTEXT && atomic_read(&debugger_active) + && kgdb_may_fault) { + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + return NOTIFY_STOP; + /* CPU roundup? */ + } else if (atomic_read(&debugger_active) && cmd == DIE_NMI_IPI) { + kgdb_nmihook(smp_processor_id(), regs); + return NOTIFY_STOP; + /* See if KGDB is interested. */ + } else if (cmd == DIE_PAGE_FAULT || user_mode(regs) || + cmd == DIE_NMI_IPI || (cmd == DIE_DEBUG && + atomic_read(&debugger_active))) + /* Userpace events, normal watchdog event, or spurious + * debug exception. Ignore. */ + return NOTIFY_DONE; + + kgdb_handle_exception(args->trapnr, args->signr, args->err, regs); + + return NOTIFY_STOP; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, + .priority = 0x7fffffff, /* we need to notified first */ +}; + +int kgdb_arch_init(void) +{ + atomic_notifier_chain_register(&die_chain, &kgdb_notifier); + return 0; +} +/* + * Skip an int3 exception when it occurs after a breakpoint has been + * removed. Backtrack eip by 1 since the int3 would have caused it to + * increment by 1. + */ + +int kgdb_skipexception(int exception, struct pt_regs *regs) +{ + if (exception == 3 && kgdb_isremovedbreak(regs->rip - 1)) { + regs->rip -= 1; + return 1; + } + return 0; +} + +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0xcc}, + .flags = KGDB_HW_BREAKPOINT, + .shadowth = 1, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/arch/x86_64/mm/fault.c linux-2.6.18-53.1.14.kgdb/arch/x86_64/mm/fault.c --- linux-2.6.18-53.1.14/arch/x86_64/mm/fault.c 2008-03-06 05:54:27.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/arch/x86_64/mm/fault.c 2008-06-10 15:38:41.000000000 +0400 @@ -557,6 +557,10 @@ no_context: if (is_errata93(regs, address)) return; + if (notify_die(DIE_PAGE_FAULT_NO_CONTEXT, "no context", regs, + error_code, 14, SIGSEGV) == NOTIFY_STOP) + return; + /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/char/keyboard.c linux-2.6.18-53.1.14.kgdb/drivers/char/keyboard.c --- linux-2.6.18-53.1.14/drivers/char/keyboard.c 2008-03-06 05:54:23.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/char/keyboard.c 2008-06-10 15:39:11.000000000 +0400 @@ -1174,6 +1174,7 @@ static void kbd_keycode(unsigned int key sysrq_down = 0; if (sysrq_down && down && !rep) { handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); + sysrq_down = 0; /* In case we miss the 'up' event. */ return; } #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/net/Makefile linux-2.6.18-53.1.14.kgdb/drivers/net/Makefile --- linux-2.6.18-53.1.14/drivers/net/Makefile 2008-03-06 05:54:59.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/net/Makefile 2008-06-10 15:37:55.000000000 +0400 @@ -221,6 +221,7 @@ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/ obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_KGDBOE) += kgdboe.o obj-$(CONFIG_FS_ENET) += fs_enet/ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/net/kgdboe.c linux-2.6.18-53.1.14.kgdb/drivers/net/kgdboe.c --- linux-2.6.18-53.1.14/drivers/net/kgdboe.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/net/kgdboe.c 2008-06-10 15:37:55.000000000 +0400 @@ -0,0 +1,294 @@ +/* + * drivers/net/kgdboe.c + * + * A network interface for GDB. + * Based upon 'gdbserial' by David Grothe + * and Scott Foehner + * + * Maintainers: Amit S. Kale and + * Tom Rini + * + * 2004 (c) Amit S. Kale + * 2004-2005 (c) MontaVista Software, Inc. + * 2005 (c) Wind River Systems, Inc. + * + * Contributors at various stages not listed above: + * San Mehat , Robert Walsh , + * wangdi , Matt Mackall , + * Pavel Machek , Jason Wessel + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define IN_BUF_SIZE 512 /* power of 2, please */ +#define NOT_CONFIGURED_STRING "not_configured" +#define OUT_BUF_SIZE 30 /* We don't want to send too big of a packet. */ +#define MAX_KGDBOE_CONFIG_STR 256 + +static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE]; +static int in_head, in_tail, out_count; +static atomic_t in_count; +/* 0 = unconfigured, 1 = netpoll options parsed, 2 = fully configured. */ +static int configured; +static struct kgdb_io local_kgdb_io_ops; +static int use_dynamic_mac; + +MODULE_DESCRIPTION("KGDB driver for network interfaces"); +MODULE_LICENSE("GPL"); +static char config[MAX_KGDBOE_CONFIG_STR] = NOT_CONFIGURED_STRING; +static struct kparam_string kps = { + .string = config, + .maxlen = MAX_KGDBOE_CONFIG_STR, +}; + +static void rx_hook(struct netpoll *np, int port, char *msg, int len, + struct sk_buff *skb) +{ + int i; + + np->remote_port = port; + + /* Copy the MAC address if we need to. */ + if (use_dynamic_mac) { + memcpy(np->remote_mac, eth_hdr(skb)->h_source, + sizeof(np->remote_mac)); + use_dynamic_mac = 0; + } + + /* + * This could be GDB trying to attach. But it could also be GDB + * finishing up a session, with kgdb_connected=0 but GDB sending + * an ACK for the final packet. To make sure we don't try and + * make a breakpoint when GDB is leaving, make sure that if + * !kgdb_connected the only len == 1 packet we allow is ^C. + */ + if (!kgdb_connected && (len != 1 || msg[0] == 3) && + !atomic_read(&kgdb_setting_breakpoint)) { + tasklet_schedule(&kgdb_tasklet_breakpoint); + } + + for (i = 0; i < len; i++) { + if (msg[i] == 3) + tasklet_schedule(&kgdb_tasklet_breakpoint); + + if (atomic_read(&in_count) >= IN_BUF_SIZE) { + /* buffer overflow, clear it */ + in_head = in_tail = 0; + atomic_set(&in_count, 0); + break; + } + in_buf[in_head++] = msg[i]; + in_head &= (IN_BUF_SIZE - 1); + atomic_inc(&in_count); + } +} + +static struct netpoll np = { + .dev_name = "eth0", + .name = "kgdboe", + .rx_hook = rx_hook, + .local_port = 6443, + .remote_port = 6442, + .remote_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, +}; + +static void eth_pre_exception_handler(void) +{ + /* Increment the module count when the debugger is active */ + if (!kgdb_connected) + try_module_get(THIS_MODULE); + netpoll_set_trap(1); +} + +static void eth_post_exception_handler(void) +{ + /* decrement the module count when the debugger detaches */ + if (!kgdb_connected) + module_put(THIS_MODULE); + netpoll_set_trap(0); +} + +static int eth_get_char(void) +{ + int chr; + + while (atomic_read(&in_count) == 0) + netpoll_poll(&np); + + chr = in_buf[in_tail++]; + in_tail &= (IN_BUF_SIZE - 1); + atomic_dec(&in_count); + return chr; +} + +static void eth_flush_buf(void) +{ + if (out_count && np.dev) { + netpoll_send_udp(&np, out_buf, out_count); + memset(out_buf, 0, sizeof(out_buf)); + out_count = 0; + } +} + +static void eth_put_char(u8 chr) +{ + out_buf[out_count++] = chr; + if (out_count == OUT_BUF_SIZE) + eth_flush_buf(); +} + +static int option_setup(char *opt) +{ + char opt_scratch[MAX_KGDBOE_CONFIG_STR]; + + /* If we're being given a new configuration, copy it in. */ + if (opt != config) + strcpy(config, opt); + /* But work on a copy as netpoll_parse_options will eat it. */ + strcpy(opt_scratch, opt); + configured = !netpoll_parse_options(&np, opt_scratch); + + use_dynamic_mac = 1; + + return 0; +} +__setup("kgdboe=", option_setup); + +/* With our config string set by some means, configure kgdboe. */ +static int configure_kgdboe(void) +{ + /* Try out the string. */ + option_setup(config); + + if (!configured) { + printk(KERN_ERR "kgdboe: configuration incorrect - kgdboe not " + "loaded.\n"); + printk(KERN_ERR " Usage: kgdboe=[src-port]@[src-ip]/[dev]," + "[tgt-port]@/\n"); + return -EINVAL; + } + + /* Bring it up. */ + if (netpoll_setup(&np)) { + printk(KERN_ERR "kgdboe: netpoll_setup failed kgdboe failed\n"); + return -EINVAL; + } + + if (kgdb_register_io_module(&local_kgdb_io_ops)) { + netpoll_cleanup(&np); + return -EINVAL; + } + + configured = 2; + + return 0; +} + +static int init_kgdboe(void) +{ + int ret; + + /* Already done? */ + if (configured == 2) + return 0; + + /* OK, go ahead and do it. */ + ret = configure_kgdboe(); + + if (configured == 2) + printk(KERN_INFO "kgdboe: debugging over ethernet enabled\n"); + + return ret; +} + +static void cleanup_kgdboe(void) +{ + netpoll_cleanup(&np); + configured = 0; + kgdb_unregister_io_module(&local_kgdb_io_ops); +} + +static int param_set_kgdboe_var(const char *kmessage, struct kernel_param *kp) +{ + char kmessage_save[MAX_KGDBOE_CONFIG_STR]; + int msg_len = strlen(kmessage); + + if (msg_len + 1 > MAX_KGDBOE_CONFIG_STR) { + printk(KERN_ERR "%s: string doesn't fit in %u chars.\n", + kp->name, MAX_KGDBOE_CONFIG_STR - 1); + return -ENOSPC; + } + + if (kgdb_connected) { + printk(KERN_ERR "kgdboe: Cannot reconfigure while KGDB is " + "connected.\n"); + return 0; + } + + /* Start the reconfiguration process by saving the old string */ + strncpy(kmessage_save, config, sizeof(kmessage_save)); + + + /* Copy in the new param and strip out invalid characters so we + * can optionally specify the MAC. + */ + strncpy(config, kmessage, sizeof(config)); + msg_len--; + while (msg_len > 0 && + (config[msg_len] < ',' || config[msg_len] > 'f')) { + config[msg_len] = '\0'; + msg_len--; + } + + /* Check to see if we are unconfiguring the io module and that it + * was in a fully configured state, as this is the only time that + * netpoll_cleanup should get called + */ + if (configured == 2 && strcmp(config, NOT_CONFIGURED_STRING) == 0) { + printk(KERN_INFO "kgdboe: reverting to unconfigured state\n"); + cleanup_kgdboe(); + return 0; + } else + /* Go and configure with the new params. */ + configure_kgdboe(); + + if (configured == 2) + return 0; + + /* If the new string was invalid, revert to the previous state, which + * is at a minimum not_configured. */ + strncpy(config, kmessage_save, sizeof(config)); + if (strcmp(kmessage_save, NOT_CONFIGURED_STRING) != 0) { + printk(KERN_INFO "kgdboe: reverting to prior configuration\n"); + /* revert back to the original config */ + strncpy(config, kmessage_save, sizeof(config)); + configure_kgdboe(); + } + return 0; +} + +static struct kgdb_io local_kgdb_io_ops = { + .read_char = eth_get_char, + .write_char = eth_put_char, + .init = init_kgdboe, + .flush = eth_flush_buf, + .pre_exception = eth_pre_exception_handler, + .post_exception = eth_post_exception_handler +}; + +module_init(init_kgdboe); +module_exit(cleanup_kgdboe); +module_param_call(kgdboe, param_set_kgdboe_var, param_get_string, &kps, 0644); +MODULE_PARM_DESC(kgdboe, " kgdboe=[src-port]@[src-ip]/[dev]," + "[tgt-port]@/\n"); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/8250.c linux-2.6.18-53.1.14.kgdb/drivers/serial/8250.c --- linux-2.6.18-53.1.14/drivers/serial/8250.c 2008-03-06 05:54:43.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/8250.c 2008-06-10 15:37:43.000000000 +0400 @@ -2656,6 +2656,25 @@ void serial8250_unregister_port(int line } EXPORT_SYMBOL(serial8250_unregister_port); +/** + * serial8250_unregister_by_port - remove a 16x50 serial port + * at runtime. + * @port: A &struct uart_port that describes the port to remove. + * + * Remove one serial port. This may not be called from interrupt + * context. We hand the port back to the our control. + */ +void serial8250_unregister_by_port(struct uart_port *port) +{ + struct uart_8250_port *uart; + + uart = serial8250_find_match_or_unused(port); + + if (uart) + serial8250_unregister_port(uart->port.line); +} +EXPORT_SYMBOL(serial8250_unregister_by_port); + static int __init serial8250_init(void) { int ret, i; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/8250_kgdb.c linux-2.6.18-53.1.14.kgdb/drivers/serial/8250_kgdb.c --- linux-2.6.18-53.1.14/drivers/serial/8250_kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/8250_kgdb.c 2008-06-10 15:37:43.000000000 +0400 @@ -0,0 +1,516 @@ +/* + * 8250 interface for kgdb. + * + * This is a merging of many different drivers, and all of the people have + * had an impact in some form or another: + * + * 2004-2005 (c) MontaVista Software, Inc. + * 2005-2006 (c) Wind River Systems, Inc. + * + * Amit Kale , David Grothe , + * Scott Foehner , George Anzinger , + * Robert Walsh , wangdi , + * San Mehat, Tom Rini , + * Jason Wessel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* For BASE_BAUD and SERIAL_PORT_DFNS */ + +#include "8250.h" + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +MODULE_DESCRIPTION("KGDB driver for the 8250"); +MODULE_LICENSE("GPL"); +/* These will conflict with early_param otherwise. */ +#ifdef CONFIG_KGDB_8250_MODULE +static char config[256]; +module_param_string(kgdb8250, config, 256, 0); +MODULE_PARM_DESC(kgdb8250, + " kgdb8250=,
,,\n"); +static struct kgdb_io local_kgdb_io_ops; +#endif /* CONFIG_KGDB_8250_MODULE */ + +/* Speed of the UART. */ +static int kgdb8250_baud; + +/* Flag for if we need to call request_mem_region */ +static int kgdb8250_needs_request_mem_region; + +static char kgdb8250_buf[GDB_BUF_SIZE]; +static atomic_t kgdb8250_buf_in_cnt; +static int kgdb8250_buf_out_inx; + +/* Old-style serial definitions, if existant, and a counter. */ +#ifdef CONFIG_KGDB_SIMPLE_SERIAL +static int __initdata should_copy_rs_table = 1; +static struct serial_state old_rs_table[] __initdata = { +#ifdef SERIAL_PORT_DFNS + SERIAL_PORT_DFNS +#endif +}; +#endif + +/* Our internal table of UARTS. */ +#define UART_NR CONFIG_SERIAL_8250_NR_UARTS +static struct uart_port kgdb8250_ports[UART_NR]; + +static struct uart_port *current_port; + +/* Base of the UART. */ +static void *kgdb8250_addr; + +/* Forward declarations. */ +static int kgdb8250_uart_init(void); +static int __init kgdb_init_io(void); +static int __init kgdb8250_opt(char *str); + +/* These are much shorter calls to ioread8/iowrite8 that take into + * account our shifts, etc. */ +static inline unsigned int kgdb_ioread(u8 mask) +{ + return ioread8(kgdb8250_addr + (mask << current_port->regshift)); +} + +static inline void kgdb_iowrite(u8 val, u8 mask) +{ + iowrite8(val, kgdb8250_addr + (mask << current_port->regshift)); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void kgdb_put_debug_char(u8 chr) +{ + while (!(kgdb_ioread(UART_LSR) & UART_LSR_THRE)) ; + + kgdb_iowrite(chr, UART_TX); +} + +/* + * Get a byte from the hardware data buffer and return it + */ +static int read_data_bfr(void) +{ + char it = kgdb_ioread(UART_LSR); + + if (it & UART_LSR_DR) + return kgdb_ioread(UART_RX); + + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + kgdb8250_uart_init(); + kgdb_put_debug_char('-'); + return '-'; + } + + return -1; +} + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + */ +static int kgdb_get_debug_char(void) +{ + int retchr; + + /* intr routine has q'd chars */ + if (atomic_read(&kgdb8250_buf_in_cnt) != 0) { + retchr = kgdb8250_buf[kgdb8250_buf_out_inx++]; + kgdb8250_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&kgdb8250_buf_in_cnt); + return retchr; + } + + do { + retchr = read_data_bfr(); + } while (retchr < 0); + + return retchr; +} + +/* + * This is the receiver interrupt routine for the GDB stub. + * All that we need to do is verify that the interrupt happened on the + * line we're in charge of. If this is true, schedule a breakpoint and + * return. + */ +static irqreturn_t +kgdb8250_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (kgdb_ioread(UART_IIR) & UART_IIR_RDI) { + /* Throw away the data if another I/O routine is active. */ + if (kgdb_io_ops.read_char != kgdb_get_debug_char && + (kgdb_ioread(UART_LSR) & UART_LSR_DR)) + kgdb_ioread(UART_RX); + else + breakpoint(); + } + + return IRQ_HANDLED; +} + +/* + * Initializes the UART. + * Returns: + * 0 on success, 1 on failure. + */ +static int +kgdb8250_uart_init (void) +{ + unsigned int ier, base_baud = current_port->uartclk ? + current_port->uartclk / 16 : BASE_BAUD; + + /* test uart existance */ + if(kgdb_ioread(UART_LSR) == 0xff) + return -1; + + /* disable interrupts */ + kgdb_iowrite(0, UART_IER); + +#if defined(CONFIG_ARCH_OMAP1510) + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (cpu_is_omap1510() && is_omap_port((void *)kgdb8250_addr)) { + if (kgdb8250_baud == 115200) { + base_baud = 1; + kgdb8250_baud = 1; + kgdb_iowrite(1, UART_OMAP_OSC_12M_SEL); + } else + kgdb_iowrite(0, UART_OMAP_OSC_12M_SEL); + } +#endif + /* set DLAB */ + kgdb_iowrite(UART_LCR_DLAB, UART_LCR); + + /* set baud */ + kgdb_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL); + kgdb_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM); + + /* reset DLAB, set LCR */ + kgdb_iowrite(UART_LCR_WLEN8, UART_LCR); + + /* set DTR and RTS */ + kgdb_iowrite(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, UART_MCR); + + /* setup fifo */ + kgdb_iowrite(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR + | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_8, + UART_FCR); + + /* clear pending interrupts */ + kgdb_ioread(UART_IIR); + kgdb_ioread(UART_RX); + kgdb_ioread(UART_LSR); + kgdb_ioread(UART_MSR); + + /* turn on RX interrupt only */ + kgdb_iowrite(UART_IER_RDI, UART_IER); + + /* + * Borrowed from the main 8250 driver. + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + ier = kgdb_ioread(UART_IER); + kgdb_iowrite(ier & ~UART_IER_UUE, UART_IER); + if (!(kgdb_ioread(UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + kgdb_iowrite(ier | UART_IER_UUE, UART_IER); + if (kgdb_ioread(UART_IER) & UART_IER_UUE) + /* + * It's an Xscale. + */ + ier |= UART_IER_UUE | UART_IER_RTOIE; + } + kgdb_iowrite(ier, UART_IER); + return 0; +} + +/* + * Copy the old serial_state table to our uart_port table if we haven't + * had values specifically configured in. We need to make sure this only + * happens once. + */ +static void __init kgdb8250_copy_rs_table(void) +{ +#ifdef CONFIG_KGDB_SIMPLE_SERIAL + int i; + + if (!should_copy_rs_table) + return; + + for (i = 0; i < ARRAY_SIZE(old_rs_table); i++) { + kgdb8250_ports[i].iobase = old_rs_table[i].port; + kgdb8250_ports[i].irq = irq_canonicalize(old_rs_table[i].irq); + kgdb8250_ports[i].uartclk = old_rs_table[i].baud_base * 16; + kgdb8250_ports[i].membase = old_rs_table[i].iomem_base; + kgdb8250_ports[i].iotype = old_rs_table[i].io_type; + kgdb8250_ports[i].regshift = old_rs_table[i].iomem_reg_shift; + kgdb8250_ports[i].line = i; + } + + should_copy_rs_table = 0; +#endif +} + +/* + * Hookup our IRQ line now that it is safe to do so, after we grab any + * memory regions we might need to. If we haven't been initialized yet, + * go ahead and copy the old_rs_table in. + */ +static void __init kgdb8250_late_init(void) +{ + /* Try and copy the old_rs_table. */ + kgdb8250_copy_rs_table(); + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + /* Take the port away from the main driver. */ + serial8250_unregister_by_port(current_port); + + /* Now reinit the port as the above has disabled things. */ + kgdb8250_uart_init(); +#endif + /* We may need to call request_mem_region() first. */ + if (kgdb8250_needs_request_mem_region) + request_mem_region(current_port->mapbase, + 8 << current_port->regshift, "kgdb"); + if (request_irq(current_port->irq, kgdb8250_interrupt, SA_SHIRQ, + "GDB-stub", current_port) < 0) + printk(KERN_ERR "KGDB failed to request the serial IRQ (%d)\n", + current_port->irq); +} + +static __init int kgdb_init_io(void) +{ + /* Give us the basic table of uarts. */ + kgdb8250_copy_rs_table(); + + /* We're either a module and parse a config string, or we have a + * semi-static config. */ +#ifdef CONFIG_KGDB_8250_MODULE + if (strlen(config)) { + if (kgdb8250_opt(config)) + return -EINVAL; + } else { + printk(KERN_ERR "kgdb8250: argument error, usage: " + "kgdb8250=,
,,\n"); + return -EINVAL; + } +#elif defined(CONFIG_KGDB_SIMPLE_SERIAL) + kgdb8250_baud = CONFIG_KGDB_BAUDRATE; + + /* Setup our pointer to the serial port now. */ + current_port = &kgdb8250_ports[CONFIG_KGDB_PORT_NUM]; +#else + if (kgdb8250_opt(CONFIG_KGDB_8250_CONF_STRING)) + return -EINVAL; +#endif + + + /* Internal driver setup. */ + switch (current_port->iotype) { + case UPIO_MEM: + if (current_port->mapbase) + kgdb8250_needs_request_mem_region = 1; + if (current_port->flags & UPF_IOREMAP) { + current_port->membase = ioremap(current_port->mapbase, + 8 << current_port->regshift); + if (!current_port->membase) + return -EIO; /* Failed. */ + } + kgdb8250_addr = current_port->membase; + break; + case UPIO_PORT: + default: + kgdb8250_addr = ioport_map(current_port->iobase, + 8 << current_port->regshift); + if (!kgdb8250_addr) + return -EIO; /* Failed. */ + } + + if (kgdb8250_uart_init() == -1) { + printk(KERN_ERR "kgdb8250: init failed\n"); + return -EIO; + } +#ifdef CONFIG_KGDB_8250_MODULE + /* Attach the kgdb irq. When this is built into the kernel, it + * is called as a part of late_init sequence. + */ + kgdb8250_late_init(); + if (kgdb_register_io_module(&local_kgdb_io_ops)) + return -EINVAL; + + printk(KERN_INFO "kgdb8250: debugging enabled\n"); +#endif /* CONFIG_KGD_8250_MODULE */ + + return 0; +} + +#ifdef CONFIG_KGDB_8250_MODULE +/* If it is a module the kgdb_io_ops should be a static which + * is passed to the KGDB I/O initialization + */ +static struct kgdb_io local_kgdb_io_ops = { +#else /* ! CONFIG_KGDB_8250_MODULE */ +struct kgdb_io kgdb_io_ops = { +#endif /* ! CONFIG_KGD_8250_MODULE */ + .read_char = kgdb_get_debug_char, + .write_char = kgdb_put_debug_char, + .init = kgdb_init_io, + .late_init = kgdb8250_late_init, +}; + +/** + * kgdb8250_add_port - Define a serial port for use with KGDB + * @i: The index of the port being added + * @serial_req: The &struct uart_port describing the port + * + * On platforms where we must register the serial device + * dynamically, this is the best option if a platform also normally + * calls early_serial_setup(). + */ +void __init kgdb8250_add_port(int i, struct uart_port *serial_req) +{ + /* Make sure we've got the built-in data before we override. */ + kgdb8250_copy_rs_table(); + + /* Copy the whole thing over. */ + if (current_port != &kgdb8250_ports[i]) + memcpy(&kgdb8250_ports[i], serial_req, sizeof(struct uart_port)); +} + +/** + * kgdb8250_add_platform_port - Define a serial port for use with KGDB + * @i: The index of the port being added + * @p: The &struct plat_serial8250_port describing the port + * + * On platforms where we must register the serial device + * dynamically, this is the best option if a platform normally + * handles uart setup with an array of &struct plat_serial8250_port. + */ +void __init kgdb8250_add_platform_port(int i, struct plat_serial8250_port *p) +{ + /* Make sure we've got the built-in data before we override. */ + kgdb8250_copy_rs_table(); + + kgdb8250_ports[i].iobase = p->iobase; + kgdb8250_ports[i].membase = p->membase; + kgdb8250_ports[i].irq = p->irq; + kgdb8250_ports[i].uartclk = p->uartclk; + kgdb8250_ports[i].regshift = p->regshift; + kgdb8250_ports[i].iotype = p->iotype; + kgdb8250_ports[i].flags = p->flags; + kgdb8250_ports[i].mapbase = p->mapbase; +} + +/* + * Syntax for this cmdline option is: + * kgdb8250=,
,," + */ +static int __init kgdb8250_opt(char *str) +{ + /* We'll fill out and use the first slot. */ + current_port = &kgdb8250_ports[0]; + + if (!strncmp(str, "io", 2)) { + current_port->iotype = UPIO_PORT; + str += 2; + } else if (!strncmp(str, "mmap", 4)) { + current_port->iotype = UPIO_MEM; + current_port->flags |= UPF_IOREMAP; + str += 4; + } else if (!strncmp(str, "mmio", 4)) { + current_port->iotype = UPIO_MEM; + current_port->flags &= ~UPF_IOREMAP; + str += 4; + } else + goto errout; + + if (*str != ',') + goto errout; + str++; + + if (current_port->iotype == UPIO_PORT) + current_port->iobase = simple_strtoul(str, &str, 16); + else { + if (current_port->flags & UPF_IOREMAP) + current_port->mapbase = + (unsigned long) simple_strtoul(str, &str, 16); + else + current_port->membase = + (void *) simple_strtoul(str, &str, 16); + } + + if (*str != ',') + goto errout; + str++; + + kgdb8250_baud = simple_strtoul(str, &str, 10); + if (!kgdb8250_baud) + goto errout; + + if (*str != ',') + goto errout; + str++; + + current_port->irq = simple_strtoul(str, &str, 10); + +#ifdef CONFIG_KGDB_SIMPLE_SERIAL + should_copy_rs_table = 0; +#endif + + return 0; + + errout: + printk(KERN_ERR "Invalid syntax for option kgdb8250=\n"); + return 1; +} + +#ifdef CONFIG_KGDB_8250_MODULE +static void cleanup_kgdb8250(void) +{ + kgdb_unregister_io_module(&local_kgdb_io_ops); + + /* Clean up the irq and memory */ + free_irq(current_port->irq, current_port); + + if (kgdb8250_needs_request_mem_region) + release_mem_region(current_port->mapbase, + 8 << current_port->regshift); + /* Hook up the serial port back to what it was previously + * hooked up to. + */ +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + /* Give the port back to the 8250 driver. */ + serial8250_register_port(current_port); +#endif +} + +module_init(kgdb_init_io); +module_exit(cleanup_kgdb8250); +#else /* ! CONFIG_KGDB_8250_MODULE */ +early_param("kgdb8250", kgdb8250_opt); +#endif /* ! CONFIG_KGDB_8250_MODULE */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/Kconfig linux-2.6.18-53.1.14.kgdb/drivers/serial/Kconfig --- linux-2.6.18-53.1.14/drivers/serial/Kconfig 2008-03-06 05:54:47.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/Kconfig 2008-06-10 15:37:43.000000000 +0400 @@ -107,7 +107,7 @@ config SERIAL_8250_CS config SERIAL_8250_NR_UARTS int "Maximum number of 8250/16550 serial ports" - depends on SERIAL_8250 + depends on SERIAL_8250 || KGDB_8250 default "4" help Set this to the number of serial ports you want the driver diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/Makefile linux-2.6.18-53.1.14.kgdb/drivers/serial/Makefile --- linux-2.6.18-53.1.14/drivers/serial/Makefile 2008-03-06 05:54:47.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/Makefile 2008-06-10 15:38:14.000000000 +0400 @@ -47,6 +47,7 @@ obj-$(CONFIG_SERIAL_IMX) += imx.o obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o +obj-$(CONFIG_KGDB_MPSC) += mpsc_kgdb.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_JSM) += jsm/ @@ -57,3 +58,4 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_se obj-$(CONFIG_SERIAL_AT91) += at91_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o +obj-$(CONFIG_KGDB_8250) += 8250_kgdb.o diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/amba-pl011.c linux-2.6.18-53.1.14.kgdb/drivers/serial/amba-pl011.c --- linux-2.6.18-53.1.14/drivers/serial/amba-pl011.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/amba-pl011.c 2008-06-10 15:38:56.000000000 +0400 @@ -340,7 +340,7 @@ static int pl011_startup(struct uart_por /* * Allocate the IRQ */ - retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); + retval = request_irq(uap->port.irq, pl011_int, SA_SHIRQ, "uart-pl011", uap); if (retval) goto clk_dis; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/Makefile linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/Makefile --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/Makefile 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/Makefile 2008-06-10 15:38:14.000000000 +0400 @@ -7,5 +7,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o # Select the correct platform objects. cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o +cpm_uart-objs-$(CONFIG_KGDB_CPM_UART) += cpm_uart_kgdb.o cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart.h linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart.h --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart.h 2008-03-06 05:54:12.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart.h 2008-06-10 15:38:14.000000000 +0400 @@ -50,6 +50,39 @@ #define SCC_WAIT_CLOSING 100 +#ifdef CONFIG_KGDB_CPM_UART + +/* Speed of the debug UART. */ +#if defined(CONFIG_KGDB_9600BAUD) +#define KGDB_BAUD B9600 +#elif defined(CONFIG_KGDB_19200BAUD) +#define KGDB_BAUD B19200 +#elif defined(CONFIG_KGDB_38400BAUD) +#define KGDB_BAUD B38400 +#elif defined(CONFIG_KGDB_57600BAUD) +#define KGDB_BAUD B57600 +#else +#define KGDB_BAUD B115200 /* Start with this if not given */ +#endif + +#ifdef CONFIG_KGDB_CPM_UART_SCC1 +#define KGDB_PINFO_INDEX UART_SCC1 +#elif CONFIG_KGDB_CPM_UART_SCC2 +#define KGDB_PINFO_INDEX UART_SCC2 +#elif CONFIG_KGDB_CPM_UART_SCC3 +#define KGDB_PINFO_INDEX UART_SCC3 +#elif CONFIG_KGDB_CPM_UART_SCC4 +#define KGDB_PINFO_INDEX UART_SCC4 +#elif CONFIG_KGDB_CPM_UART_SMC1 +#define KGDB_PINFO_INDEX UART_SMC1 +#elif CONFIG_KGDB_CPM_UART_SMC2 +#define KGDB_PINFO_INDEX UART_SMC2 +#else +#error The S(M)CC for kgdb console is undefined +#endif + +#endif /* CONFIG_KGDB_CPM_UART */ + struct uart_cpm_port { struct uart_port port; u16 rx_nrfifos; @@ -86,6 +119,9 @@ extern int cpm_uart_port_map[UART_NR]; extern int cpm_uart_nr; extern struct uart_cpm_port cpm_uart_ports[UART_NR]; +void cpm_uart_early_write(int index, const char *s, u_int count); +int cpm_uart_early_setup(int index,int early); + /* these are located in their respective files */ void cpm_line_cr_cmd(int line, int cmd); int cpm_uart_init_portdesc(void); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_core.c linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_core.c --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_core.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_core.c 2008-06-10 15:38:14.000000000 +0400 @@ -1070,22 +1070,17 @@ int cpm_uart_drv_get_platform_data(struc return 0; } -#ifdef CONFIG_SERIAL_CPM_CONSOLE -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * Note that this is called with interrupts already disabled - */ -static void cpm_uart_console_write(struct console *co, const char *s, +void cpm_uart_early_write(int index, const char *s, u_int count) { - struct uart_cpm_port *pinfo = - &cpm_uart_ports[cpm_uart_port_map[co->index]]; + struct uart_cpm_port *pinfo; unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; + BUG_ON(index>UART_NR); + pinfo = &cpm_uart_ports[index]; + /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; @@ -1149,16 +1144,11 @@ static void cpm_uart_console_write(struc pinfo->tx_cur = (volatile cbd_t *) bdp; } - -static int __init cpm_uart_console_setup(struct console *co, char *options) +int cpm_uart_early_setup(int index, int early) { + int ret; struct uart_port *port; struct uart_cpm_port *pinfo; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; struct fs_uart_platform_info *pdata; struct platform_device* pdev = early_uart_get_pdev(co->index); @@ -1169,8 +1159,9 @@ static int __init cpm_uart_console_setup cpm_uart_init_portdesc(); } + BUG_ON(index>UART_NR); port = - (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; + (struct uart_port *)&cpm_uart_ports[index]; pinfo = (struct uart_cpm_port *)port; if (!pdev) { if (pinfo->set_lineif) @@ -1184,19 +1175,6 @@ static int __init cpm_uart_console_setup cpm_uart_drv_get_platform_data(pdev, 1); } - pinfo->flags |= FLAG_CONSOLE; - - if (options) { - uart_parse_options(options, &baud, &parity, &bits, &flow); - } else { - bd_t *bd = (bd_t *) __res; - - if (bd->bi_baudrate) - baud = bd->bi_baudrate; - else - baud = 9600; - } - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1204,8 +1182,7 @@ static int __init cpm_uart_console_setup pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); } - - ret = cpm_uart_allocbuf(pinfo, 1); + ret = cpm_uart_allocbuf(pinfo, early); if (ret) return ret; @@ -1217,6 +1194,56 @@ static int __init cpm_uart_console_setup else cpm_uart_init_scc(pinfo); + return 0; +} + +#ifdef CONFIG_SERIAL_CPM_CONSOLE +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * Note that this is called with interrupts already disabled + */ + +static void cpm_uart_console_write(struct console *co, const char *s, + u_int count) +{ + cpm_uart_early_write(cpm_uart_port_map[co->index],s,count); +} + +/* + * Setup console. Be careful is called early ! + */ +static int __init cpm_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct uart_cpm_port *pinfo; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + port = + (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; + pinfo = (struct uart_cpm_port *)port; + + pinfo->flags |= FLAG_CONSOLE; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + } else { + bd_t *bd = (bd_t *) __res; + + if (bd->bi_baudrate) + baud = bd->bi_baudrate; + else + baud = 9600; + } + + ret = cpm_uart_early_setup(cpm_uart_port_map[co->index], 1); + if(ret) + return ret; uart_set_options(port, co, baud, parity, bits, flow); return 0; @@ -1364,6 +1391,12 @@ static int cpm_uart_init(void) { for (i = 0; i < cpm_uart_nr; i++) { int con = cpm_uart_port_map[i]; + +#ifdef CONFIG_KGDB_CPM_UART + /* We are not interested in ports yet utilized by kgdb */ + if(con == KGDB_PINFO_INDEX) + continue; +#endif cpm_uart_ports[con].port.line = i; cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_cpm1.c linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_cpm1.c --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_cpm1.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_cpm1.c 2008-06-10 15:38:14.000000000 +0400 @@ -52,6 +52,7 @@ void cpm_line_cr_cmd(int line, int cmd) { ushort val; volatile cpm8xx_t *cp = cpmp; + unsigned *bcsr_io; switch (line) { case UART_SMC1: @@ -94,12 +95,35 @@ void scc1_lineif(struct uart_cpm_port *p { /* XXX SCC1: insert port configuration here */ pinfo->brg = 1; + +#if defined (CONFIG_MPC885ADS) || defined (CONFIG_MPC86XADS) + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_1); + iounmap(bcsr_io); +#endif } void scc2_lineif(struct uart_cpm_port *pinfo) { /* XXX SCC2: insert port configuration here */ pinfo->brg = 2; + unsigned *bcsr_io; + +#if defined (CONFIG_MPC885ADS) || defined (CONFIG_MPC86XADS) + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_2); + iounmap(bcsr_io); +#endif } void scc3_lineif(struct uart_cpm_port *pinfo) @@ -188,6 +212,10 @@ int cpm_uart_init_portdesc(void) { pr_debug("CPM uart[-]:init portdesc\n"); + /* Check if we have called this yet. This may happen if early kgdb + breakpoint is on */ + if(cpm_uart_nr) + return 0; cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0]; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_cpm2.c linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_cpm2.c --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_cpm2.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_cpm2.c 2008-06-10 15:38:14.000000000 +0400 @@ -256,6 +256,10 @@ int cpm_uart_init_portdesc(void) { pr_debug("CPM uart[-]:init portdesc\n"); + /* Check if we have called this yet. This may happen if early kgdb + breakpoint is on */ + if(cpm_uart_nr) + return 0; cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0]; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_kgdb.c linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_kgdb.c --- linux-2.6.18-53.1.14/drivers/serial/cpm_uart/cpm_uart_kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/cpm_uart/cpm_uart_kgdb.c 2008-06-10 15:38:14.000000000 +0400 @@ -0,0 +1,195 @@ +/* + * drivers/serial/cpm_uart/cpm_uart_kgdb.c + * + * CPM UART interface for kgdb. + * + * Author: Vitaly Bordug + * + * Used some bits from drivers/serial/kgdb_8250.c as a template + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* For BASE_BAUD and SERIAL_PORT_DFNS */ + +#include "cpm_uart.h" + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + + +static char kgdb_buf[GDB_BUF_SIZE], *kgdbp; +static int kgdb_chars; + +/* Forward declarations. */ + +/* + * Receive character from the serial port. This only works well + * before the port is initialize for real use. + */ +static int kgdb_wait_key(char *obuf) +{ + struct uart_cpm_port *pinfo; + + u_char c, *cp; + volatile cbd_t *bdp; + int i; + + pinfo = &cpm_uart_ports[KGDB_PINFO_INDEX]; + + /* Get the address of the host memory buffer. + */ + bdp = pinfo->rx_cur; + while (bdp->cbd_sc & BD_SC_EMPTY); + + /* If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + cp = cpm2cpu_addr(bdp->cbd_bufaddr); + + if (obuf) { + i = c = bdp->cbd_datlen; + while (i-- > 0) + { + *obuf++ = *cp++; + } + } else { + c = *cp; + } + bdp->cbd_sc |= BD_SC_EMPTY; + + if (bdp->cbd_sc & BD_SC_WRAP) { + bdp = pinfo->rx_bd_base; + } else { + bdp++; + } + pinfo->rx_cur = (cbd_t *)bdp; + + return((int)c); +} + + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +kgdb_put_debug_char(int chr) +{ + static char ch[2]; + ch[0]=(char)chr; + cpm_uart_early_write(KGDB_PINFO_INDEX, ch, 1); +} + + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + */ +static int +kgdb_get_debug_char(void) +{ + if (kgdb_chars<=0) { + kgdb_chars = kgdb_wait_key(kgdb_buf); + kgdbp = kgdb_buf; + } + kgdb_chars--; + + return (*kgdbp++); +} + +static void termios_set_options(int index, + int baud, int parity, int bits, int flow) +{ + struct termios termios; + struct uart_port *port; + struct uart_cpm_port *pinfo; + + BUG_ON(index>UART_NR); + + port = + (struct uart_port *)&cpm_uart_ports[index]; + pinfo = (struct uart_cpm_port *)port; + + /* + * Ensure that the serial console lock is initialised + * early. + */ + spin_lock_init(&port->lock); + + memset(&termios, 0, sizeof(struct termios)); + + termios.c_cflag = CREAD | HUPCL | CLOCAL; + + termios.c_cflag |= baud; + + if (bits == 7) + termios.c_cflag |= CS7; + else + termios.c_cflag |= CS8; + + switch (parity) { + case 'o': case 'O': + termios.c_cflag |= PARODD; + /*fall through*/ + case 'e': case 'E': + termios.c_cflag |= PARENB; + break; + } + + if (flow == 'r') + termios.c_cflag |= CRTSCTS; + + port->ops->set_termios(port, &termios, NULL); +} + +/* + * Returns: + * 0 on success, 1 on failure. + */ +static int kgdb_init(void) +{ + struct uart_port *port; + struct uart_cpm_port *pinfo; + + int use_bootmem = 0; /* use dma by default */ + + if(!cpm_uart_nr) + { + use_bootmem = 1; + cpm_uart_init_portdesc(); + } + port = (struct uart_port *)&cpm_uart_ports[KGDB_PINFO_INDEX]; + pinfo = (struct uart_cpm_port *)port; + + if (cpm_uart_early_setup(KGDB_PINFO_INDEX, use_bootmem)) + return 1; + + termios_set_options(KGDB_PINFO_INDEX, KGDB_BAUD,'n',8,'n'); + if (IS_SMC(pinfo)) + pinfo->smcp->smc_smcm |= SMCM_TX; + else + pinfo->sccp->scc_sccm |= UART_SCCM_TX; + + return 0; +} + + +struct kgdb_io kgdb_io_ops = { + .read_char = kgdb_get_debug_char, + .write_char = kgdb_put_debug_char, + .init = kgdb_init, +}; + diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/mpsc.c linux-2.6.18-53.1.14.kgdb/drivers/serial/mpsc.c --- linux-2.6.18-53.1.14/drivers/serial/mpsc.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/mpsc.c 2008-06-10 15:38:14.000000000 +0400 @@ -242,6 +242,11 @@ struct mpsc_port_info *mpsc_device_remov #define MPSC_RCRR 0x0004 #define MPSC_TCRR 0x0008 +/* MPSC Interrupt registers (offset from MV64x60_SDMA_INTR_OFFSET) */ +#define MPSC_INTR_CAUSE 0x0004 +#define MPSC_INTR_MASK 0x0084 +#define MPSC_INTR_CAUSE_RCC (1<<6) + /* Serial DMA Controller Interface Registers */ #define SDMA_SDC 0x0000 #define SDMA_SDCM 0x0008 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/mpsc_kgdb.c linux-2.6.18-53.1.14.kgdb/drivers/serial/mpsc_kgdb.c --- linux-2.6.18-53.1.14/drivers/serial/mpsc_kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/mpsc_kgdb.c 2008-06-10 15:38:14.000000000 +0400 @@ -0,0 +1,299 @@ +/* + * drivers/serial/mpsc_kgdb.c + * + * KGDB driver for the Marvell MultiProtocol Serial Controller (MPCS) + * + * Based on the polled boot loader driver by Ajit Prem (ajit.prem@motorola.com) + * + * Author: Randy Vinson + * + * 2005 (c) MontaVista Software, Inc. + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpsc.h" + +/* Speed of the UART. */ +static int kgdbmpsc_baud = CONFIG_KGDB_BAUDRATE; + +/* Index of the UART, matches ttyMX naming. */ +static int kgdbmpsc_ttyMM = CONFIG_KGDB_PORT_NUM; + +#define MPSC_INTR_REG_SELECT(x) ((x) + (8 * kgdbmpsc_ttyMM)) + +static int kgdbmpsc_init(void); + +static struct platform_device mpsc_dev, shared_dev; + +static void __iomem *mpsc_base; +static void __iomem *brg_base; +static void __iomem *routing_base; +static void __iomem *sdma_base; + +static unsigned int mpsc_irq; + +static void kgdb_write_debug_char(int c) +{ + u32 data; + + data = readl(mpsc_base + MPSC_MPCR); + writeb(c, mpsc_base + MPSC_CHR_1); + mb(); + data = readl(mpsc_base + MPSC_CHR_2); + data |= MPSC_CHR_2_TTCS; + writel(data, mpsc_base + MPSC_CHR_2); + mb(); + + while (readl(mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS) ; +} + +static int kgdb_get_debug_char(void) +{ + unsigned char c; + + while (!(readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) & + MPSC_INTR_CAUSE_RCC)) ; + + c = readb(mpsc_base + MPSC_CHR_10 + (1 << 1)); + mb(); + writeb(c, mpsc_base + MPSC_CHR_10 + (1 << 1)); + mb(); + writel(~MPSC_INTR_CAUSE_RCC, sdma_base + + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)); + return (c); +} + +/* + * This is the receiver interrupt routine for the GDB stub. + * All that we need to do is verify that the interrupt happened on the + * line we're in charge of. If this is true, schedule a breakpoint and + * return. + */ +static irqreturn_t +kgdbmpsc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (irq != mpsc_irq) + return IRQ_NONE; + /* + * If there is some other CPU in KGDB then this is a + * spurious interrupt. so return without even checking a byte + */ + if (atomic_read(&debugger_active)) + return IRQ_NONE; + + if (readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) & + MPSC_INTR_CAUSE_RCC) + breakpoint(); + + return IRQ_HANDLED; +} + +static int __init kgdbmpsc_init(void) +{ + struct mpsc_pdata *pdata; + u32 cdv; + + if (!brg_base || !mpsc_base || !routing_base || !sdma_base) + return -1; + + /* Set MPSC Routing to enable both ports */ + writel(0x0, routing_base + MPSC_MRR); + + /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */ + writel(0x00000100, routing_base + MPSC_RCRR); + writel(0x00000100, routing_base + MPSC_TCRR); + + /* Disable all MPSC interrupts and clear any pending interrupts */ + writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)); + + pdata = (struct mpsc_pdata *)mpsc_dev.dev.platform_data; + + /* cdv = (clock/(2*16*baud rate)) for 16X mode. */ + cdv = ((pdata->brg_clk_freq / (32 * kgdbmpsc_baud)) - 1); + writel((pdata->brg_clk_src << 18) | (1 << 16) | cdv, + brg_base + BRG_BCR); + + /* Put MPSC into UART mode, no null modem, 16x clock mode */ + writel(0x000004c4, mpsc_base + MPSC_MMCRL); + writel(0x04400400, mpsc_base + MPSC_MMCRH); + + writel(0, mpsc_base + MPSC_CHR_1); + writel(0, mpsc_base + MPSC_CHR_9); + writel(0, mpsc_base + MPSC_CHR_10); + writel(4, mpsc_base + MPSC_CHR_3); + writel(0x20000000, mpsc_base + MPSC_CHR_4); + writel(0x9000, mpsc_base + MPSC_CHR_5); + writel(0, mpsc_base + MPSC_CHR_6); + writel(0, mpsc_base + MPSC_CHR_7); + writel(0, mpsc_base + MPSC_CHR_8); + + /* 8 data bits, 1 stop bit */ + writel((3 << 12), mpsc_base + MPSC_MPCR); + + /* Enter "hunt" mode */ + writel((1 << 31), mpsc_base + MPSC_CHR_2); + + udelay(100); + return 0; +} + +static void __iomem *__init +kgdbmpsc_map_resource(struct platform_device *pd, int type, int num) +{ + void __iomem *base = NULL; + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, num))) + base = ioremap(r->start, r->end - r->start + 1); + return base; +} + +static void __iomem *__init +kgdbmpsc_unmap_resource(struct platform_device *pd, int type, int num, + void __iomem * base) +{ + if (base) + iounmap(base); + return NULL; +} + +static void __init +kgdbmpsc_reserve_resource(struct platform_device *pd, int type, int num) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, num))) + request_mem_region(r->start, r->end - r->start + 1, "kgdb"); +} + +static int __init kgdbmpsc_local_init(void) +{ + if (!mpsc_dev.num_resources || !shared_dev.num_resources) + return 1; /* failure */ + + mpsc_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER); + brg_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER); + + /* get the platform data for the shared registers and get them mapped */ + routing_base = kgdbmpsc_map_resource(&shared_dev, + IORESOURCE_MEM, + MPSC_ROUTING_BASE_ORDER); + sdma_base = + kgdbmpsc_map_resource(&shared_dev, IORESOURCE_MEM, + MPSC_SDMA_INTR_BASE_ORDER); + + mpsc_irq = platform_get_irq(&mpsc_dev, 1); + + if (mpsc_base && brg_base && routing_base && sdma_base) + return 0; /* success */ + + return 1; /* failure */ +} + +static void __init kgdbmpsc_local_exit(void) +{ + if (sdma_base) + sdma_base = kgdbmpsc_unmap_resource(&shared_dev, IORESOURCE_MEM, + MPSC_SDMA_INTR_BASE_ORDER, + sdma_base); + if (routing_base) + routing_base = kgdbmpsc_unmap_resource(&shared_dev, + IORESOURCE_MEM, + MPSC_ROUTING_BASE_ORDER, + routing_base); + if (brg_base) + brg_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER, + brg_base); + if (mpsc_base) + mpsc_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER, mpsc_base); +} + +static void __init kgdbmpsc_update_pdata(struct platform_device *pdev) +{ + + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id); +} + +static int __init kgdbmpsc_pdev_init(void) +{ + struct platform_device *pdev; + + /* get the platform data for the specified port. */ + pdev = mv64x60_early_get_pdev_data(MPSC_CTLR_NAME, kgdbmpsc_ttyMM, 1); + if (pdev) { + memcpy(&mpsc_dev, pdev, sizeof(struct platform_device)); + if (platform_notify) { + kgdbmpsc_update_pdata(&mpsc_dev); + platform_notify(&mpsc_dev.dev); + } + + /* get the platform data for the shared registers. */ + pdev = mv64x60_early_get_pdev_data(MPSC_SHARED_NAME, 0, 0); + if (pdev) { + memcpy(&shared_dev, pdev, + sizeof(struct platform_device)); + if (platform_notify) { + kgdbmpsc_update_pdata(&shared_dev); + platform_notify(&shared_dev.dev); + } + } + } + return 0; +} + +postcore_initcall(kgdbmpsc_pdev_init); + +static int __init kgdbmpsc_init_io(void) +{ + + kgdbmpsc_pdev_init(); + + if (kgdbmpsc_local_init()) { + kgdbmpsc_local_exit(); + return -1; + } + + if (kgdbmpsc_init() == -1) + return -1; + return 0; +} + +static void __init kgdbmpsc_hookup_irq(void) +{ + unsigned int msk; + if (!request_irq(mpsc_irq, kgdbmpsc_interrupt, 0, "kgdb mpsc", NULL)) { + /* Enable interrupt */ + msk = readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + msk |= MPSC_INTR_CAUSE_RCC; + writel(msk, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + + kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER); + kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER); + } +} + +struct kgdb_io kgdb_io_ops = { + .read_char = kgdb_get_debug_char, + .write_char = kgdb_write_debug_char, + .init = kgdbmpsc_init_io, + .late_init = kgdbmpsc_hookup_irq, +}; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/pxa.c linux-2.6.18-53.1.14.kgdb/drivers/serial/pxa.c --- linux-2.6.18-53.1.14/drivers/serial/pxa.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/pxa.c 2008-06-10 15:38:56.000000000 +0400 @@ -42,6 +42,9 @@ #include #include #include +#ifdef CONFIG_KGDB_CONSOLE +#include +#endif #include #include @@ -692,6 +695,8 @@ serial_pxa_console_init(void) console_initcall(serial_pxa_console_init); #define PXA_CONSOLE &serial_pxa_console +#elif defined(CONFIG_KGDB_CONSOLE) +#define PXA_CONSOLE &kgdbcons #else #define PXA_CONSOLE NULL #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/serial_core.c linux-2.6.18-53.1.14.kgdb/drivers/serial/serial_core.c --- linux-2.6.18-53.1.14/drivers/serial/serial_core.c 2008-03-06 05:54:07.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/serial_core.c 2008-06-10 15:37:43.000000000 +0400 @@ -33,6 +33,7 @@ #include /* for serial_state and serial_icounter_struct */ #include #include +#include #include #include @@ -65,6 +66,12 @@ static struct lock_class_key port_lock_k #define uart_console(port) (0) #endif +#ifdef CONFIG_KGDB_CONSOLE +#define uart_kgdb(port) (port->cons && !strcmp(port->cons->name, "kgdb")) +#else +#define uart_kgdb(port) (0) +#endif + static void uart_change_speed(struct uart_state *state, struct termios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); @@ -1673,6 +1680,9 @@ static int uart_line_info(char *buf, str port->iotype == UPIO_MEM ? port->mapbase : (unsigned long) port->iobase, port->irq); + if (port->iotype == UPIO_MEM) + ret += sprintf(buf+ret, " membase 0x%08lX", + (unsigned long) port->membase); if (port->type == PORT_UNKNOWN) { strcat(buf, "\n"); @@ -2043,7 +2053,8 @@ uart_report_port(struct uart_driver *drv case UPIO_AU: case UPIO_TSI: snprintf(address, sizeof(address), - "MMIO 0x%lx", port->mapbase); + "MMIO map 0x%lx mem 0x%lx", port->mapbase, + (unsigned long) port->membase); break; default: strlcpy(address, "*unknown*", sizeof(address)); @@ -2095,9 +2106,9 @@ uart_configure_port(struct uart_driver * /* * Power down all ports by default, except the - * console if we have one. + * console (real or kgdb) if we have one. */ - if (!uart_console(port)) + if (!uart_console(port) && !uart_kgdb(port)) uart_change_pm(state, 3); } } @@ -2289,6 +2300,12 @@ int uart_add_one_port(struct uart_driver */ port->flags &= ~UPF_DEAD; +#if defined(CONFIG_KGDB_8250) + /* Add any 8250-like ports we find later. */ + if (port->type <= PORT_MAX_8250) + kgdb8250_add_port(port->line, port); +#endif + out: mutex_unlock(&state->mutex); mutex_unlock(&port_mutex); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/serial_txx9.c linux-2.6.18-53.1.14.kgdb/drivers/serial/serial_txx9.c --- linux-2.6.18-53.1.14/drivers/serial/serial_txx9.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/serial_txx9.c 2008-06-10 15:38:24.000000000 +0400 @@ -1164,6 +1164,96 @@ static struct pci_driver serial_txx9_pci MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); #endif /* ENABLE_SERIAL_TXX9_PCI */ +/******************************************************************************/ +/* BEG: KDBG Routines */ +/******************************************************************************/ + +#ifdef CONFIG_KGDB +int kgdb_init_count = 0; + +void txx9_sio_kgdb_hook(unsigned int port, unsigned int baud_rate) +{ + static struct resource kgdb_resource; + int ret; + struct uart_txx9_port *up = &serial_txx9_ports[port]; + + /* prevent initialization by driver */ + kgdb_resource.name = "serial_txx9(debug)"; + kgdb_resource.start = (unsigned long)up->port.membase; + kgdb_resource.end = (unsigned long)(up->port.membase + 36 - 1); + kgdb_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + ret = request_resource(&iomem_resource, &kgdb_resource); + if(ret == -EBUSY) + printk(" serial_txx9(debug): request_resource failed\n"); + + return; +} +void +txx9_sio_kdbg_init( unsigned int port_number ) +{ + if (port_number == 1) { + txx9_sio_kgdb_hook(port_number, 38400); + } else { + printk("Bad Port Number [%u] != [1]\n",port_number); + } + return; +} + +u8 +txx9_sio_kdbg_rd( void ) +{ + unsigned int status,ch; + struct uart_txx9_port *up = &serial_txx9_ports[1]; + + if (kgdb_init_count == 0) { + txx9_sio_kdbg_init(1); + kgdb_init_count = 1; + } + + while (1) { + status = sio_in(up, TXX9_SIDISR); + if ( status & 0x1f ) { + ch = sio_in(up, TXX9_SIRFIFO ); + break; + } + } + + return (ch); +} + +int +txx9_sio_kdbg_wr( u8 ch ) +{ + unsigned int status; + struct uart_txx9_port *up = &serial_txx9_ports[1]; + + if (kgdb_init_count == 0) { + txx9_sio_kdbg_init(1); + kgdb_init_count = 1; + } + + while (1) { + status = sio_in(up, TXX9_SICISR); + if (status & TXX9_SICISR_TRDY) { + if ( ch == '\n' ) { + txx9_sio_kdbg_wr( '\r' ); + } + sio_out(up, TXX9_SITFIFO, (u32)ch ); + + break; + } + } + + return (1); +} +#endif /* CONFIG_KGDB */ + + +/******************************************************************************/ +/* END: KDBG Routines */ +/******************************************************************************/ + static int __init serial_txx9_init(void) { int ret; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/drivers/serial/sh-sci.c linux-2.6.18-53.1.14.kgdb/drivers/serial/sh-sci.c --- linux-2.6.18-53.1.14/drivers/serial/sh-sci.c 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/drivers/serial/sh-sci.c 2008-06-10 15:38:50.000000000 +0400 @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef CONFIG_CPU_FREQ #include @@ -67,14 +68,16 @@ #include "sh-sci.h" -#ifdef CONFIG_SH_KGDB -#include - -static int kgdb_get_char(struct sci_port *port); -static void kgdb_put_char(struct sci_port *port, char c); -static void kgdb_handle_error(struct sci_port *port); -static struct sci_port *kgdb_sci_port; -#endif /* CONFIG_SH_KGDB */ +#ifdef CONFIG_KGDB_SH_SCI +/* Speed of the UART. */ +static int kgdbsci_baud = CONFIG_KGDB_BAUDRATE + +/* Index of the UART, matches ttySCX naming. */ +static int kgdbsci_ttySC = CONFIG_KGDB_PORT_NUM; + +/* Make life easier on us. */ +#define KGDBPORT sci_ports[kgdbsci_ttySC] +#endif /* CONFIG_KGDB_SH_SCI */ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE static struct sci_port *serial_console_port = 0; @@ -87,20 +90,17 @@ static void sci_start_rx(struct uart_por static void sci_stop_rx(struct uart_port *port); static int sci_request_irq(struct sci_port *port); static void sci_free_irq(struct sci_port *port); +static void sci_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old); +static int kgdbsci_init(void); static struct sci_port sci_ports[]; static struct uart_driver sci_uart_driver; #define SCI_NPORTS sci_uart_driver.nr -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - -static void handle_error(struct uart_port *port) -{ /* Clear error flags */ - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); -} - -static int get_char(struct uart_port *port) +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB_SH_SCI) +static int get_char_for_gdb(struct uart_port *port) { unsigned long flags; unsigned short status; @@ -110,7 +110,8 @@ static int get_char(struct uart_port *po do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - handle_error(port); + /* Clear error flags. */ + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); continue; } } while (!(status & SCxSR_RDxF(port))); @@ -121,21 +122,7 @@ static int get_char(struct uart_port *po return c; } - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; - -static __inline__ char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static __inline__ char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB_SH_SCI */ /* * Send the packet in buffer. The host gets one chance to read it. @@ -167,21 +154,14 @@ static void put_string(struct sci_port * const unsigned char *p = buffer; int i; -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +#ifdef CONFIG_SH_STANDARD_BIOS int checksum; - int usegdb=0; + const char hexchars[] = "0123456789abcdef"; -#ifdef CONFIG_SH_STANDARD_BIOS /* This call only does a trap the first time it is * called, and so is safe to do here unconditionally */ - usegdb |= sh_bios_in_gdb_mode(); -#endif -#ifdef CONFIG_SH_KGDB - usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); -#endif - - if (usegdb) { + if (sh_bios_in_gdb_mode()) { /* $#. */ do { unsigned char c; @@ -193,18 +173,18 @@ static void put_string(struct sci_port * int h, l; c = *p++; - h = highhex(c); - l = lowhex(c); + h = hexchars[c >> 4]; + l = hexchars[c % 16]; put_char(port, h); put_char(port, l); checksum += h + l; } put_char(port, '#'); - put_char(port, highhex(checksum)); - put_char(port, lowhex(checksum)); + put_char(port, hexchars[checksum >> 4]); + put_char(port, hexchars[checksum % 16]); } while (get_char(port) != '+'); } else -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ +#endif /* CONFIG_SH_STANDARD_BIOS */ for (i=0; i SCI_NPORTS + '0') + goto errout; + kgdbsci_ttySC = *str - '0'; + str++; + if (*str != ',') + goto errout; + str++; + kgdbsci_baud = simple_strtoul(str, &str, 10); + if (kgdbsci_baud != 9600 && kgdbsci_baud != 19200 && + kgdbsci_baud != 38400 && kgdbsci_baud != 57600 && + kgdbsci_baud != 115200) + goto errout; + + return 0; + +errout: + printk(KERN_ERR "Invalid syntax for option kgdbsci=\n"); + return 1; +} +__setup("kgdbsci", kgdbsci_opt); +#endif /* CONFIG_KGDB_SH_SCI */ #if defined(__H8300S__) enum { sci_disable, sci_enable }; @@ -555,6 +608,16 @@ static inline void sci_receive_chars(str continue; } +#ifdef CONFIG_KGDB_SH_SCI + /* We assume that a ^C on the port KGDB + * is using means that KGDB wants to + * interrupt the running system. + */ + if (port->line == KGDBPORT.port.line && + c == 3) + breakpoint(); +#endif + /* Store data and status */ if (status&SCxSR_FER(port)) { flag = TTY_FRAME; @@ -1618,6 +1681,7 @@ static int __init sci_console_init(void) console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ +#if 0 #ifdef CONFIG_SH_KGDB /* * FIXME: Most of this can go away.. at the moment, we rely on @@ -1663,30 +1727,9 @@ int __init kgdb_console_setup(struct con return uart_set_options(port, co, baud, parity, bits, flow); } #endif /* CONFIG_SH_KGDB */ +#endif /* 0 */ -#ifdef CONFIG_SH_KGDB_CONSOLE -static struct console kgdb_console = { - .name = "ttySC", - .write = kgdb_console_write, - .setup = kgdb_console_setup, - .flags = CON_PRINTBUFFER | CON_ENABLED, - .index = -1, - .data = &sci_uart_driver, -}; - -/* Register the KGDB console so we get messages (d'oh!) */ -static int __init kgdb_console_init(void) -{ - register_console(&kgdb_console); - return 0; -} - -console_initcall(kgdb_console_init); -#endif /* CONFIG_SH_KGDB_CONSOLE */ - -#if defined(CONFIG_SH_KGDB_CONSOLE) -#define SCI_CONSOLE &kgdb_console -#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE) +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE #define SCI_CONSOLE &serial_console #else #define SCI_CONSOLE 0 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-arm/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-arm/kgdb.h --- linux-2.6.18-53.1.14/include/asm-arm/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-arm/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,92 @@ +/* + * include/asm-arm/kgdb.h + * + * ARM KGDB support + * + * Author: Deepak Saxena + * + * Copyright (C) 2002 MontaVista Software Inc. + * + */ + +#ifndef __ASM_KGDB_H__ +#define __ASM_KGDB_H__ + +#include +#include +#include + + +/* + * GDB assumes that we're a user process being debugged, so + * it will send us an SWI command to write into memory as the + * debug trap. When an SWI occurs, the next instruction addr is + * placed into R14_svc before jumping to the vector trap. + * This doesn't work for kernel debugging as we are already in SVC + * we would loose the kernel's LR, which is a bad thing. This + * is bad thing. + * + * By doing this as an undefined instruction trap, we force a mode + * switch from SVC to UND mode, allowing us to save full kernel state. + * + * We also define a KGDB_COMPILED_BREAK which can be used to compile + * in breakpoints. This is important for things like sysrq-G and for + * the initial breakpoint from trap_init(). + * + * Note to ARM HW designers: Add real trap support like SH && PPC to + * make our lives much much simpler. :) + */ +#define BREAK_INSTR_SIZE 4 +#define GDB_BREAKINST 0xef9f0001 +#define KGDB_BREAKINST 0xe7ffdefe +#define KGDB_COMPILED_BREAK 0xe7ffdeff +#define CACHE_FLUSH_IS_SAFE 1 + +#ifndef __ASSEMBLY__ + +#define BREAKPOINT() asm(".word 0xe7ffdeff") + + +extern void kgdb_handle_bus_error(void); +extern int kgdb_fault_expected; +#endif /* !__ASSEMBLY__ */ + +/* + * From Amit S. Kale: + * + * In the register packet, words 0-15 are R0 to R10, FP, IP, SP, LR, PC. But + * Register 16 isn't cpsr. GDB passes CPSR in word 25. There are 9 words in + * between which are unused. Passing only 26 words to gdb is sufficient. + * GDB can figure out that floating point registers are not passed. + * GDB_MAX_REGS should be 26. + */ +#define GDB_MAX_REGS (26) + +#define KGDB_MAX_NO_CPUS 1 +#define BUFMAX 400 +#define NUMREGBYTES (GDB_MAX_REGS << 2) +#define NUMCRITREGBYTES (32 << 2) + +#define _R0 0 +#define _R1 1 +#define _R2 2 +#define _R3 3 +#define _R4 4 +#define _R5 5 +#define _R6 6 +#define _R7 7 +#define _R8 8 +#define _R9 9 +#define _R10 10 +#define _FP 11 +#define _IP 12 +#define _SP 13 +#define _LR 14 +#define _PC 15 +#define _CPSR (GDB_MAX_REGS - 1) + +/* So that we can denote the end of a frame for tracing, in the simple + * case. */ +#define CFI_END_FRAME(func) __CFI_END_FRAME(_PC,_SP,func) + +#endif /* __ASM_KGDB_H__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-arm/system.h linux-2.6.18-53.1.14.kgdb/include/asm-arm/system.h --- linux-2.6.18-53.1.14/include/asm-arm/system.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-arm/system.h 2008-06-10 15:38:56.000000000 +0400 @@ -444,6 +444,47 @@ static inline unsigned long __xchg(unsig extern void disable_hlt(void); extern void enable_hlt(void); +#define __HAVE_ARCH_CMPXCHG 1 + +#include + +static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, + unsigned long new) +{ + u32 retval; + unsigned long flags; + + local_irq_save(flags); + retval = *m; + if (retval == old) + *m = new; + local_irq_restore(flags); /* implies memory barrier */ + + return retval; +} + +/* This function doesn't exist, so you'll get a linker error + if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) #endif /* __ASSEMBLY__ */ #define arch_align_stack(x) (x) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-generic/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-generic/kgdb.h --- linux-2.6.18-53.1.14/include/asm-generic/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-generic/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,34 @@ +/* + * include/asm-generic/kgdb.h + * + * This provides the assembly level information so that KGDB can provide + * a GDB that has been patched with enough information to know to stop + * trying to unwind the function. + * + * Author: Tom Rini + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under the terms + * of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#ifndef __ASM_GENERIC_KGDB_H__ +#define __ASM_GENERIC_KGDB_H__ + +#include +#ifdef __ASSEMBLY__ +#ifdef CONFIG_KGDB +/* This MUST be put at the end of a given assembly function */ +#define __CFI_END_FRAME(pc,sp,func) \ +CAT3(.Lend_,func,:) \ + CFI_preamble(func,pc,0x1,-DATA_ALIGN_FACTOR) \ + CFA_define_reference(sp, 0) \ + CFA_undefine_reg(pc) \ + CFI_postamble() \ + FDE_preamble(func,func,CAT3(.Lend,_,func)) \ + FDE_postamble() +#else +#define __CFI_END_FRAME(pc,sp,fn) +#endif /* CONFIG_KGDB */ +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_GENERIC_KGDB_H__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-i386/kdebug.h linux-2.6.18-53.1.14.kgdb/include/asm-i386/kdebug.h --- linux-2.6.18-53.1.14/include/asm-i386/kdebug.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-i386/kdebug.h 2008-06-10 15:38:03.000000000 +0400 @@ -39,6 +39,7 @@ enum die_val { DIE_CALL, DIE_NMI_IPI, DIE_PAGE_FAULT, + DIE_PAGE_FAULT_NO_CONTEXT, }; static inline int notify_die(enum die_val val, const char *str, diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-i386/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-i386/kgdb.h --- linux-2.6.18-53.1.14/include/asm-i386/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-i386/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,58 @@ +#ifdef __KERNEL__ +#ifndef _ASM_KGDB_H_ +#define _ASM_KGDB_H_ + +/* + * Copyright (C) 2001-2004 Amit S. Kale + */ + +#include + +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +#define _EAX 0 +#define _ECX 1 +#define _EDX 2 +#define _EBX 3 +#define _ESP 4 +#define _EBP 5 +#define _ESI 6 +#define _EDI 7 +#define _PC 8 +#define _EIP 8 +#define _PS 9 +#define _EFLAGS 9 +#define _CS 10 +#define _SS 11 +#define _DS 12 +#define _ES 13 +#define _FS 14 +#define _GS 15 + +/* So that we can denote the end of a frame for tracing, in the simple + * case. */ +#define CFI_END_FRAME(func) __CFI_END_FRAME(_EIP,_ESP,func) + +#ifndef __ASSEMBLY__ +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 1024 + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +/* Number of bytes of registers we need to save for a setjmp/longjmp. */ +#define NUMCRITREGBYTES 24 + +#define BREAKPOINT() asm(" int $3"); +#define BREAK_INSTR_SIZE 1 +#define CACHE_FLUSH_IS_SAFE 1 +#endif /* !__ASSEMBLY__ */ +#endif /* _ASM_KGDB_H_ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ia64/kdebug.h linux-2.6.18-53.1.14.kgdb/include/asm-ia64/kdebug.h --- linux-2.6.18-53.1.14/include/asm-ia64/kdebug.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ia64/kdebug.h 2008-06-10 15:38:32.000000000 +0400 @@ -72,6 +72,7 @@ enum die_val { DIE_KDEBUG_LEAVE, DIE_KDUMP_ENTER, DIE_KDUMP_LEAVE, + DIE_PAGE_FAULT_NO_CONTEXT, }; static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ia64/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-ia64/kgdb.h --- linux-2.6.18-53.1.14/include/asm-ia64/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ia64/kgdb.h 2008-06-10 15:38:32.000000000 +0400 @@ -0,0 +1,36 @@ +#ifdef __KERNEL__ +#ifndef _ASM_KGDB_H_ +#define _ASM_KGDB_H_ + +/* + * Copyright (C) 2001-2004 Amit S. Kale + */ + +#include + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 1024 + +/* Number of bytes of registers. We set this to 0 so that certain GDB + * packets will fail, forcing the use of others, which are more friendly + * on ia64. */ +#define NUMREGBYTES 0 + +#define NUMCRITREGBYTES (70*8) +#define JMP_REGS_ALIGNMENT __attribute__ ((aligned (16))) + +#define BREAKNUM 0x00003333300LL +#define KGDBBREAKNUM 0x6665UL +#define BREAKPOINT() asm volatile ("break.m 0x6665") +#define BREAK_INSTR_SIZE 16 +#define CACHE_FLUSH_IS_SAFE 1 + +struct pt_regs; +extern volatile int kgdb_hwbreak_sstep[NR_CPUS]; +extern void smp_send_nmi_allbutself(void); +extern void kgdb_wait_ipi(struct pt_regs *); +#endif /* _ASM_KGDB_H_ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-mips/kdebug.h linux-2.6.18-53.1.14.kgdb/include/asm-mips/kdebug.h --- linux-2.6.18-53.1.14/include/asm-mips/kdebug.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-mips/kdebug.h 2008-06-10 15:38:24.000000000 +0400 @@ -0,0 +1,47 @@ +/* + * + * Copyright (C) 2004 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com + * + * 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. + * + */ +#ifndef _MIPS_KDEBUG_H +#define _MIPS_KDEBUG_H + +#include + +struct pt_regs; + +struct die_args { + struct pt_regs *regs; + const char *str; + long err; +}; + +int register_die_notifier(struct notifier_block *nb); +extern struct notifier_block *mips_die_chain; + +enum die_val { + DIE_OOPS = 1, + DIE_PANIC, + DIE_DIE, + DIE_KERNELDEBUG, + DIE_TRAP, + DIE_PAGE_FAULT, +}; + +/* + * trap number can be computed from regs and signr can be computed using + * compute_signal() + */ +static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err) +{ + struct die_args args = { .regs=regs, .str=str, .err=err }; + return notifier_call_chain(&mips_die_chain, val, &args); +} + +#endif /* _MIPS_KDEBUG_H */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-mips/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-mips/kgdb.h --- linux-2.6.18-53.1.14/include/asm-mips/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-mips/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,34 @@ +#ifdef __KERNEL__ +#ifndef _ASM_KGDB_H_ +#define _ASM_KGDB_H_ + +#ifndef __ASSEMBLY__ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) +typedef u32 gdb_reg_t; +#elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) +typedef u64 gdb_reg_t; +#else +#error need to do +#endif /* _MIPS_ISA */ + +#include + +#ifndef __ASSEMBLY__ +#define BUFMAX 2048 +#define NUMREGBYTES (90*sizeof(gdb_reg_t)) +#define NUMCRITREGBYTES (12*sizeof(gdb_reg_t)) +#define BREAK_INSTR_SIZE 4 +#define BREAKPOINT() __asm__ __volatile__( \ + ".globl breakinst\n\t" \ + ".set\tnoreorder\n\t" \ + "nop\n" \ + "breakinst:\tbreak\n\t" \ + "nop\n\t" \ + ".set\treorder") +#define CACHE_FLUSH_IS_SAFE 0 + +extern int kgdb_early_setup; + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASM_KGDB_H_ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-powerpc/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-powerpc/kgdb.h --- linux-2.6.18-53.1.14/include/asm-powerpc/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-powerpc/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,74 @@ +/* + * include/asm-powerpc/kgdb.h + * + * The PowerPC (32/64) specific defines / externs for KGDB. Based on + * the previous 32bit and 64bit specific files, which had the following + * copyrights: + * + * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) + * PPC Mods (C) 2004 Tom Rini (trini@mvista.com) + * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com) + * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) + * + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Author: Tom Rini + * + * 2006 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifdef __KERNEL__ +#ifndef __POWERPC_KGDB_H__ +#define __POWERPC_KGDB_H__ + +#include +#ifndef __ASSEMBLY__ + +#define BREAK_INSTR_SIZE 4 +#define BUFMAX ((NUMREGBYTES * 2) + 512) +#define OUTBUFMAX ((NUMREGBYTES * 2) + 512) +#define BREAKPOINT() asm(".long 0x7d821008"); /* twge r2, r2 */ +#define CACHE_FLUSH_IS_SAFE 1 + +/* The number bytes of registers we have to save depends on a few + * things. For 64bit we default to not including vector registers and + * vector state registers. */ +#ifdef CONFIG_PPC64 +/* + * 64 bit (8 byte) registers: + * 32 gpr, 32 fpr, nip, msr, link, ctr + * 32 bit (4 byte) registers: + * ccr, xer, fpscr + */ +#define NUMREGBYTES ((68 * 8) + (3 * 4)) +#if 0 +/* The following adds in vector registers and vector state registers. */ +/* 128 bit (16 byte) registers: + * 32 vr + * 64 bit (8 byte) registers: + * 32 gpr, 32 fpr, nip, msr, link, ctr + * 32 bit (4 byte) registers: + * ccr, xer, fpscr, vscr, vrsave + */ +#define NUMREGBYTES ((128 * 16) + (68 * 8) + (5 * 4)) +#endif +#define NUMCRITREGBYTES 184 +#else /* CONFIG_PPC32 */ +/* On non-E500 family PPC32 we determine the size by picking the last + * register we need, but on E500 we skip sections so we list what we + * need to store, and add it up. */ +#ifndef CONFIG_E500 +#define MAXREG (PT_FPSCR+1) +#else +/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/ +#define MAXREG ((32*2)+6+2+1) +#endif +#define NUMREGBYTES (MAXREG * sizeof(int)) +/* CR/LR, R1, R2, R13-R31 inclusive. */ +#define NUMCRITREGBYTES (23 * sizeof(int)) +#endif /* 32/64 */ +#endif /* !(__ASSEMBLY__) */ +#endif /* !__POWERPC_KGDB_H__ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ppc/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-ppc/kgdb.h --- linux-2.6.18-53.1.14/include/asm-ppc/kgdb.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ppc/kgdb.h 2008-06-10 15:38:14.000000000 +0400 @@ -1,57 +1,18 @@ -/* - * kgdb.h: Defines and declarations for serial line source level - * remote debugging of the Linux kernel using gdb. - * - * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ #ifdef __KERNEL__ -#ifndef _PPC_KGDB_H -#define _PPC_KGDB_H - +#ifndef __PPC_KGDB_H__ +#define __PPC_KGDB_H__ +#include #ifndef __ASSEMBLY__ - -/* Things specific to the gen550 backend. */ -struct uart_port; - -extern void gen550_progress(char *, unsigned short); -extern void gen550_kgdb_map_scc(void); -extern void gen550_init(int, struct uart_port *); - -/* Things specific to the pmac backend. */ -extern void zs_kgdb_hook(int tty_num); - -/* To init the kgdb engine. (called by serial hook)*/ -extern void set_debug_traps(void); - -/* To enter the debugger explicitly. */ -extern void breakpoint(void); - -/* For taking exceptions + /* For taking exceptions * these are defined in traps.c */ -extern int (*debugger)(struct pt_regs *regs); +struct pt_regs; +extern void (*debugger)(struct pt_regs *regs); extern int (*debugger_bpt)(struct pt_regs *regs); extern int (*debugger_sstep)(struct pt_regs *regs); extern int (*debugger_iabr_match)(struct pt_regs *regs); extern int (*debugger_dabr_match)(struct pt_regs *regs); extern void (*debugger_fault_handler)(struct pt_regs *regs); - -/* What we bring to the party */ -int kgdb_bpt(struct pt_regs *regs); -int kgdb_sstep(struct pt_regs *regs); -void kgdb(struct pt_regs *regs); -int kgdb_iabr_match(struct pt_regs *regs); -int kgdb_dabr_match(struct pt_regs *regs); - -/* - * external low-level support routines (ie macserial.c) - */ -extern void kgdb_interruptible(int); /* control interrupts from serial */ -extern void putDebugChar(char); /* write a single character */ -extern char getDebugChar(void); /* read and return a single char */ - -#endif /* !(__ASSEMBLY__) */ -#endif /* !(_PPC_KGDB_H) */ +#endif /* !__ASSEMBLY__ */ +#endif /* __PPC_KGDB_H__ */ #endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ppc/machdep.h linux-2.6.18-53.1.14.kgdb/include/asm-ppc/machdep.h --- linux-2.6.18-53.1.14/include/asm-ppc/machdep.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ppc/machdep.h 2008-06-10 15:38:14.000000000 +0400 @@ -72,9 +72,7 @@ struct machdep_calls { unsigned long (*find_end_of_memory)(void); void (*setup_io_mappings)(void); - void (*early_serial_map)(void); void (*progress)(char *, unsigned short); - void (*kgdb_map_scc)(void); unsigned char (*nvram_read_val)(int addr); void (*nvram_write_val)(int addr, unsigned char val); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ppc/mv64x60.h linux-2.6.18-53.1.14.kgdb/include/asm-ppc/mv64x60.h --- linux-2.6.18-53.1.14/include/asm-ppc/mv64x60.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ppc/mv64x60.h 2008-06-10 15:38:14.000000000 +0400 @@ -348,6 +348,8 @@ u32 mv64x60_calc_mem_size(struct mv64x60 void mv64x60_progress_init(u32 base); void mv64x60_mpsc_progress(char *s, unsigned short hex); +struct platform_device * mv64x60_early_get_pdev_data(const char *name, + int id, int remove); extern struct mv64x60_32bit_window gt64260_32bit_windows[MV64x60_32BIT_WIN_COUNT]; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-ppc/mv64x60_defs.h linux-2.6.18-53.1.14.kgdb/include/asm-ppc/mv64x60_defs.h --- linux-2.6.18-53.1.14/include/asm-ppc/mv64x60_defs.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-ppc/mv64x60_defs.h 2008-06-10 15:38:14.000000000 +0400 @@ -57,7 +57,8 @@ #define MV64x60_IRQ_I2C 37 #define MV64x60_IRQ_BRG 39 #define MV64x60_IRQ_MPSC_0 40 -#define MV64x60_IRQ_MPSC_1 42 +#define MV64360_IRQ_MPSC_1 41 +#define GT64260_IRQ_MPSC_1 42 #define MV64x60_IRQ_COMM 43 #define MV64x60_IRQ_P0_GPP_0_7 56 #define MV64x60_IRQ_P0_GPP_8_15 57 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-sh/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-sh/kgdb.h --- linux-2.6.18-53.1.14/include/asm-sh/kgdb.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-sh/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -2,94 +2,40 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Based on original code by Glenn Engel, Jim Kingdon, - * David Grothe , Tigran Aivazian, and - * Amit S. Kale + * Based on a file that was modified or based on files by: Glenn Engel, + * Jim Kingdon, David Grothe , Tigran Aivazian , + * Amit S. Kale , sh-stub.c from Ben Lee and + * Steve Chamberlain, Henry Bell * - * Super-H port based on sh-stub.c (Ben Lee and Steve Chamberlain) by - * Henry Bell - * - * Header file for low-level support for remote debug using GDB. + * Maintainer: Tom Rini * */ #ifndef __KGDB_H #define __KGDB_H -#include - -struct console; +#include +/* Based on sh-gdb.c from gdb-6.1, Glenn + Engel at HP Ben Lee and Steve Chamberlain */ +#define NUMREGBYTES 112 /* 92 */ +#define NUMCRITREGBYTES (9 << 2) +#define BUFMAX 400 -/* Same as pt_regs but has vbr in place of syscall_nr */ +#ifndef __ASSEMBLY__ struct kgdb_regs { unsigned long regs[16]; unsigned long pc; unsigned long pr; - unsigned long sr; unsigned long gbr; + unsigned long vbr; unsigned long mach; unsigned long macl; - unsigned long vbr; -}; - -/* State info */ -extern char kgdb_in_gdb_mode; -extern int kgdb_done_init; -extern int kgdb_enabled; -extern int kgdb_nofault; /* Ignore bus errors (in gdb mem access) */ -extern int kgdb_halt; /* Execute initial breakpoint at startup */ -extern char in_nmi; /* Debounce flag to prevent NMI reentry*/ - -/* SCI */ -extern int kgdb_portnum; -extern int kgdb_baud; -extern char kgdb_parity; -extern char kgdb_bits; -extern int kgdb_console_setup(struct console *, char *); - -/* Init and interface stuff */ -extern int kgdb_init(void); -extern int (*kgdb_serial_setup)(void); -extern int (*kgdb_getchar)(void); -extern void (*kgdb_putchar)(int); - -struct kgdb_sermap { - char *name; - int namelen; - int (*setup_fn)(struct console *, char *); - struct kgdb_sermap *next; + unsigned long sr; }; -extern void kgdb_register_sermap(struct kgdb_sermap *map); -extern struct kgdb_sermap *kgdb_porttype; -/* Trap functions */ -typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); -typedef void (kgdb_bus_error_hook_t)(void); -extern kgdb_debug_hook_t *kgdb_debug_hook; -extern kgdb_bus_error_hook_t *kgdb_bus_err_hook; - -extern void breakpoint(void); - -/* Console */ -struct console; -void kgdb_console_write(struct console *co, const char *s, unsigned count); -void kgdb_console_init(void); - -/* Prototypes for jmp fns */ -#define _JBLEN 9 -typedef int jmp_buf[_JBLEN]; -extern void longjmp(jmp_buf __jmpb, int __retval); -extern int setjmp(jmp_buf __jmpb); - -/* Variadic macro to print our own message to the console */ -#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__) - -/* Forced breakpoint */ -#define BREAKPOINT() do { \ - if (kgdb_enabled) { \ - asm volatile("trapa #0xff"); \ - } \ -} while (0) +#define BREAKPOINT() asm("trapa #0xff"); +#define BREAK_INSTR_SIZE 2 +#define CACHE_FLUSH_IS_SAFE 1 /* KGDB should be able to flush all kernel text space */ #if defined(CONFIG_CPU_SH4) @@ -102,30 +48,5 @@ extern int setjmp(jmp_buf __jmpb); #else #define kgdb_flush_icache_range(start, end) do { } while (0) #endif - -/* Kernel assert macros */ -#ifdef CONFIG_KGDB_KERNEL_ASSERTS - -/* Predefined conditions */ -#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE) -#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr)) -#define KA_VALID_KPTR(ptr) (!(ptr) || \ - ((void *)(ptr) >= (void *)PAGE_OFFSET && \ - (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE))) -#define KA_VALID_PTRORERR(errptr) \ - (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr)) -#define KA_HELD_GKL() (current->lock_depth >= 0) - -/* The actual assert */ -#define KGDB_ASSERT(condition, message) do { \ - if (!(condition) && (kgdb_enabled)) { \ - KGDB_PRINTK("Assertion failed at %s:%d: %s\n", \ - __FILE__, __LINE__, message);\ - BREAKPOINT(); \ - } \ -} while (0) -#else -#define KGDB_ASSERT(condition, message) -#endif - +#endif /* !__ASSEMBLY__ */ #endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-sh/system.h linux-2.6.18-53.1.14.kgdb/include/asm-sh/system.h --- linux-2.6.18-53.1.14/include/asm-sh/system.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-sh/system.h 2008-06-10 15:38:50.000000000 +0400 @@ -6,6 +6,7 @@ * Copyright (C) 2002 Paul Mundt */ +#include /* * switch_to() should switch tasks to task nr n, first @@ -260,6 +261,45 @@ static __inline__ unsigned long __xchg(u return x; } +static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, + unsigned long new) +{ + __u32 retval; + unsigned long flags; + + local_irq_save(flags); + retval = *m; + if (retval == old) + *m = new; + local_irq_restore(flags); /* implies memory barrier */ + return retval; +} + +/* This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +#define __HAVE_ARCH_CMPXCHG 1 + +static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + /* XXX * disable hlt during certain critical i/o operations */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-x86_64/kdebug.h linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/kdebug.h --- linux-2.6.18-53.1.14/include/asm-x86_64/kdebug.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/kdebug.h 2008-06-10 15:38:41.000000000 +0400 @@ -34,6 +34,7 @@ enum die_val { DIE_CALL, DIE_NMI_IPI, DIE_PAGE_FAULT, + DIE_PAGE_FAULT_NO_CONTEXT, }; static inline int notify_die(enum die_val val, const char *str, diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-x86_64/kgdb.h linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/kgdb.h --- linux-2.6.18-53.1.14/include/asm-x86_64/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/kgdb.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,54 @@ +#ifdef __KERNEL__ +#ifndef _ASM_KGDB_H_ +#define _ASM_KGDB_H_ + +/* + * Copyright (C) 2001-2004 Amit S. Kale + */ + +#include + +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +#define _RAX 0 +#define _RDX 1 +#define _RCX 2 +#define _RBX 3 +#define _RSI 4 +#define _RDI 5 +#define _RBP 6 +#define _RSP 7 +#define _R8 8 +#define _R9 9 +#define _R10 10 +#define _R11 11 +#define _R12 12 +#define _R13 13 +#define _R14 14 +#define _R15 15 +#define _PC 16 +#define _PS 17 + +/* Number of bytes of registers. */ +#define NUMREGBYTES ((_PS+1)*8) +#define NUMCRITREGBYTES (8 * 8) /* 8 registers. */ + +/* Help GDB to know when to stop backtracing. */ +#define CFI_END_FRAME(func) __CFI_END_FRAME(_PC,_RSP,func) +#ifndef __ASSEMBLY__ +/* BUFMAX defines the maximum number of characters in inbound/outbound + * buffers at least NUMREGBYTES*2 are needed for register packets, and + * a longer buffer is needed to list all threads. */ +#define BUFMAX 1024 +#define BREAKPOINT() asm(" int $3"); +#define CHECK_EXCEPTION_STACK() ((&__get_cpu_var(init_tss))[0].ist[0]) +#define BREAK_INSTR_SIZE 1 +#define CACHE_FLUSH_IS_SAFE 1 +#endif /* !__ASSEMBLY__ */ +#endif /* _ASM_KGDB_H_ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/asm-x86_64/system.h linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/system.h --- linux-2.6.18-53.1.14/include/asm-x86_64/system.h 2008-03-06 05:54:38.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/asm-x86_64/system.h 2008-06-10 15:38:44.000000000 +0400 @@ -22,7 +22,9 @@ /* Save restore flags to clear handle leaking NT */ #define switch_to(prev,next,last) \ - asm volatile(SAVE_CONTEXT \ + asm volatile(".globl __switch_to_begin\n\t" \ + "__switch_to_begin:\n\t" \ + SAVE_CONTEXT \ "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \ "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \ "call __switch_to\n\t" \ @@ -34,6 +36,8 @@ "movq %%rax,%%rdi\n\t" \ "jc ret_from_fork\n\t" \ RESTORE_CONTEXT \ + ".globl __switch_to_end\n\t" \ + "__switch_to_end:\n\t" \ : "=a" (last) \ : [next] "S" (next), [prev] "D" (prev), \ [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/dwarf2-lang.h linux-2.6.18-53.1.14.kgdb/include/linux/dwarf2-lang.h --- linux-2.6.18-53.1.14/include/linux/dwarf2-lang.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/linux/dwarf2-lang.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,300 @@ +#ifndef DWARF2_LANG +#define DWARF2_LANG + +/* + * This 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, or (at your option) any later + * version. + */ +/* + * This file defines macros that allow generation of DWARF debug records + * for asm files. This file is platform independent. Register numbers + * (which are about the only thing that is platform dependent) are to be + * supplied by a platform defined file. + */ +/* + * We need this to work for both asm and C. In asm we are using the + * old comment trick to concatenate while C uses the new ANSI thing. + * Here we have concat macro... The multi level thing is to allow and + * macros used in the names to be resolved prior to the cat (at which + * time they are no longer the same string). + */ +#define CAT3(a,b,c) _CAT3(a,b,c) +#define _CAT3(a,b,c) __CAT3(a,b,c) +#ifndef __STDC__ +#define __CAT3(a,b,c) a/**/b/**/c +#else +#define __CAT3(a,b,c) a##b##c +#endif +#ifdef __ASSEMBLY__ +#define IFC(a) +#define IFN_C(a) a +#define NL ; +#define QUOTE_THIS(a) a +#define DWARF_preamble .section .debug_frame,"",%progbits; +#else +#define IFC(a) a +#define IFN_C(a) +#define NL \n\t +#define QUOTE_THIS(a) _QUOTE_THIS(a) +#define _QUOTE_THIS(a) #a +/* Don't let CPP see the " and , \042=" \054=, */ +#define DWARF_preamble .section .debug_frame \054\042\042\054%progbits +#endif + +#ifdef CONFIG_64BIT +#define DATA_ALIGN_FACTOR 8 +#define ADDR_LOC .quad +#else +#define DATA_ALIGN_FACTOR 4 +#define ADDR_LOC .long +#endif + +#include +/* + * This macro starts a debug frame section. The debug_frame describes + * where to find the registers that the enclosing function saved on + * entry. + * + * ORD is use by the label generator and should be the same as what is + * passed to CFI_postamble. + * + * pc, pc register gdb ordinal. + * + * code_align this is the factor used to define locations or regions + * where the given definitions apply. If you use labels to define these + * this should be 1. + * + * data_align this is the factor used to define register offsets. If + * you use struct offset, this should be the size of the register in + * bytes or the negative of that. This is how it is used: you will + * define a register as the reference register, say the stack pointer, + * then you will say where a register is located relative to this + * reference registers value, say 40 for register 3 (the gdb register + * number). The <40> will be multiplied by to define the + * byte offset of the given register (3, in this example). So if your + * <40> is the byte offset and the reference register points at the + * begining, you would want 1 for the data_offset. If <40> was the 40th + * 4-byte element in that structure you would want 4. And if your + * reference register points at the end of the structure you would want + * a negative data_align value(and you would have to do other math as + * well). + */ + +#define CFI_preamble(ORD, pc, code_align, data_align) \ + DWARF_preamble NL \ + .align DATA_ALIGN_FACTOR NL \ + .globl CAT3(frame,_,ORD) NL \ +CAT3(frame,_,ORD): NL \ + .long 7f-6f NL \ +6: \ + .long DW_CIE_ID NL \ + .byte DW_CIE_VERSION NL \ + .byte 0 NL \ + .uleb128 code_align NL \ + .sleb128 data_align NL \ + .byte pc NL + +/* + * After the above macro and prior to the CFI_postamble, you need to + * define the initial state. This starts with defining the reference + * register and, usually the pc. Here are some helper macros: + */ + +#define CFA_define_reference(reg, offset) \ + .byte DW_CFA_def_cfa NL \ + .uleb128 reg NL \ + .uleb128 (offset) NL + +#define CFA_define_offset(reg, offset) \ + .byte (DW_CFA_offset + reg) NL \ + .uleb128 (offset) NL + +#define CFA_restore(reg) \ + .byte (DW_CFA_restore + reg) NL + +#define CFI_postamble() \ + .align DATA_ALIGN_FACTOR NL \ +7: NL \ +.previous NL + +/* + * So now your code pushs stuff on the stack, you need a new location + * and the rules for what to do. This starts a running description of + * the call frame. You need to describe what changes with respect to + * the call registers as the location of the pc moves through the code. + * The following builds an FDE (fram descriptor entry?). Like the + * above, it has a preamble and a postamble. It also is tied to the CFI + * above. + * The preamble macro is tied to the CFI thru the first parameter. The + * second is the code start address and then the code end address+1. + */ +#define FDE_preamble(ORD, initial_address, end_address) \ + DWARF_preamble NL \ + .align DATA_ALIGN_FACTOR NL \ + .long 9f-8f NL \ +8: \ + .long CAT3(frame,_,ORD) NL \ + ADDR_LOC initial_address NL \ + ADDR_LOC (end_address - initial_address) NL + +#define FDE_postamble() \ + .align DATA_ALIGN_FACTOR NL \ +9: NL \ +.previous NL + +/* + * That done, you can now add registers, subtract registers, move the + * reference and even change the reference. You can also define a new + * area of code the info applies to. For discontinuous bits you should + * start a new FDE. You may have as many as you like. + */ + +/* + * To advance the stack address by (0x3f max) + */ + +#define CFA_advance_loc(bytes) \ + .byte DW_CFA_advance_loc+bytes NL + +/* + * This one is good for 0xff or 255 + */ +#define CFA_advance_loc1(bytes) \ + .byte DW_CFA_advance_loc1 NL \ + .byte bytes NL + +#define CFA_undefine_reg(reg) \ + .byte DW_CFA_undefined NL \ + .uleb128 reg NL +/* + * With the above you can define all the register locations. But + * suppose the reference register moves... Takes the new offset NOT an + * increment. This is how esp is tracked if it is not saved. + */ + +#define CFA_define_cfa_offset(offset) \ + .byte DW_CFA_def_cfa_offset NL \ + .uleb128 (offset) NL +/* + * Or suppose you want to use a different reference register... + */ +#define CFA_define_cfa_register(reg) \ + .byte DW_CFA_def_cfa_register NL \ + .uleb128 reg NL + +/* + * If you want to mess with the stack pointer, here is the expression. + * The stack starts empty. + */ +#define CFA_def_cfa_expression \ + .byte DW_CFA_def_cfa_expression NL \ + .uleb128 20f-10f NL \ +10: NL +/* + * This expression is to be used for other regs. The stack starts with the + * stack address. + */ + +#define CFA_expression(reg) \ + .byte DW_CFA_expression NL \ + .uleb128 reg NL \ + .uleb128 20f-10f NL \ +10: NL +/* + * Here we do the expression stuff. You should code the above followed + * by expression OPs followed by CFA_expression_end. + */ + + +#define CFA_expression_end \ +20: NL + +#define CFA_exp_OP_const4s(a) \ + .byte DW_OP_const4s NL \ + .long a NL + +#define CFA_exp_OP_swap .byte DW_OP_swap NL +#define CFA_exp_OP_dup .byte DW_OP_dup NL +#define CFA_exp_OP_drop .byte DW_OP_drop NL +/* + * All these work on the top two elements on the stack, replacing them + * with the result. Top comes first where it matters. True is 1, false 0. + */ +#define CFA_exp_OP_deref .byte DW_OP_deref NL +#define CFA_exp_OP_and .byte DW_OP_and NL +#define CFA_exp_OP_div .byte DW_OP_div NL +#define CFA_exp_OP_minus .byte DW_OP_minus NL +#define CFA_exp_OP_mod .byte DW_OP_mod NL +#define CFA_exp_OP_neg .byte DW_OP_neg NL +#define CFA_exp_OP_plus .byte DW_OP_plus NL +#define CFA_exp_OP_not .byte DW_OP_not NL +#define CFA_exp_OP_or .byte DW_OP_or NL +#define CFA_exp_OP_xor .byte DW_OP_xor NL +#define CFA_exp_OP_le .byte DW_OP_le NL +#define CFA_exp_OP_ge .byte DW_OP_ge NL +#define CFA_exp_OP_eq .byte DW_OP_eq NL +#define CFA_exp_OP_lt .byte DW_OP_lt NL +#define CFA_exp_OP_gt .byte DW_OP_gt NL +#define CFA_exp_OP_ne .byte DW_OP_ne NL +/* + * These take a parameter as noted + */ +/* + * Unconditional skip to loc. loc is a label (loc:) + */ +#define CFA_exp_OP_skip(loc) \ + .byte DW_OP_skip NL \ + .hword loc-.-2 NL +/* + * Conditional skip to loc (TOS != 0, TOS--) (loc is a label) + */ +#define CFA_exp_OP_bra(loc) \ + .byte DW_OP_bra NL \ + .hword loc-.-2 NL + +/* + * TOS += no (an unsigned number) + */ +#define CFA_exp_OP_plus_uconst(no) \ + .byte DW_OP_plus_uconst NL \ + .uleb128 no NL + +/* + * ++TOS = no (a unsigned number) + */ +#define CFA_exp_OP_constu(no) \ + .byte DW_OP_constu NL \ + .uleb128 no NL +/* + * ++TOS = no (a signed number) + */ +#define CFA_exp_OP_consts(no) \ + .byte DW_OP_consts NL \ + .sleb128 no NL +/* + * ++TOS = no (an unsigned byte) + */ +#define CFA_exp_OP_const1u(no) \ + .byte DW_OP_const1u NL \ + .byte no NL + + +/* + * ++TOS = no (a address) + */ +#define CFA_exp_OP_addr(no) \ + .byte DW_OP_addr NL \ + .long no NL + +/* + * Push current frames value for "reg" + offset + * We take advantage of the opcode assignments to make this a litteral reg + * rather than use the DW_OP_bregx opcode. + */ + +#define CFA_exp_OP_breg(reg,offset) \ + .byte DW_OP_breg0+reg NL \ + .sleb128 offset NL +#endif diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/dwarf2.h linux-2.6.18-53.1.14.kgdb/include/linux/dwarf2.h --- linux-2.6.18-53.1.14/include/linux/dwarf2.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/linux/dwarf2.h 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,775 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002, + 2003 Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC 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, or (at your option) any later + version. + + GCC 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 GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +#ifndef _ELF_DWARF2_H +#define _ELF_DWARF2_H + +/* Structure found in the .debug_line section. */ +typedef struct +{ + unsigned char li_length [4]; + unsigned char li_version [2]; + unsigned char li_prologue_length [4]; + unsigned char li_min_insn_length [1]; + unsigned char li_default_is_stmt [1]; + unsigned char li_line_base [1]; + unsigned char li_line_range [1]; + unsigned char li_opcode_base [1]; +} +DWARF2_External_LineInfo; + +typedef struct +{ + unsigned long li_length; + unsigned short li_version; + unsigned int li_prologue_length; + unsigned char li_min_insn_length; + unsigned char li_default_is_stmt; + int li_line_base; + unsigned char li_line_range; + unsigned char li_opcode_base; +} +DWARF2_Internal_LineInfo; + +/* Structure found in .debug_pubnames section. */ +typedef struct +{ + unsigned char pn_length [4]; + unsigned char pn_version [2]; + unsigned char pn_offset [4]; + unsigned char pn_size [4]; +} +DWARF2_External_PubNames; + +typedef struct +{ + unsigned long pn_length; + unsigned short pn_version; + unsigned long pn_offset; + unsigned long pn_size; +} +DWARF2_Internal_PubNames; + +/* Structure found in .debug_info section. */ +typedef struct +{ + unsigned char cu_length [4]; + unsigned char cu_version [2]; + unsigned char cu_abbrev_offset [4]; + unsigned char cu_pointer_size [1]; +} +DWARF2_External_CompUnit; + +typedef struct +{ + unsigned long cu_length; + unsigned short cu_version; + unsigned long cu_abbrev_offset; + unsigned char cu_pointer_size; +} +DWARF2_Internal_CompUnit; + +typedef struct +{ + unsigned char ar_length [4]; + unsigned char ar_version [2]; + unsigned char ar_info_offset [4]; + unsigned char ar_pointer_size [1]; + unsigned char ar_segment_size [1]; +} +DWARF2_External_ARange; + +typedef struct +{ + unsigned long ar_length; + unsigned short ar_version; + unsigned long ar_info_offset; + unsigned char ar_pointer_size; + unsigned char ar_segment_size; +} +DWARF2_Internal_ARange; + + +/* Tag names and codes. */ +enum dwarf_tag + { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + /* DWARF 3. */ + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + /* SGI/MIPS Extensions. */ + DW_TAG_MIPS_loop = 0x4081, + /* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */ + DW_TAG_HP_array_descriptor = 0x4090, + /* GNU extensions. */ + DW_TAG_format_label = 0x4101, /* For FORTRAN 77 and Fortran 90. */ + DW_TAG_function_template = 0x4102, /* For C++. */ + DW_TAG_class_template = 0x4103, /* For C++. */ + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ + DW_TAG_upc_shared_type = 0x8765, + DW_TAG_upc_strict_type = 0x8766, + DW_TAG_upc_relaxed_type = 0x8767, + /* PGI (STMicroelectronics) extensions. No documentation available. */ + DW_TAG_PGI_kanji_type = 0xA000, + DW_TAG_PGI_interface_block = 0xA020 + }; + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +enum dwarf_form + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + +/* Attribute names and codes. */ +enum dwarf_attribute + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + /* DWARF 3 values. */ + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + /* SGI/MIPS extensions. */ + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + /* HP extensions. */ + DW_AT_HP_block_index = 0x2000, + DW_AT_HP_unmodifiable = 0x2001, /* Same as DW_AT_MIPS_fde. */ + DW_AT_HP_actuals_stmt_list = 0x2010, + DW_AT_HP_proc_per_section = 0x2011, + DW_AT_HP_raw_data_ptr = 0x2012, + DW_AT_HP_pass_by_reference = 0x2013, + DW_AT_HP_opt_level = 0x2014, + DW_AT_HP_prof_version_id = 0x2015, + DW_AT_HP_opt_flags = 0x2016, + DW_AT_HP_cold_region_low_pc = 0x2017, + DW_AT_HP_cold_region_high_pc = 0x2018, + DW_AT_HP_all_variables_modifiable = 0x2019, + DW_AT_HP_linkage_name = 0x201a, + DW_AT_HP_prof_flags = 0x201b, /* In comp unit of procs_info for -g. */ + /* GNU extensions. */ + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + /* VMS extensions. */ + DW_AT_VMS_rtnbeg_pd_address = 0x2201, + /* UPC extension. */ + DW_AT_upc_threads_scaled = 0x3210, + /* PGI (STMicroelectronics) extensions. */ + DW_AT_PGI_lbase = 0x3a00, + DW_AT_PGI_soffset = 0x3a01, + DW_AT_PGI_lstride = 0x3a02 + }; + +#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ +#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ + +/* Location atom names and codes. */ +enum dwarf_location_atom + { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3a, + DW_OP_lit11 = 0x3b, + DW_OP_lit12 = 0x3c, + DW_OP_lit13 = 0x3d, + DW_OP_lit14 = 0x3e, + DW_OP_lit15 = 0x3f, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4a, + DW_OP_lit27 = 0x4b, + DW_OP_lit28 = 0x4c, + DW_OP_lit29 = 0x4d, + DW_OP_lit30 = 0x4e, + DW_OP_lit31 = 0x4f, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5a, + DW_OP_reg11 = 0x5b, + DW_OP_reg12 = 0x5c, + DW_OP_reg13 = 0x5d, + DW_OP_reg14 = 0x5e, + DW_OP_reg15 = 0x5f, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6a, + DW_OP_reg27 = 0x6b, + DW_OP_reg28 = 0x6c, + DW_OP_reg29 = 0x6d, + DW_OP_reg30 = 0x6e, + DW_OP_reg31 = 0x6f, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7a, + DW_OP_breg11 = 0x7b, + DW_OP_breg12 = 0x7c, + DW_OP_breg13 = 0x7d, + DW_OP_breg14 = 0x7e, + DW_OP_breg15 = 0x7f, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8a, + DW_OP_breg27 = 0x8b, + DW_OP_breg28 = 0x8c, + DW_OP_breg29 = 0x8d, + DW_OP_breg30 = 0x8e, + DW_OP_breg31 = 0x8f, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + /* DWARF 3 extensions. */ + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0, + /* HP extensions. */ + DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ + DW_OP_HP_is_value = 0xe1, + DW_OP_HP_fltconst4 = 0xe2, + DW_OP_HP_fltconst8 = 0xe3, + DW_OP_HP_mod_range = 0xe4, + DW_OP_HP_unmod_range = 0xe5, + DW_OP_HP_tls = 0xe6 + }; + +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ +#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ + +/* Type encodings. */ +enum dwarf_type + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + /* DWARF 3. */ + DW_ATE_imaginary_float = 0x9, + /* HP extensions. */ + DW_ATE_HP_float80 = 0x80, /* Floating-point (80 bit). */ + DW_ATE_HP_complex_float80 = 0x81, /* Complex floating-point (80 bit). */ + DW_ATE_HP_float128 = 0x82, /* Floating-point (128 bit). */ + DW_ATE_HP_complex_float128 = 0x83, /* Complex floating-point (128 bit). */ + DW_ATE_HP_floathpintel = 0x84, /* Floating-point (82 bit IA64). */ + DW_ATE_HP_imaginary_float80 = 0x85, + DW_ATE_HP_imaginary_float128 = 0x86 + }; + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +enum dwarf_array_dim_ordering + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + +/* Access attribute. */ +enum dwarf_access_attribute + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + +/* Visibility. */ +enum dwarf_visibility_attribute + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + +/* Virtuality. */ +enum dwarf_virtuality_attribute + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + +/* Case sensitivity. */ +enum dwarf_id_case + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + +/* Calling convention. */ +enum dwarf_calling_convention + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3 + }; + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* Inline attribute. */ +enum dwarf_inline_attribute + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + +/* Discriminant lists. */ +enum dwarf_discrim_list + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* Line number opcodes. */ +enum dwarf_line_number_ops + { + DW_LNS_extended_op = 0, + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + +/* Line number extended opcodes. */ +enum dwarf_line_number_x_ops + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + /* HP extensions. */ + DW_LNE_HP_negate_is_UV_update = 0x11, + DW_LNE_HP_push_context = 0x12, + DW_LNE_HP_pop_context = 0x13, + DW_LNE_HP_set_file_line_column = 0x14, + DW_LNE_HP_set_routine_name = 0x15, + DW_LNE_HP_set_sequence = 0x16, + DW_LNE_HP_negate_post_semantics = 0x17, + DW_LNE_HP_negate_function_exit = 0x18, + DW_LNE_HP_negate_front_end_logical = 0x19, + DW_LNE_HP_define_proc = 0x20 + }; + +/* Call frame information. */ +enum dwarf_call_frame_info + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + /* DWARF 3. */ + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + /* SGI/MIPS specific. */ + DW_CFA_MIPS_advance_loc8 = 0x1d, + /* GNU extensions. */ + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f + }; + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +enum dwarf_source_language + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + /* DWARF 3. */ + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001, + /* UPC. */ + DW_LANG_Upc = 0x8765 + }; + +#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ +#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ + +/* Names and codes for macro information. */ +enum dwarf_macinfo_record_type + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +#endif /* _ELF_DWARF2_H */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/kgdb.h linux-2.6.18-53.1.14.kgdb/include/linux/kgdb.h --- linux-2.6.18-53.1.14/include/linux/kgdb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/linux/kgdb.h 2008-06-10 15:39:21.000000000 +0400 @@ -0,0 +1,279 @@ +/* + * include/linux/kgdb.h + * + * This provides the hooks and functions that KGDB needs to share between + * the core, I/O and arch-specific portions. + * + * Author: Amit Kale and + * Tom Rini + * + * 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc. + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#ifdef __KERNEL__ +#ifndef _KGDB_H_ +#define _KGDB_H_ + +#include + +#ifdef CONFIG_KGDB +#include +#include +#include +#include + +#ifndef CHECK_EXCEPTION_STACK +#define CHECK_EXCEPTION_STACK() 1 +#endif + +struct tasklet_struct; +struct pt_regs; +struct task_struct; +struct uart_port; + +#ifdef CONFIG_KGDB_CONSOLE +extern struct console kgdbcons; +#endif + +/* To enter the debugger explicitly. */ +extern void breakpoint(void); +extern int kgdb_connected; +extern int kgdb_may_fault; +extern struct tasklet_struct kgdb_tasklet_breakpoint; + +extern atomic_t kgdb_setting_breakpoint; +extern atomic_t cpu_doing_single_step; +extern atomic_t kgdb_sync_softlockup[NR_CPUS]; + +extern struct task_struct *kgdb_usethread, *kgdb_contthread; + +enum kgdb_bptype { + bp_breakpoint = '0', + bp_hardware_breakpoint, + bp_write_watchpoint, + bp_read_watchpoint, + bp_access_watchpoint +}; + +enum kgdb_bpstate { + bp_none = 0, + bp_removed, + bp_set, + bp_active +}; + +struct kgdb_bkpt { + unsigned long bpt_addr; + unsigned char saved_instr[BREAK_INSTR_SIZE]; + enum kgdb_bptype type; + enum kgdb_bpstate state; +}; + +/* The maximum number of KGDB I/O modules that can be loaded */ +#define MAX_KGDB_IO_HANDLERS 3 + +#ifndef MAX_BREAKPOINTS +#define MAX_BREAKPOINTS 1000 +#endif + +#define KGDB_HW_BREAKPOINT 1 + +/* Required functions. */ +/** + * regs_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @regs: The &struct pt_regs of the current process. + * + * Convert the pt_regs in @regs into the format for registers that + * GDB expects, stored in @gdb_regs. + */ +extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +/** + * sleeping_regs_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @p: The &struct task_struct of the desired process. + * + * Convert the register values of the sleeping process in @p to + * the format that GDB expects. + * This function is called when kgdb does not have access to the + * &struct pt_regs and therefore it should fill the gdb registers + * @gdb_regs with what has been saved in &struct thread_struct + * thread field during switch_to. + */ +extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, + struct task_struct *p); + +/** + * gdb_regs_to_regs - Convert GDB regs to ptrace regs. + * @gdb_regs: A pointer to hold the registers we've recieved from GDB. + * @regs: A pointer to a &struct pt_regs to hold these values in. + * + * Convert the GDB regs in @gdb_regs into the pt_regs, and store them + * in @regs. + */ +extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +/** + * kgdb_arch_handle_exception - Handle architecture specific GDB packets. + * @vector: The error vector of the exception that happened. + * @signo: The signal number of the exception that happened. + * @err_code: The error code of the exception that happened. + * @remcom_in_buffer: The buffer of the packet we have read. + * @remcom_out_buffer: The buffer, of %BUFMAX to write a packet into. + * @regs: The &struct pt_regs of the current process. + * + * This function MUST handle the 'c' and 's' command packets, + * as well packets to set / remove a hardware breakpoint, if used. + * If there are additional packets which the hardware needs to handle, + * they are handled here. The code should return -1 if it wants to + * process more packets, and a %0 or %1 if it wants to exit from the + * kgdb hook. + */ +extern int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *regs); + +#ifndef JMP_REGS_ALIGNMENT +#define JMP_REGS_ALIGNMENT +#endif + +extern unsigned long kgdb_fault_jmp_regs[]; + +/** + * kgdb_fault_setjmp - Store state in case we fault. + * @curr_context: An array to store state into. + * + * Certain functions may try and access memory, and in doing so may + * cause a fault. When this happens, we trap it, restore state to + * this call, and let ourself know that something bad has happened. + */ +extern asmlinkage int kgdb_fault_setjmp(unsigned long *curr_context); + +/** + * kgdb_fault_longjmp - Restore state when we have faulted. + * @curr_context: The previously stored state. + * + * When something bad does happen, this function is called to + * restore the known good state, and set the return value to 1, so + * we know something bad happened. + */ +extern asmlinkage void kgdb_fault_longjmp(unsigned long *curr_context); + +/* Optional functions. */ +extern int kgdb_arch_init(void); +extern void kgdb_disable_hw_debug(struct pt_regs *regs); +extern void kgdb_post_master_code(struct pt_regs *regs, int e_vector, + int err_code); +extern void kgdb_roundup_cpus(unsigned long flags); +extern int kgdb_set_hw_break(unsigned long addr); +extern int kgdb_remove_hw_break(unsigned long addr); +extern void kgdb_remove_all_hw_break(void); +extern void kgdb_correct_hw_break(void); +extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer, + unsigned threadid); +extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs, + int threadid); +extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid); +extern int kgdb_validate_break_address(unsigned long addr); +extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); +extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); + +/** + * struct kgdb_arch - Desribe architecture specific values. + * @gdb_bpt_instr: The instruction to trigger a breakpoint. + * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. + * @shadowth: A value of %1 indicates we shadow information on processes. + * @set_breakpoint: Allow an architecture to specify how to set a software + * breakpoint. + * @remove_breakpoint: Allow an architecture to specify how to remove a + * software breakpoint. + * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware + * breakpoint. + * @remove_hw_breakpoint: Allow an architecture to specify how to remove a + * hardware breakpoint. + * + * The @shadowth flag is an option to shadow information not retrievable by + * gdb otherwise. This is deprecated in favor of a binutils which supports + * CFI macros. + */ +struct kgdb_arch { + unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; + unsigned long flags; + unsigned shadowth; + int (*set_breakpoint) (unsigned long, char *); + int (*remove_breakpoint)(unsigned long, char *); + int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); + int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); +}; + +/* Thread reference */ +typedef unsigned char threadref[8]; + +/** + * struct kgdb_io - Desribe the interface for an I/O driver to talk with KGDB. + * @read_char: Pointer to a function that will return one char. + * @write_char: Pointer to a function that will write one char. + * @flush: Pointer to a function that will flush any pending writes. + * @init: Pointer to a function that will initialize the device. + * @late_init: Pointer to a function that will do any setup that has + * other dependencies. + * @pre_exception: Pointer to a function that will do any prep work for + * the I/O driver. + * @post_exception: Pointer to a function that will do any cleanup work + * for the I/O driver. + * + * The @init and @late_init function pointers allow for an I/O driver + * such as a serial driver to fully initialize the port with @init and + * be called very early, yet safely call request_irq() later in the boot + * sequence. + * + * @init is allowed to return a non-0 return value to indicate failure. + * If this is called early on, then KGDB will try again when it would call + * @late_init. If it has failed later in boot as well, the user will be + * notified. + */ +struct kgdb_io { + int (*read_char) (void); + void (*write_char) (u8); + void (*flush) (void); + int (*init) (void); + void (*late_init) (void); + void (*pre_exception) (void); + void (*post_exception) (void); +}; + +extern struct kgdb_io kgdb_io_ops; +extern struct kgdb_arch arch_kgdb_ops; +extern int kgdb_initialized; + +extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); +extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); + +extern void __init kgdb8250_add_port(int i, struct uart_port *serial_req); +extern void __init kgdb8250_add_platform_port(int i, struct plat_serial8250_port *serial_req); + +extern int kgdb_hex2long(char **ptr, long *long_val); +extern char *kgdb_mem2hex(char *mem, char *buf, int count); +extern char *kgdb_hex2mem(char *buf, char *mem, int count); +extern int kgdb_get_mem(char *addr, unsigned char *buf, int count); +extern int kgdb_set_mem(char *addr, unsigned char *buf, int count); + +int kgdb_isremovedbreak(unsigned long addr); +int kgdb_skipexception(int exception, struct pt_regs *regs); + +extern int kgdb_handle_exception(int ex_vector, int signo, int err_code, + struct pt_regs *regs); +extern void kgdb_nmihook(int cpu, void *regs); +extern int debugger_step; +extern atomic_t debugger_active; +extern struct kgdb_arch *kgdb_ops; +#else +/* Stubs for when KGDB is not set. */ +static const atomic_t debugger_active = ATOMIC_INIT(0); +#endif /* CONFIG_KGDB */ +#endif /* _KGDB_H_ */ +#endif /* __KERNEL__ */ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/module.h linux-2.6.18-53.1.14.kgdb/include/linux/module.h --- linux-2.6.18-53.1.14/include/linux/module.h 2008-03-06 05:54:41.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/include/linux/module.h 2008-06-10 15:39:15.000000000 +0400 @@ -229,8 +229,17 @@ enum module_state MODULE_STATE_LIVE, MODULE_STATE_COMING, MODULE_STATE_GOING, + MODULE_STATE_GONE, }; +#ifdef CONFIG_KGDB +#define MAX_SECTNAME 31 +struct mod_section { + void *address; + char name[MAX_SECTNAME + 1]; +}; +#endif + /* Similar stuff for section attributes. */ #define MODULE_SECT_NAME_LEN 32 struct module_sect_attr @@ -258,6 +267,13 @@ struct module /* Unique handle for this module */ char name[MODULE_NAME_LEN]; +#ifdef CONFIG_KGDB + /* keep kgdb info at the begining so that gdb doesn't have a chance to + * miss out any fields */ + unsigned long num_sections; + struct mod_section *mod_sections; +#endif + /* Sysfs stuff. */ struct module_kobject mkobj; struct module_param_attrs *param_attrs; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/netpoll.h linux-2.6.18-53.1.14.kgdb/include/linux/netpoll.h --- linux-2.6.18-53.1.14/include/linux/netpoll.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/linux/netpoll.h 2008-06-10 15:37:49.000000000 +0400 @@ -17,7 +17,7 @@ struct netpoll; struct netpoll { struct net_device *dev; char dev_name[16], *name; - void (*rx_hook)(struct netpoll *, int, char *, int); + void (*rx_hook)(struct netpoll *, int, char *, int, struct sk_buff *); void (*drop)(struct sk_buff *skb); u32 local_ip, remote_ip; u16 local_port, remote_port; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/include/linux/serial_8250.h linux-2.6.18-53.1.14.kgdb/include/linux/serial_8250.h --- linux-2.6.18-53.1.14/include/linux/serial_8250.h 2006-09-20 07:42:06.000000000 +0400 +++ linux-2.6.18-53.1.14.kgdb/include/linux/serial_8250.h 2008-06-10 15:37:43.000000000 +0400 @@ -56,6 +56,7 @@ struct uart_port; int serial8250_register_port(struct uart_port *); void serial8250_unregister_port(int line); +void serial8250_unregister_by_port(struct uart_port *port); void serial8250_suspend_port(int line); void serial8250_resume_port(int line); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/Makefile linux-2.6.18-53.1.14.kgdb/kernel/Makefile --- linux-2.6.18-53.1.14/kernel/Makefile 2008-03-06 05:54:50.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/Makefile 2008-06-10 15:37:25.000000000 +0400 @@ -42,6 +42,7 @@ obj-$(CONFIG_STOP_MACHINE) += stop_machi obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o audit_tree.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KGDB) += kgdb.o kgdbarchlib.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/kgdb.c linux-2.6.18-53.1.14.kgdb/kernel/kgdb.c --- linux-2.6.18-53.1.14/kernel/kgdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/kgdb.c 2008-06-10 15:39:21.000000000 +0400 @@ -0,0 +1,1778 @@ +/* + * kernel/kgdb.c + * + * Maintainer: Tom Rini + * + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * Copyright (C) 2002-2004 Timesys Corporation + * Copyright (C) 2003-2004 Amit S. Kale + * Copyright (C) 2004 Pavel Machek + * Copyright (C) 2004-2005 Tom Rini + * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. + * Copyright (C) 2005 Wind River Systems, Inc. + * + * Contributors at various stages not listed above: + * Jason Wessel ( jason.wessel@windriver.com ) + * George Anzinger + * Anurekh Saxena (anurekh.saxena@timesys.com) + * Lake Stevens Instrument Division (Glenn Engel) + * Jim Kingdon, Cygnus Support. + * + * Original KGDB stub: David Grothe , + * Tigran Aivazian + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int pid_max; +/* How many times to count all of the waiting CPUs */ +#define ROUNDUP_WAIT 640000 /* Arbitrary, increase if needed. */ +#define BUF_THREAD_ID_SIZE 16 + +/* + * kgdb_initialized with a value of 1 indicates that kgdb is setup and is + * all ready to serve breakpoints and other kernel exceptions. A value of + * -1 indicates that we have tried to initialize early, and need to try + * again later. + */ +int kgdb_initialized; +/* Is a host GDB connected to us? */ +int kgdb_connected; +/* Could we be about to try and access a bad memory location? If so we + * also need to flag this has happend. */ +int kgdb_may_fault; +/* All the KGDB handlers are installed */ +int kgdb_from_module_registered = 0; + +/* We provide a kgdb_io_ops structure that may be overriden. */ +struct kgdb_io __attribute__ ((weak)) kgdb_io_ops; + +static struct kgdb_io kgdb_io_ops_prev[MAX_KGDB_IO_HANDLERS]; +static int kgdb_io_handler_cnt = 0; + +/* Export the following symbols for use with kernel modules */ +EXPORT_SYMBOL(kgdb_io_ops); +EXPORT_SYMBOL(kgdb_tasklet_breakpoint); +EXPORT_SYMBOL(kgdb_connected); +EXPORT_SYMBOL(kgdb_register_io_module); +EXPORT_SYMBOL(kgdb_unregister_io_module); +EXPORT_SYMBOL(debugger_active); + +/* + * Holds information about breakpoints in a kernel. These breakpoints are + * added and removed by gdb. + */ +struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS]; + +static const char hexchars[] = "0123456789abcdef"; + +static spinlock_t slavecpulocks[NR_CPUS]; +static atomic_t procindebug[NR_CPUS]; +atomic_t kgdb_setting_breakpoint; +EXPORT_SYMBOL(kgdb_setting_breakpoint); +struct task_struct *kgdb_usethread, *kgdb_contthread; + +int debugger_step; +atomic_t debugger_active; + +/* Our I/O buffers. */ +static char remcom_in_buffer[BUFMAX]; +static char remcom_out_buffer[BUFMAX]; +/* Storage for the registers, in GDB format. */ +static unsigned long gdb_regs[(NUMREGBYTES + sizeof(unsigned long) - 1) / + sizeof(unsigned long)]; +/* Storage of registers for handling a fault. */ +unsigned long kgdb_fault_jmp_regs[NUMCRITREGBYTES / sizeof(unsigned long)] + JMP_REGS_ALIGNMENT; +static int kgdb_notify_reboot(struct notifier_block *this, + unsigned long code ,void *x); +struct debuggerinfo_struct { + void *debuggerinfo; + struct task_struct *task; +} kgdb_info[NR_CPUS]; + +/* to keep track of the CPU which is doing the single stepping*/ +atomic_t cpu_doing_single_step = ATOMIC_INIT(-1); + +atomic_t kgdb_sync_softlockup[NR_CPUS] = {ATOMIC_INIT(0)}; + +/* reboot notifier block */ +static struct notifier_block kgdb_reboot_notifier = { + .notifier_call = kgdb_notify_reboot, + .next = NULL, + .priority = INT_MAX, +}; + +static int hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +static void get_packet(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + if (!kgdb_io_ops.read_char) + return; + do { + /* Spin and wait around for the start character, ignore all + * other characters */ + while ((ch = (kgdb_io_ops.read_char())) != '$') ; + kgdb_connected = 1; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < (BUFMAX - 1)) { + ch = kgdb_io_ops.read_char(); + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(kgdb_io_ops.read_char()) << 4; + xmitcsum += hex(kgdb_io_ops.read_char()); + + if (checksum != xmitcsum) + /* failed checksum */ + kgdb_io_ops.write_char('-'); + else + /* successful transfer */ + kgdb_io_ops.write_char('+'); + if (kgdb_io_ops.flush) + kgdb_io_ops.flush(); + } + } while (checksum != xmitcsum); +} + +/* + * Send the packet in buffer. + * Check for gdb connection if asked for. + */ +static void put_packet(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + if (!kgdb_io_ops.write_char) + return; + /* $#. */ + while (1) { + kgdb_io_ops.write_char('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + kgdb_io_ops.write_char(ch); + checksum += ch; + count++; + } + + kgdb_io_ops.write_char('#'); + kgdb_io_ops.write_char(hexchars[checksum >> 4]); + kgdb_io_ops.write_char(hexchars[checksum % 16]); + if (kgdb_io_ops.flush) + kgdb_io_ops.flush(); + + /* Now see what we get in reply. */ + ch = kgdb_io_ops.read_char(); + + if (ch == 3) + ch = kgdb_io_ops.read_char(); + + /* If we get an ACK, we are done. */ + if (ch == '+') + return; + + /* If we get the start of another packet, this means + * that GDB is attempting to reconnect. We will NAK + * the packet being sent, and stop trying to send this + * packet. */ + if (ch == '$') { + kgdb_io_ops.write_char('-'); + if (kgdb_io_ops.flush) + kgdb_io_ops.flush(); + return; + } + } +} + +/* + * convert the memory pointed to by mem into hex, placing result in buf + * return a pointer to the last char put in buf (null). May return an error. + */ +char *kgdb_mem2hex(char *mem, char *buf, int count) +{ + kgdb_may_fault = 1; + if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) { + kgdb_may_fault = 0; + return ERR_PTR(-EINVAL); + } + /* Accessing some registers in a single load instruction is + * required to avoid bad side effects for some I/O registers. + */ + if ((count == 2) && (((long)mem & 1) == 0)) { + unsigned short tmp_s = *(unsigned short *)mem; + mem += 2; +#ifdef __BIG_ENDIAN + *buf++ = hexchars[(tmp_s >> 12) & 0xf]; + *buf++ = hexchars[(tmp_s >> 8) & 0xf]; + *buf++ = hexchars[(tmp_s >> 4) & 0xf]; + *buf++ = hexchars[tmp_s & 0xf]; +#else + *buf++ = hexchars[(tmp_s >> 4) & 0xf]; + *buf++ = hexchars[tmp_s & 0xf]; + *buf++ = hexchars[(tmp_s >> 12) & 0xf]; + *buf++ = hexchars[(tmp_s >> 8) & 0xf]; +#endif + } else if ((count == 4) && (((long)mem & 3) == 0)) { + unsigned long tmp_l = *(unsigned int *)mem; + mem += 4; +#ifdef __BIG_ENDIAN + *buf++ = hexchars[(tmp_l >> 28) & 0xf]; + *buf++ = hexchars[(tmp_l >> 24) & 0xf]; + *buf++ = hexchars[(tmp_l >> 20) & 0xf]; + *buf++ = hexchars[(tmp_l >> 16) & 0xf]; + *buf++ = hexchars[(tmp_l >> 12) & 0xf]; + *buf++ = hexchars[(tmp_l >> 8) & 0xf]; + *buf++ = hexchars[(tmp_l >> 4) & 0xf]; + *buf++ = hexchars[tmp_l & 0xf]; +#else + *buf++ = hexchars[(tmp_l >> 4) & 0xf]; + *buf++ = hexchars[tmp_l & 0xf]; + *buf++ = hexchars[(tmp_l >> 12) & 0xf]; + *buf++ = hexchars[(tmp_l >> 8) & 0xf]; + *buf++ = hexchars[(tmp_l >> 20) & 0xf]; + *buf++ = hexchars[(tmp_l >> 16) & 0xf]; + *buf++ = hexchars[(tmp_l >> 28) & 0xf]; + *buf++ = hexchars[(tmp_l >> 24) & 0xf]; +#endif +#ifdef CONFIG_64BIT + } else if ((count == 8) && (((long)mem & 7) == 0)) { + unsigned long long tmp_ll = *(unsigned long long *)mem; + mem += 8; +#ifdef __BIG_ENDIAN + *buf++ = hexchars[(tmp_ll >> 60) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 56) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 52) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 48) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 44) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 40) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 36) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 32) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 28) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 24) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 20) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 16) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 12) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 8) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 4) & 0xf]; + *buf++ = hexchars[tmp_ll & 0xf]; +#else + *buf++ = hexchars[(tmp_ll >> 4) & 0xf]; + *buf++ = hexchars[tmp_ll & 0xf]; + *buf++ = hexchars[(tmp_ll >> 12) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 8) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 20) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 16) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 28) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 24) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 36) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 32) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 44) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 40) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 52) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 48) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 60) & 0xf]; + *buf++ = hexchars[(tmp_ll >> 56) & 0xf]; +#endif +#endif + } else { + while (count-- > 0) { + unsigned char ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + } + kgdb_may_fault = 0; + *buf = 0; + return (buf); +} + +/* + * Copy the binary array pointed to by buf into mem. Fix $, #, and + * 0x7d escaped with 0x7d. Return a pointer to the character after + * the last byte written. + */ +static char *kgdb_ebin2mem(char *buf, char *mem, int count) +{ + kgdb_may_fault = 1; + if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) { + kgdb_may_fault = 0; + return ERR_PTR(-EINVAL); + } + for (; count > 0; count--, buf++) { + if (*buf == 0x7d) + *mem++ = *(++buf) ^ 0x20; + else + *mem++ = *buf; + } + kgdb_may_fault = 0; + return mem; +} + +/* + * convert the hex array pointed to by buf into binary to be placed in mem + * return a pointer to the character AFTER the last byte written + * May return an error. + */ +char *kgdb_hex2mem(char *buf, char *mem, int count) +{ + kgdb_may_fault = 1; + if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) { + kgdb_may_fault = 0; + return ERR_PTR(-EINVAL); + } + if ((count == 2) && (((long)mem & 1) == 0)) { + unsigned short tmp_s = 0; +#ifdef __BIG_ENDIAN + tmp_s |= hex(*buf++) << 12; + tmp_s |= hex(*buf++) << 8; + tmp_s |= hex(*buf++) << 4; + tmp_s |= hex(*buf++); +#else + tmp_s |= hex(*buf++) << 4; + tmp_s |= hex(*buf++); + tmp_s |= hex(*buf++) << 12; + tmp_s |= hex(*buf++) << 8; +#endif + *(unsigned short *)mem = tmp_s; + mem += 2; + } else if ((count == 4) && (((long)mem & 3) == 0)) { + unsigned long tmp_l = 0; +#ifdef __BIG_ENDIAN + tmp_l |= hex(*buf++) << 28; + tmp_l |= hex(*buf++) << 24; + tmp_l |= hex(*buf++) << 20; + tmp_l |= hex(*buf++) << 16; + tmp_l |= hex(*buf++) << 12; + tmp_l |= hex(*buf++) << 8; + tmp_l |= hex(*buf++) << 4; + tmp_l |= hex(*buf++); +#else + tmp_l |= hex(*buf++) << 4; + tmp_l |= hex(*buf++); + tmp_l |= hex(*buf++) << 12; + tmp_l |= hex(*buf++) << 8; + tmp_l |= hex(*buf++) << 20; + tmp_l |= hex(*buf++) << 16; + tmp_l |= hex(*buf++) << 28; + tmp_l |= hex(*buf++) << 24; +#endif + *(unsigned long *)mem = tmp_l; + mem += 4; + } else { + int i; + for (i = 0; i < count; i++) { + unsigned char ch = hex(*buf++) << 4; + ch |= hex(*buf++); + *mem++ = ch; + } + } + kgdb_may_fault = 0; + return (mem); +} + +/* + * While we find nice hex chars, build a long_val. + * Return number of chars processed. + */ +int kgdb_hex2long(char **ptr, long *long_val) +{ + int hex_val, num = 0; + + *long_val = 0; + + while (**ptr) { + hex_val = hex(**ptr); + if (hex_val >= 0) { + *long_val = (*long_val << 4) | hex_val; + num++; + } else + break; + + (*ptr)++; + } + + return (num); +} + +/* Write memory due to an 'M' or 'X' packet. */ +static char *write_mem_msg(int binary) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr, length; + + if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && + kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { + if (binary) + ptr = kgdb_ebin2mem(ptr, (char *)addr, length); + else + ptr = kgdb_hex2mem(ptr, (char *)addr, length); + if (CACHE_FLUSH_IS_SAFE) + flush_icache_range(addr, addr + length + 1); + if (IS_ERR(ptr)) + return ptr; + return NULL; + } + + return ERR_PTR(-EINVAL); +} + +static inline char *pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +static inline void error_packet(char *pkt, int error) +{ + error = -error; + pkt[0] = 'E'; + pkt[1] = hexchars[(error / 10)]; + pkt[2] = hexchars[(error % 10)]; + pkt[3] = '\0'; +} + +static char *pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *)id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + + return pkt; +} + +void int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + int i = 4; + + scan = (unsigned char *)id; + while (i--) + *scan++ = 0; + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} + +static struct task_struct *getthread(struct pt_regs *regs, int tid) +{ + if (last_pid == 0) + return current; + + if (num_online_cpus() && + (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth)) + return NULL; + + if (kgdb_ops->shadowth && (tid >= pid_max + num_online_cpus())) + return kgdb_get_shadow_thread(regs, tid - pid_max - + num_online_cpus()); + + if (tid >= pid_max) + return idle_task(tid - pid_max); + + if (!tid) + return NULL; + + return find_task_by_pid(tid); +} + +#ifdef CONFIG_SMP +static void kgdb_wait(struct pt_regs *regs) +{ + unsigned long flags; + int processor; + + local_irq_save(flags); + processor = smp_processor_id(); + kgdb_info[processor].debuggerinfo = regs; + kgdb_info[processor].task = current; + atomic_set(&procindebug[processor], 1); + atomic_set(&kgdb_sync_softlockup[smp_processor_id()], 1); + + /* Wait till master processor goes completely into the debugger. + * FIXME: this looks racy */ + while (!atomic_read(&procindebug[atomic_read(&debugger_active) - 1])) { + int i = 10; /* an arbitrary number */ + + while (--i) + cpu_relax(); + } + + /* Wait till master processor is done with debugging */ + spin_lock(&slavecpulocks[processor]); + + /* This has been taken from x86 kgdb implementation and + * will be needed by architectures that have SMP support + */ + kgdb_correct_hw_break(); + + kgdb_info[processor].debuggerinfo = NULL; + kgdb_info[processor].task = NULL; + + /* Signal the master processor that we are done */ + atomic_set(&procindebug[processor], 0); + spin_unlock(&slavecpulocks[processor]); + local_irq_restore(flags); +} +#endif + +int kgdb_get_mem(char *addr, unsigned char *buf, int count) +{ + kgdb_may_fault = 1; + if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) { + kgdb_may_fault = 0; + return -EINVAL; + } + while (count) { + if ((unsigned long)addr < TASK_SIZE) + return -EINVAL; + *buf++ = *addr++; + count--; + } + kgdb_may_fault = 0; + return 0; +} + +int kgdb_set_mem(char *addr, unsigned char *buf, int count) +{ + kgdb_may_fault = 1; + if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) { + kgdb_may_fault = 0; + return -EINVAL; + } + while (count) { + if ((unsigned long)addr < TASK_SIZE) + return -EINVAL; + *addr++ = *buf++; + count--; + } + kgdb_may_fault = 0; + return 0; +} +int kgdb_activate_sw_breakpoints(void) +{ + int i; + int error = 0; + unsigned long addr; + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != bp_set) + continue; + addr = kgdb_break[i].bpt_addr; + if ((error = kgdb_arch_set_breakpoint(addr, + kgdb_break[i].saved_instr))) + return error; + + if (CACHE_FLUSH_IS_SAFE) { + if (current->mm && addr < TASK_SIZE) + flush_cache_range(current->mm->mmap_cache, + addr, addr + BREAK_INSTR_SIZE); + else + flush_icache_range(addr, addr + + BREAK_INSTR_SIZE); + } + + kgdb_break[i].state = bp_active; + } + return 0; +} + +static int kgdb_set_sw_break(unsigned long addr) +{ + int i, breakno = -1; + int error = 0; + if ((error = kgdb_validate_break_address(addr)) < 0) + return error; + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == bp_set) && + (kgdb_break[i].bpt_addr == addr)) + return -EEXIST; + } + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state == bp_removed && + kgdb_break[i].bpt_addr == addr) { + breakno = i; + break; + } + } + + if (breakno == -1) { + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state == bp_none) { + breakno = i; + break; + } + } + } + if (breakno == -1) + return -E2BIG; + + kgdb_break[breakno].state = bp_set; + kgdb_break[breakno].type = bp_breakpoint; + kgdb_break[breakno].bpt_addr = addr; + + return 0; +} + +int kgdb_deactivate_sw_breakpoints(void) +{ + int i; + int error = 0; + unsigned long addr; + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != bp_active) + continue; + addr = kgdb_break[i].bpt_addr; + if ((error = kgdb_arch_remove_breakpoint(addr, + kgdb_break[i].saved_instr))) + return error; + + if (CACHE_FLUSH_IS_SAFE && current->mm && + addr < TASK_SIZE) + flush_cache_range(current->mm->mmap_cache, + addr, addr + BREAK_INSTR_SIZE); + else if (CACHE_FLUSH_IS_SAFE) + flush_icache_range(addr, + addr + BREAK_INSTR_SIZE); + kgdb_break[i].state = bp_set; + } + return 0; +} + +static int kgdb_remove_sw_break(unsigned long addr) +{ + int i; + + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == bp_set) && + (kgdb_break[i].bpt_addr == addr)) { + kgdb_break[i].state = bp_removed; + return 0; + } + } + return -ENOENT; +} + +int kgdb_isremovedbreak(unsigned long addr) +{ + int i; + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == bp_removed) && + (kgdb_break[i].bpt_addr == addr)) { + return 1; + } + } + return 0; +} + +int remove_all_break(void) +{ + int i; + int error; + unsigned long addr; + + /* Clear memory breakpoints. */ + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != bp_set) + continue; + addr = kgdb_break[i].bpt_addr; + if ((error = kgdb_arch_remove_breakpoint(addr, + kgdb_break[i].saved_instr))) + return error; + kgdb_break[i].state = bp_removed; + } + + /* Clear hardware breakpoints. */ + kgdb_remove_all_hw_break(); + + return 0; +} + +static inline int shadow_pid(int realpid) +{ + if (realpid) { + return realpid; + } + return pid_max + smp_processor_id(); +} + +static char gdbmsgbuf[BUFMAX + 1]; +static void kgdb_msg_write(const char *s, int len) +{ + int i; + int wcount; + char *bufptr; + + /* 'O'utput */ + gdbmsgbuf[0] = 'O'; + + /* Fill and send buffers... */ + while (len > 0) { + bufptr = gdbmsgbuf + 1; + + /* Calculate how many this time */ + if ((len << 1) > (BUFMAX - 2)) + wcount = (BUFMAX - 2) >> 1; + else + wcount = len; + + /* Pack in hex chars */ + for (i = 0; i < wcount; i++) + bufptr = pack_hex_byte(bufptr, s[i]); + *bufptr = '\0'; + + /* Move up */ + s += wcount; + len -= wcount; + + /* Write packet */ + put_packet(gdbmsgbuf); + } +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * Locking hierarchy: + * interface locks, if any (begin_session) + * kgdb lock (debugger_active) + * + * Note that since we can be in here prior to our cpumask being filled + * out, we err on the side of caution and loop over NR_CPUS instead + * of a for_each_online_cpu. + * + */ +int kgdb_handle_exception(int ex_vector, int signo, int err_code, + struct pt_regs *linux_regs) +{ + unsigned long length, addr; + char *ptr; + unsigned long flags; + unsigned i; + long threadid; + threadref thref; + struct task_struct *thread = NULL; + unsigned procid; + int numshadowth = num_online_cpus() + kgdb_ops->shadowth; + long kgdb_usethreadid = 0; + int error = 0, all_cpus_synced = 0; + struct pt_regs *shadowregs; + int processor = smp_processor_id(); + void *local_debuggerinfo; + + /* Panic on recursive debugger calls. */ + if (atomic_read(&debugger_active) == smp_processor_id() + 1) + return 0; + + acquirelock: + + /* Call the I/O drivers pre_exception routine if the I/O + * driver defined one + */ + if (kgdb_io_ops.pre_exception) + kgdb_io_ops.pre_exception(); + + /* + * Interrupts will be restored by the 'trap return' code, except when + * single stepping. + */ + local_irq_save(flags); + + /* Hold debugger_active */ + procid = smp_processor_id(); + + while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) { + int i = 25; /* an arbitrary number */ + + while (--i) + cpu_relax(); + + if (atomic_read(&cpu_doing_single_step) != -1 && + atomic_read(&cpu_doing_single_step) != procid) + udelay(1); + } + + atomic_set(&kgdb_sync_softlockup[smp_processor_id()], 1); + + /* + * Don't enter if the last instance of the exception handler wanted to + * come into the debugger again. + */ + if (atomic_read(&cpu_doing_single_step) != -1 && + atomic_read(&cpu_doing_single_step) != procid) { + atomic_set(&debugger_active, 0); + local_irq_restore(flags); + goto acquirelock; + } + + /* + * Don't enter if we have hit a removed breakpoint. + */ + if (kgdb_skipexception(ex_vector, linux_regs)) + goto kgdb_restore; + + kgdb_info[processor].debuggerinfo = linux_regs; + kgdb_info[processor].task = current; + + kgdb_disable_hw_debug(linux_regs); + + if (!debugger_step || !kgdb_contthread) + for (i = 0; i < NR_CPUS; i++) + spin_lock(&slavecpulocks[i]); + + /* Make sure we get the other CPUs */ + if (!debugger_step || !kgdb_contthread) + kgdb_roundup_cpus(flags); + + /* spin_lock code is good enough as a barrier so we don't + * need one here */ + atomic_set(&procindebug[processor], 1); + + /* Wait a reasonable time for the other CPUs to be notified and + * be waiting for us. Very early on this could be imperfect + * as num_online_cpus() could be 0.*/ + for (i = 0; i < ROUNDUP_WAIT; i++) { + int cpu, num = 0; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (atomic_read(&procindebug[cpu])) + num++; + } + if (num >= num_online_cpus()) { + all_cpus_synced = 1; + break; + } + } + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + /* Master processor is completely in the debugger */ + kgdb_post_master_code(linux_regs, ex_vector, err_code); + kgdb_deactivate_sw_breakpoints(); + debugger_step = 0; + kgdb_contthread = NULL; + + if (kgdb_connected) { + /* If we're still unable to roundup all of the CPUs, + * send an 'O' packet informing the user again. */ + if (!all_cpus_synced) + kgdb_msg_write("Not all CPUs have been synced for " + "KGDB\n", 39); + /* Reply to host that an exception has occurred */ + ptr = remcom_out_buffer; + *ptr++ = 'T'; + *ptr++ = hexchars[(signo >> 4) % 16]; + *ptr++ = hexchars[signo % 16]; + ptr += strlen(strcpy(ptr, "thread:")); + int_to_threadref(&thref, shadow_pid(current->pid)); + ptr = pack_threadid(ptr, &thref); + *ptr++ = ';'; + + put_packet(remcom_out_buffer); + } + + kgdb_usethread = kgdb_info[processor].task; + kgdb_usethreadid = shadow_pid(kgdb_info[processor].task->pid); + + while (kgdb_io_ops.read_char) { + char *bpt_type; + error = 0; + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + get_packet(remcom_in_buffer); + + switch (remcom_in_buffer[0]) { + case '?': + /* We know that this packet is only sent + * during initial connect. So to be safe, + * we clear out our breakpoints now incase + * GDB is reconnecting. */ + remove_all_break(); + /* Also, if we haven't been able to roundup all + * CPUs, send an 'O' packet informing the user + * as much. Only need to do this once. */ + if (!all_cpus_synced) + kgdb_msg_write("Not all CPUs have been " + "synced for KGDB\n", 39); + remcom_out_buffer[0] = 'S'; + remcom_out_buffer[1] = hexchars[signo >> 4]; + remcom_out_buffer[2] = hexchars[signo % 16]; + break; + + case 'g': /* return the value of the CPU registers */ + thread = kgdb_usethread; + + if (!thread) { + thread = kgdb_info[processor].task; + local_debuggerinfo = + kgdb_info[processor].debuggerinfo; + } else { + local_debuggerinfo = NULL; + for (i = 0; i < NR_CPUS; i++) { + /* Try to find the task on some other + * or possibly this node if we do not + * find the matching task then we try + * to approximate the results. + */ + if (thread == kgdb_info[i].task) + local_debuggerinfo = + kgdb_info[i].debuggerinfo; + } + } + + /* All threads that don't have debuggerinfo should be + * in __schedule() sleeping, since all other CPUs + * are in kgdb_wait, and thus have debuggerinfo. */ + if (kgdb_ops->shadowth && + kgdb_usethreadid >= pid_max + num_online_cpus()) { + shadowregs = kgdb_shadow_regs(linux_regs, + kgdb_usethreadid - + pid_max - + num_online_cpus + ()); + if (!shadowregs) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + regs_to_gdb_regs(gdb_regs, shadowregs); + } else if (local_debuggerinfo) + regs_to_gdb_regs(gdb_regs, local_debuggerinfo); + else { + /* Pull stuff saved during + * switch_to; nothing else is + * accessible (or even particularly relevant). + * This should be enough for a stack trace. */ + sleeping_thread_to_gdb_regs(gdb_regs, thread); + } + kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, + NUMREGBYTES); + break; + + /* set the value of the CPU registers - return OK */ + case 'G': + kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, + NUMREGBYTES); + + if (kgdb_usethread && kgdb_usethread != current) + error_packet(remcom_out_buffer, -EINVAL); + else { + gdb_regs_to_regs(gdb_regs, linux_regs); + strcpy(remcom_out_buffer, "OK"); + } + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && + kgdb_hex2long(&ptr, &length) > 0) { + if (IS_ERR(ptr = kgdb_mem2hex((char *)addr, + remcom_out_buffer, + length))) + error_packet(remcom_out_buffer, + PTR_ERR(ptr)); + } else + error_packet(remcom_out_buffer, -EINVAL); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ + case 'M': + if (IS_ERR(ptr = write_mem_msg(0))) + error_packet(remcom_out_buffer, PTR_ERR(ptr)); + else + strcpy(remcom_out_buffer, "OK"); + break; + /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ + case 'X': + if (IS_ERR(ptr = write_mem_msg(1))) + error_packet(remcom_out_buffer, PTR_ERR(ptr)); + else + strcpy(remcom_out_buffer, "OK"); + break; + + /* kill or detach. KGDB should treat this like a + * continue. + */ + case 'D': + if ((error = remove_all_break()) < 0) { + error_packet(remcom_out_buffer, error); + } else { + strcpy(remcom_out_buffer, "OK"); + kgdb_connected = 0; + } + put_packet(remcom_out_buffer); + goto default_handle; + + case 'k': + /* Don't care about error from remove_all_break */ + remove_all_break(); + kgdb_connected = 0; + goto default_handle; + + /* Reboot */ + case 'R': + /* For now, only honor R0 */ + if (strcmp(remcom_in_buffer, "R0") == 0) { + printk(KERN_CRIT "Executing reboot\n"); + strcpy(remcom_out_buffer, "OK"); + put_packet(remcom_out_buffer); + emergency_sync(); + /* Execution should not return from + * machine_restart() + */ + machine_restart(NULL); + kgdb_connected = 0; + goto default_handle; + } + + /* query */ + case 'q': + switch (remcom_in_buffer[1]) { + case 's': + case 'f': + if (memcmp(remcom_in_buffer + 2, "ThreadInfo", + 10)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + + /* + * If we have not yet completed in + * pidhash_init() there isn't much we + * can give back. + */ + if (last_pid == 0) { + if (remcom_in_buffer[1] == 'f') + strcpy(remcom_out_buffer, + "m0000000000000001"); + break; + } + + if (remcom_in_buffer[1] == 'f') { + threadid = 1; + } + remcom_out_buffer[0] = 'm'; + ptr = remcom_out_buffer + 1; + for (i = 0; i < 17 && threadid < pid_max + + numshadowth; threadid++) { + thread = getthread(linux_regs, + threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(ptr, &thref); + ptr += 16; + *(ptr++) = ','; + i++; + } + } + *(--ptr) = '\0'; + break; + + case 'C': + /* Current thread id */ + strcpy(remcom_out_buffer, "QC"); + + threadid = shadow_pid(current->pid); + + int_to_threadref(&thref, threadid); + pack_threadid(remcom_out_buffer + 2, &thref); + break; + case 'T': + if (memcmp(remcom_in_buffer + 1, + "ThreadExtraInfo,", 16)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + threadid = 0; + ptr = remcom_in_buffer + 17; + kgdb_hex2long(&ptr, &threadid); + if (!getthread(linux_regs, threadid)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + if (threadid < pid_max) { + kgdb_mem2hex(getthread(linux_regs, + threadid)->comm, + remcom_out_buffer, 16); + } else if (threadid >= pid_max + + num_online_cpus()) { + kgdb_shadowinfo(linux_regs, + remcom_out_buffer, + threadid - pid_max - + num_online_cpus()); + } else { + static char tmpstr[23 + + BUF_THREAD_ID_SIZE]; + sprintf(tmpstr, "Shadow task %d" + " for pid 0", + (int)(threadid - pid_max)); + kgdb_mem2hex(tmpstr, remcom_out_buffer, + strlen(tmpstr)); + } + break; + } + break; + + /* task related */ + case 'H': + switch (remcom_in_buffer[1]) { + case 'g': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &threadid); + thread = getthread(linux_regs, threadid); + if (!thread && threadid > 0) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + kgdb_usethread = thread; + kgdb_usethreadid = threadid; + strcpy(remcom_out_buffer, "OK"); + break; + + case 'c': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &threadid); + if (!threadid) { + kgdb_contthread = NULL; + } else { + thread = getthread(linux_regs, + threadid); + if (!thread && threadid > 0) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + kgdb_contthread = thread; + } + strcpy(remcom_out_buffer, "OK"); + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcom_in_buffer[1]; + kgdb_hex2long(&ptr, &threadid); + thread = getthread(linux_regs, threadid); + if (thread) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, -EINVAL); + break; + /* Since GDB-5.3, it's been drafted that '0' is a software + * breakpoint, '1' is a hardware breakpoint, so let's do + * that. + */ + case 'z': + case 'Z': + bpt_type = &remcom_in_buffer[1]; + ptr = &remcom_in_buffer[2]; + + if (kgdb_ops->set_hw_breakpoint && *bpt_type >= '1') { + /* Unsupported */ + if (*bpt_type > '4') + break; + } else if (*bpt_type != '0' && *bpt_type != '1') + /* Unsupported. */ + break; + /* Test if this is a hardware breakpoint, and + * if we support it. */ + if (*bpt_type == '1' && + !kgdb_ops->flags & KGDB_HW_BREAKPOINT) + /* Unsupported. */ + break; + + if (*(ptr++) != ',') { + error_packet(remcom_out_buffer, -EINVAL); + break; + } else if (kgdb_hex2long(&ptr, &addr)) { + if (*(ptr++) != ',' || + !kgdb_hex2long(&ptr, &length)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + } else { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + + if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') + error = kgdb_set_sw_break(addr); + else if (remcom_in_buffer[0] == 'Z' && *bpt_type == '1') + error = kgdb_set_hw_break(addr); + else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') + error = kgdb_remove_sw_break(addr); + else if (remcom_in_buffer[0] == 'z' && *bpt_type == '1') + error = kgdb_remove_hw_break(addr); + else if (remcom_in_buffer[0] == 'Z') + error = kgdb_ops->set_hw_breakpoint(addr, + (int)length, + *bpt_type); + else if (remcom_in_buffer[0] == 'z') + error = kgdb_ops->remove_hw_breakpoint(addr, + (int) + length, + *bpt_type); + + if (error == 0) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, error); + + break; + case 'c': + case 's': + if (kgdb_contthread && kgdb_contthread != current) { + /* Can't switch threads in kgdb */ + error_packet(remcom_out_buffer, -EINVAL); + break; + } + kgdb_activate_sw_breakpoints(); + /* Followthrough to default processing */ + default: + default_handle: + error = kgdb_arch_handle_exception(ex_vector, signo, + err_code, + remcom_in_buffer, + remcom_out_buffer, + linux_regs); + + if (error >= 0 || remcom_in_buffer[0] == 'D' || + remcom_in_buffer[0] == 'k') + goto kgdb_exit; + + } /* switch */ + + /* reply to the request */ + put_packet(remcom_out_buffer); + } + + kgdb_exit: + /* Call the I/O driver's post_exception routine if the I/O + * driver defined one. + */ + if (kgdb_io_ops.post_exception) + kgdb_io_ops.post_exception(); + + kgdb_info[processor].debuggerinfo = NULL; + kgdb_info[processor].task = NULL; + atomic_set(&procindebug[processor], 0); + + if (!debugger_step || !kgdb_contthread) { + for (i = 0; i < NR_CPUS; i++) + spin_unlock(&slavecpulocks[i]); + /* Wait till all the processors have quit + * from the debugger. */ + for (i = 0; i < NR_CPUS; i++) { + while (atomic_read(&procindebug[i])) { + int j = 10; /* an arbitrary number */ + + while (--j) + cpu_relax(); + } + } + } + +#ifdef CONFIG_SMP + /* This delay has a real purpose. The problem is that if you + * are single-stepping, you are sending an NMI to all the + * other processors to stop them. Interrupts come in, but + * don't get handled. Then you let them go just long enough + * to get into their interrupt routines and use up some stack. + * You stop them again, and then do the same thing. After a + * while you blow the stack on the other processors. This + * delay gives some time for interrupts to be cleared out on + * the other processors. + */ + if (debugger_step) + mdelay(2); +#endif +kgdb_restore: + /* Free debugger_active */ + atomic_set(&debugger_active, 0); + local_irq_restore(flags); + + return error; +} + +/* + * GDB places a breakpoint at this function to know dynamically + * loaded objects. It's not defined static so that only one instance with this + * name exists in the kernel. + */ + +int module_event(struct notifier_block *self, unsigned long val, void *data) +{ + return 0; +} + +static struct notifier_block kgdb_module_load_nb = { + .notifier_call = module_event, +}; + +void kgdb_nmihook(int cpu, void *regs) +{ +#ifdef CONFIG_SMP + if (!atomic_read(&procindebug[cpu]) && atomic_read(&debugger_active) != (cpu + 1)) + kgdb_wait((struct pt_regs *)regs); +#endif +} + +/* + * This is called when a panic happens. All we need to do is + * breakpoint(). + */ +static int kgdb_panic_notify(struct notifier_block *self, unsigned long cmd, + void *ptr) +{ + breakpoint(); + + return 0; +} + +static struct notifier_block kgdb_panic_notifier = { + .notifier_call = kgdb_panic_notify, +}; + +/* + * Initialization that needs to be done in either of our entry points. + */ +static void __init kgdb_internal_init(void) +{ + int i; + + /* Initialize our spinlocks. */ + for (i = 0; i < NR_CPUS; i++) + spin_lock_init(&slavecpulocks[i]); + + for (i = 0; i < MAX_BREAKPOINTS; i++) + kgdb_break[i].state = bp_none; + + /* Initialize the I/O handles */ + memset(&kgdb_io_ops_prev, 0, sizeof(kgdb_io_ops_prev)); + + /* We can't do much if this fails */ + register_module_notifier(&kgdb_module_load_nb); + + kgdb_initialized = 1; +} + +static void kgdb_register_for_panic(void) +{ + /* Register for panics(). */ + /* The registration is done in the kgdb_register_for_panic + * routine because KGDB should not try to handle a panic when + * there are no kgdb_io_ops setup. It is assumed that the + * kgdb_io_ops are setup at the time this method is called. + */ + if (!kgdb_from_module_registered) { + atomic_notifier_chain_register(&panic_notifier_list, + &kgdb_panic_notifier); + kgdb_from_module_registered = 1; + } +} + +static void kgdb_unregister_for_panic(void) +{ + /* When this routine is called KGDB should unregister from the + * panic handler and clean up, making sure it is not handling any + * break exceptions at the time. + */ + if (kgdb_from_module_registered) { + kgdb_from_module_registered = 0; + atomic_notifier_chain_unregister(&panic_notifier_list, + &kgdb_panic_notifier); + } +} + +int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops) +{ + + if (kgdb_connected) { + printk(KERN_ERR "kgdb: Cannot load I/O module while KGDB " + "connected.\n"); + return -EINVAL; + } + + /* Save the old values so they can be restored */ + if (kgdb_io_handler_cnt >= MAX_KGDB_IO_HANDLERS) { + printk(KERN_ERR "kgdb: No more I/O handles available.\n"); + return -EINVAL; + } + + /* Check to see if there is an existing driver and if so save its + * values. Also check to make sure the same driver was not trying + * to re-register. + */ + if (kgdb_io_ops.read_char != NULL && + kgdb_io_ops.read_char != local_kgdb_io_ops->read_char) { + memcpy(&kgdb_io_ops_prev[kgdb_io_handler_cnt], + &kgdb_io_ops, sizeof(struct kgdb_io)); + kgdb_io_handler_cnt++; + } + + /* Initialize the io values for this module */ + memcpy(&kgdb_io_ops, local_kgdb_io_ops, sizeof(struct kgdb_io)); + + /* Make the call to register kgdb if is not initialized */ + kgdb_register_for_panic(); + + return 0; +} + +void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops) +{ + int i; + + /* Unregister KGDB if there were no other prior io hooks, else + * restore the io hooks. + */ + if (kgdb_io_handler_cnt > 0 && kgdb_io_ops_prev[0].read_char != NULL) { + /* First check if the hook that is in use is the one being + * removed */ + if (kgdb_io_ops.read_char == local_kgdb_io_ops->read_char) { + /* Set 'i' to the value of where the list should be + * shifed */ + i = kgdb_io_handler_cnt - 1; + memcpy(&kgdb_io_ops, &kgdb_io_ops_prev[i], + sizeof(struct kgdb_io)); + } else { + /* Simple case to remove an entry for an I/O handler + * that is not in use */ + for (i = 0; i < kgdb_io_handler_cnt; i++) { + if (kgdb_io_ops_prev[i].read_char == + local_kgdb_io_ops->read_char) + break; + } + } + + /* Shift all the entries in the handler array so it is + * ordered from oldest to newest. + */ + kgdb_io_handler_cnt--; + for (; i < kgdb_io_handler_cnt; i++) { + memcpy(&kgdb_io_ops_prev[i], &kgdb_io_ops_prev[i + 1], + sizeof(struct kgdb_io)); + } + /* Handle the case if we are on the last element and set it + * to NULL; */ + memset(&kgdb_io_ops_prev[kgdb_io_handler_cnt], 0, + sizeof(struct kgdb_io)); + + if (kgdb_connected) + printk(KERN_ERR "kgdb: WARNING: I/O method changed " + "while kgdb was connected state.\n"); + } else { + /* KGDB is no longer able to communicate out, so + * unregister our hooks and reset state. */ + kgdb_unregister_for_panic(); + if (kgdb_connected) { + printk(KERN_CRIT "kgdb: I/O module was unloaded while " + "a debugging session was running. " + "KGDB will be reset.\n"); + if (remove_all_break() < 0) + printk(KERN_CRIT "kgdb: Reset failed.\n"); + kgdb_connected = 0; + } + memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io)); + } +} + +/* + * There are times we need to call a tasklet to cause a breakpoint + * as calling breakpoint() at that point might be fatal. We have to + * check that the exception stack is setup, as tasklets may be scheduled + * prior to this. When that happens, it is up to the architecture to + * schedule this when it is safe to run. + */ +static void kgdb_tasklet_bpt(unsigned long ing) +{ + if(CHECK_EXCEPTION_STACK()) + breakpoint(); +} + +DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0); + +/* + * This function can be called very early, either via early_param() or + * an explicit breakpoint() early on. + */ +static void __init kgdb_early_entry(void) +{ + /* + * Don't try and do anything until the architecture is able to + * setup the exception stack. In this case, it is up to the + * architecture to hook in and look at us when they are ready. + */ + if(!CHECK_EXCEPTION_STACK()) { + kgdb_initialized = -1; + tasklet_schedule(&kgdb_tasklet_breakpoint); + return; + } + + /* Let the architecture do any setup that it needs to. */ + kgdb_arch_init(); + + /* Now try the I/O. */ + /* For early entry kgdb_io_ops.init must be defined */ + if (!kgdb_io_ops.init || kgdb_io_ops.init()) { + /* Try again later. */ + kgdb_initialized = -1; + return; + } + + /* Finish up. */ + kgdb_internal_init(); + + /* KGDB can assume that if kgdb_io_ops.init was defined that the + * panic registion should be performed at this time. This means + * kgdb_io_ops.init did not come from a kernel module and was + * initialized statically by a built in. + */ + if (kgdb_io_ops.init) + kgdb_register_for_panic(); +} + +/* + * This function will always be invoked to make sure that KGDB will grab + * what it needs to so that if something happens while the system is + * running, KGDB will get involved. If kgdb_early_entry() has already + * been invoked, there is little we need to do. + */ +static int __init kgdb_late_entry(void) +{ + int need_break = 0; + + /* If kgdb_initialized is -1 then we were passed kgdbwait. */ + if (kgdb_initialized == -1) + need_break = 1; + + /* + * If we haven't tried to initialize KGDB yet, we need to call + * kgdb_arch_init before moving onto the I/O. + */ + if (!kgdb_initialized) + kgdb_arch_init(); + + if (kgdb_initialized != 1) { + if (kgdb_io_ops.init && kgdb_io_ops.init()) { + /* When KGDB allows I/O via modules and the core + * I/O init fails KGDB must default to defering the + * I/O setup, and appropriately print an error about + * it. + */ + printk(KERN_ERR "kgdb: Could not setup core I/O " + "for KGDB.\n"); + printk(KERN_INFO "kgdb: Defering I/O setup to kernel " + "module.\n"); + memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io)); + } + + kgdb_internal_init(); + + /* KGDB can assume that if kgdb_io_ops.init was defined that + * panic registion should be performed at this time. This means + * kgdb_io_ops.init did not come from a kernel module and was + * initialized statically by a built in. + */ + if (kgdb_io_ops.init) + kgdb_register_for_panic(); + } + + /* Registering to reboot notifier list*/ + register_reboot_notifier(&kgdb_reboot_notifier); + + /* Now do any late init of the I/O. */ + if (kgdb_io_ops.late_init) + kgdb_io_ops.late_init(); + + if (need_break) { + printk(KERN_CRIT "kgdb: Waiting for connection from remote" + " gdb...\n"); + breakpoint(); + } + + return 0; +} + +late_initcall(kgdb_late_entry); + +/* + * This function will generate a breakpoint exception. It is used at the + * beginning of a program to sync up with a debugger and can be used + * otherwise as a quick means to stop program execution and "break" into + * the debugger. + */ +void breakpoint(void) +{ + if (kgdb_initialized != 1) { + kgdb_early_entry(); + if (kgdb_initialized == 1) + printk(KERN_CRIT "Waiting for connection from remote " + "gdb...\n"); + else { + printk(KERN_CRIT "KGDB cannot initialize I/O yet.\n"); + return; + } + } + + atomic_set(&kgdb_setting_breakpoint, 1); + wmb(); + BREAKPOINT(); + wmb(); + atomic_set(&kgdb_setting_breakpoint, 0); +} + +EXPORT_SYMBOL(breakpoint); + +#ifdef CONFIG_MAGIC_SYSRQ +static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + printk("Entering GDB stub\n"); + breakpoint(); +} +static struct sysrq_key_op sysrq_gdb_op = { + .handler = sysrq_handle_gdb, + .help_msg = "Gdb", + .action_msg = "GDB", +}; + +static int gdb_register_sysrq(void) +{ + printk("Registering GDB sysrq handler\n"); + register_sysrq_key('g', &sysrq_gdb_op); + return 0; +} + +module_init(gdb_register_sysrq); +#endif + +static int kgdb_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) +{ + + unsigned long flags; + + /* If we're debugging, or KGDB has not connected, don't try + * and print. */ + if (!kgdb_connected || atomic_read(&debugger_active) != 0) + return 0; + if ((code == SYS_RESTART) || (code == SYS_HALT) || (code == SYS_POWER_OFF)){ + local_irq_save(flags); + put_packet("X00"); + local_irq_restore(flags); + } + return NOTIFY_DONE; +} + +#ifdef CONFIG_KGDB_CONSOLE +void kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + unsigned long flags; + + /* If we're debugging, or KGDB has not connected, don't try + * and print. */ + if (!kgdb_connected || atomic_read(&debugger_active) != 0) + return; + + local_irq_save(flags); + kgdb_msg_write(s, count); + local_irq_restore(flags); +} + +struct console kgdbcons = { + .name = "kgdb", + .write = kgdb_console_write, + .flags = CON_PRINTBUFFER | CON_ENABLED, +}; +static int __init kgdb_console_init(void) +{ + register_console(&kgdbcons); + return 0; +} + +console_initcall(kgdb_console_init); +#endif + +static int __init opt_kgdb_enter(char *str) +{ + /* We've already done this by an explicit breakpoint() call. */ + if (kgdb_initialized) + return 0; + + /* Call breakpoint() which will take care of init. */ + breakpoint(); + + return 0; +} + +early_param("kgdbwait", opt_kgdb_enter); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/kgdbarchlib.c linux-2.6.18-53.1.14.kgdb/kernel/kgdbarchlib.c --- linux-2.6.18-53.1.14/kernel/kgdbarchlib.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/kgdbarchlib.c 2008-06-10 15:37:25.000000000 +0400 @@ -0,0 +1,198 @@ +#include + +struct kgdb_arch *kgdb_ops = &arch_kgdb_ops; + +/** + * kgdb_arch_init - Perform any architecture specific initalization. + * + * RETURN: + * The return value is ignored. + * + * This function will handle the initalization of any architecture + * specific hooks. + */ +int __attribute__ ((weak)) + kgdb_arch_init(void) +{ + return 0; +} + +/** + * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. + * @regs: Current &struct pt_regs. + * + * This function will be called if the particular architecture must + * disable hardware debugging while it is processing gdb packets or + * handling exception. + */ +void __attribute__ ((weak)) + kgdb_disable_hw_debug(struct pt_regs *regs) +{ +} + +/* + * Skip an int3 exception when it occurs after a breakpoint has been + * removed. Backtrack eip by 1 since the int3 would have caused it to + * increment by 1. + */ +int __attribute__ ((weak)) + kgdb_skipexception(int exception, struct pt_regs *regs) +{ + return 0; +} + +/** + * kgdb_set_hw_break - Set a hardware breakpoint at @addr. + * @addr: The address to set a hardware breakpoint at. + */ +int __attribute__ ((weak)) + kgdb_set_hw_break(unsigned long addr) +{ + return 0; +} + +/** + * kgdb_remove_hw_break - Remove a hardware breakpoint at @addr. + * @addr: The address to remove a hardware breakpoint from. + */ +int __attribute__ ((weak)) + kgdb_remove_hw_break(unsigned long addr) +{ + return 0; +} + +/** + * kgdb_remove_all_hw_break - Clear all hardware breakpoints. + */ +void __attribute__ ((weak)) + kgdb_remove_all_hw_break(void) +{ +} + +/** + * kgdb_correct_hw_break - Correct hardware breakpoints. + * + * A hook to allow for changes to the hardware breakpoint, called + * after a single step (s) or continue (c) packet, and once we're about + * to let the kernel continue running. + * + * This is used to set the hardware breakpoint registers for all the + * slave cpus on an SMP configuration. This must be called after any + * changes are made to the hardware breakpoints (such as by a single + * step (s) or continue (c) packet. This is only required on + * architectures that support SMP and every processor has its own set + * of breakpoint registers. + */ +void __attribute__ ((weak)) + kgdb_correct_hw_break(void) +{ +} + +/** + * kgdb_post_master_code - Save error vector/code numbers. + * @regs: Original pt_regs. + * @e_vector: Original error vector. + * @err_code: Original error code. + * + * This is needed on architectures which support SMP and KGDB. + * This function is called after all the slave cpus have been put + * to a know spin state and the master CPU has control over KGDB. + */ + +void __attribute__ ((weak)) + kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code) +{ +} + +/** + * kgdb_roundup_cpus - Get other CPUs into a holding pattern + * @flags: Current IRQ state + * + * On SMP systems, we need to get the attention of the other CPUs + * and get them be in a known state. This should do what is needed + * to get the other CPUs to call kgdb_wait(). Note that on some arches, + * the NMI approach is not used for rounding up all the CPUs. For example, + * in case of MIPS, smp_call_function() is used to roundup CPUs. In + * this case, we have to make sure that interrupts are enabled before + * calling smp_call_function(). The argument to this function is + * the flags that will be used when restoring the interrupts. There is + * local_irq_save() call before kgdb_roundup_cpus(). + */ +void __attribute__ ((weak)) + kgdb_roundup_cpus(unsigned long flags) +{ +} + +/** + * kgdb_shadowinfo - Get shadowed information on @threadid. + * @regs: The &struct pt_regs of the current process. + * @buffer: A buffer of %BUFMAX size. + * @threadid: The thread id of the shadowed process to get information on. + */ +void __attribute__ ((weak)) + kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid) +{ +} + +/** + * kgdb_get_shadow_thread - Get the shadowed &task_struct of @threadid. + * @regs: The &struct pt_regs of the current thread. + * @threadid: The thread id of the shadowed process to get information on. + * + * RETURN: + * This returns a pointer to the &struct task_struct of the shadowed + * thread, @threadid. + */ +struct task_struct __attribute__ ((weak)) + * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid) +{ + return NULL; +} + +/** + * kgdb_shadow_regs - Return the shadowed registers of @threadid. + * @regs: The &struct pt_regs of the current thread. + * @threadid: The thread id we want the &struct pt_regs for. + * + * RETURN: + * The a pointer to the &struct pt_regs of the shadowed thread @threadid. + */ +struct pt_regs __attribute__ ((weak)) + * kgdb_shadow_regs(struct pt_regs *regs, int threadid) +{ + return NULL; +} + +int __attribute__ ((weak)) + kgdb_validate_break_address(unsigned long addr) +{ + int error = 0; + char tmp_variable[BREAK_INSTR_SIZE]; + error = kgdb_get_mem((char *)addr, tmp_variable, BREAK_INSTR_SIZE); + return error; +} + +int __attribute__ ((weak)) + kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) +{ + int error = 0; + if ((error = kgdb_get_mem((char *)addr, + saved_instr, BREAK_INSTR_SIZE)) < 0) + return error; + + if ((error = kgdb_set_mem((char *)addr, kgdb_ops->gdb_bpt_instr, + BREAK_INSTR_SIZE)) < 0) + return error; + return 0; +} + +int __attribute__ ((weak)) + kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) +{ + + int error = 0; + if ((error =kgdb_set_mem((char *)addr, (char *)bundle, + BREAK_INSTR_SIZE)) < 0) + return error; + return 0; +} diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/module.c linux-2.6.18-53.1.14.kgdb/kernel/module.c --- linux-2.6.18-53.1.14/kernel/module.c 2008-03-06 05:54:13.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/module.c 2008-06-10 15:39:15.000000000 +0400 @@ -65,6 +65,7 @@ static DEFINE_SPINLOCK(modlist_lock); /* List of modules, protected by module_mutex AND modlist_lock */ static DEFINE_MUTEX(module_mutex); static LIST_HEAD(modules); +static DECLARE_MUTEX(notify_mutex); static BLOCKING_NOTIFIER_HEAD(module_notify_list); @@ -701,6 +702,12 @@ sys_delete_module(const char __user *nam if (ret != 0) goto out; + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, + mod); + up(¬ify_mutex); + + /* Never wait if forced. */ if (!forced && module_refcount(mod) != 0) wait_for_zero_refcount(mod); @@ -713,6 +720,11 @@ sys_delete_module(const char __user *nam } free_module(mod); + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GONE, + NULL); + up(¬ify_mutex); + out: mutex_unlock(&module_mutex); return ret; @@ -1119,6 +1131,11 @@ static void free_module(struct module *m /* Arch-specific cleanup. */ module_arch_cleanup(mod); +#ifdef CONFIG_KGDB + /* kgdb info */ + vfree(mod->mod_sections); +#endif + /* Module unload stuff */ module_unload_free(mod); @@ -1378,6 +1395,31 @@ static void setup_modinfo(struct module } } +#ifdef CONFIG_KGDB +int add_modsects (struct module *mod, Elf_Ehdr *hdr, Elf_Shdr *sechdrs, const + char *secstrings) +{ + int i; + + mod->num_sections = hdr->e_shnum - 1; + mod->mod_sections = vmalloc((hdr->e_shnum - 1)* + sizeof (struct mod_section)); + + if (mod->mod_sections == NULL) { + return -ENOMEM; + } + + for (i = 1; i < hdr->e_shnum; i++) { + mod->mod_sections[i - 1].address = (void *)sechdrs[i].sh_addr; + strncpy(mod->mod_sections[i - 1].name, secstrings + + sechdrs[i].sh_name, MAX_SECTNAME); + mod->mod_sections[i - 1].name[MAX_SECTNAME] = '\0'; + } + + return 0; +} +#endif + #ifdef CONFIG_KALLSYMS int is_exported(const char *name, const struct module *mod) { @@ -1796,6 +1838,12 @@ static struct module *load_module(void _ add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); +#ifdef CONFIG_KGDB + if ((err = add_modsects(mod, hdr, sechdrs, secstrings)) < 0) { + goto nomodsectinfo; + } +#endif + err = module_finalize(hdr, sechdrs, mod); if (err < 0) goto cleanup; @@ -1856,6 +1904,11 @@ static struct module *load_module(void _ arch_cleanup: module_arch_cleanup(mod); cleanup: + +#ifdef CONFIG_KGDB +nomodsectinfo: + vfree(mod->mod_sections); +#endif module_unload_free(mod); module_free(mod, mod->module_init); free_core: @@ -1927,6 +1980,10 @@ sys_init_module(void __user *umod, /* Init routine failed: abort. Try to protect us from buggy refcounters. */ mod->state = MODULE_STATE_GOING; + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, + mod); + up(¬ify_mutex); synchronize_sched(); if (mod->unsafe) printk(KERN_ERR "%s: module is now stuck!\n", diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/sched.c linux-2.6.18-53.1.14.kgdb/kernel/sched.c --- linux-2.6.18-53.1.14/kernel/sched.c 2008-03-06 05:54:44.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/sched.c 2008-06-10 15:37:25.000000000 +0400 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -6835,6 +6836,9 @@ void __might_sleep(char *file, int line) #ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ + if (atomic_read(&debugger_active)) + return; + if ((in_atomic() || irqs_disabled()) && system_state == SYSTEM_RUNNING && !oops_in_progress) { if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/softlockup.c linux-2.6.18-53.1.14.kgdb/kernel/softlockup.c --- linux-2.6.18-53.1.14/kernel/softlockup.c 2008-03-06 05:54:44.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/softlockup.c 2008-06-10 15:39:21.000000000 +0400 @@ -13,6 +13,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(print_lock); @@ -37,6 +38,9 @@ static struct notifier_block panic_block void touch_softlockup_watchdog(void) { __raw_get_cpu_var(touch_timestamp) = jiffies; +#ifdef CONFIG_KGDB + atomic_set(&kgdb_sync_softlockup[raw_smp_processor_id()], 0); +#endif } EXPORT_SYMBOL(touch_softlockup_watchdog); diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/kernel/timer.c linux-2.6.18-53.1.14.kgdb/kernel/timer.c --- linux-2.6.18-53.1.14/kernel/timer.c 2008-03-06 05:54:50.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/kernel/timer.c 2008-06-10 15:39:21.000000000 +0400 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1385,7 +1386,11 @@ static void run_timer_softirq(struct sof */ void run_local_timers(void) { + int this_cpu = smp_processor_id(); raise_softirq(TIMER_SOFTIRQ); +#ifdef CONFIG_KGDB + if(!atomic_read(&kgdb_sync_softlockup[this_cpu])) +#endif softlockup_tick(); } diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/lib/Kconfig.debug linux-2.6.18-53.1.14.kgdb/lib/Kconfig.debug --- linux-2.6.18-53.1.14/lib/Kconfig.debug 2008-03-06 05:54:32.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/lib/Kconfig.debug 2008-06-10 15:38:56.000000000 +0400 @@ -324,7 +324,7 @@ config DEBUG_LIST config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390) + depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || SUPERH) default y if DEBUG_INFO && UML help If you say Y here the resulting kernel image will be slightly larger @@ -377,3 +377,158 @@ config RCU_TORTURE_TEST at boot time (you probably don't). Say M if you want the RCU torture tests to build as a module. Say N if you are unsure. + +config WANT_EXTRA_DEBUG_INFORMATION + bool + select DEBUG_INFO + select FRAME_POINTER if X86 || SUPERH + default n + +config KGDB + bool "KGDB: kernel debugging with remote gdb" + select WANT_EXTRA_DEBUG_INFORMATION + depends on DEBUG_KERNEL && (ARM || X86 || MIPS || (SUPERH && !SUPERH64) || IA64 || X86_64 || PPC) + help + If you say Y here, it will be possible to remotely debug the + kernel using gdb. It is strongly suggested that you enable + DEBUG_INFO, and if available on your platform, FRAME_POINTER. + Documentation of kernel debugger available at + http://kgdb.sourceforge.net as well as in DocBook form + in Documentation/DocBook/. If unsure, say N. + +config KGDB_CONSOLE + bool "KGDB: Console messages through gdb" + depends on KGDB + help + If you say Y here, console messages will appear through gdb. + Other consoles such as tty or ttyS will continue to work as usual. + Note, that if you use this in conjunction with KGDB_ETH, if the + ethernet driver runs into an error condition during use with KGDB + it is possible to hit an infinite recusrion, causing the kernel + to crash, and typically reboot. For this reason, it is preferable + to use NETCONSOLE in conjunction with KGDB_ETH instead of + KGDB_CONSOLE. + +choice + prompt "Method for KGDB communication" + depends on KGDB + default KGDB_8250_NOMODULE + default KGDB_MPSC if SERIAL_MPSC + default KGDB_CPM_UART if (8xx || 8260) + default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC + help + There are a number of different ways in which you can communicate + with KGDB. The most common is via serial, with the 8250 driver + (should your hardware have an 8250, or ns1655x style uart). + Another option is to use the NETPOLL framework and UDP, should + your ethernet card support this. Other options may exist. + You can elect to have one core I/O driver that is built into the + kernel for debugging as the kernel is booting, or using only + kernel modules. + +config KGDB_ONLY_MODULES + bool "KGDB: Use only kernel modules for I/O" + depends on MODULES + help + Use only kernel modules to configure KGDB I/O after the + kernel is booted. + +config KGDB_8250_NOMODULE + bool "KGDB: On generic serial port (8250)" + select KGDB_8250 + help + Uses generic serial port (8250) to communicate with the host + GDB. This is independent of the normal (SERIAL_8250) driver + for this chipset. + +config KGDBOE_NOMODULE + bool "KGDB: On ethernet - in kernel" + select KGDBOE + select NETPOLL + select NETPOLL_TRAP + select NETPOLL_RX + help + Uses the NETPOLL API to communicate with the host GDB via UDP. + In order for this to work, the ethernet interface specified must + support the NETPOLL API, and this must be initialized at boot. + See the documentation for syntax. + +config KGDB_MPSC + bool "KGDB on MV64x60 MPSC" + depends on SERIAL_MPSC + help + Uses a Marvell GT64260B or MV64x60 Multi-Purpose Serial + Controller (MPSC) channel. Note that the GT64260A is not + supported. + +config KGDB_CPM_UART + bool "KGDB: On CPM UART" + depends on PPC && (CPM2 || 8xx) + help + Uses CPM UART to communicate with the host GDB. + +config KGDB_SIBYTE + bool "KGDB: On the Broadcom SWARM serial port" + depends on MIPS && SIBYTE_SB1xxx_SOC +endchoice + +config KGDBOE + tristate "KGDB: On ethernet" if !KGDBOE_NOMODULE + depends on m && KGDB + select NETPOLL + select NETPOLL_TRAP + select NETPOLL_RX + help + Uses the NETPOLL API to communicate with the host GDB via UDP. + In order for this to work, the ethernet interface specified must + support the NETPOLL API, and this must be initialized at boot. + See the documentation for syntax. + +config KGDB_8250 + tristate "KGDB: On generic serial port (8250)" if !KGDB_8250_NOMODULE + depends on m && KGDB_ONLY_MODULES + help + Uses generic serial port (8250) to communicate with the host + GDB. This is independent of the normal (SERIAL_8250) driver + for this chipset. + +config KGDB_SIMPLE_SERIAL + bool "Simple selection of KGDB serial port" + depends on KGDB_8250_NOMODULE + default y + help + If you say Y here, you will only have to pick the baud rate + and port number that you wish to use for KGDB. Note that this + only works on architectures that register known serial ports + early on. If you say N, you will have to provide, either here + or on the command line, the type (I/O or MMIO), IRQ and + address to use. If in doubt, say Y. + +config KGDB_BAUDRATE + int "Debug serial port baud rate" + depends on (KGDB_8250 && KGDB_SIMPLE_SERIAL) + default "115200" + help + gdb and the kernel stub need to agree on the baud rate to be + used. Standard rates from 9600 to 115200 are allowed, and this + may be overridden via the commandline. + +config KGDB_PORT_NUM + int "Serial port number for KGDB" + range 0 1 if KGDB_MPSC + range 0 3 + depends on (KGDB_8250 && KGDB_SIMPLE_SERIAL) || KGDB_MPSC + default "1" + help + Pick the port number (0 based) for KGDB to use. + +config KGDB_8250_CONF_STRING + string "Configuration string for KGDB" + depends on KGDB_8250_NOMODULE && !KGDB_SIMPLE_SERIAL + default "io,2f8,115200,3" if X86 + help + The format of this string should be ,
,,. For example, to use the + serial port on an i386 box located at 0x2f8 and 115200 baud + on IRQ 3 at use: + io,2f8,115200,3 diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/net/core/netpoll.c linux-2.6.18-53.1.14.kgdb/net/core/netpoll.c --- linux-2.6.18-53.1.14/net/core/netpoll.c 2008-03-06 05:54:27.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/net/core/netpoll.c 2008-06-10 15:37:49.000000000 +0400 @@ -525,7 +525,8 @@ int __netpoll_rx(struct sk_buff *skb) np->rx_hook(np, ntohs(uh->source), (char *)(uh+1), - ulen - sizeof(struct udphdr)); + ulen - sizeof(struct udphdr), + skb); kfree_skb(skb); return 1; diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/scripts/dwarfh.awk linux-2.6.18-53.1.14.kgdb/scripts/dwarfh.awk --- linux-2.6.18-53.1.14/scripts/dwarfh.awk 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.18-53.1.14.kgdb/scripts/dwarfh.awk 2008-06-10 15:39:01.000000000 +0400 @@ -0,0 +1,19 @@ +BEGIN { + print "#ifndef _ELF_DWARF_H" + print "/* Machine generated from dwarf2.h by scripts/dwarfh.awk */" +} +$2 == "=" { + gsub(/,/, "", $3) + print "#define " $1 "\t " $3 +} +$1 == "#define" { + print $0 + while( index($0,"\\") == length($0)){ + getline + print $0 + } +} +/.*/ {} +END { + print "#endif" +}