/*
* kgdbts is a test suite for kgdb for the sole purpose of validating
* that key pieces of the kgdb internals are working properly such as
* HW/SW breakpoints, single stepping, and NMI.
*
* Created by: Jason Wessel <jason.wessel@windriver.com>
*
* Copyright (c) 2008 Wind River Systems, 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Information about the kgdb test suite.
* -------------------------------------
*
* The kgdb test suite is designed as a KGDB I/O module which
* simulates the communications that a debugger would have with kgdb.
* The tests are broken up in to a line by line and referenced here as
* a "get" which is kgdb requesting input and "put" which is kgdb
* sending a response.
*
* The kgdb suite can be invoked from the kernel command line
* arguments system or executed dynamically at run time. The test
* suite uses the variable "kgdbts" to obtain the information about
* which tests to run and to configure the verbosity level. The
* following are the various characters you can use with the kgdbts=
* line:
*
* When using the "kgdbts=" you only choose one of the following core
* test types:
* A = Run all the core tests silently
* V1 = Run all the core tests with minimal output
* V2 = Run all the core tests in debug mode
*
* You can also specify optional tests:
* N## = Go to sleep with interrupts of for ## seconds
* to test the HW NMI watchdog
* F## = Break at do_fork for ## iterations
* S## = Break at sys_open for ## iterations
* I## = Run the single step test ## iterations
*
* NOTE: that the do_fork and sys_open tests are mutually exclusive.
*
* To invoke the kgdb test suite from boot you use a kernel start
* argument as follows:
* kgdbts=V1 kgdbwait
* Or if you wanted to perform the NMI test for 6 seconds and do_fork
* test for 100 forks, you could use:
* kgdbts=V1N6F100 kgdbwait
*
* The test suite can also be invoked at run time with:
* echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts
* Or as another example:
* echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts
*
* When developing a new kgdb arch specific implementation or
* using these tests for the purpose of regression testing,
* several invocations are required.
*
* 1) Boot with the test suite enabled by using the kernel arguments
* "kgdbts=V1F100 kgdbwait"
* ## If kgdb arch specific implementation has NMI use
* "kgdbts=V1N6F100
*
* 2) After the system boot run the basic test.
* echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts
*
* 3) Run the concurrency tests. It is best to use n+1
* while loops where n is the number of cpus you have
* in your system. The example below uses only two
* loops.
*
* ## This tests break points on sys_open
* while [ 1 ] ; do find / > /dev/null 2>&1 ; done &
* while [ 1 ] ; do find / > /dev/null 2>&1 ; done &
* echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts
* fg # and hit control-c
* fg # and hit control-c
* ## This tests break points on do_fork
* while [ 1 ] ; do date > /dev/null ; done &
* while [ 1 ] ; do date > /dev/null ; done &
* echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts
* fg # and hit control-c
*
*/
#include <linux/kernel.h>
#include <linux/kgdb.h>
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/nmi.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <asm/sections.h>
#define v1printk(a...) do { \
if (verbose) \
printk(KERN_INFO a); \
} while (0)
#define v2printk(a...) do { \
if (verbose > 1) \
printk(KERN_INFO a); \
touch_nmi_watchdog(); \
} while (0)
#define eprintk(a...) do { \
printk(KERN_ERR a); \
WARN_ON(1); \
} while (0)
#define MAX_CONFIG_LEN 40
static struct kgdb_io kgdbts_io_ops;
static char get_buf[BUFMAX];
static int get_buf_cnt;
static char put_buf[BUFMAX];
static int put_buf_cnt;
static char scratch_buf[BUFMAX];
static int verbose;
static int repeat_test;
static int test_complete;
static int send_ack;
static int final_ack;
static int force_hwbrks;
static int hwbreaks_ok;
static int hw_break_val;
static int hw_break_val2;
static int cont_instead_of_sstep;
static unsigned long cont_thread_id;
static unsigned long sstep_thread_id;
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
static int arch_needs_sstep_emulation = 1;
#else
static int arch_needs_sstep_emulation;
#endif
static unsigned long cont_addr;
static unsigned long sstep_addr;
static int restart_from_top_after_write;
static int sstep_state;
/* Storage for the registers, in GDB format. */
static unsigned long kgdbts_gdb_regs[(NUMREGBYTES +
sizeof(unsigned long) - 1) /
sizeof(unsigned long)];
static struct pt_regs kgdbts_regs;
/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
static int configured = -1;
#ifdef CONFIG_KGDB_TESTS_BOOT_STRING
static char config[MAX_CONFIG_LEN] = CONFIG_KGDB_TESTS_BOOT_STRING;
#else
static char config[MAX_CONFIG_LEN];
#endif
static struct kparam_string kps = {
.string = config,
.maxlen = MAX_CONFIG_LEN,
};
static void fill_get_buf(char *buf);
struct test_struct {
char *get;
char *put;
void (*get_handler