[Pdbg] [PATCH 02/10] libpdbg: Add in getxer and putxer functions

Rashmica Gupta rashmica.g at gmail.com
Thu May 31 15:29:07 AEST 2018


Signed-off-by: Rashmica Gupta <rashmica.g at gmail.com>
---
 libpdbg/chip.c       | 122 ++++++++++++++++++++++++++++++++++++++++++++++++---
 libpdbg/libpdbg.h    |   2 +
 libpdbg/operations.h |  11 ++++-
 libpdbg/p9chip.c     |  16 ++++---
 4 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 50d8984..e91d775 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -84,6 +84,46 @@ static uint64_t mtmsr(uint64_t reg)
 	return MTMSR_OPCODE | (reg << 21);
 }
 
+static uint64_t mfxerf(uint64_t reg, uint64_t field)
+{
+	if (reg > 31)
+		PR_ERROR("Invalid register specified for mfxerf\n");
+
+	switch(field) {
+	case 0:
+		return MFXERF0_OPCODE | (reg << 21);
+	case 1:
+		return MFXERF1_OPCODE | (reg << 21);
+	case 2:
+		return MFXERF2_OPCODE | (reg << 21);
+	case 3:
+		return MFXERF3_OPCODE | (reg << 21);
+	default:
+		PR_ERROR("Invalid XER field specified\n");
+	}
+	return 0;
+}
+
+static uint64_t mtxerf(uint64_t reg, uint64_t field)
+{
+	if (reg > 31)
+		PR_ERROR("Invalid register specified for mtxerf\n");
+
+	switch(field) {
+	case 0:
+		return MTXERF0_OPCODE | (reg << 21);
+	case 1:
+		return MTXERF1_OPCODE | (reg << 21);
+	case 2:
+		return MTXERF2_OPCODE | (reg << 21);
+	case 3:
+		return MTXERF3_OPCODE | (reg << 21);
+	default:
+		PR_ERROR("Invalid XER field specified\n");
+	}
+	return 0;
+}
+
 static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra)
 {
 	if ((rt > 31) | (ra > 31) | (ds > 0x3fff))
@@ -168,6 +208,7 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
 	/* RAM instructions */
 	for (i = -2; i < len + 2; i++) {
 		if (i == -2)
+			/* Save r1 (assumes opcodes don't touch other registers) */
 			opcode = mtspr(277, 1);
 		else if (i == -1)
 			/* Save r0 (assumes opcodes don't touch other registers) */
@@ -185,6 +226,7 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
 			opcode = mfspr(1, 277);
 		}
 
+		PR_DEBUG("opcode %016lx!\n", opcode);
 		if (thread->ram_instruction(thread, opcode, &scratch)) {
 			PR_DEBUG("%s: %d\n", __FUNCTION__, __LINE__);
 			exception = 1;
@@ -305,6 +347,80 @@ int ram_getmem(struct pdbg_target *thread, uint64_t addr, uint64_t *value)
 	return 0;
 }
 
+int ram_getxer_field(struct pdbg_target *thread, uint64_t *value, uint64_t field)
+{
+	uint64_t opcodes[] = {mfxerf(0, field), 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_getxer(struct pdbg_target *thread, uint64_t *value)
+{
+	uint64_t fields[] = {0, 0, 0, 0};
+	int i;
+
+	if (strcmp(thread->name, "POWER8 Thread") == 0) {
+		/* On POWER8 we can't get xer with getspr. We can only get IBM
+		 * bits 33-39 and 41-43 using the xer fields. The rest of the
+		 * bits are in latches somewhere. */
+		for (i = 0; i < 4; i++) {
+			ram_getxer_field(thread, &fields[i], i);
+		}
+		*value = fields[0] | fields[1] | fields[2] | fields[3];
+	} else if (strcmp(thread->name, "POWER9 Thread") == 0) {
+		ram_getspr(thread, 1, value);
+	} else {
+		PR_ERROR("Not implemented on this version of POWER\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int ram_putxer_field(struct pdbg_target *thread, uint64_t value, uint64_t field)
+{
+	uint64_t opcodes[] = {mfspr(0, 277), mtxerf(0, field)};
+	uint64_t results[] = {value, 0};
+
+	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
+
+	return 0;
+}
+
+int ram_putxer(struct pdbg_target *thread, uint64_t value)
+{
+	uint64_t fields[] = {0, 0, 0, 0};
+	int i;
+
+	if (strcmp(thread->name, "POWER8 Thread") == 0) {
+		/* On POWER8 we can't write to xer with getspr */
+		/* The rest of the bits are in latches. Probably can only set f0 and the first
+		 * bit of f1 as these are the only bits in the four fields that are publicly
+		 * documented (IBM bits 33-34).
+		 */
+		fields[0] = (value & (0x1 << 30));
+		fields[1] = (value & (0x3 << 28));
+		fields[2] = (value & (0xf << 24));
+		fields[3] = (value & (0x7 << 20 ));
+
+		for (i = 0; i < 4; i++) {
+			ram_putxer_field(thread, fields[i], i);
+		}
+	} else if (strcmp(thread->name, "POWER9 Thread") == 0) {
+		/* On POWER9 we can only set bits 32-34 and 44-63.*/
+		ram_putspr(thread, 1, value);
+	} else {
+		PR_ERROR("Not implemented on this version of POWER\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits.
  */
@@ -364,12 +480,8 @@ int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs)
 	}
 	printf("CR    : 0x%08" PRIx32 "\n", regs->cr);
 
-#if 0
-	/* TODO: Disabling because reading SPR 0x1 reliably checkstops a P8 */
-	ram_getspr(thread, 0x1, &value);
-	regs->xer = value;
+	ram_getxer(thread, (uint64_t *)&regs->xer);
 	printf("XER   : 0x%08" PRIx32 "\n", regs->xer);
-#endif
 
 	printf("GPRS  :\n");
 	for (i = 0; i < 32; i++) {
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index b615229..2a3a337 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -149,6 +149,8 @@ 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);
 struct thread_state thread_status(struct pdbg_target *target);
+int ram_getxer(struct pdbg_target *thread, uint64_t *value);
+int ram_putxer(struct pdbg_target *thread, uint64_t value);
 int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]);
 
 enum pdbg_sleep_state {PDBG_THREAD_STATE_RUN, PDBG_THREAD_STATE_DOZE,
diff --git a/libpdbg/operations.h b/libpdbg/operations.h
index 52bfe7e..c7e3218 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -64,12 +64,21 @@
 #define MTMSR_OPCODE 0x7c000124UL
 #define MFSPR_OPCODE 0x7c0002a6UL
 #define MTSPR_OPCODE 0x7c0003a6UL
+#define MTXERF0_OPCODE 0x00000008UL
+#define MTXERF1_OPCODE 0x00000108UL
+#define MTXERF2_OPCODE 0x00000208UL
+#define MTXERF3_OPCODE 0x00000308UL
+#define MFXERF0_OPCODE 0x00000010UL
+#define MFXERF1_OPCODE 0x00000110UL
+#define MFXERF2_OPCODE 0x00000210UL
+#define MFXERF3_OPCODE 0x00000310UL
 #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 MTXER_OPCODE (MTSPR_OPCODE | ((1 & 0x1f) << 16) | ((1 & 0x3e0) << 6))
 #define LD_OPCODE 0xe8000000UL
 
-#define MFSPR_SPR(opcode) (((opcode >> 16) & 0x1f) | ((opcode >> 6) & 0x3e0))
+#define MXSPR_SPR(opcode) (((opcode >> 16) & 0x1f) | ((opcode >> 6) & 0x3e0))
 
 /* GDB server functionality */
 int gdbserver_start(uint16_t port);
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index 6e9d3ec..e49743a 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -329,7 +329,6 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
 	switch(opcode & OPCODE_MASK) {
 	case MTNIA_OPCODE:
 		predecode = 8;
-
 		/* Not currently supported as we can only MTNIA from LR */
 		PR_ERROR("MTNIA is not currently supported\n");
 		break;
@@ -339,12 +338,19 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
 		predecode = 2;
 		break;
 
-	case MTMSR_OPCODE:
-		predecode = 8;
+	case MFSPR_OPCODE:
+		switch(MXSPR_SPR(opcode)) {
+		case 1: /* XER */
+			predecode = 4;
+			break;
+		default:
+			predecode = 0;
+			break;
+		}
 		break;
 
-	case MFSPR_OPCODE:
-		switch(MFSPR_SPR(opcode)) {
+	case MTSPR_OPCODE:
+		switch(MXSPR_SPR(opcode)) {
 		case 1: /* XER */
 			predecode = 4;
 			break;
-- 
2.14.3



More information about the Pdbg mailing list