[Pdbg] [PATCH 09/10] pdbg: add 'regs' command

Nicholas Piggin npiggin at gmail.com
Thu May 3 16:27:01 AEST 2018


This uses ramming to pull out most registers. There are more
SPRs to left to add.

Ramming remains set over all register extraction, by keeping
ram_is_setup target attribut. This helps to speed things up
and minimise disturbance to the host.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 libpdbg/chip.c       | 169 ++++++++++++++++++++++++++++++++++++++++++-
 libpdbg/libpdbg.h    |  38 ++++++++++
 libpdbg/operations.h |   5 ++
 libpdbg/p8chip.c     |  10 +++
 libpdbg/p9chip.c     |  24 ++++++
 libpdbg/target.h     |   1 +
 src/main.c           |   1 +
 src/thread.c         |  18 +++++
 src/thread.h         |   1 +
 9 files changed, 265 insertions(+), 2 deletions(-)

diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index ebfaaa8..ee12614 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -15,6 +15,7 @@
  */
 #include <stdio.h>
 #include <stdint.h>
+#include <inttypes.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ccan/array_size/array_size.h>
@@ -40,6 +41,16 @@ static uint64_t mtspr(uint64_t spr, uint64_t reg)
 	return MTSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
 }
 
+static uint64_t mfocrf(uint64_t reg, uint64_t cr)
+{
+	if (reg > 31)
+		PR_ERROR("Invalid register specified\n");
+	if (cr > 7)
+		PR_ERROR("Invalid register specified\n");
+
+	return MFOCRF_OPCODE | (reg << 21) | (1U << (12 + cr));
+}
+
 static uint64_t mfnia(uint64_t reg)
 {
 	if (reg > 31)
@@ -143,10 +154,15 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
 	int i;
 	int exception = 0;
 	struct thread *thread;
+	bool did_setup = false;
 
 	assert(!strcmp(thread_target->class, "thread"));
 	thread = target_to_thread(thread_target);
-	CHECK_ERR(thread->ram_setup(thread));
+
+	if (!thread->ram_is_setup) {
+		CHECK_ERR(thread->ram_setup(thread));
+		did_setup = true;
+	}
 
 	/* RAM instructions */
 	for (i = -2; i < len + 2; i++) {
@@ -182,7 +198,8 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
 			results[i] = scratch;
 	}
 
-	CHECK_ERR(thread->ram_destroy(thread));
+	if (did_setup)
+		CHECK_ERR(thread->ram_destroy(thread));
 
 	return exception;
 }
@@ -258,6 +275,16 @@ int ram_getmsr(struct pdbg_target *thread, uint64_t *value)
 	return 0;
 }
 
+int ram_getcr(struct pdbg_target *thread, int cr, uint64_t *value)
+{
+	uint64_t opcodes[] = {mfocrf(0, cr), mtspr(277, 0)};
+	uint64_t results[] = {0, 0};
+
+	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
+	*value = results[1];
+	return 0;
+}
+
 int ram_putmsr(struct pdbg_target *thread, uint64_t value)
 {
 	uint64_t opcodes[] = {mfspr(0, 277), mtmsr(0)};
@@ -288,3 +315,141 @@ int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t rin
 	chiplet = target_to_chiplet(chiplet_target);
 	return chiplet->getring(chiplet, ring_addr, ring_len, result);
 }
+
+int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs)
+{
+	struct thread_regs _regs;
+	struct thread *t;
+	uint64_t value;
+	int i;
+
+	if (!regs)
+		regs = &_regs;
+
+	assert(!strcmp(thread->class, "thread"));
+	t = target_to_thread(thread);
+
+	CHECK_ERR(t->ram_setup(t));
+
+	/*
+	 * It would be neat to do all the ramming up front, then go through
+	 * and print everything out somewhere else. In practice so far it
+	 * can help to diagnose checkstop issues with ramming to print as
+	 * we go. Once it's more robust and tested, maybe.
+	 */
+	ram_getnia(thread, &regs->nia);
+	printf("NIA   : 0x%016" PRIx64 "\n", regs->nia);
+
+	ram_getspr(thread, 28, &regs->cfar);
+	printf("CFAR  : 0x%016" PRIx64 "\n", regs->cfar);
+
+	ram_getmsr(thread, &regs->msr);
+	printf("MSR   : 0x%016" PRIx64 "\n", regs->msr);
+
+	ram_getspr(thread, 8, &regs->lr);
+	printf("LR    : 0x%016" PRIx64 "\n", regs->lr);
+
+	ram_getspr(thread, 9, &regs->ctr);
+	printf("CTR   : 0x%016" PRIx64 "\n", regs->ctr);
+
+	ram_getspr(thread, 815, &regs->tar);
+	printf("TAR   : 0x%016" PRIx64 "\n", regs->tar);
+
+	regs->cr = 0;
+	for (i = 0; i < 8; i++) {
+		uint64_t cr;
+		ram_getcr(thread, i, &cr);
+		regs->cr |= cr;
+	}
+	printf("CR    : 0x%08" PRIx32 "\n", regs->cr);
+
+	ram_getspr(thread, 0x1, &value);
+	regs->xer = value;
+	printf("XER   : 0x%08" PRIx32 "\n", regs->xer);
+
+	printf("GPRS  :\n");
+	for (i = 0; i < 32; i++) {
+		ram_getgpr(thread, i, &regs->gprs[i]);
+		printf(" 0x%016" PRIx64 "", regs->gprs[i]);
+		if (i % 4 == 3)
+			printf("\n");
+	}
+
+	ram_getspr(thread, 318, &regs->lpcr);
+	printf("LPCR  : 0x%016" PRIx64 "\n", regs->lpcr);
+
+	ram_getspr(thread, 464, &regs->ptcr);
+	printf("PTCR  : 0x%016" PRIx64 "\n", regs->lpcr);
+
+	ram_getspr(thread, 319, &regs->lpidr);
+	printf("LPIDR : 0x%016" PRIx64 "\n", regs->lpidr);
+
+	ram_getspr(thread, 48, &regs->pidr);
+	printf("PIDR  : 0x%016" PRIx64 "\n", regs->pidr);
+
+	ram_getspr(thread, 190, &regs->hfscr);
+	printf("HFSCR : 0x%016" PRIx64 "\n", regs->hfscr);
+
+	ram_getspr(thread, 306, &value);
+	regs->hdsisr = value;
+	printf("HDSISR: 0x%08" PRIx32 "\n", regs->hdsisr);
+
+	ram_getspr(thread, 307, &regs->hdar);
+	printf("HDAR  : 0x%016" PRIx64 "\n", regs->hdar);
+
+	ram_getspr(thread, 314, &regs->hsrr0);
+	printf("HSRR0 : 0x%016" PRIx64 "\n", regs->hsrr0);
+
+	ram_getspr(thread, 315, &regs->hsrr1);
+	printf("HSRR1 : 0x%016" PRIx64 "\n", regs->hsrr1);
+
+	ram_getspr(thread, 310, &regs->hdec);
+	printf("HDEC  : 0x%016" PRIx64 "\n", regs->hdec);
+
+	ram_getspr(thread, 304, &regs->hsprg0);
+	printf("HSPRG0: 0x%016" PRIx64 "\n", regs->hsprg0);
+
+	ram_getspr(thread, 305, &regs->hsprg1);
+	printf("HSPRG1: 0x%016" PRIx64 "\n", regs->hsprg1);
+
+	ram_getspr(thread, 153, &regs->fscr);
+	printf("FSCR  : 0x%016" PRIx64 "\n", regs->fscr);
+
+	ram_getspr(thread, 18, &value);
+	regs->dsisr = value;
+	printf("DSISR : 0x%08" PRIx32 "\n", regs->dsisr);
+
+	ram_getspr(thread, 19, &regs->dar);
+	printf("DAR   : 0x%016" PRIx64 "\n", regs->dar);
+
+	ram_getspr(thread, 26, &regs->srr0);
+	printf("SRR0  : 0x%016" PRIx64 "\n", regs->srr0);
+
+	ram_getspr(thread, 27, &regs->srr1);
+	printf("SRR1  : 0x%016" PRIx64 "\n", regs->srr1);
+
+	ram_getspr(thread, 22, &regs->dec);
+	printf("DEC   : 0x%016" PRIx64 "\n", regs->dec);
+
+	ram_getspr(thread, 268, &regs->tb);
+	printf("TB    : 0x%016" PRIx64 "\n", regs->tb);
+
+	ram_getspr(thread, 272, &regs->sprg0);
+	printf("SPRG0 : 0x%016" PRIx64 "\n", regs->sprg0);
+
+	ram_getspr(thread, 273, &regs->sprg1);
+	printf("SPRG1 : 0x%016" PRIx64 "\n", regs->sprg1);
+
+	ram_getspr(thread, 274, &regs->sprg2);
+	printf("SPRG2 : 0x%016" PRIx64 "\n", regs->sprg2);
+
+	ram_getspr(thread, 275, &regs->sprg3);
+	printf("SPRG3 : 0x%016" PRIx64 "\n", regs->sprg3);
+
+	ram_getspr(thread, 896, &regs->ppr);
+	printf("PPR   : 0x%016" PRIx64 "\n", regs->ppr);
+
+	CHECK_ERR(t->ram_destroy(t));
+
+	return 0;
+}
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index 2fec479..9ce5999 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -90,6 +90,43 @@ int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val);
 int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val);
 int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data);
 
+struct thread_regs {
+	uint64_t nia;
+	uint64_t msr;
+	uint64_t cfar;
+	uint64_t lr;
+	uint64_t ctr;
+	uint64_t tar;
+	uint32_t cr;
+	uint32_t xer;
+	uint64_t gprs[32];
+
+	uint64_t lpcr;
+	uint64_t ptcr;
+	uint64_t lpidr;
+	uint64_t pidr;
+	uint64_t hfscr;
+	uint32_t hdsisr;
+	uint64_t hdar;
+	uint64_t hsrr0;
+	uint64_t hsrr1;
+	uint64_t hdec;
+	uint64_t hsprg0;
+	uint64_t hsprg1;
+	uint64_t fscr;
+	uint32_t dsisr;
+	uint64_t dar;
+	uint64_t srr0;
+	uint64_t srr1;
+	uint64_t dec;
+	uint64_t tb;
+	uint64_t sprg0;
+	uint64_t sprg1;
+	uint64_t sprg2;
+	uint64_t sprg3;
+	uint64_t ppr;
+};
+
 int ram_putmsr(struct pdbg_target *target, uint64_t val);
 int ram_putnia(struct pdbg_target *target, uint64_t val);
 int ram_putspr(struct pdbg_target *target, int spr, uint64_t val);
@@ -102,6 +139,7 @@ int ram_start_thread(struct pdbg_target *target);
 int ram_step_thread(struct pdbg_target *target, int steps);
 int ram_stop_thread(struct pdbg_target *target);
 int ram_sreset_thread(struct pdbg_target *target);
+int ram_state_thread(struct pdbg_target *target, struct thread_regs *regs);
 uint64_t thread_status(struct pdbg_target *target);
 int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]);
 
diff --git a/libpdbg/operations.h b/libpdbg/operations.h
index 3954c59..2b0f092 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -67,8 +67,13 @@ int adu_putmem(struct pdbg_target *target, uint64_t start_addr, uint8_t *input,
 #define MTMSR_OPCODE 0x7c000124UL
 #define MFSPR_OPCODE 0x7c0002a6UL
 #define MTSPR_OPCODE 0x7c0003a6UL
+#define MFOCRF_OPCODE 0x7c100026UL
+#define MFSPR_MASK (MFSPR_OPCODE | ((0x1f) << 16) | ((0x3e0) << 6))
+#define MFXER_OPCODE (MFSPR_OPCODE | ((1 & 0x1f) << 16) | ((1 & 0x3e0) << 6))
 #define LD_OPCODE 0xe8000000UL
 
+#define MFSPR_SPR(opcode) (((opcode >> 16) & 0x1f) | ((opcode >> 6) & 0x3e0))
+
 /* GDB server functionality */
 int gdbserver_start(uint16_t port);
 
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index 6cae663..b256c57 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -222,6 +222,9 @@ static int p8_ram_setup(struct thread *thread)
 	struct core *chip = target_to_core(thread->target.parent);
 	uint64_t ram_mode, val;
 
+	if (thread->ram_is_setup)
+		return 1;
+
 	/* We can only ram a thread if all the threads on the core/chip are
 	 * quiesced */
 	dt_for_each_compatible(&chip->target, target, "ibm,power8-thread") {
@@ -246,6 +249,8 @@ static int p8_ram_setup(struct thread *thread)
 	CHECK_ERR(pib_write(&chip->target, SPR_MODE_REG, val));
 	CHECK_ERR(pib_write(&chip->target, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR));
 
+	thread->ram_is_setup = true;
+
 	return 0;
 }
 
@@ -254,6 +259,9 @@ static int p8_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *
 	struct core *chip = target_to_core(thread->target.parent);
 	uint64_t val;
 
+	if (!thread->ram_is_setup)
+		return 1;
+
 	CHECK_ERR(pib_write(&chip->target, SCR0_REG, *scratch));
 
 	/* ram instruction */
@@ -291,6 +299,8 @@ static int p8_ram_destroy(struct thread *thread)
 	ram_mode &= ~RAM_MODE_ENABLE;
 	CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode));
 
+	thread->ram_is_setup = false;
+
 	return 0;
 }
 
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index 7182ae1..f6fd849 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -241,6 +241,9 @@ static int p9_ram_setup(struct thread *thread)
 	struct core *chip = target_to_core(thread->target.parent);
 	uint64_t value;
 
+	if (thread->ram_is_setup)
+		return 1;
+
 	if (pdbg_expert_mode)
 		goto expert;
 
@@ -299,6 +302,8 @@ expert:
 
 	thread->status = p9_get_thread_status(thread);
 
+	thread->ram_is_setup = true;
+
 	return 0;
 
 out_fail:
@@ -313,6 +318,9 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
 	uint64_t predecode, value;
 	int rc;
 
+	if (!thread->ram_is_setup)
+		return 1;
+
 	switch(opcode & OPCODE_MASK) {
 	case MTNIA_OPCODE:
 		predecode = 8;
@@ -330,6 +338,17 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
 		predecode = 8;
 		break;
 
+	case MFSPR_OPCODE:
+		switch(MFSPR_SPR(opcode)) {
+		case 1: /* XER */
+			predecode = 4;
+			break;
+		default:
+			predecode = 0;
+			break;
+		}
+		break;
+
 	default:
 		predecode = 0;
 	}
@@ -392,6 +411,9 @@ static int p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *
 
 static int p9_ram_destroy(struct thread *thread)
 {
+	if (!thread->ram_is_setup)
+		return 1;
+
 	/* Disable ram mode */
 	CHECK_ERR(thread_write(thread, P9_RAM_MODEREG, 0));
 
@@ -402,6 +424,8 @@ static int p9_ram_destroy(struct thread *thread)
 
 	ram_nonexpert_cleanup(thread);
 
+	thread->ram_is_setup = false;
+
 	return 0;
 }
 
diff --git a/libpdbg/target.h b/libpdbg/target.h
index 0d310fd..de7f33c 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -156,6 +156,7 @@ struct thread {
 	/* ram_setup() should be called prior to using ram_instruction() to
 	 * actually ram the instruction and return the result. ram_destroy()
 	 * should be called at completion to clean-up. */
+	bool ram_is_setup;
 	int (*ram_setup)(struct thread *);
 	int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch);
 	int (*ram_destroy)(struct thread *);
diff --git a/src/main.c b/src/main.c
index a295ef1..6540c8c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -107,6 +107,7 @@ static struct action actions[] = {
 	{ "probe", "", "", &handle_probe },
 	{ "threadstatus", "", "Print the status of a thread", &thread_status_print },
 	{ "sreset",  "", "Reset", &thread_sreset },
+	{ "regs",  "", "State", &thread_state },
 };
 
 
diff --git a/src/thread.c b/src/thread.c
index 13fa09d..a6e096b 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -127,6 +127,13 @@ static int sreset_thread(struct pdbg_target *thread_target, uint32_t index, uint
 	return ram_sreset_thread(thread_target) ? 0 : 1;
 }
 
+static int state_thread(struct pdbg_target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
+{
+	struct thread_regs regs;
+
+	return ram_state_thread(thread_target, &regs) ? 0 : 1;
+}
+
 int thread_start(int optind, int argc, char *argv[])
 {
 	return for_each_target("thread", start_thread, NULL, NULL);
@@ -167,3 +174,14 @@ int thread_sreset(int optind, int argc, char *argv[])
 {
 	return for_each_target("thread", sreset_thread, NULL, NULL);
 }
+
+int thread_state(int optind, int argc, char *argv[])
+{
+	int err;
+
+	err = for_each_target("thread", state_thread, NULL, NULL);
+
+	for_each_target_release("thread");
+
+	return err;
+}
diff --git a/src/thread.h b/src/thread.h
index 01a8034..5fc2a80 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -22,3 +22,4 @@ int thread_step(int optind, int argc, char *argv[]);
 int thread_stop(int optind, int argc, char *argv[]);
 int thread_status_print(int optind, int argc, char *argv[]);
 int thread_sreset(int optind, int argc, char *argv[]);
+int thread_state(int optind, int argc, char *argv[]);
-- 
2.17.0



More information about the Pdbg mailing list