On Thu, Jun 30, 2011 at 6:25 PM, Drasko DRASKOVIC
<drasko.drasko...@gmail.com> wrote:
> Now, in case of EJTAG communication implementation in mips32_pracc.c
> this is not a simple thing to implement. I am currently adding missing
> opcodes and trying to craft a miniprogram based on bytecode, similar
> to existing stuff. It is quite a headache to debug, but I previously
> spent a lot of time on demistfying this implementation and wrote one
> draft doc to this list (more complete doc is on the way, and will be
> contributed as a separate patch).

OK, I have first draft of the patch which adds raw bytecodes and spits
them out to CPU via EJTAG,
implementing miniprogram that is given in the MIPS32 Architecture For
Programmers Volume II: The MIPS32 Instruction Set (pasted below)

I have debugged and tested this implementation and it seems that it
works quite fine, even without notable performance penalty.

So, the good new is that I can now debug Linux on MIPS with OpenOCD,
because soft breakpointswork fine and caches are coherent.

I will let this patch cook for a while and then send an official PULL
reques once it is completely ready.
I am just posting it now so that I can get some responses and
commenets - what do you thisnk about this implementation ? Does this
sound reasonable ?


> In the MIPS official doc MD00086  (MIPS32™ Architecture For
> Programmers Volume II: The MIPS32™ Instruction Set), we can find
> interesting procedure to synchronize caches using synci (Synchronize
> Caches to Make Instruction Writes Effective) instruction. I am
> referencing here Programming Notes given in the chapter describing
> this instruction (page 287). Based on this, I re-implemented this
> procedure to the detail in bytecode minirpogram and I have first
> working draft.

Here is the program from the mentioned ref. manual that I implemented
via opcodes :

Programming Notes:
When the instruction stream is written, the SYNCI instruction should
be used in conjunction with other instructions
to make the newly-written instructions effective. The following
example shows a routine which can be called after
the new instruction stream is written to make those changes effective.
Note that the SYNCI instruction could be
replaced with the corresponding sequence of CACHE instructions (when
access to Coprocessor 0 is available), and
that the JR.HB instruction could be replaced with JALR.HB, ERET, or
DERET instructions, as appropriate.
/*
* This routine makes changes to the instruction stream effective to the
* hardware. It should be called after the instruction stream is written.
* On return, the new instructions are effective.
*
* Inputs:
* a0 = Start address of new instruction stream
* a1 = Size, in bytes, of new instruction stream
*/
addu a1, a0, a1 /* Calculate end address + 1 */
rdhwr v0, HW_SYNCI_Step /* Get step size for SYNCI from new */
/* Release 2 instruction */
beq v0, zero, 20f /* If no caches require synchronization, */
nop /* branch around */
10: synci 0(a0) /* Synchronize all caches around address */
sltu v1, a0, a1 /* Compare current with end address */
bne v1, zero, 10b /* Branch if more to do */
addu a0, a0, v0 /* Add step size in delay slot */
sync /* Clear memory hazards */
20: jr.hb ra /* Return, clearing instruction hazards */
nop

Best regards,
Drasko
From 04da97fd411df3de844f50864c598df2e479b688 Mon Sep 17 00:00:00 2001
From: Drasko DRASKOVIC <drasko.drasko...@gmail.com>
Date: Tue, 5 Jul 2011 16:26:49 +0200
Subject: [PATCH] mips32 : Synchronize Caches to Make Instruction Writes
 Effective

Pprogram that loads another program into memory is actually writing the D- side cache.
The instructions it has loaded can't be executed until they reach the I-cache.

After the instructions have been written, the loader should arrange to write back
any containing D-cache line and invalidate any locations already in the I-cache.
---
 src/target/mips32.h       |   70 +++++++++++++++++---------
 src/target/mips32_pracc.c |  119 ++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 153 insertions(+), 36 deletions(-)

diff --git a/src/target/mips32.h b/src/target/mips32.h
index 4f0f0ef..7dde7e7 100644
--- a/src/target/mips32.h
+++ b/src/target/mips32.h
@@ -4,6 +4,8 @@
  *                                                                         *
  *   Copyright (C) 2008 by David T.L. Wong                                 *
  *                                                                         *
+ *   Copyright (C) 2011 by Drasko DRASKOVIC <drasko.drasko...@gmail.com>   *
+ *                                                                         *
  *   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     *
@@ -92,7 +94,9 @@ struct mips32_algorithm
 	enum mips32_isa_mode isa_mode;
 };
 
+#define MIPS32_OP_ADDIU 0x21
 #define MIPS32_OP_BEQ	0x04
+#define MIPS32_OP_BGTZ	0x07
 #define MIPS32_OP_BNE	0x05
 #define MIPS32_OP_ADDI	0x08
 #define MIPS32_OP_AND	0x24
@@ -106,12 +110,21 @@ struct mips32_algorithm
 #define MIPS32_OP_MTHI	0x11
 #define MIPS32_OP_MFLO	0x12
 #define MIPS32_OP_MTLO	0x13
+#define MIPS32_OP_RDHWR 0x3B
 #define MIPS32_OP_SB	0x28
 #define MIPS32_OP_SH	0x29
 #define MIPS32_OP_SW	0x2B
 #define MIPS32_OP_ORI	0x0D
 #define MIPS32_OP_XOR	0x26
+#define MIPS32_OP_SLTU  0x2B
 #define MIPS32_OP_SRL	0x03
+#define MIPS32_OP_SYNCI	0x1F
+
+#define MIPS32_OP_REGIMM	0x01
+#define MIPS32_OP_SDBBP		0x3F
+#define MIPS32_OP_SPECIAL	0x00
+#define MIPS32_OP_SPECIAL2	0x07
+#define MIPS32_OP_SPECIAL3	0x1F
 
 #define MIPS32_COP0_MF	0x00
 #define MIPS32_COP0_MT	0x04
@@ -120,33 +133,42 @@ struct mips32_algorithm
 #define MIPS32_I_INST(opcode, rs, rt, immd)	(((opcode) << 26) |((rs) << 21) | ((rt) << 16) | (immd))
 #define MIPS32_J_INST(opcode, addr)	(((opcode) << 26) |(addr))
 
-#define MIPS32_NOP					0
-#define MIPS32_ADDI(tar, src, val)	MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val)
-#define MIPS32_AND(reg, off, val)	MIPS32_R_INST(0, off, val, reg, 0, MIPS32_OP_AND)
-#define MIPS32_B(off)				MIPS32_BEQ(0, 0, off)
-#define MIPS32_BEQ(src,tar,off)		MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off)
-#define MIPS32_BNE(src,tar,off)		MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off)
-#define MIPS32_JR(reg)				MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR)
-#define MIPS32_MFC0(gpr, cpr, sel)	MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel)
-#define MIPS32_MTC0(gpr,cpr, sel)	MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel)
-#define MIPS32_LBU(reg, off, base)	MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off)
-#define MIPS32_LHU(reg, off, base)	MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off)
-#define MIPS32_LUI(reg, val)		MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val)
-#define MIPS32_LW(reg, off, base)	MIPS32_I_INST(MIPS32_OP_LW, base, reg, off)
-#define MIPS32_MFLO(reg)			MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO)
-#define MIPS32_MFHI(reg)			MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI)
-#define MIPS32_MTLO(reg)			MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO)
-#define MIPS32_MTHI(reg)			MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI)
-#define MIPS32_ORI(tar, src, val)	MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val)
-#define MIPS32_SB(reg, off, base)	MIPS32_I_INST(MIPS32_OP_SB, base, reg, off)
-#define MIPS32_SH(reg, off, base)	MIPS32_I_INST(MIPS32_OP_SH, base, reg, off)
-#define MIPS32_SW(reg, off, base)	MIPS32_I_INST(MIPS32_OP_SW, base, reg, off)
-#define MIPS32_XOR(reg, val1, val2)	MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR)
-#define MIPS32_SRL(reg, src, off)	MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL)
+#define MIPS32_NOP						0
+#define MIPS32_ADDI(tar, src, val)		MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val)
+#define MIPS32_ADDU(dst, src, tar)		MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDIU)
+#define MIPS32_AND(reg, off, val)		MIPS32_R_INST(0, off, val, reg, 0, MIPS32_OP_AND)
+#define MIPS32_B(off)					MIPS32_BEQ(0, 0, off)
+#define MIPS32_BEQ(src,tar,off)			MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off)
+#define MIPS32_BGTZ(reg, off)			MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off)
+#define MIPS32_BNE(src,tar,off)			MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off)
+#define MIPS32_CACHE(reg, off, base)	MIPS32_I_INST(MIPS32_OP_CACHE, base, reg, off)
+#define MIPS32_JR(reg)					MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR)
+#define MIPS32_MFC0(gpr, cpr, sel)		MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel)
+#define MIPS32_MTC0(gpr,cpr, sel)		MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel)
+#define MIPS32_LBU(reg, off, base)		MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off)
+#define MIPS32_LHU(reg, off, base)		MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off)
+#define MIPS32_LUI(reg, val)			MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val)
+#define MIPS32_LW(reg, off, base)		MIPS32_I_INST(MIPS32_OP_LW, base, reg, off)
+#define MIPS32_MFLO(reg)				MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO)
+#define MIPS32_MFHI(reg)				MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI)
+#define MIPS32_MTLO(reg)				MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO)
+#define MIPS32_MTHI(reg)				MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI)
+#define MIPS32_ORI(tar, src, val)		MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val)
+#define MIPS32_RDHWR(tar, dst)			MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR)
+#define MIPS32_SB(reg, off, base)		MIPS32_I_INST(MIPS32_OP_SB, base, reg, off)
+#define MIPS32_SH(reg, off, base)		MIPS32_I_INST(MIPS32_OP_SH, base, reg, off)
+#define MIPS32_SW(reg, off, base)		MIPS32_I_INST(MIPS32_OP_SW, base, reg, off)
+#define MIPS32_XOR(reg, val1, val2)		MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR)
+#define MIPS32_SRL(reg, src, off)		MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL)
+#define MIPS32_SLTU(dst, src, tar)		MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU)
+#define MIPS32_SYNCI(off, base)			MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off)
+
+#define MIPS32_SYNC			0xF
+#define MIPS32_SYNCI_STEP	0x1	/* reg num od address step size to be used with synci instruction */
 
 /* ejtag specific instructions */
 #define MIPS32_DRET					0x4200001F
-#define MIPS32_SDBBP				0x7000003F
+#define MIPS32_SDBBP				0x7000003F	/* MIPS32_J_INST(MIPS32_OP_SPECIAL2, MIPS32_OP_SDBBP) */
 #define MIPS16_SDBBP				0xE801
 
 int mips32_arch_state(struct target *target);
diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c
index af60d32..039edc3 100644
--- a/src/target/mips32_pracc.c
+++ b/src/target/mips32_pracc.c
@@ -6,6 +6,8 @@
  *                                                                         *
  *   Copyright (C) 2009 by David N. Claffey <dnclaf...@gmail.com>          *
  *                                                                         *
+ *   Copyright (C) 2011 by Drasko DRASKOVIC <drasko.drasko...@gmail.com>   *
+ *                                                                         *
  *   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     *
@@ -110,23 +112,20 @@ static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info,
 static int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info,
 		uint32_t addr, uint32_t *buf);
 
+static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
+		uint32_t start_addr, uint32_t end_addr);
+
 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
 {
 	uint32_t ejtag_ctrl;
 	long long then = timeval_ms();
 	int timeout;
+	int retval;
 
 	/* wait for the PrAcc to become "1" */
 	mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
 	ejtag_ctrl = ejtag_info->ejtag_ctrl;
 
-	int retval;
-	if ((retval = jtag_execute_queue()) != ERROR_OK)
-	{
-		LOG_ERROR("fastdata load failed");
-		return retval;
-	}
-
 	while (1)
 	{
 		retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
@@ -574,24 +573,120 @@ static int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr,
 	return retval;
 }
 
+/**
+ * Synchronize Caches to Make Instruction Writes Effective
+ *
+ * (ref. doc. MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set,
+ *  Document Number: MD00086, Revision 2.00, June 9, 2003)
+ *
+ * When the instruction stream is written, the SYNCI instruction should be used
+ * in conjunction with other instructions to make the newly-written instructions effective.
+ *
+ * Explanation :
+ * A program that loads another program into memory is actually writing the D- side cache.
+ * The instructions it has loaded can't be executed until they reach the I-cache.
+ *
+ * After the instructions have been written, the loader should arrange
+ * to write back any containing D-cache line and invalidate any locations
+ * already in the I-cache.
+ *
+ * You can do that with cache instructions, but those instructions are only available in kernel mode,
+ * and a loader writing instructions for the use of its own process need not be privileged software.
+ *
+ * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
+ * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
+ * That is, it arranges a D-cache write-back and an I-cache invalidate.
+ *
+ * To employ synci at user level, you need to know the size of a cache line,
+ * and that can be obtained with a rdhwr SYNCI_Step
+ * from one of the standard “hardware registers”.
+ */
+static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
+											uint32_t start_addr, uint32_t end_addr)
+{
+	static const uint32_t code[] = {
+															/* start: */
+		MIPS32_MTC0(15,31,0),								/* move $15 to COP0 DeSave */
+		MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),			/* $15 = MIPS32_PRACC_STACK */
+		MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
+		MIPS32_SW(8,0,15),									/* sw $8,($15) */
+		MIPS32_SW(9,0,15),									/* sw $9,($15) */
+		MIPS32_SW(10,0,15),									/* sw $10,($15) */
+		MIPS32_SW(11,0,15),									/* sw $11,($15) */
+
+		MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),		/* $8 = MIPS32_PRACC_PARAM_IN */
+		MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
+		MIPS32_LW(9,0,8),									/* Load write start_addr to $9 */
+		MIPS32_LW(10,4,8),									/* Load write end_addr to $10 */
+
+		MIPS32_RDHWR(11, MIPS32_SYNCI_STEP),				/* $11 = MIPS32_SYNCI_STEP */
+		MIPS32_BEQ(11,0,6),									/* beq $11, $0, end */
+		MIPS32_NOP,
+															/* synci_loop : */
+		MIPS32_SYNCI(0,9),									/* synci 0($9) */
+		MIPS32_SLTU(8,10,9),								/* sltu $8, $10, $9  # $8 = $10 < $9 ? 1 : 0 */
+		MIPS32_BNE(8,0,NEG16(3)),							/* bne $8, $0, synci_loop */
+		MIPS32_ADDU(9, 9, 11),								/* $9 += MIPS32_SYNCI_STEP */
+		MIPS32_SYNC,
+															/* end: */
+		MIPS32_LW(11,0,15),									/* lw $11,($15) */
+		MIPS32_LW(10,0,15),									/* lw $10,($15) */
+		MIPS32_LW(9,0,15),									/* lw $9,($15) */
+		MIPS32_LW(8,0,15),									/* lw $8,($15) */
+		MIPS32_B(NEG16(24)),								/* b start */
+		MIPS32_MFC0(15,31,0),								/* move COP0 DeSave to $15 */
+	};
+
+	/* TODO remove array */
+	uint32_t *param_in = malloc(2 * sizeof(uint32_t));
+	int retval;
+	param_in[0] = start_addr;
+	param_in[1] = end_addr;
+
+	retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 2, param_in, 0, NULL, 1);
+
+	free(param_in);
+
+	return retval;
+}
+
+
 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
 {
+	int retval;
+	uint32_t start_addr, end_addr;
+
 	switch (size)
 	{
 		case 1:
-			return mips32_pracc_write_mem8(ejtag_info, addr, count, (uint8_t*)buf);
+			retval = mips32_pracc_write_mem8(ejtag_info, addr, count, (uint8_t*)buf);
+			break;
 		case 2:
-			return mips32_pracc_write_mem16(ejtag_info, addr, count,(uint16_t*)buf);
+			retval = mips32_pracc_write_mem16(ejtag_info, addr, count,(uint16_t*)buf);
+			break;
 		case 4:
 			if (count == 1)
-				return mips32_pracc_write_u32(ejtag_info, addr, (uint32_t*)buf);
+			{
+				retval = mips32_pracc_write_u32(ejtag_info, addr, (uint32_t*)buf);
+			}
 			else
-				return mips32_pracc_write_mem32(ejtag_info, addr, count, (uint32_t*)buf);
+			{
+				retval = mips32_pracc_write_mem32(ejtag_info, addr, count, (uint32_t*)buf);
+			}
+			break;
+		default:
+			retval = ERROR_FAIL;
 	}
 
-	return ERROR_OK;
+	/* we must clean D$ + invalidate I$ for a dirty region */
+	start_addr = addr;
+	end_addr = addr + count * size;
+	mips32_pracc_sync_cache(ejtag_info, start_addr, end_addr);
+
+	return retval;
 }
 
+
 static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
 {
 	static const uint32_t code[] = {
-- 
1.7.6

_______________________________________________
Openocd-development mailing list
Openocd-development@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to