target/mips32: optimize pracc access

Update mips32 instructions, add barrier and sync related insts.
Add SYNC and barrier instruction blocks for memory access safety.

These instructions are not supported on Lexra and/or MIPSr1 CPUs,
detections were added and they will be executed conditionally.

Rework mips32_pracc_read/write_regs function.
Checkpatch-ignore: MACRO_ARG_REUSE

Change-Id: Ib14112f37ff1f060b1633df73d671a6b09bb2178
Signed-off-by: Walter Ji <walter.ji@oss.cipunited.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7865
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Walter Ji
2023-08-29 13:27:49 +08:00
committed by Antonio Borneo
parent 019bf5f83c
commit b123128737
5 changed files with 208 additions and 39 deletions

View File

@@ -61,6 +61,7 @@
#include <helper/time_support.h>
#include <jtag/adapter.h>
#include "mips_cpu.h"
#include "mips32.h"
#include "mips32_pracc.h"
@@ -452,6 +453,8 @@ static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, u
pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper addr */
pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */
if (mips32_cpu_support_sync(ejtag_info))
pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */
pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
@@ -508,6 +511,8 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size
else
pracc_add(&ctx, 0, MIPS32_LBU(ctx.isa, 8, LOWER16(addr), 9));
if (mips32_cpu_support_sync(ejtag_info))
pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, /* store $8 at param out */
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + i * 4, 15));
addr += size;
@@ -550,6 +555,8 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_r
pracc_queue_init(&ctx);
pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, cp0_reg, cp0_sel)); /* move cp0 reg / sel to $8 */
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */
@@ -571,6 +578,8 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r
pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */
pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, cp0_reg, cp0_sel)); /* write $15 to cp0 reg / sel */
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */
pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */
@@ -786,6 +795,7 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz
if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff)))
return retval; /*Nothing to do*/
/* Reads Config0 */
mips32_cp0_read(ejtag_info, &conf, 16, 0);
switch (KSEGX(addr)) {
@@ -813,11 +823,28 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz
uint32_t start_addr = addr;
uint32_t end_addr = addr + count * size;
uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
if (rel > 1) {
LOG_DEBUG("Unknown release in cache code");
/* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
if (rel > MIPS32_RELEASE_2) {
LOG_DEBUG("Unsupported MIPS Release ( > 5)");
return ERROR_FAIL;
}
retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel);
} else {
struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
pracc_queue_init(&ctx);
if (mips32_cpu_support_sync(ejtag_info))
pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa));
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */
pracc_add(&ctx, 0, MIPS32_NOP);
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
if (ctx.retval != ERROR_OK) {
LOG_ERROR("Unable to barrier");
retval = ctx.retval;
}
pracc_queue_free(&ctx);
}
return retval;
@@ -866,6 +893,8 @@ int mips32_pracc_write_regs(struct mips32_common *mips32)
pracc_add(&ctx, 0, cp0_write_code[i]);
}
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
/* load registers 2 to 31 with li32, optimize */
for (int i = 2; i < 32; i++)
pracc_add_li32(&ctx, i, gprs[i], 1);
@@ -1019,6 +1048,70 @@ int mips32_pracc_read_regs(struct mips32_common *mips32)
return ctx.retval;
}
/**
* mips32_pracc_fastdata_xfer_synchronize_cache - Synchronize cache for fast data transfer
* @param[in] ejtag_info: EJTAG information structure
* @param[in] addr: Starting address for cache synchronization
* @param[in] size: Size of each data element
* @param[in] count: Number of data elements
*
* @brief Synchronizes the cache for fast data transfer based on
* the specified address and cache configuration.
* If the region is cacheable (write-back cache or write-through cache),
* it synchronizes the cache for the specified range.
* The synchronization is performed using the MIPS32 cache synchronization function.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag *ejtag_info,
uint32_t addr, int size, int count)
{
int retval = ERROR_OK;
if ((KSEGX(addr) == KSEG1) || (addr >= 0xff200000 && addr <= 0xff3fffff)) // DESEG?
return retval; /*Nothing to do*/
int cached = 0;
uint32_t conf = 0;
mips32_cp0_read(ejtag_info, &conf, 16, 0);
switch (KSEGX(addr)) {
case KUSEG:
cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
break;
case KSEG0:
cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
break;
case KSEG2:
case KSEG3:
cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
break;
default:
/* what ? */
break;
}
/**
* Check cacheability bits coherency algorithm
* is the region cacheable or uncached.
* If cacheable we have to synchronize the cache
*/
if (cached == 3 || cached == 0) { /* Write back cache or write through cache */
uint32_t start_addr = addr;
uint32_t end_addr = addr + count * size;
uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
/* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
if (rel > MIPS32_RELEASE_2) {
LOG_DEBUG("Unsupported MIPS Release ( > 5)");
return ERROR_FAIL;
}
retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel);
}
return retval;
}
/* fastdata upload/download requires an initialized working area
* to load the download code; it should not be called otherwise
* fetch order from the fastdata area
@@ -1039,13 +1132,17 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are
/* start of fastdata area in t0 */
MIPS32_LUI(isa, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
MIPS32_ORI(isa, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */
MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */
/* loop: */
MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */
mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */
MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */
mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */
/* loop: */
write_t ? MIPS32_LW(isa, 11, 0, 8) : MIPS32_LW(isa, 11, 0, 9), /* from xfer area : from memory */
write_t ? MIPS32_SW(isa, 11, 0, 9) : MIPS32_SW(isa, 11, 0, 8), /* to memory : to xfer area */
MIPS32_BNE(isa, 10, 9, NEG16(3 << isa)), /* bne $t2,t1,loop */
mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */
MIPS32_BNE(isa, 10, 9, NEG16(4 << isa)), /* bne $t2,t1,loop */
MIPS32_ADDI(isa, 9, 9, 4), /* addi t1,t1,4 */
MIPS32_LW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
@@ -1055,7 +1152,9 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are
MIPS32_LUI(isa, 15, UPPER16(MIPS32_PRACC_TEXT)),
MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_PRACC_TEXT) | isa), /* isa bit for JR instr */
MIPS32_JR(isa, 15), /* jr start */
mips32_cpu_support_hazard_barrier(ejtag_info)
? MIPS32_JRHB(isa, 15)
: MIPS32_JR(isa, 15), /* jr start */
MIPS32_MFC0(isa, 15, 31, 0), /* move COP0 DeSave to $15 */
};
@@ -1075,7 +1174,9 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are
uint32_t jmp_code[] = {
MIPS32_LUI(isa, 15, UPPER16(source->address)), /* load addr of jump in $15 */
MIPS32_ORI(isa, 15, 15, LOWER16(source->address) | isa), /* isa bit for JR instr */
MIPS32_JR(isa, 15), /* jump to ram program */
mips32_cpu_support_hazard_barrier(ejtag_info)
? MIPS32_JRHB(isa, 15)
: MIPS32_JR(isa, 15), /* jump to ram program */
isa ? MIPS32_XORI(isa, 15, 15, 1) : MIPS32_NOP, /* drop isa bit, needed for LW/SW instructions */
};
@@ -1139,5 +1240,5 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are
if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT)
LOG_ERROR("mini program did not return to start");
return retval;
return mips32_pracc_fastdata_xfer_synchronize_cache(ejtag_info, addr, 4, count);
}