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

Message ID 20180531052915.31171-2-rashmica.g@gmail.com
State Changes Requested
Headers show
Series
  • [01/10] libpdbg: Print the name of the instruction when erroring
Related show

Commit Message

Rashmica Gupta May 31, 2018, 5:29 a.m.
Signed-off-by: Rashmica Gupta <rashmica.g@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(-)

Comments

Alistair Popple June 4, 2018, 6:13 a.m. | #1
Hi Rashmica,

A couple of comments below.

On Thursday, 31 May 2018 3:29:07 PM AEST Rashmica Gupta wrote:
> +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) {

This should be checking the "compatible" property as the "name" property is just
an arbitrary freeform name that could change where as the "compatible" property
is how everything gets matched up.

However given the implementation of getxer is completely different between P8
and P9 really what you want to do is add a target specific callback for this.

Ie. Add the following to `struct thread` in target.h:

struct thread {
       ...

       int (*ram_getxer)(struct thread *, uint64_t value);

};

And move the P8 and P9 implementations into their respective pNchip.c.

- Alistair

> +		/* 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;
>

Patch

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;