Severe bug in Pracc code
[openocd.git] / src / target / mips32_pracc.c
1 /***************************************************************************
2 * Copyright (C) 2008 by Spencer Oliver *
3 * spen@spen-soft.co.uk *
4 * *
5 * Copyright (C) 2008 by David T.L. Wong *
6 * *
7 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
8 * *
9 * Copyright (C) 2011 by Drasko DRASKOVIC *
10 * drasko.draskovic@gmail.com *
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program; if not, write to the *
24 * Free Software Foundation, Inc., *
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26 ***************************************************************************/
27
28 /*
29 * This version has optimized assembly routines for 32 bit operations:
30 * - read word
31 * - write word
32 * - write array of words
33 *
34 * One thing to be aware of is that the MIPS32 cpu will execute the
35 * instruction after a branch instruction (one delay slot).
36 *
37 * For example:
38 * LW $2, ($5 +10)
39 * B foo
40 * LW $1, ($2 +100)
41 *
42 * The LW $1, ($2 +100) instruction is also executed. If this is
43 * not wanted a NOP can be inserted:
44 *
45 * LW $2, ($5 +10)
46 * B foo
47 * NOP
48 * LW $1, ($2 +100)
49 *
50 * or the code can be changed to:
51 *
52 * B foo
53 * LW $2, ($5 +10)
54 * LW $1, ($2 +100)
55 *
56 * The original code contained NOPs. I have removed these and moved
57 * the branches.
58 *
59 * I also moved the PRACC_STACK to 0xFF204000. This allows
60 * the use of 16 bits offsets to get pointers to the input
61 * and output area relative to the stack. Note that the stack
62 * isn't really a stack (the stack pointer is not 'moving')
63 * but a FIFO simulated in software.
64 *
65 * These changes result in a 35% speed increase when programming an
66 * external flash.
67 *
68 * More improvement could be gained if the registers do no need
69 * to be preserved but in that case the routines should be aware
70 * OpenOCD is used as a flash programmer or as a debug tool.
71 *
72 * Nico Coesel
73 */
74
75 #ifdef HAVE_CONFIG_H
76 #include "config.h"
77 #endif
78
79 #include <helper/time_support.h>
80
81 #include "mips32.h"
82 #include "mips32_pracc.h"
83
84 struct mips32_pracc_context {
85 uint32_t *local_iparam;
86 int num_iparam;
87 uint32_t *local_oparam;
88 int num_oparam;
89 const uint32_t *code;
90 int code_len;
91 uint32_t stack[32];
92 int stack_offset;
93 struct mips_ejtag *ejtag_info;
94 };
95
96 static int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info,
97 uint32_t addr, int count, uint8_t *buf);
98 static int mips32_pracc_read_mem16(struct mips_ejtag *ejtag_info,
99 uint32_t addr, int count, uint16_t *buf);
100 static int mips32_pracc_read_mem32(struct mips_ejtag *ejtag_info,
101 uint32_t addr, int count, uint32_t *buf);
102 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info,
103 uint32_t addr, uint32_t *buf);
104
105 static int mips32_pracc_write_mem8(struct mips_ejtag *ejtag_info,
106 uint32_t addr, int count, uint8_t *buf);
107 static int mips32_pracc_write_mem16(struct mips_ejtag *ejtag_info,
108 uint32_t addr, int count, uint16_t *buf);
109 static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info,
110 uint32_t addr, int count, uint32_t *buf);
111 static int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info,
112 uint32_t addr, uint32_t *buf);
113
114 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
115 uint32_t start_addr, uint32_t end_addr);
116 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
117 uint32_t start_addr, uint32_t end_addr);
118
119 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
120 {
121 uint32_t ejtag_ctrl;
122 long long then = timeval_ms();
123 int timeout;
124 int retval;
125
126 /* wait for the PrAcc to become "1" */
127 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
128
129 while (1) {
130 ejtag_ctrl = ejtag_info->ejtag_ctrl;
131 retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
132 if (retval != ERROR_OK)
133 return retval;
134
135 if (ejtag_ctrl & EJTAG_CTRL_PRACC)
136 break;
137
138 timeout = timeval_ms() - then;
139 if (timeout > 1000) {
140 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
141 return ERROR_JTAG_DEVICE_ERROR;
142 }
143 }
144
145 *ctrl = ejtag_ctrl;
146 return ERROR_OK;
147 }
148
149 static int mips32_pracc_exec_read(struct mips32_pracc_context *ctx, uint32_t address)
150 {
151 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
152 int offset;
153 uint32_t ejtag_ctrl, data;
154
155 if ((address >= MIPS32_PRACC_PARAM_IN)
156 && (address < MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) {
157 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
158 data = ctx->local_iparam[offset];
159 } else if ((address >= MIPS32_PRACC_PARAM_OUT)
160 && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) {
161 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
162 data = ctx->local_oparam[offset];
163 } else if ((address >= MIPS32_PRACC_TEXT)
164 && (address < MIPS32_PRACC_TEXT + ctx->code_len * 4)) {
165 offset = (address - MIPS32_PRACC_TEXT) / 4;
166 data = ctx->code[offset];
167 } else if (address == MIPS32_PRACC_STACK) {
168 if (ctx->stack_offset <= 0) {
169 LOG_ERROR("Error: Pracc stack out of bounds");
170 return ERROR_JTAG_DEVICE_ERROR;
171 }
172 /* save to our debug stack */
173 data = ctx->stack[--ctx->stack_offset];
174 } else {
175 /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
176 * to start of debug vector */
177
178 LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address);
179 return ERROR_JTAG_DEVICE_ERROR;
180 }
181
182 /* Send the data out */
183 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
184 mips_ejtag_drscan_32_out(ctx->ejtag_info, data);
185
186 /* Clear the access pending bit (let the processor eat!) */
187 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
188 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
189 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
190
191 return jtag_execute_queue();
192 }
193
194 static int mips32_pracc_exec_write(struct mips32_pracc_context *ctx, uint32_t address)
195 {
196 uint32_t ejtag_ctrl, data;
197 int offset;
198 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
199 int retval;
200
201 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
202 retval = mips_ejtag_drscan_32(ctx->ejtag_info, &data);
203 if (retval != ERROR_OK)
204 return retval;
205
206 /* Clear access pending bit */
207 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
208 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
209 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
210
211 retval = jtag_execute_queue();
212 if (retval != ERROR_OK)
213 return retval;
214
215 if ((address >= MIPS32_PRACC_PARAM_IN)
216 && (address < MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) {
217 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
218 ctx->local_iparam[offset] = data;
219 } else if ((address >= MIPS32_PRACC_PARAM_OUT)
220 && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) {
221 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
222 ctx->local_oparam[offset] = data;
223 } else if (address == MIPS32_PRACC_STACK) {
224 if (ctx->stack_offset >= 32) {
225 LOG_ERROR("Error: Pracc stack out of bounds");
226 return ERROR_JTAG_DEVICE_ERROR;
227 }
228 /* save data onto our stack */
229 ctx->stack[ctx->stack_offset++] = data;
230 } else {
231 LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address);
232 return ERROR_JTAG_DEVICE_ERROR;
233 }
234
235 return ERROR_OK;
236 }
237
238 int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code,
239 int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle)
240 {
241 uint32_t ejtag_ctrl;
242 uint32_t address;
243 struct mips32_pracc_context ctx;
244 int retval;
245 int pass = 0;
246
247 ctx.local_iparam = param_in;
248 ctx.local_oparam = param_out;
249 ctx.num_iparam = num_param_in;
250 ctx.num_oparam = num_param_out;
251 ctx.code = code;
252 ctx.code_len = code_len;
253 ctx.ejtag_info = ejtag_info;
254 ctx.stack_offset = 0;
255
256 while (1) {
257 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
258 if (retval != ERROR_OK)
259 return retval;
260
261 address = 0;
262 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
263 retval = mips_ejtag_drscan_32(ejtag_info, &address);
264 if (retval != ERROR_OK)
265 return retval;
266
267 /* Check for read or write */
268 if (ejtag_ctrl & EJTAG_CTRL_PRNW) {
269 retval = mips32_pracc_exec_write(&ctx, address);
270 if (retval != ERROR_OK)
271 return retval;
272 } else {
273 /* Check to see if its reading at the debug vector. The first pass through
274 * the module is always read at the vector, so the first one we allow. When
275 * the second read from the vector occurs we are done and just exit. */
276 if ((address == MIPS32_PRACC_TEXT) && (pass++))
277 break;
278
279 retval = mips32_pracc_exec_read(&ctx, address);
280 if (retval != ERROR_OK)
281 return retval;
282 }
283
284 if (cycle == 0)
285 break;
286 }
287
288 /* stack sanity check */
289 if (ctx.stack_offset != 0)
290 LOG_DEBUG("Pracc Stack not zero");
291
292 return ERROR_OK;
293 }
294
295 int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
296 {
297 switch (size) {
298 case 1:
299 return mips32_pracc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf);
300 case 2:
301 return mips32_pracc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf);
302 case 4:
303 if (count == 1)
304 return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf);
305 else
306 return mips32_pracc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf);
307 }
308
309 return ERROR_OK;
310 }
311
312 static int mips32_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
313 {
314 static const uint32_t code[] = {
315 /* start: */
316 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
317 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
318 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
319 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
320 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
321 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
322 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
323
324 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
325 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
326 MIPS32_LW(9, 0, 8), /* $9 = mem[$8]; read addr */
327 MIPS32_LW(10, 4, 8), /* $10 = mem[$8 + 4]; read count */
328 MIPS32_LUI(11, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
329 MIPS32_ORI(11, 11, LOWER16(MIPS32_PRACC_PARAM_OUT)),
330 /* loop: */
331 MIPS32_BEQ(0, 10, 8), /* beq 0, $10, end */
332 MIPS32_NOP,
333
334 MIPS32_LW(8, 0, 9), /* lw $8,0($9), Load $8 with the word @mem[$9] */
335 MIPS32_SW(8, 0, 11), /* sw $8,0($11) */
336
337 MIPS32_ADDI(10, 10, NEG16(1)), /* $10-- */
338 MIPS32_ADDI(9, 9, 4), /* $1 += 4 */
339 MIPS32_ADDI(11, 11, 4), /* $11 += 4 */
340
341 MIPS32_B(NEG16(8)), /* b loop */
342 MIPS32_NOP,
343 /* end: */
344 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
345 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
346 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
347 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
348 MIPS32_B(NEG16(27)), /* b start */
349 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
350 };
351
352 int retval = ERROR_OK;
353 int blocksize;
354 int wordsread;
355 uint32_t param_in[2];
356
357 wordsread = 0;
358
359 while (count > 0) {
360 blocksize = count;
361 if (count > 0x400)
362 blocksize = 0x400;
363
364 param_in[0] = addr;
365 param_in[1] = blocksize;
366
367 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
368 ARRAY_SIZE(param_in), param_in, blocksize, &buf[wordsread], 1);
369 if (retval != ERROR_OK)
370 return retval;
371
372 count -= blocksize;
373 addr += blocksize*sizeof(uint32_t);
374 wordsread += blocksize;
375 }
376
377 return retval;
378 }
379
380 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
381 {
382 static const uint32_t code[] = {
383 /* start: */
384 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
385 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
386 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
387 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
388
389 MIPS32_LW(8, NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN), 15), /* load R8 @ param_in[0] = address */
390
391 MIPS32_LW(8, 0, 8), /* lw $8,0($8), Load $8 with the word @mem[$8] */
392 MIPS32_SW(8, NEG16(MIPS32_PRACC_STACK - MIPS32_PRACC_PARAM_OUT), 15), /* store R8 @ param_out[0] */
393
394 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
395 MIPS32_B(NEG16(9)), /* b start */
396 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
397 };
398
399 int retval = ERROR_OK;
400 uint32_t param_in[1];
401
402 param_in[0] = addr;
403
404 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
405 ARRAY_SIZE(param_in), param_in, 1, buf, 1);
406 if (retval != ERROR_OK)
407 return retval;
408
409 return retval;
410 }
411
412 static int mips32_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
413 {
414 static const uint32_t code[] = {
415 /* start: */
416 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
417 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
418 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
419 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
420 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
421 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
422 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
423
424 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
425 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
426 MIPS32_LW(9, 0, 8), /* $9 = mem[$8]; read addr */
427 MIPS32_LW(10, 4, 8), /* $10 = mem[$8 + 4]; read count */
428 MIPS32_LUI(11, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
429 MIPS32_ORI(11, 11, LOWER16(MIPS32_PRACC_PARAM_OUT)),
430 /* loop: */
431 MIPS32_BEQ(0, 10, 8), /* beq 0, $10, end */
432 MIPS32_NOP,
433
434 MIPS32_LHU(8, 0, 9), /* lw $8,0($9), Load $8 with the halfword @mem[$9] */
435 MIPS32_SW(8, 0, 11), /* sw $8,0($11) */
436
437 MIPS32_ADDI(10, 10, NEG16(1)), /* $10-- */
438 MIPS32_ADDI(9, 9, 2), /* $9 += 2 */
439 MIPS32_ADDI(11, 11, 4), /* $11 += 4 */
440 MIPS32_B(NEG16(8)), /* b loop */
441 MIPS32_NOP,
442 /* end: */
443 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
444 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
445 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
446 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
447 MIPS32_B(NEG16(27)), /* b start */
448 MIPS32_MFC0(15, 30, 0), /* move COP0 DeSave to $15 */
449 };
450
451 /* TODO remove array */
452 uint32_t *param_out = malloc(count * sizeof(uint32_t));
453 if (param_out == NULL) {
454 LOG_ERROR("Out of memory");
455 return ERROR_FAIL;
456 }
457
458 int retval = ERROR_OK;
459 int blocksize;
460 int hwordsread = 0;
461 uint32_t param_in[2];
462
463 while (count > 0) {
464 blocksize = count;
465 if (count > 0x400)
466 blocksize = 0x400;
467
468 param_in[0] = addr;
469 param_in[1] = blocksize;
470
471 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
472 ARRAY_SIZE(param_in), param_in, blocksize, &param_out[hwordsread], 1);
473
474 if (retval != ERROR_OK)
475 return retval;
476
477 count -= blocksize;
478 addr += blocksize*sizeof(uint16_t);
479 hwordsread += blocksize;
480 }
481
482 int i;
483 for (i = 0; i < hwordsread; i++)
484 buf[i] = param_out[i];
485
486 free(param_out);
487 return retval;
488 }
489
490 static int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
491 {
492 static const uint32_t code[] = {
493 /* start: */
494 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
495 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
496 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
497 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
498 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
499 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
500 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
501
502 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
503 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
504 MIPS32_LW(9, 0, 8), /* $9 = mem[$8]; read addr */
505 MIPS32_LW(10, 4, 8), /* $10 = mem[$8 + 4]; read count */
506 MIPS32_LUI(11, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
507 MIPS32_ORI(11, 11, LOWER16(MIPS32_PRACC_PARAM_OUT)),
508 /* loop: */
509 MIPS32_BEQ(0, 10, 8), /* beq 0, $10, end */
510 MIPS32_NOP,
511
512 MIPS32_LBU(8, 0, 9), /* lw $8,0($9), Load t4 with the byte @mem[t1] */
513 MIPS32_SW(8, 0, 11), /* sw $8,0($11) */
514
515 MIPS32_ADDI(10, 10, NEG16(1)), /* $10-- */
516 MIPS32_ADDI(9, 9, 1), /* $9 += 1 */
517 MIPS32_ADDI(11, 11, 4), /* $11 += 4 */
518 MIPS32_B(NEG16(8)), /* b loop */
519 MIPS32_NOP,
520 /* end: */
521 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
522 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
523 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
524 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
525 MIPS32_B(NEG16(27)), /* b start */
526 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
527 };
528
529 /* TODO remove array */
530 uint32_t *param_out = malloc(count * sizeof(uint32_t));
531 if (param_out == NULL) {
532 LOG_ERROR("Out of memory");
533 return ERROR_FAIL;
534 }
535
536 int retval = ERROR_OK;
537 int blocksize;
538 uint32_t param_in[2];
539 int bytesread = 0;
540
541 while (count > 0) {
542 blocksize = count;
543 if (count > 0x400)
544 blocksize = 0x400;
545
546 param_in[0] = addr;
547 param_in[1] = blocksize;
548
549 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
550 ARRAY_SIZE(param_in), param_in, count, &param_out[bytesread], 1);
551
552 if (retval != ERROR_OK)
553 return retval;
554
555 count -= blocksize;
556 addr += blocksize;
557 bytesread += blocksize;
558 }
559 int i;
560 for (i = 0; i < bytesread; i++)
561 buf[i] = param_out[i];
562
563 free(param_out);
564 return retval;
565 }
566
567 int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel)
568 {
569 /**
570 * Do not make this code static, but regenerate it every time,
571 * as 5th element has to be changed to add parameters
572 */
573 uint32_t code[] = {
574 /* start: */
575 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
576 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
577 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
578 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
579 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
580
581 /* 5 */ MIPS32_MFC0(8, 0, 0), /* move COP0 [cp0_reg select] to $8 */
582
583 MIPS32_LUI(9, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
584 MIPS32_ORI(9, 9, LOWER16(MIPS32_PRACC_PARAM_OUT)),
585 MIPS32_SW(8, 0, 9), /* sw $8,0($9) */
586
587 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
588 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
589 MIPS32_B(NEG16(12)), /* b start */
590 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
591 };
592
593 /**
594 * Note that our input parametes cp0_reg and cp0_sel
595 * are numbers (not gprs) which make part of mfc0 instruction opcode.
596 *
597 * These are not fix, but can be different for each mips32_cp0_read() function call,
598 * and that is why we must insert them directly into opcode,
599 * i.e. we can not pass it on EJTAG microprogram stack (via param_in),
600 * and put them into the gprs later from MIPS32_PRACC_STACK
601 * because mfc0 do not use gpr as a parameter for the cp0_reg and select part,
602 * but plain (immediate) number.
603 *
604 * MIPS32_MTC0 is implemented via MIPS32_R_INST macro.
605 * In order to insert our parameters, we must change rd and funct fields.
606 */
607 code[5] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct of MIPS32_R_INST macro */
608
609 /* TODO remove array */
610 uint32_t *param_out = val;
611 int retval;
612
613 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 1, param_out, 1);
614
615 return retval;
616 }
617
618 int mips32_cp0_write(struct mips_ejtag *ejtag_info,
619 uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel)
620 {
621 uint32_t code[] = {
622 /* start: */
623 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
624 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
625 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
626 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
627 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
628
629 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
630 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
631 MIPS32_LW(9, 0, 8), /* Load write val to $9 */
632
633 /* 8 */ MIPS32_MTC0(9, 0, 0), /* move $9 to COP0 [cp0_reg select] */
634
635 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
636 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
637 MIPS32_B(NEG16(12)), /* b start */
638 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
639 };
640
641 /**
642 * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro.
643 * In order to insert our parameters, we must change rd and funct fields.
644 */
645 code[8] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct fields of MIPS32_R_INST macro */
646
647 /* TODO remove array */
648 uint32_t *param_in = malloc(1 * sizeof(uint32_t));
649 int retval;
650 param_in[0] = val;
651
652 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 1, param_in, 0, NULL, 1);
653
654 free(param_in);
655
656 return retval;
657 }
658
659 /**
660 * \b mips32_pracc_sync_cache
661 *
662 * Synchronize Caches to Make Instruction Writes Effective
663 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
664 * Document Number: MD00086, Revision 2.00, June 9, 2003)
665 *
666 * When the instruction stream is written, the SYNCI instruction should be used
667 * in conjunction with other instructions to make the newly-written instructions effective.
668 *
669 * Explanation :
670 * A program that loads another program into memory is actually writing the D- side cache.
671 * The instructions it has loaded can't be executed until they reach the I-cache.
672 *
673 * After the instructions have been written, the loader should arrange
674 * to write back any containing D-cache line and invalidate any locations
675 * already in the I-cache.
676 *
677 * You can do that with cache instructions, but those instructions are only available in kernel mode,
678 * and a loader writing instructions for the use of its own process need not be privileged software.
679 *
680 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
681 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
682 * That is, it arranges a D-cache write-back and an I-cache invalidate.
683 *
684 * To employ synci at user level, you need to know the size of a cache line,
685 * and that can be obtained with a rdhwr SYNCI_Step
686 * from one of the standard “hardware registers”.
687 */
688 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
689 uint32_t start_addr, uint32_t end_addr)
690 {
691 static const uint32_t code[] = {
692 /* start: */
693 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
694 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
695 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
696 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
697 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
698 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
699 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
700
701 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
702 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
703 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
704 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
705
706 MIPS32_RDHWR(11, MIPS32_SYNCI_STEP), /* $11 = MIPS32_SYNCI_STEP */
707 MIPS32_BEQ(11, 0, 6), /* beq $11, $0, end */
708 MIPS32_NOP,
709 /* synci_loop : */
710 MIPS32_SYNCI(0, 9), /* synci 0($9) */
711 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */
712 MIPS32_BNE(8, 0, NEG16(3)), /* bne $8, $0, synci_loop */
713 MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */
714 MIPS32_SYNC,
715 /* end: */
716 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
717 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
718 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
719 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
720 MIPS32_B(NEG16(24)), /* b start */
721 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
722 };
723
724 /* TODO remove array */
725 uint32_t *param_in = malloc(2 * sizeof(uint32_t));
726 int retval;
727 param_in[0] = start_addr;
728 param_in[1] = end_addr;
729
730 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 2, param_in, 0, NULL, 1);
731
732 free(param_in);
733
734 return retval;
735 }
736
737 /**
738 * \b mips32_pracc_clean_invalidate_cache
739 *
740 * Writeback D$ and Invalidate I$
741 * so that the instructions written can be visible to CPU
742 */
743 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
744 uint32_t start_addr, uint32_t end_addr)
745 {
746 static const uint32_t code[] = {
747 /* start: */
748 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
749 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
750 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
751 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
752 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
753 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
754 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
755
756 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
757 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
758 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
759 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
760 MIPS32_LW(11, 8, 8), /* Load write clsiz to $11 */
761
762 /* cache_loop: */
763 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */
764 MIPS32_BGTZ(8, 6), /* bgtz $8, end */
765 MIPS32_NOP,
766
767 MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK, 0, 9), /* cache Hit_Writeback_D, 0($9) */
768 MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE, 0, 9), /* cache Hit_Invalidate_I, 0($9) */
769
770 MIPS32_ADDU(9, 9, 11), /* $9 += $11 */
771
772 MIPS32_B(NEG16(7)), /* b cache_loop */
773 MIPS32_NOP,
774 /* end: */
775 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
776 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
777 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
778 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
779 MIPS32_B(NEG16(25)), /* b start */
780 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
781 };
782
783 /**
784 * Find cache line size in bytes
785 */
786 uint32_t conf;
787 uint32_t dl, clsiz;
788
789 mips32_cp0_read(ejtag_info, &conf, 16, 1);
790 dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT;
791
792 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */
793 clsiz = 0x2 << dl;
794
795 /* TODO remove array */
796 uint32_t *param_in = malloc(3 * sizeof(uint32_t));
797 int retval;
798 param_in[0] = start_addr;
799 param_in[1] = end_addr;
800 param_in[2] = clsiz;
801
802 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 3, param_in, 0, NULL, 1);
803
804 free(param_in);
805
806 return retval;
807 }
808
809
810 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
811 {
812 int retval;
813
814 switch (size) {
815 case 1:
816 retval = mips32_pracc_write_mem8(ejtag_info, addr, count, (uint8_t *)buf);
817 break;
818 case 2:
819 retval = mips32_pracc_write_mem16(ejtag_info, addr, count, (uint16_t *)buf);
820 break;
821 case 4:
822 if (count == 1)
823 retval = mips32_pracc_write_u32(ejtag_info, addr, (uint32_t *)buf);
824 else
825 retval = mips32_pracc_write_mem32(ejtag_info, addr, count, (uint32_t *)buf);
826 break;
827 default:
828 retval = ERROR_FAIL;
829 }
830
831 /**
832 * If we are in the cachable regoion and cache is activated,
833 * we must clean D$ + invalidate I$ after we did the write,
834 * so that changes do not continue to live only in D$, but to be
835 * replicated in I$ also (maybe we wrote the istructions)
836 */
837 uint32_t conf = 0;
838 int cached = 0;
839
840 if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff)))
841 return retval; /*Nothing to do*/
842
843 mips32_cp0_read(ejtag_info, &conf, 16, 0);
844
845 switch (KSEGX(addr)) {
846 case KUSEG:
847 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
848 break;
849 case KSEG0:
850 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
851 break;
852 case KSEG2:
853 case KSEG3:
854 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
855 break;
856 default:
857 /* what ? */
858 break;
859 }
860
861 /**
862 * Check cachablitiy bits coherency algorithm -
863 * is the region cacheable or uncached.
864 * If cacheable we have to synchronize the cache
865 */
866 if (cached == 0x3) {
867 uint32_t start_addr, end_addr;
868 uint32_t rel;
869
870 start_addr = addr;
871 end_addr = addr + count * size;
872
873 /** select cache synchronisation mechanism based on Architecture Release */
874 rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
875 switch (rel) {
876 case MIPS32_ARCH_REL1:
877 /* MIPS32/64 Release 1 - we must use cache instruction */
878 mips32_pracc_clean_invalidate_cache(ejtag_info, start_addr, end_addr);
879 break;
880 case MIPS32_ARCH_REL2:
881 /* MIPS32/64 Release 2 - we can use synci instruction */
882 mips32_pracc_sync_cache(ejtag_info, start_addr, end_addr);
883 break;
884 default:
885 /* what ? */
886 break;
887 }
888 }
889
890 return retval;
891 }
892
893 static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
894 {
895 static const uint32_t code[] = {
896 /* start: */
897 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
898 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
899 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
900 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
901 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
902 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
903 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
904
905 MIPS32_ADDI(8, 15, NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)), /* $8= MIPS32_PRACC_PARAM_IN */
906 MIPS32_LW(9, 0, 8), /* Load write addr to $9 */
907 MIPS32_LW(10, 4, 8), /* Load write count to $10 */
908 MIPS32_ADDI(8, 8, 8), /* $8 += 8 beginning of data */
909
910 /* loop: */
911 MIPS32_LW(11, 0, 8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
912 MIPS32_SW(11, 0, 9), /* sw $11,0($9) */
913
914 MIPS32_ADDI(9, 9, 4), /* $9 += 4 */
915 MIPS32_BNE(10, 9, NEG16(4)), /* bne $10, $9, loop */
916 MIPS32_ADDI(8, 8, 4), /* $8 += 4 */
917
918 /* end: */
919 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
920 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
921 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
922 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
923 MIPS32_B(NEG16(21)), /* b start */
924 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
925 };
926
927 /* TODO remove array */
928 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
929 param_in[0] = addr;
930 param_in[1] = addr + (count * sizeof(uint32_t)); /* last address */
931
932 memcpy(&param_in[2], buf, count * sizeof(uint32_t));
933
934 int retval;
935 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
936 count + 2, param_in, 0, NULL, 1);
937
938 free(param_in);
939
940 return retval;
941 }
942
943 static int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
944 {
945 static const uint32_t code[] = {
946 /* start: */
947 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
948 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
949 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
950 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
951 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
952
953 MIPS32_LW(8, NEG16((MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)-4), 15), /* load R8 @ param_in[1] = data */
954 MIPS32_LW(9, NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN), 15), /* load R9 @ param_in[0] = address */
955
956 MIPS32_SW(8, 0, 9), /* sw $8,0($9) */
957
958 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
959 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
960 MIPS32_B(NEG16(11)), /* b start */
961 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
962 };
963
964 /* TODO remove array */
965 uint32_t param_in[1 + 1];
966 param_in[0] = addr;
967 param_in[1] = *buf;
968
969 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
970 ARRAY_SIZE(param_in), param_in, 0, NULL, 1);
971 }
972
973 static int mips32_pracc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
974 {
975 static const uint32_t code[] = {
976 /* start: */
977 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
978 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
979 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
980 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
981 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
982 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
983 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
984
985 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
986 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
987 MIPS32_LW(9, 0, 8), /* Load write addr to $9 */
988 MIPS32_LW(10, 4, 8), /* Load write count to $10 */
989 MIPS32_ADDI(8, 8, 8), /* $8 += 8 */
990 /* loop: */
991 MIPS32_BEQ(0, 10, 8), /* beq $0, $10, end */
992 MIPS32_NOP,
993
994 MIPS32_LW(11, 0, 8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
995 MIPS32_SH(11, 0, 9), /* sh $11,0($9) */
996
997 MIPS32_ADDI(10, 10, NEG16(1)), /* $10-- */
998 MIPS32_ADDI(9, 9, 2), /* $9 += 2 */
999 MIPS32_ADDI(8, 8, 4), /* $8 += 4 */
1000
1001 MIPS32_B(NEG16(8)), /* b loop */
1002 MIPS32_NOP,
1003 /* end: */
1004 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
1005 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
1006 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
1007 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
1008 MIPS32_B(NEG16(26)), /* b start */
1009 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1010 };
1011
1012 /* TODO remove array */
1013 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
1014 int i;
1015 param_in[0] = addr;
1016 param_in[1] = count;
1017
1018 for (i = 0; i < count; i++)
1019 param_in[i + 2] = buf[i];
1020
1021 int retval;
1022 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1023 count + 2, param_in, 0, NULL, 1);
1024
1025 free(param_in);
1026
1027 return retval;
1028 }
1029
1030 static int mips32_pracc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
1031 {
1032 static const uint32_t code[] = {
1033 /* start: */
1034 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
1035 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1036 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
1037 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
1038 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
1039 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
1040 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
1041
1042 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
1043 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
1044 MIPS32_LW(9, 0, 8), /* Load write addr to $9 */
1045 MIPS32_LW(10, 4, 8), /* Load write count to $10 */
1046 MIPS32_ADDI(8, 8, 8), /* $8 += 8 */
1047 /* loop: */
1048 MIPS32_BEQ(0, 10, 8), /* beq $0, $10, end */
1049 MIPS32_NOP,
1050
1051 MIPS32_LW(11, 0, 8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
1052 MIPS32_SB(11, 0, 9), /* sb $11,0($9) */
1053
1054 MIPS32_ADDI(10, 10, NEG16(1)), /* $10-- */
1055 MIPS32_ADDI(9, 9, 1), /* $9 += 1 */
1056 MIPS32_ADDI(8, 8, 4), /* $8 += 4 */
1057
1058 MIPS32_B(NEG16(8)), /* b loop */
1059 MIPS32_NOP,
1060 /* end: */
1061 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
1062 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
1063 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
1064 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
1065 MIPS32_B(NEG16(26)), /* b start */
1066 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1067 };
1068
1069 /* TODO remove array */
1070 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
1071 int retval;
1072 int i;
1073 param_in[0] = addr;
1074 param_in[1] = count;
1075
1076 for (i = 0; i < count; i++)
1077 param_in[i + 2] = buf[i];
1078
1079 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1080 count + 2, param_in, 0, NULL, 1);
1081
1082 free(param_in);
1083
1084 return retval;
1085 }
1086
1087 int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
1088 {
1089 static const uint32_t code[] = {
1090 /* start: */
1091 MIPS32_LUI(2, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $2 = MIPS32_PRACC_PARAM_IN */
1092 MIPS32_ORI(2, 2, LOWER16(MIPS32_PRACC_PARAM_IN)),
1093 MIPS32_LW(1, 1*4, 2), /* lw $1,1*4($2) */
1094 MIPS32_LW(15, 15*4, 2), /* lw $15,15*4($2) */
1095 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
1096 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1097 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
1098 MIPS32_SW(1, 0, 15), /* sw $1,($15) */
1099 MIPS32_LUI(1, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $1 = MIPS32_PRACC_PARAM_IN */
1100 MIPS32_ORI(1, 1, LOWER16(MIPS32_PRACC_PARAM_IN)),
1101 MIPS32_LW(3, 3*4, 1), /* lw $3,3*4($1) */
1102 MIPS32_LW(4, 4*4, 1), /* lw $4,4*4($1) */
1103 MIPS32_LW(5, 5*4, 1), /* lw $5,5*4($1) */
1104 MIPS32_LW(6, 6*4, 1), /* lw $6,6*4($1) */
1105 MIPS32_LW(7, 7*4, 1), /* lw $7,7*4($1) */
1106 MIPS32_LW(8, 8*4, 1), /* lw $8,8*4($1) */
1107 MIPS32_LW(9, 9*4, 1), /* lw $9,9*4($1) */
1108 MIPS32_LW(10, 10*4, 1), /* lw $10,10*4($1) */
1109 MIPS32_LW(11, 11*4, 1), /* lw $11,11*4($1) */
1110 MIPS32_LW(12, 12*4, 1), /* lw $12,12*4($1) */
1111 MIPS32_LW(13, 13*4, 1), /* lw $13,13*4($1) */
1112 MIPS32_LW(14, 14*4, 1), /* lw $14,14*4($1) */
1113 MIPS32_LW(16, 16*4, 1), /* lw $16,16*4($1) */
1114 MIPS32_LW(17, 17*4, 1), /* lw $17,17*4($1) */
1115 MIPS32_LW(18, 18*4, 1), /* lw $18,18*4($1) */
1116 MIPS32_LW(19, 19*4, 1), /* lw $19,19*4($1) */
1117 MIPS32_LW(20, 20*4, 1), /* lw $20,20*4($1) */
1118 MIPS32_LW(21, 21*4, 1), /* lw $21,21*4($1) */
1119 MIPS32_LW(22, 22*4, 1), /* lw $22,22*4($1) */
1120 MIPS32_LW(23, 23*4, 1), /* lw $23,23*4($1) */
1121 MIPS32_LW(24, 24*4, 1), /* lw $24,24*4($1) */
1122 MIPS32_LW(25, 25*4, 1), /* lw $25,25*4($1) */
1123 MIPS32_LW(26, 26*4, 1), /* lw $26,26*4($1) */
1124 MIPS32_LW(27, 27*4, 1), /* lw $27,27*4($1) */
1125 MIPS32_LW(28, 28*4, 1), /* lw $28,28*4($1) */
1126 MIPS32_LW(29, 29*4, 1), /* lw $29,29*4($1) */
1127 MIPS32_LW(30, 30*4, 1), /* lw $30,30*4($1) */
1128 MIPS32_LW(31, 31*4, 1), /* lw $31,31*4($1) */
1129
1130 MIPS32_LW(2, 32*4, 1), /* lw $2,32*4($1) */
1131 MIPS32_MTC0(2, 12, 0), /* move $2 to status */
1132 MIPS32_LW(2, 33*4, 1), /* lw $2,33*4($1) */
1133 MIPS32_MTLO(2), /* move $2 to lo */
1134 MIPS32_LW(2, 34*4, 1), /* lw $2,34*4($1) */
1135 MIPS32_MTHI(2), /* move $2 to hi */
1136 MIPS32_LW(2, 35*4, 1), /* lw $2,35*4($1) */
1137 MIPS32_MTC0(2, 8, 0), /* move $2 to badvaddr */
1138 MIPS32_LW(2, 36*4, 1), /* lw $2,36*4($1) */
1139 MIPS32_MTC0(2, 13, 0), /* move $2 to cause*/
1140 MIPS32_LW(2, 37*4, 1), /* lw $2,37*4($1) */
1141 MIPS32_MTC0(2, 24, 0), /* move $2 to depc (pc) */
1142
1143 MIPS32_LW(2, 2*4, 1), /* lw $2,2*4($1) */
1144 MIPS32_LW(1, 0, 15), /* lw $1,($15) */
1145 MIPS32_B(NEG16(53)), /* b start */
1146 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1147 };
1148
1149 int retval;
1150
1151 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1152 MIPS32NUMCOREREGS, regs, 0, NULL, 1);
1153
1154 return retval;
1155 }
1156
1157 int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
1158 {
1159 static const uint32_t code[] = {
1160 /* start: */
1161 MIPS32_MTC0(2, 31, 0), /* move $2 to COP0 DeSave */
1162 MIPS32_LUI(2, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $2 = MIPS32_PRACC_PARAM_OUT */
1163 MIPS32_ORI(2, 2, LOWER16(MIPS32_PRACC_PARAM_OUT)),
1164 MIPS32_SW(0, 0*4, 2), /* sw $0,0*4($2) */
1165 MIPS32_SW(1, 1*4, 2), /* sw $1,1*4($2) */
1166 MIPS32_SW(15, 15*4, 2), /* sw $15,15*4($2) */
1167 MIPS32_MFC0(2, 31, 0), /* move COP0 DeSave to $2 */
1168 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
1169 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1170 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
1171 MIPS32_SW(1, 0, 15), /* sw $1,($15) */
1172 MIPS32_SW(2, 0, 15), /* sw $2,($15) */
1173 MIPS32_LUI(1, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $1 = MIPS32_PRACC_PARAM_OUT */
1174 MIPS32_ORI(1, 1, LOWER16(MIPS32_PRACC_PARAM_OUT)),
1175 MIPS32_SW(2, 2*4, 1), /* sw $2,2*4($1) */
1176 MIPS32_SW(3, 3*4, 1), /* sw $3,3*4($1) */
1177 MIPS32_SW(4, 4*4, 1), /* sw $4,4*4($1) */
1178 MIPS32_SW(5, 5*4, 1), /* sw $5,5*4($1) */
1179 MIPS32_SW(6, 6*4, 1), /* sw $6,6*4($1) */
1180 MIPS32_SW(7, 7*4, 1), /* sw $7,7*4($1) */
1181 MIPS32_SW(8, 8*4, 1), /* sw $8,8*4($1) */
1182 MIPS32_SW(9, 9*4, 1), /* sw $9,9*4($1) */
1183 MIPS32_SW(10, 10*4, 1), /* sw $10,10*4($1) */
1184 MIPS32_SW(11, 11*4, 1), /* sw $11,11*4($1) */
1185 MIPS32_SW(12, 12*4, 1), /* sw $12,12*4($1) */
1186 MIPS32_SW(13, 13*4, 1), /* sw $13,13*4($1) */
1187 MIPS32_SW(14, 14*4, 1), /* sw $14,14*4($1) */
1188 MIPS32_SW(16, 16*4, 1), /* sw $16,16*4($1) */
1189 MIPS32_SW(17, 17*4, 1), /* sw $17,17*4($1) */
1190 MIPS32_SW(18, 18*4, 1), /* sw $18,18*4($1) */
1191 MIPS32_SW(19, 19*4, 1), /* sw $19,19*4($1) */
1192 MIPS32_SW(20, 20*4, 1), /* sw $20,20*4($1) */
1193 MIPS32_SW(21, 21*4, 1), /* sw $21,21*4($1) */
1194 MIPS32_SW(22, 22*4, 1), /* sw $22,22*4($1) */
1195 MIPS32_SW(23, 23*4, 1), /* sw $23,23*4($1) */
1196 MIPS32_SW(24, 24*4, 1), /* sw $24,24*4($1) */
1197 MIPS32_SW(25, 25*4, 1), /* sw $25,25*4($1) */
1198 MIPS32_SW(26, 26*4, 1), /* sw $26,26*4($1) */
1199 MIPS32_SW(27, 27*4, 1), /* sw $27,27*4($1) */
1200 MIPS32_SW(28, 28*4, 1), /* sw $28,28*4($1) */
1201 MIPS32_SW(29, 29*4, 1), /* sw $29,29*4($1) */
1202 MIPS32_SW(30, 30*4, 1), /* sw $30,30*4($1) */
1203 MIPS32_SW(31, 31*4, 1), /* sw $31,31*4($1) */
1204
1205 MIPS32_MFC0(2, 12, 0), /* move status to $2 */
1206 MIPS32_SW(2, 32*4, 1), /* sw $2,32*4($1) */
1207 MIPS32_MFLO(2), /* move lo to $2 */
1208 MIPS32_SW(2, 33*4, 1), /* sw $2,33*4($1) */
1209 MIPS32_MFHI(2), /* move hi to $2 */
1210 MIPS32_SW(2, 34*4, 1), /* sw $2,34*4($1) */
1211 MIPS32_MFC0(2, 8, 0), /* move badvaddr to $2 */
1212 MIPS32_SW(2, 35*4, 1), /* sw $2,35*4($1) */
1213 MIPS32_MFC0(2, 13, 0), /* move cause to $2 */
1214 MIPS32_SW(2, 36*4, 1), /* sw $2,36*4($1) */
1215 MIPS32_MFC0(2, 24, 0), /* move depc (pc) to $2 */
1216 MIPS32_SW(2, 37*4, 1), /* sw $2,37*4($1) */
1217
1218 MIPS32_LW(2, 0, 15), /* lw $2,($15) */
1219 MIPS32_LW(1, 0, 15), /* lw $1,($15) */
1220 MIPS32_B(NEG16(58)), /* b start */
1221 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1222 };
1223
1224 int retval;
1225
1226 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1227 0, NULL, MIPS32NUMCOREREGS, regs, 1);
1228
1229 return retval;
1230 }
1231
1232 /* fastdata upload/download requires an initialized working area
1233 * to load the download code; it should not be called otherwise
1234 * fetch order from the fastdata area
1235 * 1. start addr
1236 * 2. end addr
1237 * 3. data ...
1238 */
1239 int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source,
1240 int write_t, uint32_t addr, int count, uint32_t *buf)
1241 {
1242 uint32_t handler_code[] = {
1243 /* caution when editing, table is modified below */
1244 /* r15 points to the start of this code */
1245 MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
1246 MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
1247 MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
1248 MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
1249 /* start of fastdata area in t0 */
1250 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
1251 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
1252 MIPS32_LW(9, 0, 8), /* start addr in t1 */
1253 MIPS32_LW(10, 0, 8), /* end addr to t2 */
1254 /* loop: */
1255 /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */
1256 /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */
1257 MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */
1258 MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */
1259
1260 MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
1261 MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
1262 MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
1263 MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
1264
1265 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT)),
1266 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT)),
1267 MIPS32_JR(15), /* jr start */
1268 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1269 };
1270
1271 uint32_t jmp_code[] = {
1272 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
1273 /* 1 */ MIPS32_LUI(15, 0), /* addr of working area added below */
1274 /* 2 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */
1275 MIPS32_JR(15), /* jump to ram program */
1276 MIPS32_NOP,
1277 };
1278
1279 int retval, i;
1280 uint32_t val, ejtag_ctrl, address;
1281
1282 if (source->size < MIPS32_FASTDATA_HANDLER_SIZE)
1283 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1284
1285 if (write_t) {
1286 handler_code[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */
1287 handler_code[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */
1288 } else {
1289 handler_code[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */
1290 handler_code[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */
1291 }
1292
1293 /* write program into RAM */
1294 if (write_t != ejtag_info->fast_access_save) {
1295 mips32_pracc_write_mem32(ejtag_info, source->address, ARRAY_SIZE(handler_code), handler_code);
1296 /* save previous operation to speed to any consecutive read/writes */
1297 ejtag_info->fast_access_save = write_t;
1298 }
1299
1300 LOG_DEBUG("%s using 0x%.8" PRIx32 " for write handler", __func__, source->address);
1301
1302 jmp_code[1] |= UPPER16(source->address);
1303 jmp_code[2] |= LOWER16(source->address);
1304
1305 for (i = 0; i < (int) ARRAY_SIZE(jmp_code); i++) {
1306 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
1307 if (retval != ERROR_OK)
1308 return retval;
1309
1310 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
1311 mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]);
1312
1313 /* Clear the access pending bit (let the processor eat!) */
1314 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
1315 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
1316 mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl);
1317 }
1318
1319 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
1320 if (retval != ERROR_OK)
1321 return retval;
1322
1323 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1324 address = 0;
1325 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
1326 retval = mips_ejtag_drscan_32(ejtag_info, &address);
1327 if (retval != ERROR_OK)
1328 return retval;
1329
1330 if (address != MIPS32_PRACC_FASTDATA_AREA)
1331 return ERROR_FAIL;
1332
1333 /* wait PrAcc pending bit for FASTDATA write */
1334 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
1335 if (retval != ERROR_OK)
1336 return retval;
1337
1338 /* Send the load start address */
1339 val = addr;
1340 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
1341 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
1342
1343 /* Send the load end address */
1344 val = addr + (count - 1) * 4;
1345 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
1346
1347 for (i = 0; i < count; i++) {
1348 retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++);
1349 if (retval != ERROR_OK)
1350 return retval;
1351 }
1352
1353 retval = jtag_execute_queue();
1354 if (retval != ERROR_OK) {
1355 LOG_ERROR("fastdata load failed");
1356 return retval;
1357 }
1358
1359 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
1360 if (retval != ERROR_OK)
1361 return retval;
1362
1363 address = 0;
1364 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
1365 retval = mips_ejtag_drscan_32(ejtag_info, &address);
1366 if (retval != ERROR_OK)
1367 return retval;
1368
1369 if (address != MIPS32_PRACC_TEXT)
1370 LOG_ERROR("mini program did not return to start");
1371
1372 return retval;
1373 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)