Blame view

drivers/misc/kgdbts.c 30.1 KB
450515395   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
e8d31c204   Jason Wessel   kgdb: add kgdb in...
2
3
4
5
6
7
8
9
  /*
   * 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.
e8d31c204   Jason Wessel   kgdb: add kgdb in...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   */
  /* 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
7cfcd985d   Jason Wessel   kgdb: 1000 loops ...
38
   * I## = Run the single step test ## iterations
e8d31c204   Jason Wessel   kgdb: add kgdb in...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
   *
   * 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>
eb12a679b   Paul Gortmaker   drivers/misc: Add...
93
  #include <linux/module.h>
299300258   Ingo Molnar   sched/headers: Pr...
94
  #include <linux/sched/task.h>
e78acf67b   Tiejun Chen   kgdb/kgdbts: supp...
95
  #include <asm/sections.h>
e8d31c204   Jason Wessel   kgdb: add kgdb in...
96
97
98
99
100
101
102
103
104
105
  
  #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)
974460c5b   Jason Wessel   kgdb: allow stati...
106
107
108
109
  #define eprintk(a...) do { \
  		printk(KERN_ERR a); \
  		WARN_ON(1); \
  	} while (0)
e8d31c204   Jason Wessel   kgdb: add kgdb in...
110
  #define MAX_CONFIG_LEN		40
e8d31c204   Jason Wessel   kgdb: add kgdb in...
111
112
113
114
115
116
117
118
119
120
121
  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;
b33cb815b   Jason Wessel   kgdbts: Use HW br...
122
123
  static int force_hwbrks;
  static int hwbreaks_ok;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
124
125
  static int hw_break_val;
  static int hw_break_val2;
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
126
127
128
  static int cont_instead_of_sstep;
  static unsigned long cont_thread_id;
  static unsigned long sstep_thread_id;
4d7ffa499   David S. Miller   kgdbts: Sparc nee...
129
  #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
e8d31c204   Jason Wessel   kgdb: add kgdb in...
130
131
132
133
  static int arch_needs_sstep_emulation = 1;
  #else
  static int arch_needs_sstep_emulation;
  #endif
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
134
  static unsigned long cont_addr;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
135
  static unsigned long sstep_addr;
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
136
  static int restart_from_top_after_write;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
137
138
139
140
141
142
143
144
145
146
  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;
974460c5b   Jason Wessel   kgdb: allow stati...
147
148
149
  #ifdef CONFIG_KGDB_TESTS_BOOT_STRING
  static char config[MAX_CONFIG_LEN] = CONFIG_KGDB_TESTS_BOOT_STRING;
  #else
e8d31c204   Jason Wessel   kgdb: add kgdb in...
150
  static char config[MAX_CONFIG_LEN];
974460c5b   Jason Wessel   kgdb: allow stati...
151
  #endif
e8d31c204   Jason Wessel   kgdb: add kgdb in...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  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)(char *);
  	int (*put_handler)(char *, char *);
  };
  
  struct test_state {
  	char *name;
  	struct test_struct *tst;
  	int idx;
  	int (*run_test) (int, int);
  	int (*validate_put) (char *);
  };
  
  static struct test_state ts;
  
  static int kgdbts_unreg_thread(void *ptr)
  {
  	/* Wait until the tests are complete and then ungresiter the I/O
  	 * driver.
  	 */
  	while (!final_ack)
  		msleep_interruptible(1500);
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
183
184
  	/* Pause for any other threads to exit after final ack. */
  	msleep_interruptible(1000);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	if (configured)
  		kgdb_unregister_io_module(&kgdbts_io_ops);
  	configured = 0;
  
  	return 0;
  }
  
  /* This is noinline such that it can be used for a single location to
   * place a breakpoint
   */
  static noinline void kgdbts_break_test(void)
  {
  	v2printk("kgdbts: breakpoint complete
  ");
  }
  
  /* Lookup symbol info in the kernel */
  static unsigned long lookup_addr(char *arg)
  {
  	unsigned long addr = 0;
  
  	if (!strcmp(arg, "kgdbts_break_test"))
  		addr = (unsigned long)kgdbts_break_test;
  	else if (!strcmp(arg, "sys_open"))
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
209
  		addr = (unsigned long)do_sys_open;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
210
  	else if (!strcmp(arg, "do_fork"))
3033f14ab   Josh Triplett   clone: support pa...
211
  		addr = (unsigned long)_do_fork;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
212
213
  	else if (!strcmp(arg, "hw_break_val"))
  		addr = (unsigned long)&hw_break_val;
e78acf67b   Tiejun Chen   kgdb/kgdbts: supp...
214
  	addr = (unsigned long) dereference_function_descriptor((void *)addr);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  	return addr;
  }
  
  static void break_helper(char *bp_type, char *arg, unsigned long vaddr)
  {
  	unsigned long addr;
  
  	if (arg)
  		addr = lookup_addr(arg);
  	else
  		addr = vaddr;
  
  	sprintf(scratch_buf, "%s,%lx,%i", bp_type, addr,
  		BREAK_INSTR_SIZE);
  	fill_get_buf(scratch_buf);
  }
  
  static void sw_break(char *arg)
  {
b33cb815b   Jason Wessel   kgdbts: Use HW br...
234
  	break_helper(force_hwbrks ? "Z1" : "Z0", arg, 0);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
235
236
237
238
  }
  
  static void sw_rem_break(char *arg)
  {
b33cb815b   Jason Wessel   kgdbts: Use HW br...
239
  	break_helper(force_hwbrks ? "z1" : "z0", arg, 0);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  }
  
  static void hw_break(char *arg)
  {
  	break_helper("Z1", arg, 0);
  }
  
  static void hw_rem_break(char *arg)
  {
  	break_helper("z1", arg, 0);
  }
  
  static void hw_write_break(char *arg)
  {
  	break_helper("Z2", arg, 0);
  }
  
  static void hw_rem_write_break(char *arg)
  {
  	break_helper("z2", arg, 0);
  }
  
  static void hw_access_break(char *arg)
  {
  	break_helper("Z4", arg, 0);
  }
  
  static void hw_rem_access_break(char *arg)
  {
  	break_helper("z4", arg, 0);
  }
  
  static void hw_break_val_access(void)
  {
  	hw_break_val2 = hw_break_val;
  }
  
  static void hw_break_val_write(void)
  {
  	hw_break_val++;
  }
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
281
282
283
284
285
286
287
288
289
  static int get_thread_id_continue(char *put_str, char *arg)
  {
  	char *ptr = &put_str[11];
  
  	if (put_str[1] != 'T' || put_str[2] != '0')
  		return 1;
  	kgdb_hex2long(&ptr, &cont_thread_id);
  	return 0;
  }
e8d31c204   Jason Wessel   kgdb: add kgdb in...
290
291
292
  static int check_and_rewind_pc(char *put_str, char *arg)
  {
  	unsigned long addr = lookup_addr(arg);
63ab25ebb   Mike Frysinger   kgdbts: unify/gen...
293
  	unsigned long ip;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
294
295
296
297
298
  	int offset = 0;
  
  	kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
  		 NUMREGBYTES);
  	gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
63ab25ebb   Mike Frysinger   kgdbts: unify/gen...
299
300
301
302
303
304
305
  	ip = instruction_pointer(&kgdbts_regs);
  	v2printk("Stopped at IP: %lx
  ", ip);
  #ifdef GDB_ADJUSTS_BREAK_OFFSET
  	/* On some arches, a breakpoint stop requires it to be decremented */
  	if (addr + BREAK_INSTR_SIZE == ip)
  		offset = -BREAK_INSTR_SIZE;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
306
  #endif
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
307
308
309
310
311
312
313
314
315
  
  	if (arch_needs_sstep_emulation && sstep_addr &&
  	    ip + offset == sstep_addr &&
  	    ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) {
  		/* This is special case for emulated single step */
  		v2printk("Emul: rewind hit single step bp
  ");
  		restart_from_top_after_write = 1;
  	} else if (strcmp(arg, "silent") && ip + offset != addr) {
974460c5b   Jason Wessel   kgdb: allow stati...
316
317
  		eprintk("kgdbts: BP mismatch %lx expected %lx
  ",
63ab25ebb   Mike Frysinger   kgdbts: unify/gen...
318
  			   ip + offset, addr);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
319
320
  		return 1;
  	}
63ab25ebb   Mike Frysinger   kgdbts: unify/gen...
321
  	/* Readjust the instruction pointer if needed */
603d04b20   Mike Frysinger   kgdbts: only use ...
322
  	ip += offset;
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
323
  	cont_addr = ip;
603d04b20   Mike Frysinger   kgdbts: only use ...
324
325
326
  #ifdef GDB_ADJUSTS_BREAK_OFFSET
  	instruction_pointer_set(&kgdbts_regs, ip);
  #endif
e8d31c204   Jason Wessel   kgdb: add kgdb in...
327
328
329
330
331
332
  	return 0;
  }
  
  static int check_single_step(char *put_str, char *arg)
  {
  	unsigned long addr = lookup_addr(arg);
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
333
  	static int matched_id;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
334
335
336
337
338
339
340
341
342
343
  	/*
  	 * From an arch indepent point of view the instruction pointer
  	 * should be on a different instruction
  	 */
  	kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
  		 NUMREGBYTES);
  	gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
  	v2printk("Singlestep stopped at IP: %lx
  ",
  		   instruction_pointer(&kgdbts_regs));
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
344

23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
345
  	if (sstep_thread_id != cont_thread_id) {
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
346
347
348
349
350
351
352
  		/*
  		 * Ensure we stopped in the same thread id as before, else the
  		 * debugger should continue until the original thread that was
  		 * single stepped is scheduled again, emulating gdb's behavior.
  		 */
  		v2printk("ThrID does not match: %lx
  ", cont_thread_id);
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
353
354
355
356
357
358
359
360
361
  		if (arch_needs_sstep_emulation) {
  			if (matched_id &&
  			    instruction_pointer(&kgdbts_regs) != addr)
  				goto continue_test;
  			matched_id++;
  			ts.idx -= 2;
  			sstep_state = 0;
  			return 0;
  		}
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
362
363
364
365
  		cont_instead_of_sstep = 1;
  		ts.idx -= 4;
  		return 0;
  	}
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
366
367
  continue_test:
  	matched_id = 0;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
368
  	if (instruction_pointer(&kgdbts_regs) == addr) {
974460c5b   Jason Wessel   kgdb: allow stati...
369
370
  		eprintk("kgdbts: SingleStep failed at %lx
  ",
e8d31c204   Jason Wessel   kgdb: add kgdb in...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  			   instruction_pointer(&kgdbts_regs));
  		return 1;
  	}
  
  	return 0;
  }
  
  static void write_regs(char *arg)
  {
  	memset(scratch_buf, 0, sizeof(scratch_buf));
  	scratch_buf[0] = 'G';
  	pt_regs_to_gdb_regs(kgdbts_gdb_regs, &kgdbts_regs);
  	kgdb_mem2hex((char *)kgdbts_gdb_regs, &scratch_buf[1], NUMREGBYTES);
  	fill_get_buf(scratch_buf);
  }
  
  static void skip_back_repeat_test(char *arg)
  {
  	int go_back = simple_strtol(arg, NULL, 10);
  
  	repeat_test--;
0296c248b   Daniel Thompson   misc: kgdbts: Dis...
392
  	if (repeat_test <= 0) {
e8d31c204   Jason Wessel   kgdb: add kgdb in...
393
  		ts.idx++;
0296c248b   Daniel Thompson   misc: kgdbts: Dis...
394
395
396
397
  	} else {
  		if (repeat_test % 100 == 0)
  			v1printk("kgdbts:RUN ... %d remaining
  ", repeat_test);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
398
  		ts.idx -= go_back;
0296c248b   Daniel Thompson   misc: kgdbts: Dis...
399
  	}
e8d31c204   Jason Wessel   kgdb: add kgdb in...
400
401
402
403
404
405
406
407
408
409
410
411
412
  	fill_get_buf(ts.tst[ts.idx].get);
  }
  
  static int got_break(char *put_str, char *arg)
  {
  	test_complete = 1;
  	if (!strncmp(put_str+1, arg, 2)) {
  		if (!strncmp(arg, "T0", 2))
  			test_complete = 2;
  		return 0;
  	}
  	return 1;
  }
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  static void get_cont_catch(char *arg)
  {
  	/* Always send detach because the test is completed at this point */
  	fill_get_buf("D");
  }
  
  static int put_cont_catch(char *put_str, char *arg)
  {
  	/* This is at the end of the test and we catch any and all input */
  	v2printk("kgdbts: cleanup task: %lx
  ", sstep_thread_id);
  	ts.idx--;
  	return 0;
  }
  
  static int emul_reset(char *put_str, char *arg)
  {
  	if (strncmp(put_str, "$OK", 3))
  		return 1;
  	if (restart_from_top_after_write) {
  		restart_from_top_after_write = 0;
  		ts.idx = -1;
  	}
  	return 0;
  }
e8d31c204   Jason Wessel   kgdb: add kgdb in...
438
439
440
  static void emul_sstep_get(char *arg)
  {
  	if (!arch_needs_sstep_emulation) {
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
441
442
443
444
445
446
  		if (cont_instead_of_sstep) {
  			cont_instead_of_sstep = 0;
  			fill_get_buf("c");
  		} else {
  			fill_get_buf(arg);
  		}
e8d31c204   Jason Wessel   kgdb: add kgdb in...
447
448
449
450
451
452
453
454
455
456
457
  		return;
  	}
  	switch (sstep_state) {
  	case 0:
  		v2printk("Emulate single step
  ");
  		/* Start by looking at the current PC */
  		fill_get_buf("g");
  		break;
  	case 1:
  		/* set breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
458
  		break_helper("Z0", NULL, sstep_addr);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
459
460
461
462
463
464
465
  		break;
  	case 2:
  		/* Continue */
  		fill_get_buf("c");
  		break;
  	case 3:
  		/* Clear breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
466
  		break_helper("z0", NULL, sstep_addr);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
467
468
  		break;
  	default:
974460c5b   Jason Wessel   kgdb: allow stati...
469
470
  		eprintk("kgdbts: ERROR failed sstep get emulation
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
471
472
473
474
475
476
477
  	}
  	sstep_state++;
  }
  
  static int emul_sstep_put(char *put_str, char *arg)
  {
  	if (!arch_needs_sstep_emulation) {
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
478
479
480
481
482
  		char *ptr = &put_str[11];
  		if (put_str[1] != 'T' || put_str[2] != '0')
  			return 1;
  		kgdb_hex2long(&ptr, &sstep_thread_id);
  		return 0;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
483
484
485
486
487
488
489
490
491
492
493
  	}
  	switch (sstep_state) {
  	case 1:
  		/* validate the "g" packet to get the IP */
  		kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
  			 NUMREGBYTES);
  		gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
  		v2printk("Stopped at IP: %lx
  ",
  			 instruction_pointer(&kgdbts_regs));
  		/* Want to stop at IP + break instruction size by default */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
494
  		sstep_addr = cont_addr + BREAK_INSTR_SIZE;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
495
496
497
  		break;
  	case 2:
  		if (strncmp(put_str, "$OK", 3)) {
974460c5b   Jason Wessel   kgdb: allow stati...
498
499
  			eprintk("kgdbts: failed sstep break set
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
500
501
502
503
504
  			return 1;
  		}
  		break;
  	case 3:
  		if (strncmp(put_str, "$T0", 3)) {
974460c5b   Jason Wessel   kgdb: allow stati...
505
506
  			eprintk("kgdbts: failed continue sstep
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
507
  			return 1;
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
508
509
510
  		} else {
  			char *ptr = &put_str[11];
  			kgdb_hex2long(&ptr, &sstep_thread_id);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
511
512
513
514
  		}
  		break;
  	case 4:
  		if (strncmp(put_str, "$OK", 3)) {
974460c5b   Jason Wessel   kgdb: allow stati...
515
516
  			eprintk("kgdbts: failed sstep break unset
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
517
518
519
520
521
522
  			return 1;
  		}
  		/* Single step is complete so continue on! */
  		sstep_state = 0;
  		return 0;
  	default:
974460c5b   Jason Wessel   kgdb: allow stati...
523
524
  		eprintk("kgdbts: ERROR failed sstep put emulation
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  	}
  
  	/* Continue on the same test line until emulation is complete */
  	ts.idx--;
  	return 0;
  }
  
  static int final_ack_set(char *put_str, char *arg)
  {
  	if (strncmp(put_str+1, arg, 2))
  		return 1;
  	final_ack = 1;
  	return 0;
  }
  /*
   * Test to plant a breakpoint and detach, which should clear out the
   * breakpoint and restore the original instruction.
   */
  static struct test_struct plant_and_detach_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
  	{ "D", "OK" }, /* Detach */
  	{ "", "" },
  };
  
  /*
   * Simple test to write in a software breakpoint, check for the
   * correct stop location and detach.
   */
  static struct test_struct sw_breakpoint_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
  	{ "c", "T0*", }, /* Continue */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
558
  	{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
559
560
561
  	{ "write", "OK", write_regs },
  	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
  	{ "D", "OK" }, /* Detach */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
562
  	{ "D", "OK", NULL,  got_break }, /* On success we made it here */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  	{ "", "" },
  };
  
  /*
   * Test a known bad memory read location to test the fault handler and
   * read bytes 1-8 at the bad address
   */
  static struct test_struct bad_read_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "m0,1", "E*" }, /* read 1 byte at address 1 */
  	{ "m0,2", "E*" }, /* read 1 byte at address 2 */
  	{ "m0,3", "E*" }, /* read 1 byte at address 3 */
  	{ "m0,4", "E*" }, /* read 1 byte at address 4 */
  	{ "m0,5", "E*" }, /* read 1 byte at address 5 */
  	{ "m0,6", "E*" }, /* read 1 byte at address 6 */
  	{ "m0,7", "E*" }, /* read 1 byte at address 7 */
  	{ "m0,8", "E*" }, /* read 1 byte at address 8 */
  	{ "D", "OK" }, /* Detach which removes all breakpoints and continues */
  	{ "", "" },
  };
  
  /*
   * Test for hitting a breakpoint, remove it, single step, plant it
   * again and detach.
   */
  static struct test_struct singlestep_break_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
591
592
  	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
  	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
593
  	{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
594
  	{ "write", "OK", write_regs }, /* Write registers */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
595
  	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
596
  	{ "g", "kgdbts_break_test", NULL, check_single_step },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
597
598
  	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
  	{ "c", "T0*", }, /* Continue */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
599
  	{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
600
601
602
603
604
605
606
607
608
609
610
611
  	{ "write", "OK", write_regs }, /* Write registers */
  	{ "D", "OK" }, /* Remove all breakpoints and continues */
  	{ "", "" },
  };
  
  /*
   * Test for hitting a breakpoint at do_fork for what ever the number
   * of iterations required by the variable repeat_test.
   */
  static struct test_struct do_fork_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
612
613
  	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
  	{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
614
  	{ "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
615
  	{ "write", "OK", write_regs, emul_reset }, /* Write registers */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
616
  	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
617
  	{ "g", "do_fork", NULL, check_single_step },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
618
619
  	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
  	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
620
  	{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
621
  	{ "", "", get_cont_catch, put_cont_catch },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
622
623
624
625
626
627
628
629
  };
  
  /* Test for hitting a breakpoint at sys_open for what ever the number
   * of iterations required by the variable repeat_test.
   */
  static struct test_struct sys_open_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
486c5987a   Jason Wessel   kgdbts: (1 of 2) ...
630
631
  	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
  	{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
632
  	{ "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
633
  	{ "write", "OK", write_regs, emul_reset }, /* Write registers */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
634
  	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
635
  	{ "g", "sys_open", NULL, check_single_step },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
636
637
  	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
  	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
638
  	{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
639
  	{ "", "", get_cont_catch, put_cont_catch },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
640
641
642
643
644
645
646
647
648
  };
  
  /*
   * Test for hitting a simple hw breakpoint
   */
  static struct test_struct hw_breakpoint_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
  	{ "c", "T0*", }, /* Continue */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
649
  	{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
650
651
652
  	{ "write", "OK", write_regs },
  	{ "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
  	{ "D", "OK" }, /* Detach */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
653
  	{ "D", "OK", NULL,  got_break }, /* On success we made it here */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
654
655
656
657
658
659
660
661
662
  	{ "", "" },
  };
  
  /*
   * Test for hitting a hw write breakpoint
   */
  static struct test_struct hw_write_break_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
663
664
  	{ "c", "T0*", NULL, got_break }, /* Continue */
  	{ "g", "silent", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
665
666
667
  	{ "write", "OK", write_regs },
  	{ "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
  	{ "D", "OK" }, /* Detach */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
668
  	{ "D", "OK", NULL,  got_break }, /* On success we made it here */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
669
670
671
672
673
674
675
676
677
  	{ "", "" },
  };
  
  /*
   * Test for hitting a hw access breakpoint
   */
  static struct test_struct hw_access_break_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
  	{ "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
678
679
  	{ "c", "T0*", NULL, got_break }, /* Continue */
  	{ "g", "silent", NULL, check_and_rewind_pc },
e8d31c204   Jason Wessel   kgdb: add kgdb in...
680
681
682
  	{ "write", "OK", write_regs },
  	{ "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
  	{ "D", "OK" }, /* Detach */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
683
  	{ "D", "OK", NULL,  got_break }, /* On success we made it here */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
684
685
686
687
688
689
690
691
  	{ "", "" },
  };
  
  /*
   * Test for hitting a hw access breakpoint
   */
  static struct test_struct nmi_sleep_test[] = {
  	{ "?", "S0*" }, /* Clear break points */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
692
  	{ "c", "T0*", NULL, got_break }, /* Continue */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
693
  	{ "D", "OK" }, /* Detach */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
694
  	{ "D", "OK", NULL,  got_break }, /* On success we made it here */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
  	{ "", "" },
  };
  
  static void fill_get_buf(char *buf)
  {
  	unsigned char checksum = 0;
  	int count = 0;
  	char ch;
  
  	strcpy(get_buf, "$");
  	strcat(get_buf, buf);
  	while ((ch = buf[count])) {
  		checksum += ch;
  		count++;
  	}
  	strcat(get_buf, "#");
827e609b4   Harvey Harrison   kgdb: use common ...
711
712
  	get_buf[count + 2] = hex_asc_hi(checksum);
  	get_buf[count + 3] = hex_asc_lo(checksum);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  	get_buf[count + 4] = '\0';
  	v2printk("get%i: %s
  ", ts.idx, get_buf);
  }
  
  static int validate_simple_test(char *put_str)
  {
  	char *chk_str;
  
  	if (ts.tst[ts.idx].put_handler)
  		return ts.tst[ts.idx].put_handler(put_str,
  			ts.tst[ts.idx].put);
  
  	chk_str = ts.tst[ts.idx].put;
  	if (*put_str == '$')
  		put_str++;
  
  	while (*chk_str != '\0' && *put_str != '\0') {
  		/* If someone does a * to match the rest of the string, allow
25985edce   Lucas De Marchi   Fix common misspe...
732
  		 * it, or stop if the received string is complete.
e8d31c204   Jason Wessel   kgdb: add kgdb in...
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  		 */
  		if (*put_str == '#' || *chk_str == '*')
  			return 0;
  		if (*put_str != *chk_str)
  			return 1;
  
  		chk_str++;
  		put_str++;
  	}
  	if (*chk_str == '\0' && (*put_str == '\0' || *put_str == '#'))
  		return 0;
  
  	return 1;
  }
  
  static int run_simple_test(int is_get_char, int chr)
  {
  	int ret = 0;
  	if (is_get_char) {
  		/* Send an ACK on the get if a prior put completed and set the
  		 * send ack variable
  		 */
  		if (send_ack) {
  			send_ack = 0;
  			return '+';
  		}
  		/* On the first get char, fill the transmit buffer and then
  		 * take from the get_string.
  		 */
  		if (get_buf_cnt == 0) {
  			if (ts.tst[ts.idx].get_handler)
  				ts.tst[ts.idx].get_handler(ts.tst[ts.idx].get);
  			else
  				fill_get_buf(ts.tst[ts.idx].get);
  		}
  
  		if (get_buf[get_buf_cnt] == '\0') {
974460c5b   Jason Wessel   kgdb: allow stati...
770
771
  			eprintk("kgdbts: ERROR GET: EOB on '%s' at %i
  ",
e8d31c204   Jason Wessel   kgdb: add kgdb in...
772
773
774
775
776
777
778
779
780
781
782
783
  			   ts.name, ts.idx);
  			get_buf_cnt = 0;
  			fill_get_buf("D");
  		}
  		ret = get_buf[get_buf_cnt];
  		get_buf_cnt++;
  		return ret;
  	}
  
  	/* This callback is a put char which is when kgdb sends data to
  	 * this I/O module.
  	 */
23bbd8e34   Jason Wessel   kgdbts: (2 of 2) ...
784
785
  	if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' &&
  	    !ts.tst[ts.idx].get_handler) {
974460c5b   Jason Wessel   kgdb: allow stati...
786
  		eprintk("kgdbts: ERROR: beyond end of test on"
e8d31c204   Jason Wessel   kgdb: add kgdb in...
787
788
789
790
791
792
  			   " '%s' line %i
  ", ts.name, ts.idx);
  		return 0;
  	}
  
  	if (put_buf_cnt >= BUFMAX) {
974460c5b   Jason Wessel   kgdb: allow stati...
793
  		eprintk("kgdbts: ERROR: put buffer overflow on"
e8d31c204   Jason Wessel   kgdb: add kgdb in...
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  			   " '%s' line %i
  ", ts.name, ts.idx);
  		put_buf_cnt = 0;
  		return 0;
  	}
  	/* Ignore everything until the first valid packet start '$' */
  	if (put_buf_cnt == 0 && chr != '$')
  		return 0;
  
  	put_buf[put_buf_cnt] = chr;
  	put_buf_cnt++;
  
  	/* End of packet == #XX so look for the '#' */
  	if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') {
b4f1b67be   Roel Kluin   kgdbts: Read buff...
808
809
810
811
812
813
814
  		if (put_buf_cnt >= BUFMAX) {
  			eprintk("kgdbts: ERROR: put buffer overflow on"
  				" '%s' line %i
  ", ts.name, ts.idx);
  			put_buf_cnt = 0;
  			return 0;
  		}
e8d31c204   Jason Wessel   kgdb: add kgdb in...
815
816
817
818
819
  		put_buf[put_buf_cnt] = '\0';
  		v2printk("put%i: %s
  ", ts.idx, put_buf);
  		/* Trigger check here */
  		if (ts.validate_put && ts.validate_put(put_buf)) {
974460c5b   Jason Wessel   kgdb: allow stati...
820
  			eprintk("kgdbts: ERROR PUT: end of test "
e8d31c204   Jason Wessel   kgdb: add kgdb in...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
  			   "buffer on '%s' line %i expected %s got %s
  ",
  			   ts.name, ts.idx, ts.tst[ts.idx].put, put_buf);
  		}
  		ts.idx++;
  		put_buf_cnt = 0;
  		get_buf_cnt = 0;
  		send_ack = 1;
  	}
  	return 0;
  }
  
  static void init_simple_test(void)
  {
  	memset(&ts, 0, sizeof(ts));
  	ts.run_test = run_simple_test;
  	ts.validate_put = validate_simple_test;
  }
  
  static void run_plant_and_detach_test(int is_early)
  {
  	char before[BREAK_INSTR_SIZE];
  	char after[BREAK_INSTR_SIZE];
  
  	probe_kernel_read(before, (char *)kgdbts_break_test,
  	  BREAK_INSTR_SIZE);
  	init_simple_test();
  	ts.tst = plant_and_detach_test;
  	ts.name = "plant_and_detach_test";
  	/* Activate test with initial breakpoint */
  	if (!is_early)
  		kgdb_breakpoint();
  	probe_kernel_read(after, (char *)kgdbts_break_test,
  	  BREAK_INSTR_SIZE);
  	if (memcmp(before, after, BREAK_INSTR_SIZE)) {
  		printk(KERN_CRIT "kgdbts: ERROR kgdb corrupted memory
  ");
  		panic("kgdb memory corruption");
  	}
  
  	/* complete the detach test */
  	if (!is_early)
  		kgdbts_break_test();
  }
  
  static void run_breakpoint_test(int is_hw_breakpoint)
  {
  	test_complete = 0;
  	init_simple_test();
  	if (is_hw_breakpoint) {
  		ts.tst = hw_breakpoint_test;
  		ts.name = "hw_breakpoint_test";
  	} else {
  		ts.tst = sw_breakpoint_test;
  		ts.name = "sw_breakpoint_test";
  	}
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  	/* run code with the break point in it */
  	kgdbts_break_test();
  	kgdb_breakpoint();
  
  	if (test_complete)
  		return;
974460c5b   Jason Wessel   kgdb: allow stati...
885
886
  	eprintk("kgdbts: ERROR %s test failed
  ", ts.name);
b33cb815b   Jason Wessel   kgdbts: Use HW br...
887
888
  	if (is_hw_breakpoint)
  		hwbreaks_ok = 0;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  }
  
  static void run_hw_break_test(int is_write_test)
  {
  	test_complete = 0;
  	init_simple_test();
  	if (is_write_test) {
  		ts.tst = hw_write_break_test;
  		ts.name = "hw_write_break_test";
  	} else {
  		ts.tst = hw_access_break_test;
  		ts.name = "hw_access_break_test";
  	}
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  	hw_break_val_access();
  	if (is_write_test) {
b33cb815b   Jason Wessel   kgdbts: Use HW br...
906
  		if (test_complete == 2) {
974460c5b   Jason Wessel   kgdb: allow stati...
907
908
  			eprintk("kgdbts: ERROR %s broke on access
  ",
e8d31c204   Jason Wessel   kgdb: add kgdb in...
909
  				ts.name);
b33cb815b   Jason Wessel   kgdbts: Use HW br...
910
911
  			hwbreaks_ok = 0;
  		}
e8d31c204   Jason Wessel   kgdb: add kgdb in...
912
913
914
915
916
917
  		hw_break_val_write();
  	}
  	kgdb_breakpoint();
  
  	if (test_complete == 1)
  		return;
974460c5b   Jason Wessel   kgdb: allow stati...
918
919
  	eprintk("kgdbts: ERROR %s test failed
  ", ts.name);
b33cb815b   Jason Wessel   kgdbts: Use HW br...
920
  	hwbreaks_ok = 0;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
  }
  
  static void run_nmi_sleep_test(int nmi_sleep)
  {
  	unsigned long flags;
  
  	init_simple_test();
  	ts.tst = nmi_sleep_test;
  	ts.name = "nmi_sleep_test";
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  	local_irq_save(flags);
  	mdelay(nmi_sleep*1000);
  	touch_nmi_watchdog();
  	local_irq_restore(flags);
  	if (test_complete != 2)
974460c5b   Jason Wessel   kgdb: allow stati...
937
938
  		eprintk("kgdbts: ERROR nmi_test did not hit nmi
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
939
940
941
  	kgdb_breakpoint();
  	if (test_complete == 1)
  		return;
974460c5b   Jason Wessel   kgdb: allow stati...
942
943
  	eprintk("kgdbts: ERROR %s test failed
  ", ts.name);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
  }
  
  static void run_bad_read_test(void)
  {
  	init_simple_test();
  	ts.tst = bad_read_test;
  	ts.name = "bad_read_test";
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  }
  
  static void run_do_fork_test(void)
  {
  	init_simple_test();
  	ts.tst = do_fork_test;
  	ts.name = "do_fork_test";
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  }
  
  static void run_sys_open_test(void)
  {
  	init_simple_test();
  	ts.tst = sys_open_test;
  	ts.name = "sys_open_test";
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  }
  
  static void run_singlestep_break_test(void)
  {
  	init_simple_test();
  	ts.tst = singlestep_break_test;
  	ts.name = "singlestep_breakpoint_test";
  	/* Activate test with initial breakpoint */
  	kgdb_breakpoint();
  	kgdbts_break_test();
  	kgdbts_break_test();
  }
  
  static void kgdbts_run_tests(void)
  {
  	char *ptr;
  	int fork_test = 0;
001fddf5f   Harvey Harrison   kgdb: trivial spa...
988
  	int do_sys_open_test = 0;
7cfcd985d   Jason Wessel   kgdb: 1000 loops ...
989
  	int sstep_test = 1000;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
990
  	int nmi_sleep = 0;
7cfcd985d   Jason Wessel   kgdb: 1000 loops ...
991
  	int i;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
992

fa0218ef7   Laura Abbott   misc: kgdbts: Fix...
993
994
995
996
997
  	verbose = 0;
  	if (strstr(config, "V1"))
  		verbose = 1;
  	if (strstr(config, "V2"))
  		verbose = 2;
59d309f9c   Geert Uytterhoeven   kgdb: Replace str...
998
  	ptr = strchr(config, 'F');
e8d31c204   Jason Wessel   kgdb: add kgdb in...
999
  	if (ptr)
001fddf5f   Harvey Harrison   kgdb: trivial spa...
1000
  		fork_test = simple_strtol(ptr + 1, NULL, 10);
59d309f9c   Geert Uytterhoeven   kgdb: Replace str...
1001
  	ptr = strchr(config, 'S');
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1002
  	if (ptr)
001fddf5f   Harvey Harrison   kgdb: trivial spa...
1003
  		do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
59d309f9c   Geert Uytterhoeven   kgdb: Replace str...
1004
  	ptr = strchr(config, 'N');
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1005
1006
  	if (ptr)
  		nmi_sleep = simple_strtol(ptr+1, NULL, 10);
59d309f9c   Geert Uytterhoeven   kgdb: Replace str...
1007
  	ptr = strchr(config, 'I');
7cfcd985d   Jason Wessel   kgdb: 1000 loops ...
1008
1009
  	if (ptr)
  		sstep_test = simple_strtol(ptr+1, NULL, 10);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1010

456ca7ff2   Jason Wessel   kgdbts: Fix kerne...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  	/* All HW break point tests */
  	if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
  		hwbreaks_ok = 1;
  		v1printk("kgdbts:RUN hw breakpoint test
  ");
  		run_breakpoint_test(1);
  		v1printk("kgdbts:RUN hw write breakpoint test
  ");
  		run_hw_break_test(1);
  		v1printk("kgdbts:RUN access write breakpoint test
  ");
  		run_hw_break_test(0);
  	}
456ca7ff2   Jason Wessel   kgdbts: Fix kerne...
1024

e8d31c204   Jason Wessel   kgdb: add kgdb in...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  	/* required internal KGDB tests */
  	v1printk("kgdbts:RUN plant and detach test
  ");
  	run_plant_and_detach_test(0);
  	v1printk("kgdbts:RUN sw breakpoint test
  ");
  	run_breakpoint_test(0);
  	v1printk("kgdbts:RUN bad memory access test
  ");
  	run_bad_read_test();
7cfcd985d   Jason Wessel   kgdb: 1000 loops ...
1035
1036
1037
1038
1039
1040
1041
1042
1043
  	v1printk("kgdbts:RUN singlestep test %i iterations
  ", sstep_test);
  	for (i = 0; i < sstep_test; i++) {
  		run_singlestep_break_test();
  		if (i % 100 == 0)
  			v1printk("kgdbts:RUN singlestep [%i/%i]
  ",
  				 i, sstep_test);
  	}
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1044
1045
  
  	/* ===Optional tests=== */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
  	if (nmi_sleep) {
  		v1printk("kgdbts:RUN NMI sleep %i seconds test
  ", nmi_sleep);
  		run_nmi_sleep_test(nmi_sleep);
  	}
  
  	/* If the do_fork test is run it will be the last test that is
  	 * executed because a kernel thread will be spawned at the very
  	 * end to unregister the debug hooks.
  	 */
  	if (fork_test) {
  		repeat_test = fork_test;
  		printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints
  ",
  			repeat_test);
001fddf5f   Harvey Harrison   kgdb: trivial spa...
1061
  		kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1062
1063
1064
1065
1066
1067
1068
1069
  		run_do_fork_test();
  		return;
  	}
  
  	/* If the sys_open test is run it will be the last test that is
  	 * executed because a kernel thread will be spawned at the very
  	 * end to unregister the debug hooks.
  	 */
001fddf5f   Harvey Harrison   kgdb: trivial spa...
1070
1071
  	if (do_sys_open_test) {
  		repeat_test = do_sys_open_test;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1072
1073
1074
  		printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints
  ",
  			repeat_test);
001fddf5f   Harvey Harrison   kgdb: trivial spa...
1075
  		kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
  		run_sys_open_test();
  		return;
  	}
  	/* Shutdown and unregister */
  	kgdb_unregister_io_module(&kgdbts_io_ops);
  	configured = 0;
  }
  
  static int kgdbts_option_setup(char *opt)
  {
adb4b83c1   Dan Carpenter   kgdboc,kgdbts: st...
1086
  	if (strlen(opt) >= MAX_CONFIG_LEN) {
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1087
1088
1089
1090
1091
  		printk(KERN_ERR "kgdbts: config string too long
  ");
  		return -ENOSPC;
  	}
  	strcpy(config, opt);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  	return 0;
  }
  
  __setup("kgdbts=", kgdbts_option_setup);
  
  static int configure_kgdbts(void)
  {
  	int err = 0;
  
  	if (!strlen(config) || isspace(config[0]))
  		goto noconfig;
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  
  	final_ack = 0;
  	run_plant_and_detach_test(1);
  
  	err = kgdb_register_io_module(&kgdbts_io_ops);
  	if (err) {
  		configured = 0;
  		return err;
  	}
  	configured = 1;
  	kgdbts_run_tests();
  
  	return err;
  
  noconfig:
  	config[0] = 0;
  	configured = 0;
  
  	return err;
  }
  
  static int __init init_kgdbts(void)
  {
  	/* Already configured? */
  	if (configured == 1)
  		return 0;
  
  	return configure_kgdbts();
  }
67dd339c7   Paul Gortmaker   drivers/misc: mak...
1132
  device_initcall(init_kgdbts);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1133

e8d31c204   Jason Wessel   kgdb: add kgdb in...
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  static int kgdbts_get_char(void)
  {
  	int val = 0;
  
  	if (ts.run_test)
  		val = ts.run_test(1, 0);
  
  	return val;
  }
  
  static void kgdbts_put_char(u8 chr)
  {
  	if (ts.run_test)
  		ts.run_test(0, chr);
  }
e4dca7b7a   Kees Cook   treewide: Fix fun...
1149
1150
  static int param_set_kgdbts_var(const char *kmessage,
  				const struct kernel_param *kp)
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1151
  {
b281218ad   Young Xiao   Drivers: misc: fi...
1152
  	size_t len = strlen(kmessage);
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
  
  	if (len >= MAX_CONFIG_LEN) {
  		printk(KERN_ERR "kgdbts: config string too long
  ");
  		return -ENOSPC;
  	}
  
  	/* Only copy in the string if the init function has not run yet */
  	if (configured < 0) {
  		strcpy(config, kmessage);
  		return 0;
  	}
4dacd5c07   Dongdong Deng   kgdbts: prevent r...
1165
1166
1167
  	if (configured == 1) {
  		printk(KERN_ERR "kgdbts: ERROR: Already configured and running.
  ");
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1168
1169
1170
1171
1172
1173
  		return -EBUSY;
  	}
  
  	strcpy(config, kmessage);
  	/* Chop out 
   char as a result of echo */
b281218ad   Young Xiao   Drivers: misc: fi...
1174
1175
  	if (len && config[len - 1] == '
  ')
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1176
  		config[len - 1] = '\0';
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
  	/* Go and configure with the new params. */
  	return configure_kgdbts();
  }
  
  static void kgdbts_pre_exp_handler(void)
  {
  	/* Increment the module count when the debugger is active */
  	if (!kgdb_connected)
  		try_module_get(THIS_MODULE);
  }
  
  static void kgdbts_post_exp_handler(void)
  {
  	/* decrement the module count when the debugger detaches */
  	if (!kgdb_connected)
  		module_put(THIS_MODULE);
  }
  
  static struct kgdb_io kgdbts_io_ops = {
  	.name			= "kgdbts",
  	.read_char		= kgdbts_get_char,
  	.write_char		= kgdbts_put_char,
  	.pre_exception		= kgdbts_pre_exp_handler,
  	.post_exception		= kgdbts_post_exp_handler,
  };
67dd339c7   Paul Gortmaker   drivers/misc: mak...
1202
1203
1204
1205
  /*
   * not really modular, but the easiest way to keep compat with existing
   * bootargs behaviour is to continue using module_param here.
   */
e8d31c204   Jason Wessel   kgdb: add kgdb in...
1206
1207
  module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644);
  MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]");