aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/target/Makefile.am10
-rw-r--r--src/target/mips64.c627
-rw-r--r--src/target/mips64.h226
-rw-r--r--src/target/mips64_pracc.c1431
-rw-r--r--src/target/mips64_pracc.h59
-rw-r--r--src/target/mips_ejtag.c144
-rw-r--r--src/target/mips_ejtag.h24
7 files changed, 2521 insertions, 0 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index afa5f49b..2a7cc4b3 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 00000000..f65aec11
--- /dev/null
+++ b/src/target/mips64.c
@@ -0,0 +1,627 @@
+/*
+ * Support for processors implementing MIPS64 instruction set
+ *
+ * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014 by Antony Pavlov <antonynpavlov@gmail.com>
+ * Copyright (C) 2014 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * 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 = &reg_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 00000000..3453e4ed
--- /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 <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * 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 00000000..57addc72
--- /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 <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * 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 00000000..65ff6e6a
--- /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 <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * 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 03a09529..0b8122e1 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 c64e858a..cfba0ab5 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 */