From 1fbe8450a9dd99a66f6a4035652beb400deb9277 Mon Sep 17 00:00:00 2001 From: Peter Mamonov Date: Tue, 23 Sep 2014 12:46:02 +0400 Subject: [PATCH] mips: Add MIPS64 support The patch adds support for processors implementing MIPS64 instruction set. Change-Id: I79a983dfdead81553457a0f3e9e739a9785afaac Signed-off-by: Konstantin Kostyukhin Signed-off-by: Andrey Sidorov Signed-off-by: Aleksey Kuleshov Signed-off-by: Antony Pavlov Signed-off-by: Peter Mamonov Signed-off-by: Oleksij Rempel CC: Dongxue Zhang CC: Paul Fertser CC: Salvador Arroyo CC: Spencer Oliver Reviewed-on: http://openocd.zylin.com/2321 Tested-by: jenkins Reviewed-by: Paul Fertser --- src/target/Makefile.am | 10 + src/target/mips64.c | 627 ++++++++++++++++ src/target/mips64.h | 226 ++++++ src/target/mips64_pracc.c | 1431 +++++++++++++++++++++++++++++++++++++ src/target/mips64_pracc.h | 59 ++ src/target/mips_ejtag.c | 144 ++++ src/target/mips_ejtag.h | 24 + 7 files changed, 2521 insertions(+) create mode 100644 src/target/mips64.c create mode 100644 src/target/mips64.h create mode 100644 src/target/mips64_pracc.c create mode 100644 src/target/mips64_pracc.h diff --git a/src/target/Makefile.am b/src/target/Makefile.am index afa5f49b6..2a7cc4b3b 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -32,6 +32,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la if TARGET64 %C%_libtarget_la_SOURCES +=$(ARMV8_SRC) +%C%_libtarget_la_SOURCES +=$(MIPS64_SRC) endif TARGET_CORE_SRC = \ @@ -120,6 +121,13 @@ MIPS32_SRC = \ %D%/mips32_dmaacc.c \ %D%/mips_ejtag.c +MIPS64_SRC = \ + %D%/mips64.c \ + %D%/mips32_pracc.c \ + %D%/mips64_pracc.c \ + %D%/trace.c \ + %D%/mips_ejtag.c + NDS32_SRC = \ %D%/nds32.c \ %D%/nds32_reg.c \ @@ -193,10 +201,12 @@ ESIRISC_SRC = \ %D%/etm_dummy.h \ %D%/image.h \ %D%/mips32.h \ + %D%/mips64.h \ %D%/mips_m4k.h \ %D%/mips_ejtag.h \ %D%/mips32_pracc.h \ %D%/mips32_dmaacc.h \ + %D%/mips64_pracc.h \ %D%/oocd_trace.h \ %D%/register.h \ %D%/target.h \ diff --git a/src/target/mips64.c b/src/target/mips64.c new file mode 100644 index 000000000..f65aec114 --- /dev/null +++ b/src/target/mips64.c @@ -0,0 +1,627 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014 by Antony Pavlov + * Copyright (C) 2014 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if BUILD_TARGET64 == 1 + +#include "mips64.h" + +static const struct { + unsigned id; + const char *name; + enum reg_type type; + const char *group; + const char *feature; + int flag; +} mips64_regs[] = { + { 0, "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 1, "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 2, "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 3, "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 4, "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 5, "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 6, "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 7, "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 8, "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 9, "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, +}; + +static int reg_type2size(enum reg_type type) +{ + switch (type) { + case REG_TYPE_UINT32: + case REG_TYPE_INT: + return 32; + case REG_TYPE_UINT64: + case REG_TYPE_IEEE_DOUBLE: + return 64; + default: + return 64; + } +} + +static int mips64_get_core_reg(struct reg *reg) +{ + int retval; + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + struct mips64_common *mips64_target = target->arch_info; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = mips64_target->read_core_reg(target, mips64_reg->num); + + return retval; +} + +static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + uint64_t value = buf_get_u64(buf, 0, 64); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u64(reg->value, 0, 64, value); + reg->dirty = 1; + reg->valid = 1; + + return ERROR_OK; +} + +static int mips64_read_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = mips64->core_regs[num]; + buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int mips64_write_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); + mips64->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num , reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +int mips64_invalidate_core_regs(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + unsigned int i; + + for (i = 0; i < mips64->core_cache->num_regs; i++) { + mips64->core_cache->reg_list[i].valid = 0; + mips64->core_cache->reg_list[i].dirty = 0; + } + + return ERROR_OK; +} + + +int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + register int i; + + /* include floating point registers */ + *reg_list_size = MIPS64_NUM_REGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < MIPS64_NUM_REGS; i++) + (*reg_list)[i] = &mips64->core_cache->reg_list[i]; + + return ERROR_OK; +} + +int mips64_save_context(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs); + if (retval != ERROR_OK) + return retval; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) + retval = mips64->read_core_reg(target, i); + + return retval; +} + +int mips64_restore_context(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) { + if (mips64->core_cache->reg_list[i].dirty) + mips64->write_core_reg(target, i); + } + + return mips64_pracc_write_regs(ejtag_info, mips64->core_regs); +} + +int mips64_arch_state(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + + if (mips64->common_magic != MIPS64_COMMON_MAGIC) { + LOG_ERROR("BUG: called for a non-MIPS64 target"); + exit(-1); + } + + LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", + debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); + + return ERROR_OK; +} + +static const struct reg_arch_type mips64_reg_type = { + .get = mips64_get_core_reg, + .set = mips64_set_core_reg, +}; + +int mips64_build_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct reg_cache **cache_p, *cache; + struct mips64_core_reg *arch_info = NULL; + struct reg *reg_list = NULL; + unsigned i; + + cache = calloc(1, sizeof(*cache)); + if (!cache) { + LOG_ERROR("unable to allocate cache"); + return ERROR_FAIL; + } + + reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list)); + if (!reg_list) { + LOG_ERROR("unable to allocate reg_list"); + goto alloc_fail; + } + + arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info)); + if (!arch_info) { + LOG_ERROR("unable to allocate arch_info"); + goto alloc_fail; + } + + for (i = 0; i < MIPS64_NUM_REGS; i++) { + struct mips64_core_reg *a = &arch_info[i]; + struct reg *r = ®_list[i]; + + r->arch_info = &arch_info[i]; + r->caller_save = true; /* gdb defaults to true */ + r->exist = true; + r->feature = &a->feature; + r->feature->name = mips64_regs[i].feature; + r->group = mips64_regs[i].group; + r->name = mips64_regs[i].name; + r->number = i; + r->reg_data_type = &a->reg_data_type; + r->reg_data_type->type = mips64_regs[i].type; + r->size = reg_type2size(mips64_regs[i].type); + r->type = &mips64_reg_type; + r->value = &a->value[0]; + + a->mips64_common = mips64; + a->num = mips64_regs[i].id; + a->target = target; + } + + cache->name = "mips64 registers"; + cache->reg_list = reg_list; + cache->num_regs = MIPS64_NUM_REGS; + + cache_p = register_get_last_cache_p(&target->reg_cache); + (*cache_p) = cache; + + mips64->core_cache = cache; + + return ERROR_OK; + +alloc_fail: + free(cache); + free(reg_list); + free(arch_info); + + return ERROR_FAIL; +} + +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, + struct jtag_tap *tap) +{ + mips64->bp_scanned = false; + mips64->common_magic = MIPS64_COMMON_MAGIC; + mips64->data_break_list = NULL; + mips64->ejtag_info.tap = tap; + mips64->fast_data_area = NULL; + mips64->mips64mode32 = false; + mips64->read_core_reg = mips64_read_core_reg; + mips64->write_core_reg = mips64_write_core_reg; + + return ERROR_OK; +} + +int mips64_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + /* TODO */ + return ERROR_OK; +} + +int mips64_examine(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + + if (target_was_examined(target)) + return ERROR_OK; + + /* TODO: why we do not do mips64_configure_break_unit() here? */ + mips64->bp_scanned = false; + mips64->num_data_bpoints = 0; + mips64->num_data_bpoints_avail = 0; + mips64->num_inst_bpoints = 0; + mips64->num_inst_bpoints_avail = 0; + + target_set_examined(target); + + return ERROR_OK; +} + +static int mips64_configure_i_break_unit(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *ibl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of inst breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints; + ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl)); + if (!ibl) { + LOG_ERROR("unable to allocate inst_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_inst_bpoints; i++) + ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i); + + mips64->inst_break_list = ibl; + /* clear IBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_IBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int mips64_configure_d_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *dbl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of data breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_data_bpoints_avail = mips64->num_data_bpoints; + + dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl)); + + if (!dbl) { + LOG_ERROR("unable to allocate data_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_data_bpoints; i++) + dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i); + + mips64->data_break_list = dbl; + + /* clear DBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_DBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +int mips64_configure_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + uint64_t dcr; + int retval; + + if (mips64->bp_scanned) + return ERROR_OK; + + /* get info about breakpoint support */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (dcr & EJTAG64_DCR_IB) { + retval = mips64_configure_i_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + if (dcr & EJTAG64_DCR_DB) { + retval = mips64_configure_d_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr, + mips64->num_inst_bpoints, mips64->num_data_bpoints); + + mips64->bp_scanned = true; + + return ERROR_OK; +} + +int mips64_enable_interrupts(struct target *target, bool enable) +{ + int retval; + bool update = false; + uint64_t dcr; + + /* read debug control register */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (enable) { + if (!(dcr & EJTAG64_DCR_INTE)) { + /* enable interrupts */ + dcr |= EJTAG64_DCR_INTE; + update = true; + } + } else { + if (dcr & EJTAG64_DCR_INTE) { + /* disable interrupts */ + dcr &= ~(uint64_t)EJTAG64_DCR_INTE; + update = true; + } + } + + if (update) { + retval = target_write_u64(target, EJTAG64_DCR, dcr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +#endif /* BUILD_TARGET64 */ diff --git a/src/target/mips64.h b/src/target/mips64.h new file mode 100644 index 000000000..3453e4ed1 --- /dev/null +++ b/src/target/mips64.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_H +#define OPENOCD_TARGET_MIPS64_H + +#include "target.h" +#include "register.h" +#include "mips64_pracc.h" + +#define MIPS64_COMMON_MAGIC 0xB640B640 + +/* MIPS64 CP0 registers */ +#define MIPS64_C0_INDEX 0 +#define MIPS64_C0_RANDOM 1 +#define MIPS64_C0_ENTRYLO0 2 +#define MIPS64_C0_ENTRYLO1 3 +#define MIPS64_C0_CONTEXT 4 +#define MIPS64_C0_PAGEMASK 5 +#define MIPS64_C0_WIRED 6 +#define MIPS64_C0_BADVADDR 8 +#define MIPS64_C0_COUNT 9 +#define MIPS64_C0_ENTRYHI 10 +#define MIPS64_C0_COMPARE 11 +#define MIPS64_C0_STATUS 12 +#define MIPS64_C0_CAUSE 13 +#define MIPS64_C0_EPC 14 +#define MIPS64_C0_PRID 15 +#define MIPS64_C0_CONFIG 16 +#define MIPS64_C0_LLA 17 +#define MIPS64_C0_WATCHLO 18 +#define MIPS64_C0_WATCHHI 19 +#define MIPS64_C0_XCONTEXT 20 +#define MIPS64_C0_MEMCTRL 22 +#define MIPS64_C0_DEBUG 23 +#define MIPS64_C0_DEPC 24 +#define MIPS64_C0_PERFCOUNT 25 +#define MIPS64_C0_ECC 26 +#define MIPS64_C0_CACHERR 27 +#define MIPS64_C0_TAGLO 28 +#define MIPS64_C0_TAGHI 29 +#define MIPS64_C0_DATAHI 29 +#define MIPS64_C0_EEPC 30 + +/* MIPS64 CP1 registers */ +#define MIPS64_C1_FIR 0 +#define MIPS64_C1_FCONFIG 24 +#define MIPS64_C1_FCSR 31 +#define MIPS64_C1_FCCR 25 +#define MIPS64_C1_FEXR 26 +#define MIPS64_C1_FENR 28 + +/* offsets into mips64 register cache */ +#define MIPS64_NUM_CORE_REGS 34 +#define MIPS64_NUM_C0_REGS 34 +#define MIPS64_NUM_FP_REGS 38 + +#define MIPS64_NUM_REGS (MIPS64_NUM_CORE_REGS + \ + MIPS64_NUM_C0_REGS + \ + MIPS64_NUM_FP_REGS) + +#define MIPS64_NUM_CORE_C0_REGS (MIPS64_NUM_CORE_REGS + MIPS64_NUM_C0_REGS) + +#define MIPS64_PC MIPS64_NUM_CORE_REGS + +struct mips64_comparator { + bool used; + uint64_t bp_value; + uint64_t reg_address; +}; + +struct mips64_common { + uint32_t common_magic; + void *arch_info; + struct reg_cache *core_cache; + struct mips_ejtag ejtag_info; + uint64_t core_regs[MIPS64_NUM_REGS]; + + struct working_area *fast_data_area; + + bool bp_scanned; + int num_inst_bpoints; + int num_data_bpoints; + int num_inst_bpoints_avail; + int num_data_bpoints_avail; + struct mips64_comparator *inst_break_list; + struct mips64_comparator *data_break_list; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, int num); + int (*write_core_reg)(struct target *target, int num); + + bool mips64mode32; +}; + +struct mips64_core_reg { + uint32_t num; + struct target *target; + struct mips64_common *mips64_common; + uint8_t value[8]; + struct reg_feature feature; + struct reg_data_type reg_data_type; +}; + +#define MIPS64_OP_SRL 0x02 +#define MIPS64_OP_BEQ 0x04 +#define MIPS64_OP_BNE 0x05 +#define MIPS64_OP_ADDI 0x08 +#define MIPS64_OP_ANDI 0x0c +#define MIPS64_OP_DADDI 0x18 +#define MIPS64_OP_DADDIU 0x19 +#define MIPS64_OP_AND 0x24 +#define MIPS64_OP_LUI 0x0F +#define MIPS64_OP_LW 0x23 +#define MIPS64_OP_LD 0x37 +#define MIPS64_OP_LBU 0x24 +#define MIPS64_OP_LHU 0x25 +#define MIPS64_OP_MFHI 0x10 +#define MIPS64_OP_MTHI 0x11 +#define MIPS64_OP_MFLO 0x12 +#define MIPS64_OP_MTLO 0x13 +#define MIPS64_OP_SB 0x28 +#define MIPS64_OP_SH 0x29 +#define MIPS64_OP_SW 0x2B +#define MIPS64_OP_SD 0x3F +#define MIPS64_OP_ORI 0x0D +#define MIPS64_OP_JR 0x08 + +#define MIPS64_OP_COP0 0x10 +#define MIPS64_OP_COP1 0x11 +#define MIPS64_OP_COP2 0x12 + +#define MIPS64_COP_MF 0x00 +#define MIPS64_COP_DMF 0x01 +#define MIPS64_COP_MT 0x04 +#define MIPS64_COP_DMT 0x05 +#define MIPS64_COP_CF 0x02 +#define MIPS64_COP_CT 0x06 + +#define MIPS64_R_INST(opcode, rs, rt, rd, shamt, funct) \ +(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) +#define MIPS64_I_INST(opcode, rs, rt, immd) (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) +#define MIPS64_J_INST(opcode, addr) (((opcode) << 26) | (addr)) + +#define MIPS64_NOP 0 +#define MIPS64_ADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_ADDI, src, tar, val) +#define MIPS64_DADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDI, src, tar, val) +#define MIPS64_DADDIU(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDIU, src, tar, val) +#define MIPS64_AND(reg, off, val) MIPS64_R_INST(0, off, val, reg, 0, MIPS64_OP_AND) +#define MIPS64_ANDI(d, s, im) MIPS64_I_INST(MIPS64_OP_ANDI, s, d, im) +#define MIPS64_SRL(d, w, sh) MIPS64_R_INST(0, 0, w, d, sh, MIPS64_OP_SRL) +#define MIPS64_B(off) MIPS64_BEQ(0, 0, off) +#define MIPS64_BEQ(src, tar, off) MIPS64_I_INST(MIPS64_OP_BEQ, src, tar, off) +#define MIPS64_BNE(src, tar, off) MIPS64_I_INST(MIPS64_OP_BNE, src, tar, off) +#define MIPS64_MFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_DMFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMF, gpr, cpr, 0, sel) +#define MIPS64_MTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_DMTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMT, gpr, cpr, 0, sel) +#define MIPS64_MFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MF, gpr, cpr, 0, 0) +#define MIPS64_DMFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMF, gpr, cpr, 0, 0) +#define MIPS64_MTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MT, gpr, cpr, 0, 0) +#define MIPS64_DMTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMT, gpr, cpr, 0, 0) +#define MIPS64_MFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_MTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_CFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CF, gpr, cpr, 0, 0) +#define MIPS64_CTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CT, gpr, cpr, 0, 0) +#define MIPS64_CFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CF, gpr, cpr, 0, sel) +#define MIPS64_CTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CT, gpr, cpr, 0, sel) +#define MIPS64_LBU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LBU, base, reg, off) +#define MIPS64_LHU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LHU, base, reg, off) +#define MIPS64_LUI(reg, val) MIPS64_I_INST(MIPS64_OP_LUI, 0, reg, val) +#define MIPS64_LW(reg, off, base) MIPS64_I_INST(MIPS64_OP_LW, base, reg, off) +#define MIPS64_LD(reg, off, base) MIPS64_I_INST(MIPS64_OP_LD, base, reg, off) +#define MIPS64_MFLO(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFLO) +#define MIPS64_MFHI(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFHI) +#define MIPS64_MTLO(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTLO) +#define MIPS64_MTHI(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTHI) +#define MIPS64_ORI(src, tar, val) MIPS64_I_INST(MIPS64_OP_ORI, src, tar, val) +#define MIPS64_SB(reg, off, base) MIPS64_I_INST(MIPS64_OP_SB, base, reg, off) +#define MIPS64_SH(reg, off, base) MIPS64_I_INST(MIPS64_OP_SH, base, reg, off) +#define MIPS64_SW(reg, off, base) MIPS64_I_INST(MIPS64_OP_SW, base, reg, off) +#define MIPS64_SD(reg, off, base) MIPS64_I_INST(MIPS64_OP_SD, base, reg, off) +#define MIPS64_CACHE(op, reg, off) (47 << 26 | (reg) << 21 | (op) << 16 | (off)) +#define MIPS64_SYNCI(reg, off) (1 << 26 | (reg) << 21 | 0x1f << 16 | (off)) +#define MIPS64_JR(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_JR) + +/* ejtag specific instructions */ +#define MIPS64_DRET 0x4200001F +#define MIPS64_SDBBP 0x7000003F +#define MIPS64_SDBBP_LE 0x3f000007 +#define MIPS64_SDBBP_SIZE 4 +#define MIPS16_SDBBP_SIZE 2 + +#define MIPS64_SYNC 0x0000000F + +int mips64_arch_state(struct target *target); +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap); +int mips64_restore_context(struct target *target); +int mips64_save_context(struct target *target); +int mips64_build_reg_cache(struct target *target); +int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + int timeout_ms, void *arch_info); +int mips64_configure_break_unit(struct target *target); +int mips64_enable_interrupts(struct target *target, bool enable); +int mips64_examine(struct target *target); + +int mips64_register_commands(struct command_context *cmd_ctx); +int mips64_invalidate_core_regs(struct target *target); +int mips64_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); + +#endif /* OPENOCD_TARGET_MIPS64_H */ diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c new file mode 100644 index 000000000..57addc72a --- /dev/null +++ b/src/target/mips64_pracc.c @@ -0,0 +1,1431 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if BUILD_TARGET64 == 1 + +#include "mips64.h" +#include "mips64_pracc.h" + +#include "time_support.h" + +#define STACK_DEPTH 32 + +typedef struct { + uint64_t *local_iparam; + unsigned num_iparam; + uint64_t *local_oparam; + unsigned num_oparam; + const uint32_t *code; + unsigned code_len; + uint64_t stack[STACK_DEPTH]; + unsigned stack_offset; + struct mips_ejtag *ejtag_info; +} mips64_pracc_context; + +static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) +{ + uint32_t ejtag_ctrl; + int nt = 5; + int rc; + + while (1) { + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + ejtag_ctrl = ejtag_info->ejtag_ctrl; + rc = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + if (ejtag_ctrl & EJTAG_CTRL_PRACC) + break; + LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n"); + if (nt == 0) + return ERROR_JTAG_DEVICE_ERROR; + nt--; + } + + *ctrl = ejtag_ctrl; + return ERROR_OK; +} + +static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) +{ + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + unsigned offset; + uint32_t ejtag_ctrl; + uint64_t data; + int rc; + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + + if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) { + LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected reading of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_iparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected reading of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_oparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_TEXT) + && (address < MIPS64_PRACC_TEXT + ctx->code_len * MIPS64_PRACC_ADDR_STEP)) { + + offset = ((address & ~7ull) - MIPS64_PRACC_TEXT) / MIPS64_PRACC_ADDR_STEP; + data = (uint64_t)ctx->code[offset] << 32; + if (offset + 1 < ctx->code_len) + data |= (uint64_t)ctx->code[offset + 1]; + + LOG_DEBUG("Running commands %" PRIx64 " at %" PRIx64, data, + address); + + } else if ((address & ~7llu) == MIPS64_PRACC_STACK) { + + /* load from our debug stack */ + if (ctx->stack_offset == 0) { + LOG_ERROR("Error reading from stack: stack is empty"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->stack[--ctx->stack_offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else { + /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back + * to start of debug vector */ + + data = 0; + LOG_ERROR("Error reading unexpected address %" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* Send the data out */ + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear the access pending bit (let the processor eat!) */ + + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + + return jtag_execute_queue(); +} + +static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) +{ + uint32_t ejtag_ctrl; + uint64_t data; + unsigned offset; + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + int rc; + + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear access pending bit */ + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + rc = jtag_execute_queue(); + if (rc != ERROR_OK) + return rc; + + LOG_DEBUG("Writing %" PRIx64 " at %" PRIx64, data, address); + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected writing of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_iparam[offset] = data; + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected writing of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_oparam[offset] = data; + } else if (address == MIPS64_PRACC_STACK) { + /* save data onto our stack */ + if (ctx->stack_offset >= STACK_DEPTH) { + LOG_ERROR("Error: PrAcc stack depth exceeded"); + return ERROR_FAIL; + } + ctx->stack[ctx->stack_offset++] = data; + } else { + LOG_ERROR("Error writing unexpected address 0x%" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out) +{ + uint32_t ejtag_ctrl; + uint64_t address = 0, address_prev = 0, data; + mips64_pracc_context ctx; + int retval; + int pass = 0; + bool first_time_call = true; + unsigned i; + + for (i = 0; i < code_len; i++) + LOG_DEBUG("%08x", code[i]); + + ctx.local_iparam = param_in; + ctx.local_oparam = param_out; + ctx.num_iparam = num_param_in; + ctx.num_oparam = num_param_out; + ctx.code = code; + ctx.code_len = code_len; + ctx.ejtag_info = ejtag_info; + ctx.stack_offset = 0; + + while (true) { + uint32_t address32; + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR wait_for_pracc_rw"); + return retval; + } + if (pass) + address_prev = address; + else + address_prev = 0; + address32 = data = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + mips_ejtag_drscan_32(ejtag_info, &address32); + LOG_DEBUG("-> %08x", address32); + address = 0xffffffffff200000ull | address32; + + int psz = (ejtag_ctrl >> 29) & 3; + int address20 = address & 7; + switch (psz) { + case 3: + if (address20 != 7) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + address &= ~7ull; + break; + case 2: + if (address20 != 0 && address20 != 4) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + break; + default: + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + + if (first_time_call && address != MIPS64_PRACC_TEXT) { + LOG_ERROR("Error reading address " TARGET_ADDR_FMT " (0x%08llx expected)", + address, MIPS64_PRACC_TEXT); + return ERROR_JTAG_DEVICE_ERROR; + } + + first_time_call = false; + + /* Check for read or write */ + if (ejtag_ctrl & EJTAG_CTRL_PRNW) { + retval = mips64_pracc_exec_write(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_write\n"); + return retval; + } + } else { + /* Check to see if its reading at the debug vector. The first pass through + * the module is always read at the vector, so the first one we allow. When + * the second read from the vector occurs we are done and just exit. */ + if ((address == MIPS64_PRACC_TEXT) && (pass++)) { + LOG_DEBUG("@MIPS64_PRACC_TEXT, address_prev=%" PRIx64, address_prev); + break; + } + retval = mips64_pracc_exec_read(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_read\n"); + return retval; + } + + } + } + + /* stack sanity check */ + if (ctx.stack_offset != 0) + LOG_ERROR("Pracc Stack not zero"); + + return ERROR_OK; +} + +static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* ld $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LD(8, 0, 8), + /* sd $8, 0($15) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[1]; + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 1, (uint64_t *) buf); +} + +static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LW(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval = ERROR_OK; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint32_t) param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LHU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint16_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LBU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint8_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned size, unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_read_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_read_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_read_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_read_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN)-8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sd $8, 0($9) */ + MIPS64_SD(8, 0, 9), + MIPS64_SYNCI(9, 0), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(13)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + MIPS64_DMTC0(15, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(8, 0, 15), + /* sd $8, ($15) */ + MIPS64_SD(9, 0, 15), + /* sd $9, ($15) */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_SW(8, 0, 9), + /* sw $8, 0($9) */ + MIPS64_SYNCI(9, 0), + MIPS64_LD(9, 0, 15), + /* ld $9, ($15) */ + MIPS64_LD(8, 0, 15), + /* ld $8, ($15) */ + MIPS64_SYNC, + MIPS64_B(NEG16(13)), + /* b start */ + MIPS64_DMFC0(15, 31, 0), + /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[1 + 1]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SH(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SB(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned size, + unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_write_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_write_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_write_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_write_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_IN)), + /* sd $0, 0*8($2) */ + MIPS64_LD(1, 1*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_LD(15, 15*8, 2), + /* sd $11, ($15) */ + MIPS64_DMFC0(2, 31, 0), + MIPS64_DMTC0(15, 31, 0), + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), + /* $11 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_LD(3, 3*8, 1), + MIPS64_LD(4, 4*8, 1), + MIPS64_LD(5, 5*8, 1), + MIPS64_LD(6, 6*8, 1), + MIPS64_LD(7, 7*8, 1), + MIPS64_LD(8, 8*8, 1), + MIPS64_LD(9, 9*8, 1), + MIPS64_LD(10, 10*8, 1), + MIPS64_LD(11, 11*8, 1), + MIPS64_LD(12, 12*8, 1), + MIPS64_LD(13, 13*8, 1), + MIPS64_LD(14, 14*8, 1), + MIPS64_LD(16, 16*8, 1), + MIPS64_LD(17, 17*8, 1), + MIPS64_LD(18, 18*8, 1), + MIPS64_LD(19, 19*8, 1), + MIPS64_LD(20, 20*8, 1), + MIPS64_LD(21, 21*8, 1), + MIPS64_LD(22, 22*8, 1), + MIPS64_LD(23, 23*8, 1), + MIPS64_LD(24, 24*8, 1), + MIPS64_LD(25, 25*8, 1), + MIPS64_LD(26, 26*8, 1), + MIPS64_LD(27, 27*8, 1), + MIPS64_LD(28, 28*8, 1), + MIPS64_LD(29, 29*8, 1), + MIPS64_LD(30, 30*8, 1), + MIPS64_LD(31, 31*8, 1), + MIPS64_LD(2, 32*8, 1), + MIPS64_MTLO(2), + MIPS64_LD(2, 33*8, 1), + MIPS64_MTHI(2), + MIPS64_LD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DEPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_WIRED, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_STATUS, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_LLA, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_ECC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EEPC, 0), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers restoration if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FIR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCSR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCCR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FEXR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FENR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMTC1(2, 0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMTC1(2, 1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMTC1(2, 2, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMTC1(2, 3, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMTC1(2, 4, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMTC1(2, 5, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMTC1(2, 6, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMTC1(2, 7, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMTC1(2, 8, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMTC1(2, 9, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMTC1(2, 10, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMTC1(2, 11, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMTC1(2, 12, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMTC1(2, 13, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMTC1(2, 14, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMTC1(2, 15, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMTC1(2, 16, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMTC1(2, 17, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMTC1(2, 18, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMTC1(2, 19, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMTC1(2, 20, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMTC1(2, 21, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMTC1(2, 22, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMTC1(2, 23, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMTC1(2, 24, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMTC1(2, 25, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMTC1(2, 26, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMTC1(2, 27, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMTC1(2, 28, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMTC1(2, 29, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMTC1(2, 30, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_DMTC1(2, 31, 0), + MIPS64_LD(2, 2 * 8, 1), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(181)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + MIPS64_NUM_REGS, regs, 0, NULL); +} + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $2 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_OUT)), + /* sd $0, 0*8($2) */ + MIPS64_SD(0, 0*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_SD(1, 1*8, 2), + /* sd $15, 15*8($2) */ + MIPS64_SD(15, 15*8, 2), + /* move COP0 DeSave to $2 */ + MIPS64_DMFC0(2, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $1, ($15) */ + MIPS64_SD(1, 0, 15), + /* sd $2, ($15) */ + MIPS64_SD(2, 0, 15), + /* $1 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_SD(2, 2 * 8, 1), + MIPS64_SD(3, 3 * 8, 1), + MIPS64_SD(4, 4 * 8, 1), + MIPS64_SD(5, 5 * 8, 1), + MIPS64_SD(6, 6 * 8, 1), + MIPS64_SD(7, 7 * 8, 1), + MIPS64_SD(8, 8 * 8, 1), + MIPS64_SD(9, 9 * 8, 1), + MIPS64_SD(10, 10 * 8, 1), + MIPS64_SD(11, 11 * 8, 1), + MIPS64_SD(12, 12 * 8, 1), + MIPS64_SD(13, 13 * 8, 1), + MIPS64_SD(14, 14 * 8, 1), + MIPS64_SD(16, 16 * 8, 1), + MIPS64_SD(17, 17 * 8, 1), + MIPS64_SD(18, 18 * 8, 1), + MIPS64_SD(19, 19 * 8, 1), + MIPS64_SD(20, 20 * 8, 1), + MIPS64_SD(21, 21 * 8, 1), + MIPS64_SD(22, 22 * 8, 1), + MIPS64_SD(23, 23 * 8, 1), + MIPS64_SD(24, 24 * 8, 1), + MIPS64_SD(25, 25 * 8, 1), + MIPS64_SD(26, 26 * 8, 1), + MIPS64_SD(27, 27 * 8, 1), + MIPS64_SD(28, 28 * 8, 1), + MIPS64_SD(29, 29 * 8, 1), + MIPS64_SD(30, 30 * 8, 1), + MIPS64_SD(31, 31 * 8, 1), + MIPS64_MFLO(2), + MIPS64_SD(2, 32 * 8, 1), + MIPS64_MFHI(2), + MIPS64_SD(2, 33 * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DEPC, 0), + MIPS64_SD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_RANDOM, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 1) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_WIRED, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_BADVADDR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 7) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PRID, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 14) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_LLA, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_DEBUG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 23) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_ECC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EEPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers dump if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_CFC1(2, MIPS64_C1_FIR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCSR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCCR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FEXR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FENR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_DMFC1(2, 0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMFC1(2, 1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMFC1(2, 2, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMFC1(2, 3, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMFC1(2, 4, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMFC1(2, 5, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMFC1(2, 6, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMFC1(2, 7, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMFC1(2, 8, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMFC1(2, 9, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMFC1(2, 10, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMFC1(2, 11, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMFC1(2, 12, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMFC1(2, 13, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMFC1(2, 14, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMFC1(2, 15, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMFC1(2, 16, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMFC1(2, 17, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMFC1(2, 18, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMFC1(2, 19, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMFC1(2, 20, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMFC1(2, 21, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMFC1(2, 22, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMFC1(2, 23, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMFC1(2, 24, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMFC1(2, 25, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMFC1(2, 26, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMFC1(2, 27, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMFC1(2, 28, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMFC1(2, 29, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMFC1(2, 30, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMFC1(2, 31, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(192)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 0, NULL, MIPS64_NUM_REGS, regs); +} + +/* 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 + * 1. start addr + * 2. end addr + * 3. data ... + */ +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf) +{ + uint32_t handler_code[] = { + /* caution when editing, table is modified below */ + /* r15 points to the start of this code */ + MIPS64_SD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_SD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_SD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_SD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + /* start of fastdata area in t0 */ + MIPS64_LUI(8, UPPER16(MIPS64_PRACC_FASTDATA_AREA)), + MIPS64_ORI(8, 8, LOWER16(MIPS64_PRACC_FASTDATA_AREA)), + /* start addr in t1 */ + MIPS64_LD(9, 0, 8), + /* end addr to t2 */ + MIPS64_LD(10, 0, 8), + + /* loop: */ + /* lw t3,[t8 | r9] */ + /* 8 */ MIPS64_LD(11, 0, 0), + /* sw t3,[r9 | r8] */ + /* 9 */ MIPS64_SD(11, 0, 0), + /* bne $t2,t1,loop */ + MIPS64_BNE(10, 9, NEG16(3)), + /* addi t1,t1,4 */ + MIPS64_DADDIU(9, 9, 8), + + MIPS64_LD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_LD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_LD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_LD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_TEXT)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_TEXT)), + /* jr start */ + MIPS64_JR(15), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + }; + + uint32_t jmp_code[] = { + /* addr of working area added below */ + /* 0 */ MIPS64_LUI(15, 0), + /* addr of working area added below */ + /* 1 */ MIPS64_ORI(15, 15, 0), + /* jump to ram program */ + MIPS64_JR(15), + MIPS64_NOP, + }; + + int retval; + unsigned i; + uint32_t ejtag_ctrl, address32; + uint64_t address, val; + + if (source->size < MIPS64_FASTDATA_HANDLER_SIZE) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (write_t) { + /* load data from probe at fastdata area */ + handler_code[8] = MIPS64_LD(11, 0, 8); + /* store data to RAM @ r9 */ + handler_code[9] = MIPS64_SD(11, 0, 9); + } else { + /* load data from RAM @ r9 */ + handler_code[8] = MIPS64_LD(11, 0, 9); + /* store data to probe at fastdata area */ + handler_code[9] = MIPS64_SD(11, 0, 8); + } + + /* write program into RAM */ + if (write_t != ejtag_info->fast_access_save) { + mips64_pracc_write_mem(ejtag_info, source->address, 4, + ARRAY_SIZE(handler_code), handler_code); + /* save previous operation to speed to any consecutive read/writes */ + ejtag_info->fast_access_save = write_t; + } + + LOG_DEBUG("%s using " TARGET_ADDR_FMT " for write handler", __func__, + source->address); + LOG_DEBUG("daddiu: %08x", handler_code[11]); + + jmp_code[0] |= UPPER16(source->address); + jmp_code[1] |= LOWER16(source->address); + mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(jmp_code), jmp_code, + 0, NULL, 0, NULL); + + /* next fetch to dmseg should be in FASTDATA_AREA, check */ + address = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) + return retval; + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_FASTDATA_AREA) { + LOG_ERROR("! @MIPS64_PRACC_FASTDATA_AREA (" TARGET_ADDR_FMT ")", address); + return ERROR_FAIL; + } + /* Send the load start address */ + val = addr; + LOG_DEBUG("start: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) + return retval; + + /* Send the load end address */ + val = addr + (count - 1) * 8; + LOG_DEBUG("stop: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + /* like in legacy code */ + unsigned num_clocks = 0; + if (ejtag_info->mode != 0) + num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + LOG_DEBUG("num_clocks=%d", num_clocks); + for (i = 0; i < count; i++) { + jtag_add_clocks(num_clocks); + retval = mips64_ejtag_fastdata_scan(ejtag_info, write_t, buf++); + if (retval != ERROR_OK) { + LOG_ERROR("mips64_ejtag_fastdata_scan failed"); + return retval; + } + } + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("jtag_execute_queue failed"); + return retval; + } + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_ERROR("wait_for_pracc_rw failed"); + return retval; + } + + address = 0; + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) { + LOG_ERROR("mips_ejtag_drscan_32 failed"); + return retval; + } + + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_TEXT) + LOG_ERROR("mini program did not return to start"); + + return retval; +} + +#endif /* BUILD_TARGET64 */ diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h new file mode 100644 index 000000000..65ff6e6ac --- /dev/null +++ b/src/target/mips64_pracc.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov + * Copyright (C) 2014 by Aleksey Kuleshov + * Copyright (C) 2014-2019 by Peter Mamonov + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_PRACC_H +#define OPENOCD_TARGET_MIPS64_PRACC_H + +#include "mips_ejtag.h" + +#define MIPS64_PRACC_TEXT 0xffffffffFF200200ull + +#define MIPS64_PRACC_STACK 0xffffffffFF204000ull +#define MIPS64_PRACC_PARAM_IN 0xffffffffFF201000ull +#define MIPS64_PRACC_PARAM_IN_SIZE 0x1000 +#define MIPS64_PRACC_PARAM_OUT (MIPS64_PRACC_PARAM_IN + MIPS64_PRACC_PARAM_IN_SIZE) +#define MIPS64_PRACC_PARAM_OUT_SIZE 0x1000 + +#undef UPPER16 +#undef LOWER16 +#define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) +#define LOWER16(v) ((uint32_t)(v & 0xFFFF)) +#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000 +#define MIPS64_PRACC_FASTDATA_SIZE 16 +#define MIPS64_FASTDATA_HANDLER_SIZE 0x80 + +/* FIXME: 16-bit NEG */ +#undef NEG16 +#define NEG16(v) ((uint32_t)(((~(v)) + 1) & 0xFFFF)) + +#define MIPS64_PRACC_ADDR_STEP 4 +#define MIPS64_PRACC_DATA_STEP 8 + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out); + +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf); + +#endif /* OPENOCD_TARGET_MIPS64_PRACC_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 03a09529c..0b8122e1c 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -28,6 +28,11 @@ #include "mips_ejtag.h" #include "mips32_dmaacc.h" +#if BUILD_TARGET64 == 1 +#include "mips64.h" +#include "mips64_pracc.h" +#endif + void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { assert(ejtag_info->tap != NULL); @@ -87,6 +92,36 @@ void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32 keep_alive(); } +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) +{ + struct jtag_tap *tap; + tap = ejtag_info->tap; + + if (tap == NULL) + return ERROR_FAIL; + struct scan_field field; + uint8_t t[8], r[8]; + int retval; + + field.num_bits = 64; + field.out_value = t; + buf_set_u64(t, 0, field.num_bits, *data); + field.in_value = r; + + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("register read failed"); + return retval; + } + + *data = buf_get_u64(field.in_value, 0, 64); + + keep_alive(); + + return ERROR_OK; +} + void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) { assert(ejtag_info->tap != NULL); @@ -422,3 +457,112 @@ int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_ return ERROR_OK; } + +#if BUILD_TARGET64 == 1 + +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step) +{ + const uint32_t code_enable[] = { + MIPS64_MTC0(1, 31, 0), /* move $1 to COP0 DeSave */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_ORI(1, 1, 0x0100), /* set SSt bit in debug reg */ + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_B(NEG16(5)), + MIPS64_MFC0(1, 31, 0), /* move COP0 DeSave to $1 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + const uint32_t code_disable[] = { + MIPS64_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), /* sw $1,($15) */ + MIPS64_SD(2, 0, 15), /* sw $2,($15) */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_LUI(2, 0xFFFF), /* $2 = 0xfffffeff */ + MIPS64_ORI(2, 2, 0xFEFF), + MIPS64_AND(1, 1, 2), + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + MIPS64_B(NEG16(14)), + MIPS64_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + const uint32_t *code = enable_step ? code_enable : code_disable; + unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) : + ARRAY_SIZE(code_disable); + + return mips64_pracc_exec(ejtag_info, + code_len, code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info) +{ + const uint32_t code[] = { + MIPS64_DRET, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(code), code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data) +{ + struct jtag_tap *tap; + + tap = ejtag_info->tap; + assert(tap != NULL); + + struct scan_field fields[2]; + uint8_t spracc = 0; + uint8_t t[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + /* fastdata 1-bit register */ + fields[0].num_bits = 1; + fields[0].out_value = &spracc; + fields[0].in_value = NULL; + + /* processor access data register 64 bit */ + fields[1].num_bits = 64; + fields[1].out_value = t; + + if (write_t) { + fields[1].in_value = NULL; + buf_set_u64(t, 0, 64, *data); + } else + fields[1].in_value = (uint8_t *) data; + + jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); + + if (!write_t && data) + jtag_add_callback(mips_le_to_h_u64, + (jtag_callback_data_t) data); + keep_alive(); + + return ERROR_OK; +} + +#endif /* BUILD_TARGET64 */ diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index c64e858a3..cfba0ab56 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -182,6 +182,20 @@ #define EJTAG_VERSION_41 4 #define EJTAG_VERSION_51 5 +/* + * Additional defines for MIPS64 EJTAG + */ +#define EJTAG64_DCR 0xFFFFFFFFFF300000ull +#define EJTAG64_DCR_ENM (1llu << 29) +#define EJTAG64_DCR_DB (1llu << 17) +#define EJTAG64_DCR_IB (1llu << 16) +#define EJTAG64_DCR_INTE (1llu << 4) +#define EJTAG64_DCR_MP (1llu << 2) +#define EJTAG64_V25_DBA0 0xFFFFFFFFFF302100ull +#define EJTAG64_V25_DBS 0xFFFFFFFFFF302000ull +#define EJTAG64_V25_IBA0 0xFFFFFFFFFF301100ull +#define EJTAG64_V25_IBS 0xFFFFFFFFFF301000ull + struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; @@ -224,17 +238,21 @@ struct mips_ejtag { void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step); static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { @@ -242,4 +260,10 @@ static inline void mips_le_to_h_u32(jtag_callback_data_t arg) *((uint32_t *)arg) = le_to_h_u32(in); } +static inline void mips_le_to_h_u64(jtag_callback_data_t arg) +{ + uint8_t *in = (uint8_t *)arg; + *((uint64_t *)arg) = le_to_h_u64(in); +} + #endif /* OPENOCD_TARGET_MIPS_EJTAG_H */