mips32.c 20.6 KB
Newer Older
ntfreak's avatar
ntfreak committed
1
2
3
4
5
6
/***************************************************************************
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
 *   Copyright (C) 2008 by David T.L. Wong                                 *
 *                                                                         *
7
 *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
8
9
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
ntfreak's avatar
ntfreak committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "mips32.h"
30
31
#include "breakpoints.h"
#include "algorithm.h"
32
#include "register.h"
ntfreak's avatar
ntfreak committed
33
34
35

char* mips32_core_reg_list[] =
{
ntfreak's avatar
ntfreak committed
36
37
38
39
	"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
	"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
	"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
	"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
ntfreak's avatar
ntfreak committed
40
41
42
	"status", "lo", "hi", "badvaddr", "cause", "pc"
};

43
44
45
46
47
const char *mips_isa_strings[] =
{
	"MIPS32", "MIPS16e"
};

48
struct mips32_core_reg mips32_core_reg_list_arch_info[MIPS32NUMCOREREGS] =
ntfreak's avatar
ntfreak committed
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
{
	{0, NULL, NULL},
	{1, NULL, NULL},
	{2, NULL, NULL},
	{3, NULL, NULL},
	{4, NULL, NULL},
	{5, NULL, NULL},
	{6, NULL, NULL},
	{7, NULL, NULL},
	{8, NULL, NULL},
	{9, NULL, NULL},
	{10, NULL, NULL},
	{11, NULL, NULL},
	{12, NULL, NULL},
	{13, NULL, NULL},
	{14, NULL, NULL},
	{15, NULL, NULL},
	{16, NULL, NULL},
	{17, NULL, NULL},
	{18, NULL, NULL},
	{19, NULL, NULL},
	{20, NULL, NULL},
	{21, NULL, NULL},
	{22, NULL, NULL},
	{23, NULL, NULL},
	{24, NULL, NULL},
	{25, NULL, NULL},
	{26, NULL, NULL},
	{27, NULL, NULL},
	{28, NULL, NULL},
	{29, NULL, NULL},
	{30, NULL, NULL},
	{31, NULL, NULL},
82

ntfreak's avatar
ntfreak committed
83
84
85
86
87
88
89
90
	{32, NULL, NULL},
	{33, NULL, NULL},
	{34, NULL, NULL},
	{35, NULL, NULL},
	{36, NULL, NULL},
	{37, NULL, NULL},
};

91
92
/* number of mips dummy fp regs fp0 - fp31 + fsr and fir
 * we also add 18 unknown registers to handle gdb requests */
ntfreak's avatar
ntfreak committed
93

94
#define MIPS32NUMFPREGS 34 + 18
ntfreak's avatar
ntfreak committed
95

96
uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0};
ntfreak's avatar
ntfreak committed
97

Zachary T Welch's avatar
Zachary T Welch committed
98
struct reg mips32_gdb_dummy_fp_reg =
ntfreak's avatar
ntfreak committed
99
{
100
101
102
103
104
105
	.name = "GDB dummy floating-point register",
	.value = mips32_gdb_dummy_fp_value,
	.dirty = 0,
	.valid = 1,
	.size = 32,
	.arch_info = NULL,
ntfreak's avatar
ntfreak committed
106
107
};

Zachary T Welch's avatar
Zachary T Welch committed
108
int mips32_get_core_reg(struct reg *reg)
ntfreak's avatar
ntfreak committed
109
110
{
	int retval;
111
	struct mips32_core_reg *mips32_reg = reg->arch_info;
Zachary T Welch's avatar
Zachary T Welch committed
112
	struct target *target = mips32_reg->target;
113
	struct mips32_common *mips32_target = target_to_mips32(target);
114

ntfreak's avatar
ntfreak committed
115
116
117
118
119
120
	if (target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}

	retval = mips32_target->read_core_reg(target, mips32_reg->num);
121

ntfreak's avatar
ntfreak committed
122
123
124
	return retval;
}

Zachary T Welch's avatar
Zachary T Welch committed
125
int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
ntfreak's avatar
ntfreak committed
126
{
127
	struct mips32_core_reg *mips32_reg = reg->arch_info;
Zachary T Welch's avatar
Zachary T Welch committed
128
	struct target *target = mips32_reg->target;
129
	uint32_t value = buf_get_u32(buf, 0, 32);
130

ntfreak's avatar
ntfreak committed
131
132
133
134
	if (target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}
135

ntfreak's avatar
ntfreak committed
136
137
138
139
140
141
142
	buf_set_u32(reg->value, 0, 32, value);
	reg->dirty = 1;
	reg->valid = 1;

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
143
int mips32_read_core_reg(struct target *target, int num)
ntfreak's avatar
ntfreak committed
144
{
145
	uint32_t reg_value;
146
	struct mips32_core_reg *mips_core_reg;
147

ntfreak's avatar
ntfreak committed
148
	/* get pointers to arch-specific information */
149
	struct mips32_common *mips32 = target_to_mips32(target);
150

ntfreak's avatar
ntfreak committed
151
152
153
154
155
156
157
158
	if ((num < 0) || (num >= MIPS32NUMCOREREGS))
		return ERROR_INVALID_ARGUMENTS;

	mips_core_reg = mips32->core_cache->reg_list[num].arch_info;
	reg_value = mips32->core_regs[num];
	buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
	mips32->core_cache->reg_list[num].valid = 1;
	mips32->core_cache->reg_list[num].dirty = 0;
159
160

	return ERROR_OK;
ntfreak's avatar
ntfreak committed
161
162
}

Zachary T Welch's avatar
Zachary T Welch committed
163
int mips32_write_core_reg(struct target *target, int num)
ntfreak's avatar
ntfreak committed
164
{
165
	uint32_t reg_value;
166
	struct mips32_core_reg *mips_core_reg;
167

ntfreak's avatar
ntfreak committed
168
	/* get pointers to arch-specific information */
169
	struct mips32_common *mips32 = target_to_mips32(target);
ntfreak's avatar
ntfreak committed
170
171
172

	if ((num < 0) || (num >= MIPS32NUMCOREREGS))
		return ERROR_INVALID_ARGUMENTS;
173

ntfreak's avatar
ntfreak committed
174
175
176
	reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
	mips_core_reg = mips32->core_cache->reg_list[num].arch_info;
	mips32->core_regs[num] = reg_value;
duane's avatar
duane committed
177
	LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value);
ntfreak's avatar
ntfreak committed
178
179
	mips32->core_cache->reg_list[num].valid = 1;
	mips32->core_cache->reg_list[num].dirty = 0;
180

ntfreak's avatar
ntfreak committed
181
182
183
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
184
int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
ntfreak's avatar
ntfreak committed
185
186
{
	/* get pointers to arch-specific information */
187
	struct mips32_common *mips32 = target_to_mips32(target);
ntfreak's avatar
ntfreak committed
188
	int i;
189

190
191
	/* include floating point registers */
	*reg_list_size = MIPS32NUMCOREREGS + MIPS32NUMFPREGS;
Zachary T Welch's avatar
Zachary T Welch committed
192
	*reg_list = malloc(sizeof(struct reg*) * (*reg_list_size));
193

ntfreak's avatar
ntfreak committed
194
195
196
197
	for (i = 0; i < MIPS32NUMCOREREGS; i++)
	{
		(*reg_list)[i] = &mips32->core_cache->reg_list[i];
	}
198

ntfreak's avatar
ntfreak committed
199
	/* add dummy floating points regs */
200
201
202
203
204
	for (i = MIPS32NUMCOREREGS; i < (MIPS32NUMCOREREGS + MIPS32NUMFPREGS); i++)
	{
		(*reg_list)[i] = &mips32_gdb_dummy_fp_reg;
	}

ntfreak's avatar
ntfreak committed
205
206
207
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
208
int mips32_save_context(struct target *target)
ntfreak's avatar
ntfreak committed
209
210
{
	int i;
211

ntfreak's avatar
ntfreak committed
212
	/* get pointers to arch-specific information */
213
	struct mips32_common *mips32 = target_to_mips32(target);
214
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
215

ntfreak's avatar
ntfreak committed
216
217
	/* read core registers */
	mips32_pracc_read_regs(ejtag_info, mips32->core_regs);
218

ntfreak's avatar
ntfreak committed
219
220
221
222
223
224
225
	for (i = 0; i < MIPS32NUMCOREREGS; i++)
	{
		if (!mips32->core_cache->reg_list[i].valid)
		{
			mips32->read_core_reg(target, i);
		}
	}
226
227

	return ERROR_OK;
ntfreak's avatar
ntfreak committed
228
229
}

Zachary T Welch's avatar
Zachary T Welch committed
230
int mips32_restore_context(struct target *target)
ntfreak's avatar
ntfreak committed
231
232
{
	int i;
233

ntfreak's avatar
ntfreak committed
234
	/* get pointers to arch-specific information */
235
	struct mips32_common *mips32 = target_to_mips32(target);
236
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
237

ntfreak's avatar
ntfreak committed
238
239
240
241
242
243
244
	for (i = 0; i < MIPS32NUMCOREREGS; i++)
	{
		if (mips32->core_cache->reg_list[i].dirty)
		{
			mips32->write_core_reg(target, i);
		}
	}
245

ntfreak's avatar
ntfreak committed
246
247
	/* write core regs */
	mips32_pracc_write_regs(ejtag_info, mips32->core_regs);
248
249

	return ERROR_OK;
ntfreak's avatar
ntfreak committed
250
251
}

Zachary T Welch's avatar
Zachary T Welch committed
252
int mips32_arch_state(struct target *target)
ntfreak's avatar
ntfreak committed
253
{
254
	struct mips32_common *mips32 = target_to_mips32(target);
255

256
257
	LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "",
		mips_isa_strings[mips32->isa_mode],
258
		debug_reason_name(target),
ntfreak's avatar
ntfreak committed
259
		buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32));
260

ntfreak's avatar
ntfreak committed
261
262
263
	return ERROR_OK;
}

264
265
266
267
268
static const struct reg_arch_type mips32_reg_type = {
	.get = mips32_get_core_reg,
	.set = mips32_set_core_reg,
};

Zachary T Welch's avatar
Zachary T Welch committed
269
struct reg_cache *mips32_build_reg_cache(struct target *target)
ntfreak's avatar
ntfreak committed
270
271
{
	/* get pointers to arch-specific information */
272
	struct mips32_common *mips32 = target_to_mips32(target);
ntfreak's avatar
ntfreak committed
273
274

	int num_regs = MIPS32NUMCOREREGS;
275
276
	struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
	struct reg_cache *cache = malloc(sizeof(struct reg_cache));
Zachary T Welch's avatar
Zachary T Welch committed
277
	struct reg *reg_list = malloc(sizeof(struct reg) * num_regs);
278
	struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs);
ntfreak's avatar
ntfreak committed
279
	int i;
280

281
	register_init_dummy(&mips32_gdb_dummy_fp_reg);
282

283
	/* Build the process context cache */
ntfreak's avatar
ntfreak committed
284
285
286
287
288
289
	cache->name = "mips32 registers";
	cache->next = NULL;
	cache->reg_list = reg_list;
	cache->num_regs = num_regs;
	(*cache_p) = cache;
	mips32->core_cache = cache;
290

ntfreak's avatar
ntfreak committed
291
292
293
294
295
296
297
298
299
300
	for (i = 0; i < num_regs; i++)
	{
		arch_info[i] = mips32_core_reg_list_arch_info[i];
		arch_info[i].target = target;
		arch_info[i].mips32_common = mips32;
		reg_list[i].name = mips32_core_reg_list[i];
		reg_list[i].size = 32;
		reg_list[i].value = calloc(1, 4);
		reg_list[i].dirty = 0;
		reg_list[i].valid = 0;
301
		reg_list[i].type = &mips32_reg_type;
ntfreak's avatar
ntfreak committed
302
303
		reg_list[i].arch_info = &arch_info[i];
	}
304

ntfreak's avatar
ntfreak committed
305
306
307
	return cache;
}

Zachary T Welch's avatar
Zachary T Welch committed
308
int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap)
ntfreak's avatar
ntfreak committed
309
310
311
{
	target->arch_info = mips32;
	mips32->common_magic = MIPS32_COMMON_MAGIC;
312

313
314
315
	/* has breakpoint/watchpint unit been scanned */
	mips32->bp_scanned = 0;
	mips32->data_break_list = NULL;
316

317
	mips32->ejtag_info.tap = tap;
ntfreak's avatar
ntfreak committed
318
319
	mips32->read_core_reg = mips32_read_core_reg;
	mips32->write_core_reg = mips32_write_core_reg;
320

ntfreak's avatar
ntfreak committed
321
322
323
	return ERROR_OK;
}

324
325
326
/* run to exit point. return error if exit point was not reached. */
static int mips32_run_and_wait(struct target *target, uint32_t entry_point,
		int timeout_ms, uint32_t exit_point, struct mips32_common *mips32)
ntfreak's avatar
ntfreak committed
327
{
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
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
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
	uint32_t pc;
	int retval;
	/* This code relies on the target specific  resume() and  poll()->debug_entry()
	 * sequence to write register values to the processor and the read them back */
	if ((retval = target_resume(target, 0, entry_point, 0, 1)) != ERROR_OK)
	{
		return retval;
	}

	retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
	/* If the target fails to halt due to the breakpoint, force a halt */
	if (retval != ERROR_OK || target->state != TARGET_HALTED)
	{
		if ((retval = target_halt(target)) != ERROR_OK)
			return retval;
		if ((retval = target_wait_state(target, TARGET_HALTED, 500)) != ERROR_OK)
		{
			return retval;
		}
		return ERROR_TARGET_TIMEOUT;
	}

	pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
	if (pc != exit_point)
	{
		LOG_DEBUG("failed algoritm halted at 0x%" PRIx32 " ", pc);
		return ERROR_TARGET_TIMEOUT;
	}

	return ERROR_OK;
}

int mips32_run_algorithm(struct target *target, int num_mem_params,
		struct mem_param *mem_params, int num_reg_params,
		struct reg_param *reg_params, uint32_t entry_point,
		uint32_t exit_point, int timeout_ms, void *arch_info)
{
	struct mips32_common *mips32 = target_to_mips32(target);
	struct mips32_algorithm *mips32_algorithm_info = arch_info;
	enum mips32_isa_mode isa_mode = mips32->isa_mode;

	uint32_t context[MIPS32NUMCOREREGS];
	int i;
	int retval = ERROR_OK;

	LOG_DEBUG("Running algorithm");

	/* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint
	 * at the exit point */

	if (mips32->common_magic != MIPS32_COMMON_MAGIC)
	{
		LOG_ERROR("current target isn't a MIPS32 target");
		return ERROR_TARGET_INVALID;
	}

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* refresh core register cache */
	for (unsigned i = 0; i < MIPS32NUMCOREREGS; i++)
	{
		if (!mips32->core_cache->reg_list[i].valid)
			mips32->read_core_reg(target, i);
		context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
	}

	for (i = 0; i < num_mem_params; i++)
	{
		if ((retval = target_write_buffer(target, mem_params[i].address,
				mem_params[i].size, mem_params[i].value)) != ERROR_OK)
		{
			return retval;
		}
	}

	for (int i = 0; i < num_reg_params; i++)
	{
		struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0);

		if (!reg)
		{
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
			return ERROR_INVALID_ARGUMENTS;
		}

		if (reg->size != reg_params[i].size)
		{
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
					reg_params[i].reg_name);
			return ERROR_INVALID_ARGUMENTS;
		}

		mips32_set_core_reg(reg, reg_params[i].value);
	}

	mips32->isa_mode = mips32_algorithm_info->isa_mode;

	retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32);

	if (retval != ERROR_OK)
		return retval;

	for (i = 0; i < num_mem_params; i++)
	{
		if (mem_params[i].direction != PARAM_OUT)
		{
			if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size,
					mem_params[i].value)) != ERROR_OK)
			{
				return retval;
			}
		}
	}

	for (i = 0; i < num_reg_params; i++)
	{
		if (reg_params[i].direction != PARAM_OUT)
		{
			struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0);
			if (!reg)
			{
				LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
				return ERROR_INVALID_ARGUMENTS;
			}

			if (reg->size != reg_params[i].size)
			{
				LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
						reg_params[i].reg_name);
				return ERROR_INVALID_ARGUMENTS;
			}

			buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
		}
	}

	/* restore everything we saved before */
	for (i = 0; i < MIPS32NUMCOREREGS; i++)
	{
		uint32_t regvalue;
		regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
		if (regvalue != context[i])
		{
			LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
				mips32->core_cache->reg_list[i].name, context[i]);
			buf_set_u32(mips32->core_cache->reg_list[i].value,
					0, 32, context[i]);
			mips32->core_cache->reg_list[i].valid = 1;
			mips32->core_cache->reg_list[i].dirty = 1;
		}
	}

	mips32->isa_mode = isa_mode;

ntfreak's avatar
ntfreak committed
486
487
	return ERROR_OK;
}
488

Zachary T Welch's avatar
Zachary T Welch committed
489
int mips32_examine(struct target *target)
490
{
491
	struct mips32_common *mips32 = target_to_mips32(target);
492

ntfreak's avatar
ntfreak committed
493
	if (!target_was_examined(target))
494
	{
495
		target_set_examined(target);
496

497
498
499
500
501
502
503
		/* we will configure later */
		mips32->bp_scanned = 0;
		mips32->num_inst_bpoints = 0;
		mips32->num_data_bpoints = 0;
		mips32->num_inst_bpoints_avail = 0;
		mips32->num_data_bpoints_avail = 0;
	}
504

505
506
507
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
508
int mips32_configure_break_unit(struct target *target)
509
510
{
	/* get pointers to arch-specific information */
511
	struct mips32_common *mips32 = target_to_mips32(target);
512
	int retval;
513
	uint32_t dcr, bpinfo;
514
	int i;
515

516
517
	if (mips32->bp_scanned)
		return ERROR_OK;
518

519
520
521
	/* get info about breakpoint support */
	if ((retval = target_read_u32(target, EJTAG_DCR, &dcr)) != ERROR_OK)
		return retval;
522

523
	if (dcr & EJTAG_DCR_IB)
524
525
526
527
	{
		/* get number of inst breakpoints */
		if ((retval = target_read_u32(target, EJTAG_IBS, &bpinfo)) != ERROR_OK)
			return retval;
528

529
530
		mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F;
		mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints;
531
		mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator));
532
533
534
535
		for (i = 0; i < mips32->num_inst_bpoints; i++)
		{
			mips32->inst_break_list[i].reg_address = EJTAG_IBA1 + (0x100 * i);
		}
536

537
538
539
540
		/* clear IBIS reg */
		if ((retval = target_write_u32(target, EJTAG_IBS, 0)) != ERROR_OK)
			return retval;
	}
541

542
	if (dcr & EJTAG_DCR_DB)
543
544
545
546
	{
		/* get number of data breakpoints */
		if ((retval = target_read_u32(target, EJTAG_DBS, &bpinfo)) != ERROR_OK)
			return retval;
547

548
549
		mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F;
		mips32->num_data_bpoints_avail = mips32->num_data_bpoints;
550
		mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator));
551
552
553
554
		for (i = 0; i < mips32->num_data_bpoints; i++)
		{
			mips32->data_break_list[i].reg_address = EJTAG_DBA1 + (0x100 * i);
		}
555

556
557
558
559
		/* clear DBIS reg */
		if ((retval = target_write_u32(target, EJTAG_DBS, 0)) != ERROR_OK)
			return retval;
	}
560

561
562
	LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints,
			mips32->num_data_bpoints);
563

564
	mips32->bp_scanned = 1;
565

566
567
	return ERROR_OK;
}
568

Zachary T Welch's avatar
Zachary T Welch committed
569
int mips32_enable_interrupts(struct target *target, int enable)
570
571
572
{
	int retval;
	int update = 0;
573
	uint32_t dcr;
574

575
576
577
	/* read debug control register */
	if ((retval = target_read_u32(target, EJTAG_DCR, &dcr)) != ERROR_OK)
		return retval;
578

579
580
	if (enable)
	{
581
		if (!(dcr & EJTAG_DCR_INTE))
582
583
		{
			/* enable interrupts */
584
			dcr |= EJTAG_DCR_INTE;
585
586
587
588
589
			update = 1;
		}
	}
	else
	{
590
		if (dcr & EJTAG_DCR_INTE)
591
592
		{
			/* disable interrupts */
593
			dcr &= ~EJTAG_DCR_INTE;
594
595
596
			update = 1;
		}
	}
597

598
599
600
601
602
	if (update)
	{
		if ((retval = target_write_u32(target, EJTAG_DCR, dcr)) != ERROR_OK)
			return retval;
	}
603

604
605
	return ERROR_OK;
}
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752

int mips32_checksum_memory(struct target *target, uint32_t address,
		uint32_t count, uint32_t* checksum)
{
	struct working_area *crc_algorithm;
	struct reg_param reg_params[2];
	struct mips32_algorithm mips32_info;
	int retval;
	uint32_t i;

	static const uint32_t mips_crc_code[] =
	{
		0x248C0000,		/* addiu 	$t4, $a0, 0 */
		0x24AA0000,		/* addiu	$t2, $a1, 0 */
		0x2404FFFF,		/* addiu	$a0, $zero, 0xffffffff */
		0x10000010,		/* beq		$zero, $zero, ncomp */
		0x240B0000,		/* addiu	$t3, $zero, 0 */
						/* nbyte: */
		0x81850000,		/* lb		$a1, ($t4) */
		0x218C0001,		/* addi		$t4, $t4, 1 */
		0x00052E00,		/* sll		$a1, $a1, 24 */
		0x3C0204C1,		/* lui		$v0, 0x04c1 */
		0x00852026,		/* xor		$a0, $a0, $a1 */
		0x34471DB7,		/* ori		$a3, $v0, 0x1db7 */
		0x00003021,		/* addu		$a2, $zero, $zero */
						/* loop: */
		0x00044040,		/* sll		$t0, $a0, 1 */
		0x24C60001,		/* addiu	$a2, $a2, 1 */
		0x28840000,		/* slti		$a0, $a0, 0 */
		0x01074826,		/* xor		$t1, $t0, $a3 */
		0x0124400B,		/* movn		$t0, $t1, $a0 */
		0x28C30008,		/* slti		$v1, $a2, 8 */
		0x1460FFF9,		/* bne		$v1, $zero, loop */
		0x01002021,		/* addu		$a0, $t0, $zero */
						/* ncomp: */
		0x154BFFF0,		/* bne		$t2, $t3, nbyte */
		0x256B0001,		/* addiu	$t3, $t3, 1 */
		0x7000003F,		/* sdbbp */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(mips_crc_code); i++)
		target_write_u32(target, crc_algorithm->address + i*sizeof(uint32_t), mips_crc_code[i]);

	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
	mips32_info.isa_mode = MIPS32_ISA_MIPS32;

	init_reg_param(&reg_params[0], "a0", 32, PARAM_IN_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

	init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, count);

	if ((retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
			crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), 10000,
			&mips32_info)) != ERROR_OK)
	{
		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		target_free_working_area(target, crc_algorithm);
		return 0;
	}

	*checksum = buf_get_u32(reg_params[0].value, 0, 32);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);

	target_free_working_area(target, crc_algorithm);

	return ERROR_OK;
}

/** Checks whether a memory region is zeroed. */
int mips32_blank_check_memory(struct target *target,
		uint32_t address, uint32_t count, uint32_t* blank)
{
	struct working_area *erase_check_algorithm;
	struct reg_param reg_params[3];
	struct mips32_algorithm mips32_info;
	int retval;
	uint32_t i;

	static const uint32_t erase_check_code[] =
	{
						/* nbyte: */
		0x80880000,		/* lb		$t0, ($a0) */
		0x00C83024,		/* and		$a2, $a2, $t0 */
		0x24A5FFFF,		/* addiu	$a1, $a1, -1 */
		0x14A0FFFC,		/* bne		$a1, $zero, nbyte */
		0x24840001,		/* addiu	$a0, $a0, 1 */
		0x7000003F		/* sdbbp */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(erase_check_code); i++)
	{
		target_write_u32(target, erase_check_algorithm->address + i*sizeof(uint32_t),
				erase_check_code[i]);
	}

	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
	mips32_info.isa_mode = MIPS32_ISA_MIPS32;

	init_reg_param(&reg_params[0], "a0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

	init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, count);

	init_reg_param(&reg_params[2], "a2", 32, PARAM_IN_OUT);
	buf_set_u32(reg_params[2].value, 0, 32, 0xff);

	if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
			erase_check_algorithm->address,
			erase_check_algorithm->address + (sizeof(erase_check_code)-2),
			10000, &mips32_info)) != ERROR_OK)
	{
		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		destroy_reg_param(&reg_params[2]);
		target_free_working_area(target, erase_check_algorithm);
		return 0;
	}

	*blank = buf_get_u32(reg_params[2].value, 0, 32);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);

	target_free_working_area(target, erase_check_algorithm);

	return ERROR_OK;
}