145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e8d31c20SJason Wessel /* 3e8d31c20SJason Wessel * kgdbts is a test suite for kgdb for the sole purpose of validating 4e8d31c20SJason Wessel * that key pieces of the kgdb internals are working properly such as 5e8d31c20SJason Wessel * HW/SW breakpoints, single stepping, and NMI. 6e8d31c20SJason Wessel * 7e8d31c20SJason Wessel * Created by: Jason Wessel <jason.wessel@windriver.com> 8e8d31c20SJason Wessel * 9e8d31c20SJason Wessel * Copyright (c) 2008 Wind River Systems, Inc. 10e8d31c20SJason Wessel */ 11e8d31c20SJason Wessel /* Information about the kgdb test suite. 12e8d31c20SJason Wessel * ------------------------------------- 13e8d31c20SJason Wessel * 14e8d31c20SJason Wessel * The kgdb test suite is designed as a KGDB I/O module which 15e8d31c20SJason Wessel * simulates the communications that a debugger would have with kgdb. 16e8d31c20SJason Wessel * The tests are broken up in to a line by line and referenced here as 17e8d31c20SJason Wessel * a "get" which is kgdb requesting input and "put" which is kgdb 18e8d31c20SJason Wessel * sending a response. 19e8d31c20SJason Wessel * 20e8d31c20SJason Wessel * The kgdb suite can be invoked from the kernel command line 21e8d31c20SJason Wessel * arguments system or executed dynamically at run time. The test 22e8d31c20SJason Wessel * suite uses the variable "kgdbts" to obtain the information about 23e8d31c20SJason Wessel * which tests to run and to configure the verbosity level. The 24e8d31c20SJason Wessel * following are the various characters you can use with the kgdbts= 25e8d31c20SJason Wessel * line: 26e8d31c20SJason Wessel * 27e8d31c20SJason Wessel * When using the "kgdbts=" you only choose one of the following core 28e8d31c20SJason Wessel * test types: 29e8d31c20SJason Wessel * A = Run all the core tests silently 30e8d31c20SJason Wessel * V1 = Run all the core tests with minimal output 31e8d31c20SJason Wessel * V2 = Run all the core tests in debug mode 32e8d31c20SJason Wessel * 33e8d31c20SJason Wessel * You can also specify optional tests: 34e8d31c20SJason Wessel * N## = Go to sleep with interrupts of for ## seconds 35e8d31c20SJason Wessel * to test the HW NMI watchdog 36f30897c1SChristian Brauner * F## = Break at kernel_clone for ## iterations 37e8d31c20SJason Wessel * S## = Break at sys_open for ## iterations 387cfcd985SJason Wessel * I## = Run the single step test ## iterations 39e8d31c20SJason Wessel * 40f30897c1SChristian Brauner * NOTE: that the kernel_clone and sys_open tests are mutually exclusive. 41e8d31c20SJason Wessel * 42e8d31c20SJason Wessel * To invoke the kgdb test suite from boot you use a kernel start 43e8d31c20SJason Wessel * argument as follows: 44e8d31c20SJason Wessel * kgdbts=V1 kgdbwait 45f30897c1SChristian Brauner * Or if you wanted to perform the NMI test for 6 seconds and kernel_clone 46e8d31c20SJason Wessel * test for 100 forks, you could use: 47e8d31c20SJason Wessel * kgdbts=V1N6F100 kgdbwait 48e8d31c20SJason Wessel * 49e8d31c20SJason Wessel * The test suite can also be invoked at run time with: 50e8d31c20SJason Wessel * echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts 51e8d31c20SJason Wessel * Or as another example: 52e8d31c20SJason Wessel * echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts 53e8d31c20SJason Wessel * 54e8d31c20SJason Wessel * When developing a new kgdb arch specific implementation or 55e8d31c20SJason Wessel * using these tests for the purpose of regression testing, 56e8d31c20SJason Wessel * several invocations are required. 57e8d31c20SJason Wessel * 58e8d31c20SJason Wessel * 1) Boot with the test suite enabled by using the kernel arguments 59e8d31c20SJason Wessel * "kgdbts=V1F100 kgdbwait" 60e8d31c20SJason Wessel * ## If kgdb arch specific implementation has NMI use 61e8d31c20SJason Wessel * "kgdbts=V1N6F100 62e8d31c20SJason Wessel * 63e8d31c20SJason Wessel * 2) After the system boot run the basic test. 64e8d31c20SJason Wessel * echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts 65e8d31c20SJason Wessel * 66e8d31c20SJason Wessel * 3) Run the concurrency tests. It is best to use n+1 67e8d31c20SJason Wessel * while loops where n is the number of cpus you have 68e8d31c20SJason Wessel * in your system. The example below uses only two 69e8d31c20SJason Wessel * loops. 70e8d31c20SJason Wessel * 71e8d31c20SJason Wessel * ## This tests break points on sys_open 72e8d31c20SJason Wessel * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & 73e8d31c20SJason Wessel * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & 74e8d31c20SJason Wessel * echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts 75e8d31c20SJason Wessel * fg # and hit control-c 76e8d31c20SJason Wessel * fg # and hit control-c 77f30897c1SChristian Brauner * ## This tests break points on kernel_clone 78e8d31c20SJason Wessel * while [ 1 ] ; do date > /dev/null ; done & 79e8d31c20SJason Wessel * while [ 1 ] ; do date > /dev/null ; done & 80e8d31c20SJason Wessel * echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts 81e8d31c20SJason Wessel * fg # and hit control-c 82e8d31c20SJason Wessel * 83e8d31c20SJason Wessel */ 84e8d31c20SJason Wessel 85e8d31c20SJason Wessel #include <linux/kernel.h> 86e8d31c20SJason Wessel #include <linux/kgdb.h> 87e8d31c20SJason Wessel #include <linux/ctype.h> 88e8d31c20SJason Wessel #include <linux/uaccess.h> 89e8d31c20SJason Wessel #include <linux/syscalls.h> 90e8d31c20SJason Wessel #include <linux/nmi.h> 91e8d31c20SJason Wessel #include <linux/delay.h> 92e8d31c20SJason Wessel #include <linux/kthread.h> 93eb12a679SPaul Gortmaker #include <linux/module.h> 9429930025SIngo Molnar #include <linux/sched/task.h> 951114ab22SDaniel Thompson #include <linux/kallsyms.h> 9629930025SIngo Molnar 97e78acf67STiejun Chen #include <asm/sections.h> 98e8d31c20SJason Wessel 99e8d31c20SJason Wessel #define v1printk(a...) do { \ 100e8d31c20SJason Wessel if (verbose) \ 101e8d31c20SJason Wessel printk(KERN_INFO a); \ 102e8d31c20SJason Wessel } while (0) 103e8d31c20SJason Wessel #define v2printk(a...) do { \ 104*bda7d3abSGreg Kroah-Hartman if (verbose > 1) { \ 105e8d31c20SJason Wessel printk(KERN_INFO a); \ 106*bda7d3abSGreg Kroah-Hartman } \ 107e8d31c20SJason Wessel touch_nmi_watchdog(); \ 108e8d31c20SJason Wessel } while (0) 109974460c5SJason Wessel #define eprintk(a...) do { \ 110974460c5SJason Wessel printk(KERN_ERR a); \ 111974460c5SJason Wessel WARN_ON(1); \ 112974460c5SJason Wessel } while (0) 113e8d31c20SJason Wessel #define MAX_CONFIG_LEN 40 114e8d31c20SJason Wessel 115e8d31c20SJason Wessel static struct kgdb_io kgdbts_io_ops; 116e8d31c20SJason Wessel static char get_buf[BUFMAX]; 117e8d31c20SJason Wessel static int get_buf_cnt; 118e8d31c20SJason Wessel static char put_buf[BUFMAX]; 119e8d31c20SJason Wessel static int put_buf_cnt; 120e8d31c20SJason Wessel static char scratch_buf[BUFMAX]; 121e8d31c20SJason Wessel static int verbose; 122e8d31c20SJason Wessel static int repeat_test; 123e8d31c20SJason Wessel static int test_complete; 124e8d31c20SJason Wessel static int send_ack; 125e8d31c20SJason Wessel static int final_ack; 126b33cb815SJason Wessel static int force_hwbrks; 127b33cb815SJason Wessel static int hwbreaks_ok; 128e8d31c20SJason Wessel static int hw_break_val; 129e8d31c20SJason Wessel static int hw_break_val2; 130486c5987SJason Wessel static int cont_instead_of_sstep; 131486c5987SJason Wessel static unsigned long cont_thread_id; 132486c5987SJason Wessel static unsigned long sstep_thread_id; 1334d7ffa49SDavid S. Miller #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) 134e8d31c20SJason Wessel static int arch_needs_sstep_emulation = 1; 135e8d31c20SJason Wessel #else 136e8d31c20SJason Wessel static int arch_needs_sstep_emulation; 137e8d31c20SJason Wessel #endif 13823bbd8e3SJason Wessel static unsigned long cont_addr; 139e8d31c20SJason Wessel static unsigned long sstep_addr; 14023bbd8e3SJason Wessel static int restart_from_top_after_write; 141e8d31c20SJason Wessel static int sstep_state; 142e8d31c20SJason Wessel 143e8d31c20SJason Wessel /* Storage for the registers, in GDB format. */ 144e8d31c20SJason Wessel static unsigned long kgdbts_gdb_regs[(NUMREGBYTES + 145e8d31c20SJason Wessel sizeof(unsigned long) - 1) / 146e8d31c20SJason Wessel sizeof(unsigned long)]; 147e8d31c20SJason Wessel static struct pt_regs kgdbts_regs; 148e8d31c20SJason Wessel 149e8d31c20SJason Wessel /* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ 150e8d31c20SJason Wessel static int configured = -1; 151e8d31c20SJason Wessel 152974460c5SJason Wessel #ifdef CONFIG_KGDB_TESTS_BOOT_STRING 153974460c5SJason Wessel static char config[MAX_CONFIG_LEN] = CONFIG_KGDB_TESTS_BOOT_STRING; 154974460c5SJason Wessel #else 155e8d31c20SJason Wessel static char config[MAX_CONFIG_LEN]; 156974460c5SJason Wessel #endif 157e8d31c20SJason Wessel static struct kparam_string kps = { 158e8d31c20SJason Wessel .string = config, 159e8d31c20SJason Wessel .maxlen = MAX_CONFIG_LEN, 160e8d31c20SJason Wessel }; 161e8d31c20SJason Wessel 162e8d31c20SJason Wessel static void fill_get_buf(char *buf); 163e8d31c20SJason Wessel 164e8d31c20SJason Wessel struct test_struct { 165e8d31c20SJason Wessel char *get; 166e8d31c20SJason Wessel char *put; 167e8d31c20SJason Wessel void (*get_handler)(char *); 168e8d31c20SJason Wessel int (*put_handler)(char *, char *); 169e8d31c20SJason Wessel }; 170e8d31c20SJason Wessel 171e8d31c20SJason Wessel struct test_state { 172e8d31c20SJason Wessel char *name; 173e8d31c20SJason Wessel struct test_struct *tst; 174e8d31c20SJason Wessel int idx; 175e8d31c20SJason Wessel int (*run_test) (int, int); 176e8d31c20SJason Wessel int (*validate_put) (char *); 177e8d31c20SJason Wessel }; 178e8d31c20SJason Wessel 179e8d31c20SJason Wessel static struct test_state ts; 180e8d31c20SJason Wessel 181e8d31c20SJason Wessel static int kgdbts_unreg_thread(void *ptr) 182e8d31c20SJason Wessel { 183e8d31c20SJason Wessel /* Wait until the tests are complete and then ungresiter the I/O 184e8d31c20SJason Wessel * driver. 185e8d31c20SJason Wessel */ 186e8d31c20SJason Wessel while (!final_ack) 187e8d31c20SJason Wessel msleep_interruptible(1500); 18823bbd8e3SJason Wessel /* Pause for any other threads to exit after final ack. */ 18923bbd8e3SJason Wessel msleep_interruptible(1000); 190e8d31c20SJason Wessel if (configured) 191e8d31c20SJason Wessel kgdb_unregister_io_module(&kgdbts_io_ops); 192e8d31c20SJason Wessel configured = 0; 193e8d31c20SJason Wessel 194e8d31c20SJason Wessel return 0; 195e8d31c20SJason Wessel } 196e8d31c20SJason Wessel 197e8d31c20SJason Wessel /* This is noinline such that it can be used for a single location to 198e8d31c20SJason Wessel * place a breakpoint 199e8d31c20SJason Wessel */ 200e8d31c20SJason Wessel static noinline void kgdbts_break_test(void) 201e8d31c20SJason Wessel { 202e8d31c20SJason Wessel v2printk("kgdbts: breakpoint complete\n"); 203e8d31c20SJason Wessel } 204e8d31c20SJason Wessel 2051114ab22SDaniel Thompson /* 2061114ab22SDaniel Thompson * This is a cached wrapper for kallsyms_lookup_name(). 2071114ab22SDaniel Thompson * 2081114ab22SDaniel Thompson * The cache is a big win for several tests. For example it more the doubles 2091114ab22SDaniel Thompson * the cycles per second during the sys_open test. This is not theoretic, 2101114ab22SDaniel Thompson * the performance improvement shows up at human scale, especially when 2111114ab22SDaniel Thompson * testing using emulators. 2121114ab22SDaniel Thompson * 2131114ab22SDaniel Thompson * Obviously neither re-entrant nor thread-safe but that is OK since it 2141114ab22SDaniel Thompson * can only be called from the debug trap (and therefore all other CPUs 2151114ab22SDaniel Thompson * are halted). 2161114ab22SDaniel Thompson */ 217e8d31c20SJason Wessel static unsigned long lookup_addr(char *arg) 218e8d31c20SJason Wessel { 2191114ab22SDaniel Thompson static char cached_arg[KSYM_NAME_LEN]; 2201114ab22SDaniel Thompson static unsigned long cached_addr; 221e8d31c20SJason Wessel 2221114ab22SDaniel Thompson if (strcmp(arg, cached_arg)) { 2231114ab22SDaniel Thompson strscpy(cached_arg, arg, KSYM_NAME_LEN); 2241114ab22SDaniel Thompson cached_addr = kallsyms_lookup_name(arg); 2251114ab22SDaniel Thompson } 2261114ab22SDaniel Thompson 2271114ab22SDaniel Thompson return (unsigned long)dereference_function_descriptor( 2281114ab22SDaniel Thompson (void *)cached_addr); 229e8d31c20SJason Wessel } 230e8d31c20SJason Wessel 231e8d31c20SJason Wessel static void break_helper(char *bp_type, char *arg, unsigned long vaddr) 232e8d31c20SJason Wessel { 233e8d31c20SJason Wessel unsigned long addr; 234e8d31c20SJason Wessel 235e8d31c20SJason Wessel if (arg) 236e8d31c20SJason Wessel addr = lookup_addr(arg); 237e8d31c20SJason Wessel else 238e8d31c20SJason Wessel addr = vaddr; 239e8d31c20SJason Wessel 240e8d31c20SJason Wessel sprintf(scratch_buf, "%s,%lx,%i", bp_type, addr, 241e8d31c20SJason Wessel BREAK_INSTR_SIZE); 242e8d31c20SJason Wessel fill_get_buf(scratch_buf); 243e8d31c20SJason Wessel } 244e8d31c20SJason Wessel 245e8d31c20SJason Wessel static void sw_break(char *arg) 246e8d31c20SJason Wessel { 247b33cb815SJason Wessel break_helper(force_hwbrks ? "Z1" : "Z0", arg, 0); 248e8d31c20SJason Wessel } 249e8d31c20SJason Wessel 250e8d31c20SJason Wessel static void sw_rem_break(char *arg) 251e8d31c20SJason Wessel { 252b33cb815SJason Wessel break_helper(force_hwbrks ? "z1" : "z0", arg, 0); 253e8d31c20SJason Wessel } 254e8d31c20SJason Wessel 255e8d31c20SJason Wessel static void hw_break(char *arg) 256e8d31c20SJason Wessel { 257e8d31c20SJason Wessel break_helper("Z1", arg, 0); 258e8d31c20SJason Wessel } 259e8d31c20SJason Wessel 260e8d31c20SJason Wessel static void hw_rem_break(char *arg) 261e8d31c20SJason Wessel { 262e8d31c20SJason Wessel break_helper("z1", arg, 0); 263e8d31c20SJason Wessel } 264e8d31c20SJason Wessel 265e8d31c20SJason Wessel static void hw_write_break(char *arg) 266e8d31c20SJason Wessel { 267e8d31c20SJason Wessel break_helper("Z2", arg, 0); 268e8d31c20SJason Wessel } 269e8d31c20SJason Wessel 270e8d31c20SJason Wessel static void hw_rem_write_break(char *arg) 271e8d31c20SJason Wessel { 272e8d31c20SJason Wessel break_helper("z2", arg, 0); 273e8d31c20SJason Wessel } 274e8d31c20SJason Wessel 275e8d31c20SJason Wessel static void hw_access_break(char *arg) 276e8d31c20SJason Wessel { 277e8d31c20SJason Wessel break_helper("Z4", arg, 0); 278e8d31c20SJason Wessel } 279e8d31c20SJason Wessel 280e8d31c20SJason Wessel static void hw_rem_access_break(char *arg) 281e8d31c20SJason Wessel { 282e8d31c20SJason Wessel break_helper("z4", arg, 0); 283e8d31c20SJason Wessel } 284e8d31c20SJason Wessel 285e8d31c20SJason Wessel static void hw_break_val_access(void) 286e8d31c20SJason Wessel { 287e8d31c20SJason Wessel hw_break_val2 = hw_break_val; 288e8d31c20SJason Wessel } 289e8d31c20SJason Wessel 290e8d31c20SJason Wessel static void hw_break_val_write(void) 291e8d31c20SJason Wessel { 292e8d31c20SJason Wessel hw_break_val++; 293e8d31c20SJason Wessel } 294e8d31c20SJason Wessel 295486c5987SJason Wessel static int get_thread_id_continue(char *put_str, char *arg) 296486c5987SJason Wessel { 297486c5987SJason Wessel char *ptr = &put_str[11]; 298486c5987SJason Wessel 299486c5987SJason Wessel if (put_str[1] != 'T' || put_str[2] != '0') 300486c5987SJason Wessel return 1; 301486c5987SJason Wessel kgdb_hex2long(&ptr, &cont_thread_id); 302486c5987SJason Wessel return 0; 303486c5987SJason Wessel } 304486c5987SJason Wessel 305e8d31c20SJason Wessel static int check_and_rewind_pc(char *put_str, char *arg) 306e8d31c20SJason Wessel { 307e8d31c20SJason Wessel unsigned long addr = lookup_addr(arg); 30863ab25ebSMike Frysinger unsigned long ip; 309e8d31c20SJason Wessel int offset = 0; 310e8d31c20SJason Wessel 311e8d31c20SJason Wessel kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, 312e8d31c20SJason Wessel NUMREGBYTES); 313e8d31c20SJason Wessel gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); 31463ab25ebSMike Frysinger ip = instruction_pointer(&kgdbts_regs); 31563ab25ebSMike Frysinger v2printk("Stopped at IP: %lx\n", ip); 31663ab25ebSMike Frysinger #ifdef GDB_ADJUSTS_BREAK_OFFSET 31763ab25ebSMike Frysinger /* On some arches, a breakpoint stop requires it to be decremented */ 31863ab25ebSMike Frysinger if (addr + BREAK_INSTR_SIZE == ip) 31963ab25ebSMike Frysinger offset = -BREAK_INSTR_SIZE; 320e8d31c20SJason Wessel #endif 32123bbd8e3SJason Wessel 32223bbd8e3SJason Wessel if (arch_needs_sstep_emulation && sstep_addr && 32323bbd8e3SJason Wessel ip + offset == sstep_addr && 3241114ab22SDaniel Thompson ((!strcmp(arg, "do_sys_openat2") || !strcmp(arg, "kernel_clone")))) { 32523bbd8e3SJason Wessel /* This is special case for emulated single step */ 32623bbd8e3SJason Wessel v2printk("Emul: rewind hit single step bp\n"); 32723bbd8e3SJason Wessel restart_from_top_after_write = 1; 32823bbd8e3SJason Wessel } else if (strcmp(arg, "silent") && ip + offset != addr) { 329974460c5SJason Wessel eprintk("kgdbts: BP mismatch %lx expected %lx\n", 33063ab25ebSMike Frysinger ip + offset, addr); 331e8d31c20SJason Wessel return 1; 332e8d31c20SJason Wessel } 33363ab25ebSMike Frysinger /* Readjust the instruction pointer if needed */ 334603d04b2SMike Frysinger ip += offset; 33523bbd8e3SJason Wessel cont_addr = ip; 336603d04b2SMike Frysinger #ifdef GDB_ADJUSTS_BREAK_OFFSET 337603d04b2SMike Frysinger instruction_pointer_set(&kgdbts_regs, ip); 338603d04b2SMike Frysinger #endif 339e8d31c20SJason Wessel return 0; 340e8d31c20SJason Wessel } 341e8d31c20SJason Wessel 342e8d31c20SJason Wessel static int check_single_step(char *put_str, char *arg) 343e8d31c20SJason Wessel { 344e8d31c20SJason Wessel unsigned long addr = lookup_addr(arg); 34523bbd8e3SJason Wessel static int matched_id; 34623bbd8e3SJason Wessel 347e8d31c20SJason Wessel /* 348e8d31c20SJason Wessel * From an arch indepent point of view the instruction pointer 349e8d31c20SJason Wessel * should be on a different instruction 350e8d31c20SJason Wessel */ 351e8d31c20SJason Wessel kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, 352e8d31c20SJason Wessel NUMREGBYTES); 353e8d31c20SJason Wessel gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); 354e8d31c20SJason Wessel v2printk("Singlestep stopped at IP: %lx\n", 355e8d31c20SJason Wessel instruction_pointer(&kgdbts_regs)); 356486c5987SJason Wessel 35723bbd8e3SJason Wessel if (sstep_thread_id != cont_thread_id) { 358486c5987SJason Wessel /* 359486c5987SJason Wessel * Ensure we stopped in the same thread id as before, else the 360486c5987SJason Wessel * debugger should continue until the original thread that was 361486c5987SJason Wessel * single stepped is scheduled again, emulating gdb's behavior. 362486c5987SJason Wessel */ 363486c5987SJason Wessel v2printk("ThrID does not match: %lx\n", cont_thread_id); 36423bbd8e3SJason Wessel if (arch_needs_sstep_emulation) { 36523bbd8e3SJason Wessel if (matched_id && 36623bbd8e3SJason Wessel instruction_pointer(&kgdbts_regs) != addr) 36723bbd8e3SJason Wessel goto continue_test; 36823bbd8e3SJason Wessel matched_id++; 36923bbd8e3SJason Wessel ts.idx -= 2; 37023bbd8e3SJason Wessel sstep_state = 0; 37123bbd8e3SJason Wessel return 0; 37223bbd8e3SJason Wessel } 373486c5987SJason Wessel cont_instead_of_sstep = 1; 374486c5987SJason Wessel ts.idx -= 4; 375486c5987SJason Wessel return 0; 376486c5987SJason Wessel } 37723bbd8e3SJason Wessel continue_test: 37823bbd8e3SJason Wessel matched_id = 0; 379e8d31c20SJason Wessel if (instruction_pointer(&kgdbts_regs) == addr) { 380974460c5SJason Wessel eprintk("kgdbts: SingleStep failed at %lx\n", 381e8d31c20SJason Wessel instruction_pointer(&kgdbts_regs)); 382e8d31c20SJason Wessel return 1; 383e8d31c20SJason Wessel } 384e8d31c20SJason Wessel 385e8d31c20SJason Wessel return 0; 386e8d31c20SJason Wessel } 387e8d31c20SJason Wessel 388e8d31c20SJason Wessel static void write_regs(char *arg) 389e8d31c20SJason Wessel { 390e8d31c20SJason Wessel memset(scratch_buf, 0, sizeof(scratch_buf)); 391e8d31c20SJason Wessel scratch_buf[0] = 'G'; 392e8d31c20SJason Wessel pt_regs_to_gdb_regs(kgdbts_gdb_regs, &kgdbts_regs); 393e8d31c20SJason Wessel kgdb_mem2hex((char *)kgdbts_gdb_regs, &scratch_buf[1], NUMREGBYTES); 394e8d31c20SJason Wessel fill_get_buf(scratch_buf); 395e8d31c20SJason Wessel } 396e8d31c20SJason Wessel 397e8d31c20SJason Wessel static void skip_back_repeat_test(char *arg) 398e8d31c20SJason Wessel { 399e8d31c20SJason Wessel int go_back = simple_strtol(arg, NULL, 10); 400e8d31c20SJason Wessel 401e8d31c20SJason Wessel repeat_test--; 4020296c248SDaniel Thompson if (repeat_test <= 0) { 403e8d31c20SJason Wessel ts.idx++; 4040296c248SDaniel Thompson } else { 4050296c248SDaniel Thompson if (repeat_test % 100 == 0) 4060296c248SDaniel Thompson v1printk("kgdbts:RUN ... %d remaining\n", repeat_test); 4070296c248SDaniel Thompson 408e8d31c20SJason Wessel ts.idx -= go_back; 4090296c248SDaniel Thompson } 410e8d31c20SJason Wessel fill_get_buf(ts.tst[ts.idx].get); 411e8d31c20SJason Wessel } 412e8d31c20SJason Wessel 413e8d31c20SJason Wessel static int got_break(char *put_str, char *arg) 414e8d31c20SJason Wessel { 415e8d31c20SJason Wessel test_complete = 1; 416e8d31c20SJason Wessel if (!strncmp(put_str+1, arg, 2)) { 417e8d31c20SJason Wessel if (!strncmp(arg, "T0", 2)) 418e8d31c20SJason Wessel test_complete = 2; 419e8d31c20SJason Wessel return 0; 420e8d31c20SJason Wessel } 421e8d31c20SJason Wessel return 1; 422e8d31c20SJason Wessel } 423e8d31c20SJason Wessel 42423bbd8e3SJason Wessel static void get_cont_catch(char *arg) 42523bbd8e3SJason Wessel { 42623bbd8e3SJason Wessel /* Always send detach because the test is completed at this point */ 42723bbd8e3SJason Wessel fill_get_buf("D"); 42823bbd8e3SJason Wessel } 42923bbd8e3SJason Wessel 43023bbd8e3SJason Wessel static int put_cont_catch(char *put_str, char *arg) 43123bbd8e3SJason Wessel { 43223bbd8e3SJason Wessel /* This is at the end of the test and we catch any and all input */ 43323bbd8e3SJason Wessel v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id); 43423bbd8e3SJason Wessel ts.idx--; 43523bbd8e3SJason Wessel return 0; 43623bbd8e3SJason Wessel } 43723bbd8e3SJason Wessel 43823bbd8e3SJason Wessel static int emul_reset(char *put_str, char *arg) 43923bbd8e3SJason Wessel { 44023bbd8e3SJason Wessel if (strncmp(put_str, "$OK", 3)) 44123bbd8e3SJason Wessel return 1; 44223bbd8e3SJason Wessel if (restart_from_top_after_write) { 44323bbd8e3SJason Wessel restart_from_top_after_write = 0; 44423bbd8e3SJason Wessel ts.idx = -1; 44523bbd8e3SJason Wessel } 44623bbd8e3SJason Wessel return 0; 44723bbd8e3SJason Wessel } 44823bbd8e3SJason Wessel 449e8d31c20SJason Wessel static void emul_sstep_get(char *arg) 450e8d31c20SJason Wessel { 451e8d31c20SJason Wessel if (!arch_needs_sstep_emulation) { 452486c5987SJason Wessel if (cont_instead_of_sstep) { 453486c5987SJason Wessel cont_instead_of_sstep = 0; 454486c5987SJason Wessel fill_get_buf("c"); 455486c5987SJason Wessel } else { 456e8d31c20SJason Wessel fill_get_buf(arg); 457486c5987SJason Wessel } 458e8d31c20SJason Wessel return; 459e8d31c20SJason Wessel } 460e8d31c20SJason Wessel switch (sstep_state) { 461e8d31c20SJason Wessel case 0: 462e8d31c20SJason Wessel v2printk("Emulate single step\n"); 463e8d31c20SJason Wessel /* Start by looking at the current PC */ 464e8d31c20SJason Wessel fill_get_buf("g"); 465e8d31c20SJason Wessel break; 466e8d31c20SJason Wessel case 1: 467e8d31c20SJason Wessel /* set breakpoint */ 468001fddf5SHarvey Harrison break_helper("Z0", NULL, sstep_addr); 469e8d31c20SJason Wessel break; 470e8d31c20SJason Wessel case 2: 471e8d31c20SJason Wessel /* Continue */ 472e8d31c20SJason Wessel fill_get_buf("c"); 473e8d31c20SJason Wessel break; 474e8d31c20SJason Wessel case 3: 475e8d31c20SJason Wessel /* Clear breakpoint */ 476001fddf5SHarvey Harrison break_helper("z0", NULL, sstep_addr); 477e8d31c20SJason Wessel break; 478e8d31c20SJason Wessel default: 479974460c5SJason Wessel eprintk("kgdbts: ERROR failed sstep get emulation\n"); 480e8d31c20SJason Wessel } 481e8d31c20SJason Wessel sstep_state++; 482e8d31c20SJason Wessel } 483e8d31c20SJason Wessel 484e8d31c20SJason Wessel static int emul_sstep_put(char *put_str, char *arg) 485e8d31c20SJason Wessel { 486e8d31c20SJason Wessel if (!arch_needs_sstep_emulation) { 487486c5987SJason Wessel char *ptr = &put_str[11]; 488486c5987SJason Wessel if (put_str[1] != 'T' || put_str[2] != '0') 489e8d31c20SJason Wessel return 1; 490486c5987SJason Wessel kgdb_hex2long(&ptr, &sstep_thread_id); 491486c5987SJason Wessel return 0; 492e8d31c20SJason Wessel } 493e8d31c20SJason Wessel switch (sstep_state) { 494e8d31c20SJason Wessel case 1: 495e8d31c20SJason Wessel /* validate the "g" packet to get the IP */ 496e8d31c20SJason Wessel kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, 497e8d31c20SJason Wessel NUMREGBYTES); 498e8d31c20SJason Wessel gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); 499e8d31c20SJason Wessel v2printk("Stopped at IP: %lx\n", 500e8d31c20SJason Wessel instruction_pointer(&kgdbts_regs)); 501e8d31c20SJason Wessel /* Want to stop at IP + break instruction size by default */ 50223bbd8e3SJason Wessel sstep_addr = cont_addr + BREAK_INSTR_SIZE; 503e8d31c20SJason Wessel break; 504e8d31c20SJason Wessel case 2: 505e8d31c20SJason Wessel if (strncmp(put_str, "$OK", 3)) { 506974460c5SJason Wessel eprintk("kgdbts: failed sstep break set\n"); 507e8d31c20SJason Wessel return 1; 508e8d31c20SJason Wessel } 509e8d31c20SJason Wessel break; 510e8d31c20SJason Wessel case 3: 511e8d31c20SJason Wessel if (strncmp(put_str, "$T0", 3)) { 512974460c5SJason Wessel eprintk("kgdbts: failed continue sstep\n"); 513e8d31c20SJason Wessel return 1; 51423bbd8e3SJason Wessel } else { 51523bbd8e3SJason Wessel char *ptr = &put_str[11]; 51623bbd8e3SJason Wessel kgdb_hex2long(&ptr, &sstep_thread_id); 517e8d31c20SJason Wessel } 518e8d31c20SJason Wessel break; 519e8d31c20SJason Wessel case 4: 520e8d31c20SJason Wessel if (strncmp(put_str, "$OK", 3)) { 521974460c5SJason Wessel eprintk("kgdbts: failed sstep break unset\n"); 522e8d31c20SJason Wessel return 1; 523e8d31c20SJason Wessel } 524e8d31c20SJason Wessel /* Single step is complete so continue on! */ 525e8d31c20SJason Wessel sstep_state = 0; 526e8d31c20SJason Wessel return 0; 527e8d31c20SJason Wessel default: 528974460c5SJason Wessel eprintk("kgdbts: ERROR failed sstep put emulation\n"); 529e8d31c20SJason Wessel } 530e8d31c20SJason Wessel 531e8d31c20SJason Wessel /* Continue on the same test line until emulation is complete */ 532e8d31c20SJason Wessel ts.idx--; 533e8d31c20SJason Wessel return 0; 534e8d31c20SJason Wessel } 535e8d31c20SJason Wessel 536e8d31c20SJason Wessel static int final_ack_set(char *put_str, char *arg) 537e8d31c20SJason Wessel { 538e8d31c20SJason Wessel if (strncmp(put_str+1, arg, 2)) 539e8d31c20SJason Wessel return 1; 540e8d31c20SJason Wessel final_ack = 1; 541e8d31c20SJason Wessel return 0; 542e8d31c20SJason Wessel } 543e8d31c20SJason Wessel /* 544e8d31c20SJason Wessel * Test to plant a breakpoint and detach, which should clear out the 545e8d31c20SJason Wessel * breakpoint and restore the original instruction. 546e8d31c20SJason Wessel */ 547e8d31c20SJason Wessel static struct test_struct plant_and_detach_test[] = { 548e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 549e8d31c20SJason Wessel { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 550e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 551e8d31c20SJason Wessel { "", "" }, 552e8d31c20SJason Wessel }; 553e8d31c20SJason Wessel 554e8d31c20SJason Wessel /* 555e8d31c20SJason Wessel * Simple test to write in a software breakpoint, check for the 556e8d31c20SJason Wessel * correct stop location and detach. 557e8d31c20SJason Wessel */ 558e8d31c20SJason Wessel static struct test_struct sw_breakpoint_test[] = { 559e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 560e8d31c20SJason Wessel { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 561e8d31c20SJason Wessel { "c", "T0*", }, /* Continue */ 562001fddf5SHarvey Harrison { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, 563e8d31c20SJason Wessel { "write", "OK", write_regs }, 564e8d31c20SJason Wessel { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ 565e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 566001fddf5SHarvey Harrison { "D", "OK", NULL, got_break }, /* On success we made it here */ 567e8d31c20SJason Wessel { "", "" }, 568e8d31c20SJason Wessel }; 569e8d31c20SJason Wessel 570e8d31c20SJason Wessel /* 571e8d31c20SJason Wessel * Test a known bad memory read location to test the fault handler and 572e8d31c20SJason Wessel * read bytes 1-8 at the bad address 573e8d31c20SJason Wessel */ 574e8d31c20SJason Wessel static struct test_struct bad_read_test[] = { 575e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 576e8d31c20SJason Wessel { "m0,1", "E*" }, /* read 1 byte at address 1 */ 577e8d31c20SJason Wessel { "m0,2", "E*" }, /* read 1 byte at address 2 */ 578e8d31c20SJason Wessel { "m0,3", "E*" }, /* read 1 byte at address 3 */ 579e8d31c20SJason Wessel { "m0,4", "E*" }, /* read 1 byte at address 4 */ 580e8d31c20SJason Wessel { "m0,5", "E*" }, /* read 1 byte at address 5 */ 581e8d31c20SJason Wessel { "m0,6", "E*" }, /* read 1 byte at address 6 */ 582e8d31c20SJason Wessel { "m0,7", "E*" }, /* read 1 byte at address 7 */ 583e8d31c20SJason Wessel { "m0,8", "E*" }, /* read 1 byte at address 8 */ 584e8d31c20SJason Wessel { "D", "OK" }, /* Detach which removes all breakpoints and continues */ 585e8d31c20SJason Wessel { "", "" }, 586e8d31c20SJason Wessel }; 587e8d31c20SJason Wessel 588e8d31c20SJason Wessel /* 589e8d31c20SJason Wessel * Test for hitting a breakpoint, remove it, single step, plant it 590e8d31c20SJason Wessel * again and detach. 591e8d31c20SJason Wessel */ 592e8d31c20SJason Wessel static struct test_struct singlestep_break_test[] = { 593e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 594e8d31c20SJason Wessel { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 595486c5987SJason Wessel { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ 596486c5987SJason Wessel { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ 597001fddf5SHarvey Harrison { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, 598e8d31c20SJason Wessel { "write", "OK", write_regs }, /* Write registers */ 599e8d31c20SJason Wessel { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 600001fddf5SHarvey Harrison { "g", "kgdbts_break_test", NULL, check_single_step }, 601e8d31c20SJason Wessel { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 602e8d31c20SJason Wessel { "c", "T0*", }, /* Continue */ 603001fddf5SHarvey Harrison { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, 604e8d31c20SJason Wessel { "write", "OK", write_regs }, /* Write registers */ 605e8d31c20SJason Wessel { "D", "OK" }, /* Remove all breakpoints and continues */ 606e8d31c20SJason Wessel { "", "" }, 607e8d31c20SJason Wessel }; 608e8d31c20SJason Wessel 609e8d31c20SJason Wessel /* 610f30897c1SChristian Brauner * Test for hitting a breakpoint at kernel_clone for what ever the number 611e8d31c20SJason Wessel * of iterations required by the variable repeat_test. 612e8d31c20SJason Wessel */ 613f30897c1SChristian Brauner static struct test_struct do_kernel_clone_test[] = { 614e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 615f30897c1SChristian Brauner { "kernel_clone", "OK", sw_break, }, /* set sw breakpoint */ 616486c5987SJason Wessel { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ 617f30897c1SChristian Brauner { "kernel_clone", "OK", sw_rem_break }, /*remove breakpoint */ 618f30897c1SChristian Brauner { "g", "kernel_clone", NULL, check_and_rewind_pc }, /* check location */ 61923bbd8e3SJason Wessel { "write", "OK", write_regs, emul_reset }, /* Write registers */ 620e8d31c20SJason Wessel { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 621f30897c1SChristian Brauner { "g", "kernel_clone", NULL, check_single_step }, 622f30897c1SChristian Brauner { "kernel_clone", "OK", sw_break, }, /* set sw breakpoint */ 623e8d31c20SJason Wessel { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ 624001fddf5SHarvey Harrison { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ 62523bbd8e3SJason Wessel { "", "", get_cont_catch, put_cont_catch }, 626e8d31c20SJason Wessel }; 627e8d31c20SJason Wessel 628e8d31c20SJason Wessel /* Test for hitting a breakpoint at sys_open for what ever the number 629e8d31c20SJason Wessel * of iterations required by the variable repeat_test. 630e8d31c20SJason Wessel */ 631e8d31c20SJason Wessel static struct test_struct sys_open_test[] = { 632e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 6331114ab22SDaniel Thompson { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ 634486c5987SJason Wessel { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ 6351114ab22SDaniel Thompson { "do_sys_openat2", "OK", sw_rem_break }, /*remove breakpoint */ 6361114ab22SDaniel Thompson { "g", "do_sys_openat2", NULL, check_and_rewind_pc }, /* check location */ 63723bbd8e3SJason Wessel { "write", "OK", write_regs, emul_reset }, /* Write registers */ 638e8d31c20SJason Wessel { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 6391114ab22SDaniel Thompson { "g", "do_sys_openat2", NULL, check_single_step }, 6401114ab22SDaniel Thompson { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ 641e8d31c20SJason Wessel { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ 642001fddf5SHarvey Harrison { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ 64323bbd8e3SJason Wessel { "", "", get_cont_catch, put_cont_catch }, 644e8d31c20SJason Wessel }; 645e8d31c20SJason Wessel 646e8d31c20SJason Wessel /* 647e8d31c20SJason Wessel * Test for hitting a simple hw breakpoint 648e8d31c20SJason Wessel */ 649e8d31c20SJason Wessel static struct test_struct hw_breakpoint_test[] = { 650e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 651e8d31c20SJason Wessel { "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */ 652e8d31c20SJason Wessel { "c", "T0*", }, /* Continue */ 653001fddf5SHarvey Harrison { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, 654e8d31c20SJason Wessel { "write", "OK", write_regs }, 655e8d31c20SJason Wessel { "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */ 656e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 657001fddf5SHarvey Harrison { "D", "OK", NULL, got_break }, /* On success we made it here */ 658e8d31c20SJason Wessel { "", "" }, 659e8d31c20SJason Wessel }; 660e8d31c20SJason Wessel 661e8d31c20SJason Wessel /* 662e8d31c20SJason Wessel * Test for hitting a hw write breakpoint 663e8d31c20SJason Wessel */ 664e8d31c20SJason Wessel static struct test_struct hw_write_break_test[] = { 665e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 666e8d31c20SJason Wessel { "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */ 667001fddf5SHarvey Harrison { "c", "T0*", NULL, got_break }, /* Continue */ 668001fddf5SHarvey Harrison { "g", "silent", NULL, check_and_rewind_pc }, 669e8d31c20SJason Wessel { "write", "OK", write_regs }, 670e8d31c20SJason Wessel { "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */ 671e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 672001fddf5SHarvey Harrison { "D", "OK", NULL, got_break }, /* On success we made it here */ 673e8d31c20SJason Wessel { "", "" }, 674e8d31c20SJason Wessel }; 675e8d31c20SJason Wessel 676e8d31c20SJason Wessel /* 677e8d31c20SJason Wessel * Test for hitting a hw access breakpoint 678e8d31c20SJason Wessel */ 679e8d31c20SJason Wessel static struct test_struct hw_access_break_test[] = { 680e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 681e8d31c20SJason Wessel { "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */ 682001fddf5SHarvey Harrison { "c", "T0*", NULL, got_break }, /* Continue */ 683001fddf5SHarvey Harrison { "g", "silent", NULL, check_and_rewind_pc }, 684e8d31c20SJason Wessel { "write", "OK", write_regs }, 685e8d31c20SJason Wessel { "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */ 686e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 687001fddf5SHarvey Harrison { "D", "OK", NULL, got_break }, /* On success we made it here */ 688e8d31c20SJason Wessel { "", "" }, 689e8d31c20SJason Wessel }; 690e8d31c20SJason Wessel 691e8d31c20SJason Wessel /* 692e8d31c20SJason Wessel * Test for hitting a hw access breakpoint 693e8d31c20SJason Wessel */ 694e8d31c20SJason Wessel static struct test_struct nmi_sleep_test[] = { 695e8d31c20SJason Wessel { "?", "S0*" }, /* Clear break points */ 696001fddf5SHarvey Harrison { "c", "T0*", NULL, got_break }, /* Continue */ 697e8d31c20SJason Wessel { "D", "OK" }, /* Detach */ 698001fddf5SHarvey Harrison { "D", "OK", NULL, got_break }, /* On success we made it here */ 699e8d31c20SJason Wessel { "", "" }, 700e8d31c20SJason Wessel }; 701e8d31c20SJason Wessel 702e8d31c20SJason Wessel static void fill_get_buf(char *buf) 703e8d31c20SJason Wessel { 704e8d31c20SJason Wessel unsigned char checksum = 0; 705e8d31c20SJason Wessel int count = 0; 706e8d31c20SJason Wessel char ch; 707e8d31c20SJason Wessel 708e8d31c20SJason Wessel strcpy(get_buf, "$"); 709e8d31c20SJason Wessel strcat(get_buf, buf); 710e8d31c20SJason Wessel while ((ch = buf[count])) { 711e8d31c20SJason Wessel checksum += ch; 712e8d31c20SJason Wessel count++; 713e8d31c20SJason Wessel } 714e8d31c20SJason Wessel strcat(get_buf, "#"); 715827e609bSHarvey Harrison get_buf[count + 2] = hex_asc_hi(checksum); 716827e609bSHarvey Harrison get_buf[count + 3] = hex_asc_lo(checksum); 717e8d31c20SJason Wessel get_buf[count + 4] = '\0'; 718e8d31c20SJason Wessel v2printk("get%i: %s\n", ts.idx, get_buf); 719e8d31c20SJason Wessel } 720e8d31c20SJason Wessel 721e8d31c20SJason Wessel static int validate_simple_test(char *put_str) 722e8d31c20SJason Wessel { 723e8d31c20SJason Wessel char *chk_str; 724e8d31c20SJason Wessel 725e8d31c20SJason Wessel if (ts.tst[ts.idx].put_handler) 726e8d31c20SJason Wessel return ts.tst[ts.idx].put_handler(put_str, 727e8d31c20SJason Wessel ts.tst[ts.idx].put); 728e8d31c20SJason Wessel 729e8d31c20SJason Wessel chk_str = ts.tst[ts.idx].put; 730e8d31c20SJason Wessel if (*put_str == '$') 731e8d31c20SJason Wessel put_str++; 732e8d31c20SJason Wessel 733e8d31c20SJason Wessel while (*chk_str != '\0' && *put_str != '\0') { 734e8d31c20SJason Wessel /* If someone does a * to match the rest of the string, allow 73525985edcSLucas De Marchi * it, or stop if the received string is complete. 736e8d31c20SJason Wessel */ 737e8d31c20SJason Wessel if (*put_str == '#' || *chk_str == '*') 738e8d31c20SJason Wessel return 0; 739e8d31c20SJason Wessel if (*put_str != *chk_str) 740e8d31c20SJason Wessel return 1; 741e8d31c20SJason Wessel 742e8d31c20SJason Wessel chk_str++; 743e8d31c20SJason Wessel put_str++; 744e8d31c20SJason Wessel } 745e8d31c20SJason Wessel if (*chk_str == '\0' && (*put_str == '\0' || *put_str == '#')) 746e8d31c20SJason Wessel return 0; 747e8d31c20SJason Wessel 748e8d31c20SJason Wessel return 1; 749e8d31c20SJason Wessel } 750e8d31c20SJason Wessel 751e8d31c20SJason Wessel static int run_simple_test(int is_get_char, int chr) 752e8d31c20SJason Wessel { 753e8d31c20SJason Wessel int ret = 0; 754e8d31c20SJason Wessel if (is_get_char) { 755e8d31c20SJason Wessel /* Send an ACK on the get if a prior put completed and set the 756e8d31c20SJason Wessel * send ack variable 757e8d31c20SJason Wessel */ 758e8d31c20SJason Wessel if (send_ack) { 759e8d31c20SJason Wessel send_ack = 0; 760e8d31c20SJason Wessel return '+'; 761e8d31c20SJason Wessel } 762e8d31c20SJason Wessel /* On the first get char, fill the transmit buffer and then 763e8d31c20SJason Wessel * take from the get_string. 764e8d31c20SJason Wessel */ 765e8d31c20SJason Wessel if (get_buf_cnt == 0) { 766e8d31c20SJason Wessel if (ts.tst[ts.idx].get_handler) 767e8d31c20SJason Wessel ts.tst[ts.idx].get_handler(ts.tst[ts.idx].get); 768e8d31c20SJason Wessel else 769e8d31c20SJason Wessel fill_get_buf(ts.tst[ts.idx].get); 770e8d31c20SJason Wessel } 771e8d31c20SJason Wessel 772e8d31c20SJason Wessel if (get_buf[get_buf_cnt] == '\0') { 773974460c5SJason Wessel eprintk("kgdbts: ERROR GET: EOB on '%s' at %i\n", 774e8d31c20SJason Wessel ts.name, ts.idx); 775e8d31c20SJason Wessel get_buf_cnt = 0; 776e8d31c20SJason Wessel fill_get_buf("D"); 777e8d31c20SJason Wessel } 778e8d31c20SJason Wessel ret = get_buf[get_buf_cnt]; 779e8d31c20SJason Wessel get_buf_cnt++; 780e8d31c20SJason Wessel return ret; 781e8d31c20SJason Wessel } 782e8d31c20SJason Wessel 783e8d31c20SJason Wessel /* This callback is a put char which is when kgdb sends data to 784e8d31c20SJason Wessel * this I/O module. 785e8d31c20SJason Wessel */ 78623bbd8e3SJason Wessel if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' && 78723bbd8e3SJason Wessel !ts.tst[ts.idx].get_handler) { 788974460c5SJason Wessel eprintk("kgdbts: ERROR: beyond end of test on" 789e8d31c20SJason Wessel " '%s' line %i\n", ts.name, ts.idx); 790e8d31c20SJason Wessel return 0; 791e8d31c20SJason Wessel } 792e8d31c20SJason Wessel 793e8d31c20SJason Wessel if (put_buf_cnt >= BUFMAX) { 794974460c5SJason Wessel eprintk("kgdbts: ERROR: put buffer overflow on" 795e8d31c20SJason Wessel " '%s' line %i\n", ts.name, ts.idx); 796e8d31c20SJason Wessel put_buf_cnt = 0; 797e8d31c20SJason Wessel return 0; 798e8d31c20SJason Wessel } 799e8d31c20SJason Wessel /* Ignore everything until the first valid packet start '$' */ 800e8d31c20SJason Wessel if (put_buf_cnt == 0 && chr != '$') 801e8d31c20SJason Wessel return 0; 802e8d31c20SJason Wessel 803e8d31c20SJason Wessel put_buf[put_buf_cnt] = chr; 804e8d31c20SJason Wessel put_buf_cnt++; 805e8d31c20SJason Wessel 806e8d31c20SJason Wessel /* End of packet == #XX so look for the '#' */ 807e8d31c20SJason Wessel if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') { 808b4f1b67bSRoel Kluin if (put_buf_cnt >= BUFMAX) { 809b4f1b67bSRoel Kluin eprintk("kgdbts: ERROR: put buffer overflow on" 810b4f1b67bSRoel Kluin " '%s' line %i\n", ts.name, ts.idx); 811b4f1b67bSRoel Kluin put_buf_cnt = 0; 812b4f1b67bSRoel Kluin return 0; 813b4f1b67bSRoel Kluin } 814e8d31c20SJason Wessel put_buf[put_buf_cnt] = '\0'; 815e8d31c20SJason Wessel v2printk("put%i: %s\n", ts.idx, put_buf); 816e8d31c20SJason Wessel /* Trigger check here */ 817e8d31c20SJason Wessel if (ts.validate_put && ts.validate_put(put_buf)) { 818974460c5SJason Wessel eprintk("kgdbts: ERROR PUT: end of test " 819e8d31c20SJason Wessel "buffer on '%s' line %i expected %s got %s\n", 820e8d31c20SJason Wessel ts.name, ts.idx, ts.tst[ts.idx].put, put_buf); 821e8d31c20SJason Wessel } 822e8d31c20SJason Wessel ts.idx++; 823e8d31c20SJason Wessel put_buf_cnt = 0; 824e8d31c20SJason Wessel get_buf_cnt = 0; 825e8d31c20SJason Wessel send_ack = 1; 826e8d31c20SJason Wessel } 827e8d31c20SJason Wessel return 0; 828e8d31c20SJason Wessel } 829e8d31c20SJason Wessel 830e8d31c20SJason Wessel static void init_simple_test(void) 831e8d31c20SJason Wessel { 832e8d31c20SJason Wessel memset(&ts, 0, sizeof(ts)); 833e8d31c20SJason Wessel ts.run_test = run_simple_test; 834e8d31c20SJason Wessel ts.validate_put = validate_simple_test; 835e8d31c20SJason Wessel } 836e8d31c20SJason Wessel 837e8d31c20SJason Wessel static void run_plant_and_detach_test(int is_early) 838e8d31c20SJason Wessel { 839e8d31c20SJason Wessel char before[BREAK_INSTR_SIZE]; 840e8d31c20SJason Wessel char after[BREAK_INSTR_SIZE]; 841e8d31c20SJason Wessel 842fe557319SChristoph Hellwig copy_from_kernel_nofault(before, (char *)kgdbts_break_test, 843e8d31c20SJason Wessel BREAK_INSTR_SIZE); 844e8d31c20SJason Wessel init_simple_test(); 845e8d31c20SJason Wessel ts.tst = plant_and_detach_test; 846e8d31c20SJason Wessel ts.name = "plant_and_detach_test"; 847e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 848e8d31c20SJason Wessel if (!is_early) 849e8d31c20SJason Wessel kgdb_breakpoint(); 850fe557319SChristoph Hellwig copy_from_kernel_nofault(after, (char *)kgdbts_break_test, 851e8d31c20SJason Wessel BREAK_INSTR_SIZE); 852e8d31c20SJason Wessel if (memcmp(before, after, BREAK_INSTR_SIZE)) { 853e8d31c20SJason Wessel printk(KERN_CRIT "kgdbts: ERROR kgdb corrupted memory\n"); 854e8d31c20SJason Wessel panic("kgdb memory corruption"); 855e8d31c20SJason Wessel } 856e8d31c20SJason Wessel 857e8d31c20SJason Wessel /* complete the detach test */ 858e8d31c20SJason Wessel if (!is_early) 859e8d31c20SJason Wessel kgdbts_break_test(); 860e8d31c20SJason Wessel } 861e8d31c20SJason Wessel 862e8d31c20SJason Wessel static void run_breakpoint_test(int is_hw_breakpoint) 863e8d31c20SJason Wessel { 864e8d31c20SJason Wessel test_complete = 0; 865e8d31c20SJason Wessel init_simple_test(); 866e8d31c20SJason Wessel if (is_hw_breakpoint) { 867e8d31c20SJason Wessel ts.tst = hw_breakpoint_test; 868e8d31c20SJason Wessel ts.name = "hw_breakpoint_test"; 869e8d31c20SJason Wessel } else { 870e8d31c20SJason Wessel ts.tst = sw_breakpoint_test; 871e8d31c20SJason Wessel ts.name = "sw_breakpoint_test"; 872e8d31c20SJason Wessel } 873e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 874e8d31c20SJason Wessel kgdb_breakpoint(); 875e8d31c20SJason Wessel /* run code with the break point in it */ 876e8d31c20SJason Wessel kgdbts_break_test(); 877e8d31c20SJason Wessel kgdb_breakpoint(); 878e8d31c20SJason Wessel 879e8d31c20SJason Wessel if (test_complete) 880e8d31c20SJason Wessel return; 881e8d31c20SJason Wessel 882974460c5SJason Wessel eprintk("kgdbts: ERROR %s test failed\n", ts.name); 883b33cb815SJason Wessel if (is_hw_breakpoint) 884b33cb815SJason Wessel hwbreaks_ok = 0; 885e8d31c20SJason Wessel } 886e8d31c20SJason Wessel 887e8d31c20SJason Wessel static void run_hw_break_test(int is_write_test) 888e8d31c20SJason Wessel { 889e8d31c20SJason Wessel test_complete = 0; 890e8d31c20SJason Wessel init_simple_test(); 891e8d31c20SJason Wessel if (is_write_test) { 892e8d31c20SJason Wessel ts.tst = hw_write_break_test; 893e8d31c20SJason Wessel ts.name = "hw_write_break_test"; 894e8d31c20SJason Wessel } else { 895e8d31c20SJason Wessel ts.tst = hw_access_break_test; 896e8d31c20SJason Wessel ts.name = "hw_access_break_test"; 897e8d31c20SJason Wessel } 898e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 899e8d31c20SJason Wessel kgdb_breakpoint(); 900e8d31c20SJason Wessel hw_break_val_access(); 901e8d31c20SJason Wessel if (is_write_test) { 902b33cb815SJason Wessel if (test_complete == 2) { 903974460c5SJason Wessel eprintk("kgdbts: ERROR %s broke on access\n", 904e8d31c20SJason Wessel ts.name); 905b33cb815SJason Wessel hwbreaks_ok = 0; 906b33cb815SJason Wessel } 907e8d31c20SJason Wessel hw_break_val_write(); 908e8d31c20SJason Wessel } 909e8d31c20SJason Wessel kgdb_breakpoint(); 910e8d31c20SJason Wessel 911e8d31c20SJason Wessel if (test_complete == 1) 912e8d31c20SJason Wessel return; 913e8d31c20SJason Wessel 914974460c5SJason Wessel eprintk("kgdbts: ERROR %s test failed\n", ts.name); 915b33cb815SJason Wessel hwbreaks_ok = 0; 916e8d31c20SJason Wessel } 917e8d31c20SJason Wessel 918e8d31c20SJason Wessel static void run_nmi_sleep_test(int nmi_sleep) 919e8d31c20SJason Wessel { 920e8d31c20SJason Wessel unsigned long flags; 921e8d31c20SJason Wessel 922e8d31c20SJason Wessel init_simple_test(); 923e8d31c20SJason Wessel ts.tst = nmi_sleep_test; 924e8d31c20SJason Wessel ts.name = "nmi_sleep_test"; 925e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 926e8d31c20SJason Wessel kgdb_breakpoint(); 927e8d31c20SJason Wessel local_irq_save(flags); 928e8d31c20SJason Wessel mdelay(nmi_sleep*1000); 929e8d31c20SJason Wessel touch_nmi_watchdog(); 930e8d31c20SJason Wessel local_irq_restore(flags); 931e8d31c20SJason Wessel if (test_complete != 2) 932974460c5SJason Wessel eprintk("kgdbts: ERROR nmi_test did not hit nmi\n"); 933e8d31c20SJason Wessel kgdb_breakpoint(); 934e8d31c20SJason Wessel if (test_complete == 1) 935e8d31c20SJason Wessel return; 936e8d31c20SJason Wessel 937974460c5SJason Wessel eprintk("kgdbts: ERROR %s test failed\n", ts.name); 938e8d31c20SJason Wessel } 939e8d31c20SJason Wessel 940e8d31c20SJason Wessel static void run_bad_read_test(void) 941e8d31c20SJason Wessel { 942e8d31c20SJason Wessel init_simple_test(); 943e8d31c20SJason Wessel ts.tst = bad_read_test; 944e8d31c20SJason Wessel ts.name = "bad_read_test"; 945e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 946e8d31c20SJason Wessel kgdb_breakpoint(); 947e8d31c20SJason Wessel } 948e8d31c20SJason Wessel 949f30897c1SChristian Brauner static void run_kernel_clone_test(void) 950e8d31c20SJason Wessel { 951e8d31c20SJason Wessel init_simple_test(); 952f30897c1SChristian Brauner ts.tst = do_kernel_clone_test; 953f30897c1SChristian Brauner ts.name = "do_kernel_clone_test"; 954e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 955e8d31c20SJason Wessel kgdb_breakpoint(); 956e8d31c20SJason Wessel } 957e8d31c20SJason Wessel 958e8d31c20SJason Wessel static void run_sys_open_test(void) 959e8d31c20SJason Wessel { 960e8d31c20SJason Wessel init_simple_test(); 961e8d31c20SJason Wessel ts.tst = sys_open_test; 962e8d31c20SJason Wessel ts.name = "sys_open_test"; 963e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 964e8d31c20SJason Wessel kgdb_breakpoint(); 965e8d31c20SJason Wessel } 966e8d31c20SJason Wessel 967e8d31c20SJason Wessel static void run_singlestep_break_test(void) 968e8d31c20SJason Wessel { 969e8d31c20SJason Wessel init_simple_test(); 970e8d31c20SJason Wessel ts.tst = singlestep_break_test; 971e8d31c20SJason Wessel ts.name = "singlestep_breakpoint_test"; 972e8d31c20SJason Wessel /* Activate test with initial breakpoint */ 973e8d31c20SJason Wessel kgdb_breakpoint(); 974e8d31c20SJason Wessel kgdbts_break_test(); 975e8d31c20SJason Wessel kgdbts_break_test(); 976e8d31c20SJason Wessel } 977e8d31c20SJason Wessel 978e8d31c20SJason Wessel static void kgdbts_run_tests(void) 979e8d31c20SJason Wessel { 980e8d31c20SJason Wessel char *ptr; 981f30897c1SChristian Brauner int clone_test = 0; 982001fddf5SHarvey Harrison int do_sys_open_test = 0; 9837cfcd985SJason Wessel int sstep_test = 1000; 984e8d31c20SJason Wessel int nmi_sleep = 0; 9857cfcd985SJason Wessel int i; 986e8d31c20SJason Wessel 987fa0218efSLaura Abbott verbose = 0; 988fa0218efSLaura Abbott if (strstr(config, "V1")) 989fa0218efSLaura Abbott verbose = 1; 990fa0218efSLaura Abbott if (strstr(config, "V2")) 991fa0218efSLaura Abbott verbose = 2; 992fa0218efSLaura Abbott 99359d309f9SGeert Uytterhoeven ptr = strchr(config, 'F'); 994e8d31c20SJason Wessel if (ptr) 995f30897c1SChristian Brauner clone_test = simple_strtol(ptr + 1, NULL, 10); 99659d309f9SGeert Uytterhoeven ptr = strchr(config, 'S'); 997e8d31c20SJason Wessel if (ptr) 998001fddf5SHarvey Harrison do_sys_open_test = simple_strtol(ptr + 1, NULL, 10); 99959d309f9SGeert Uytterhoeven ptr = strchr(config, 'N'); 1000e8d31c20SJason Wessel if (ptr) 1001e8d31c20SJason Wessel nmi_sleep = simple_strtol(ptr+1, NULL, 10); 100259d309f9SGeert Uytterhoeven ptr = strchr(config, 'I'); 10037cfcd985SJason Wessel if (ptr) 10047cfcd985SJason Wessel sstep_test = simple_strtol(ptr+1, NULL, 10); 1005e8d31c20SJason Wessel 1006456ca7ffSJason Wessel /* All HW break point tests */ 1007456ca7ffSJason Wessel if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { 1008456ca7ffSJason Wessel hwbreaks_ok = 1; 1009456ca7ffSJason Wessel v1printk("kgdbts:RUN hw breakpoint test\n"); 1010456ca7ffSJason Wessel run_breakpoint_test(1); 1011456ca7ffSJason Wessel v1printk("kgdbts:RUN hw write breakpoint test\n"); 1012456ca7ffSJason Wessel run_hw_break_test(1); 1013456ca7ffSJason Wessel v1printk("kgdbts:RUN access write breakpoint test\n"); 1014456ca7ffSJason Wessel run_hw_break_test(0); 1015456ca7ffSJason Wessel } 1016456ca7ffSJason Wessel 1017e8d31c20SJason Wessel /* required internal KGDB tests */ 1018e8d31c20SJason Wessel v1printk("kgdbts:RUN plant and detach test\n"); 1019e8d31c20SJason Wessel run_plant_and_detach_test(0); 1020e8d31c20SJason Wessel v1printk("kgdbts:RUN sw breakpoint test\n"); 1021e8d31c20SJason Wessel run_breakpoint_test(0); 1022e8d31c20SJason Wessel v1printk("kgdbts:RUN bad memory access test\n"); 1023e8d31c20SJason Wessel run_bad_read_test(); 10247cfcd985SJason Wessel v1printk("kgdbts:RUN singlestep test %i iterations\n", sstep_test); 10257cfcd985SJason Wessel for (i = 0; i < sstep_test; i++) { 1026e8d31c20SJason Wessel run_singlestep_break_test(); 10277cfcd985SJason Wessel if (i % 100 == 0) 10287cfcd985SJason Wessel v1printk("kgdbts:RUN singlestep [%i/%i]\n", 10297cfcd985SJason Wessel i, sstep_test); 10307cfcd985SJason Wessel } 1031e8d31c20SJason Wessel 1032e8d31c20SJason Wessel /* ===Optional tests=== */ 1033e8d31c20SJason Wessel 1034e8d31c20SJason Wessel if (nmi_sleep) { 1035e8d31c20SJason Wessel v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep); 1036e8d31c20SJason Wessel run_nmi_sleep_test(nmi_sleep); 1037e8d31c20SJason Wessel } 1038e8d31c20SJason Wessel 1039f30897c1SChristian Brauner /* If the kernel_clone test is run it will be the last test that is 1040e8d31c20SJason Wessel * executed because a kernel thread will be spawned at the very 1041e8d31c20SJason Wessel * end to unregister the debug hooks. 1042e8d31c20SJason Wessel */ 1043f30897c1SChristian Brauner if (clone_test) { 1044f30897c1SChristian Brauner repeat_test = clone_test; 1045f30897c1SChristian Brauner printk(KERN_INFO "kgdbts:RUN kernel_clone for %i breakpoints\n", 1046e8d31c20SJason Wessel repeat_test); 1047001fddf5SHarvey Harrison kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg"); 1048f30897c1SChristian Brauner run_kernel_clone_test(); 1049e8d31c20SJason Wessel return; 1050e8d31c20SJason Wessel } 1051e8d31c20SJason Wessel 1052e8d31c20SJason Wessel /* If the sys_open test is run it will be the last test that is 1053e8d31c20SJason Wessel * executed because a kernel thread will be spawned at the very 1054e8d31c20SJason Wessel * end to unregister the debug hooks. 1055e8d31c20SJason Wessel */ 1056001fddf5SHarvey Harrison if (do_sys_open_test) { 1057001fddf5SHarvey Harrison repeat_test = do_sys_open_test; 1058e8d31c20SJason Wessel printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n", 1059e8d31c20SJason Wessel repeat_test); 1060001fddf5SHarvey Harrison kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg"); 1061e8d31c20SJason Wessel run_sys_open_test(); 1062e8d31c20SJason Wessel return; 1063e8d31c20SJason Wessel } 1064e8d31c20SJason Wessel /* Shutdown and unregister */ 1065e8d31c20SJason Wessel kgdb_unregister_io_module(&kgdbts_io_ops); 1066e8d31c20SJason Wessel configured = 0; 1067e8d31c20SJason Wessel } 1068e8d31c20SJason Wessel 1069e8d31c20SJason Wessel static int kgdbts_option_setup(char *opt) 1070e8d31c20SJason Wessel { 1071adb4b83cSDan Carpenter if (strlen(opt) >= MAX_CONFIG_LEN) { 1072e8d31c20SJason Wessel printk(KERN_ERR "kgdbts: config string too long\n"); 1073e8d31c20SJason Wessel return -ENOSPC; 1074e8d31c20SJason Wessel } 1075e8d31c20SJason Wessel strcpy(config, opt); 1076e8d31c20SJason Wessel return 0; 1077e8d31c20SJason Wessel } 1078e8d31c20SJason Wessel 1079e8d31c20SJason Wessel __setup("kgdbts=", kgdbts_option_setup); 1080e8d31c20SJason Wessel 1081e8d31c20SJason Wessel static int configure_kgdbts(void) 1082e8d31c20SJason Wessel { 1083e8d31c20SJason Wessel int err = 0; 1084e8d31c20SJason Wessel 1085e8d31c20SJason Wessel if (!strlen(config) || isspace(config[0])) 1086e8d31c20SJason Wessel goto noconfig; 1087e8d31c20SJason Wessel 1088e8d31c20SJason Wessel final_ack = 0; 1089e8d31c20SJason Wessel run_plant_and_detach_test(1); 1090e8d31c20SJason Wessel 1091e8d31c20SJason Wessel err = kgdb_register_io_module(&kgdbts_io_ops); 1092e8d31c20SJason Wessel if (err) { 1093e8d31c20SJason Wessel configured = 0; 1094e8d31c20SJason Wessel return err; 1095e8d31c20SJason Wessel } 1096e8d31c20SJason Wessel configured = 1; 1097e8d31c20SJason Wessel kgdbts_run_tests(); 1098e8d31c20SJason Wessel 1099e8d31c20SJason Wessel return err; 1100e8d31c20SJason Wessel 1101e8d31c20SJason Wessel noconfig: 1102e8d31c20SJason Wessel config[0] = 0; 1103e8d31c20SJason Wessel configured = 0; 1104e8d31c20SJason Wessel 1105e8d31c20SJason Wessel return err; 1106e8d31c20SJason Wessel } 1107e8d31c20SJason Wessel 1108e8d31c20SJason Wessel static int __init init_kgdbts(void) 1109e8d31c20SJason Wessel { 1110e8d31c20SJason Wessel /* Already configured? */ 1111e8d31c20SJason Wessel if (configured == 1) 1112e8d31c20SJason Wessel return 0; 1113e8d31c20SJason Wessel 1114e8d31c20SJason Wessel return configure_kgdbts(); 1115e8d31c20SJason Wessel } 111667dd339cSPaul Gortmaker device_initcall(init_kgdbts); 1117e8d31c20SJason Wessel 1118e8d31c20SJason Wessel static int kgdbts_get_char(void) 1119e8d31c20SJason Wessel { 1120e8d31c20SJason Wessel int val = 0; 1121e8d31c20SJason Wessel 1122e8d31c20SJason Wessel if (ts.run_test) 1123e8d31c20SJason Wessel val = ts.run_test(1, 0); 1124e8d31c20SJason Wessel 1125e8d31c20SJason Wessel return val; 1126e8d31c20SJason Wessel } 1127e8d31c20SJason Wessel 1128e8d31c20SJason Wessel static void kgdbts_put_char(u8 chr) 1129e8d31c20SJason Wessel { 1130e8d31c20SJason Wessel if (ts.run_test) 1131e8d31c20SJason Wessel ts.run_test(0, chr); 1132e8d31c20SJason Wessel } 1133e8d31c20SJason Wessel 1134e4dca7b7SKees Cook static int param_set_kgdbts_var(const char *kmessage, 1135e4dca7b7SKees Cook const struct kernel_param *kp) 1136e8d31c20SJason Wessel { 1137b281218aSYoung Xiao size_t len = strlen(kmessage); 1138e8d31c20SJason Wessel 1139e8d31c20SJason Wessel if (len >= MAX_CONFIG_LEN) { 1140e8d31c20SJason Wessel printk(KERN_ERR "kgdbts: config string too long\n"); 1141e8d31c20SJason Wessel return -ENOSPC; 1142e8d31c20SJason Wessel } 1143e8d31c20SJason Wessel 1144e8d31c20SJason Wessel /* Only copy in the string if the init function has not run yet */ 1145e8d31c20SJason Wessel if (configured < 0) { 1146e8d31c20SJason Wessel strcpy(config, kmessage); 1147e8d31c20SJason Wessel return 0; 1148e8d31c20SJason Wessel } 1149e8d31c20SJason Wessel 11504dacd5c0SDongdong Deng if (configured == 1) { 11514dacd5c0SDongdong Deng printk(KERN_ERR "kgdbts: ERROR: Already configured and running.\n"); 1152e8d31c20SJason Wessel return -EBUSY; 1153e8d31c20SJason Wessel } 1154e8d31c20SJason Wessel 1155e8d31c20SJason Wessel strcpy(config, kmessage); 1156e8d31c20SJason Wessel /* Chop out \n char as a result of echo */ 1157b281218aSYoung Xiao if (len && config[len - 1] == '\n') 1158e8d31c20SJason Wessel config[len - 1] = '\0'; 1159e8d31c20SJason Wessel 1160e8d31c20SJason Wessel /* Go and configure with the new params. */ 1161e8d31c20SJason Wessel return configure_kgdbts(); 1162e8d31c20SJason Wessel } 1163e8d31c20SJason Wessel 1164e8d31c20SJason Wessel static void kgdbts_pre_exp_handler(void) 1165e8d31c20SJason Wessel { 1166e8d31c20SJason Wessel /* Increment the module count when the debugger is active */ 1167e8d31c20SJason Wessel if (!kgdb_connected) 1168e8d31c20SJason Wessel try_module_get(THIS_MODULE); 1169e8d31c20SJason Wessel } 1170e8d31c20SJason Wessel 1171e8d31c20SJason Wessel static void kgdbts_post_exp_handler(void) 1172e8d31c20SJason Wessel { 1173e8d31c20SJason Wessel /* decrement the module count when the debugger detaches */ 1174e8d31c20SJason Wessel if (!kgdb_connected) 1175e8d31c20SJason Wessel module_put(THIS_MODULE); 1176e8d31c20SJason Wessel } 1177e8d31c20SJason Wessel 1178e8d31c20SJason Wessel static struct kgdb_io kgdbts_io_ops = { 1179e8d31c20SJason Wessel .name = "kgdbts", 1180e8d31c20SJason Wessel .read_char = kgdbts_get_char, 1181e8d31c20SJason Wessel .write_char = kgdbts_put_char, 1182e8d31c20SJason Wessel .pre_exception = kgdbts_pre_exp_handler, 1183e8d31c20SJason Wessel .post_exception = kgdbts_post_exp_handler, 1184e8d31c20SJason Wessel }; 1185e8d31c20SJason Wessel 118667dd339cSPaul Gortmaker /* 118767dd339cSPaul Gortmaker * not really modular, but the easiest way to keep compat with existing 118867dd339cSPaul Gortmaker * bootargs behaviour is to continue using module_param here. 118967dd339cSPaul Gortmaker */ 1190e8d31c20SJason Wessel module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644); 1191e8d31c20SJason Wessel MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]"); 1192