diff mbox series

[03/19] libpdbg: Add in getxer and putxer functions

Message ID 20180829015047.7355-4-rashmica.g@gmail.com
State Superseded
Headers show
Series Basic gdbserver for POWER8 | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied
snowpatch_ozlabs/build-multiarch success Test build-multiarch on branch master

Commit Message

Rashmica Gupta Aug. 29, 2018, 1:50 a.m. UTC
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
 libpdbg/chip.c       | 40 ++++++++++++++++++------
 libpdbg/chip.h       | 24 +++++++++++++++
 libpdbg/libpdbg.h    |  4 ++-
 libpdbg/operations.h |  3 +-
 libpdbg/p8chip.c     | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 libpdbg/p9chip.c     | 31 +++++++++++++++++--
 libpdbg/target.h     |  2 ++
 7 files changed, 177 insertions(+), 13 deletions(-)
 create mode 100644 libpdbg/chip.h

Comments

Nicholas Piggin Aug. 29, 2018, 7:53 a.m. UTC | #1
This is all pretty awesome, I'm having a look over it...

On Wed, 29 Aug 2018 11:50:31 +1000
Rashmica Gupta <rashmica.g@gmail.com> wrote:


> diff --git a/libpdbg/target.h b/libpdbg/target.h
> index 9f055ac..8bad405 100644
> --- a/libpdbg/target.h
> +++ b/libpdbg/target.h
> @@ -153,6 +153,8 @@ struct thread {
>  	int (*ram_setup)(struct thread *);
>  	int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch);
>  	int (*ram_destroy)(struct thread *);
> +	int (*ram_getxer)(struct pdbg_target *, uint64_t *value);
> +	int (*ram_putxer)(struct pdbg_target *, uint64_t value);
>  };
>  #define target_to_thread(x) container_of(x, struct thread, target)

I would say we might want to end up having a ram_spr function
that each target can use to filter things out or do their magic
overrides. MSR and NIA and other fake SPRs can be included too.
This is fine for now though.

pdbg doesn't have a big development process, but as a general
comment I like putting bug fixes (and you've made quite a few)
and cleanups at the start of a series.

Thanks,
Nick
Rashmica Gupta Aug. 29, 2018, 11:38 p.m. UTC | #2
On 29/08/18 17:53, Nicholas Piggin wrote:

> This is all pretty awesome, I'm having a look over it...
>
> On Wed, 29 Aug 2018 11:50:31 +1000
> Rashmica Gupta <rashmica.g@gmail.com> wrote:
>
>
>> diff --git a/libpdbg/target.h b/libpdbg/target.h
>> index 9f055ac..8bad405 100644
>> --- a/libpdbg/target.h
>> +++ b/libpdbg/target.h
>> @@ -153,6 +153,8 @@ struct thread {
>>  	int (*ram_setup)(struct thread *);
>>  	int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch);
>>  	int (*ram_destroy)(struct thread *);
>> +	int (*ram_getxer)(struct pdbg_target *, uint64_t *value);
>> +	int (*ram_putxer)(struct pdbg_target *, uint64_t value);
>>  };
>>  #define target_to_thread(x) container_of(x, struct thread, target)
> I would say we might want to end up having a ram_spr function
> that each target can use to filter things out or do their magic
> overrides. MSR and NIA and other fake SPRs can be included too.
> This is fine for now though.

Ooh that's a nice idea.

> pdbg doesn't have a big development process, but as a general
> comment I like putting bug fixes (and you've made quite a few)
> and cleanups at the start of a series.

That makes sense. I'll make sure to do that in the future.

>
> Thanks,
> Nick
>
diff mbox series

Patch

diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 1c5080e..01c9b58 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -26,7 +26,7 @@ 
 #include "bitutils.h"
 #include "debug.h"
 
-static uint64_t mfspr(uint64_t reg, uint64_t spr)
+uint64_t mfspr(uint64_t reg, uint64_t spr)
 {
 	if (reg > 31)
 		PR_ERROR("Invalid register specified for mfspr\n");
@@ -34,7 +34,7 @@  static uint64_t mfspr(uint64_t reg, uint64_t spr)
 	return MFSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
 }
 
-static uint64_t mtspr(uint64_t spr, uint64_t reg)
+uint64_t mtspr(uint64_t spr, uint64_t reg)
 {
 	if (reg > 31)
 		PR_ERROR("Invalid register specified for mtspr\n");
@@ -148,7 +148,7 @@  int ram_sreset_thread(struct pdbg_target *thread_target)
  * data. Note that only register r0 is saved and restored so opcodes
  * must not touch other registers.
  */
-static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes,
+int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes,
 			    uint64_t *results, int len, unsigned int lpar)
 {
 	uint64_t opcode = 0, r0 = 0, r1 = 0, scratch = 0;
@@ -168,6 +168,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) */
@@ -309,6 +310,31 @@  int ram_getmem(struct pdbg_target *thread, uint64_t addr, uint64_t *value)
 	return 0;
 }
 
+int ram_getxer(struct pdbg_target *thread_target, uint64_t *value)
+{
+
+	struct thread *thread;
+
+	assert(!strcmp(thread_target->class, "thread"));
+	thread = target_to_thread(thread_target);
+
+	CHECK_ERR(thread->ram_getxer(thread_target, value));
+
+	return 0;
+}
+
+int ram_putxer(struct pdbg_target *thread_target, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(!strcmp(thread_target->class, "thread"));
+	thread = target_to_thread(thread_target);
+
+	CHECK_ERR(thread->ram_putxer(thread_target, value));
+
+	return 0;
+}
+
 /*
  * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits.
  */
@@ -368,12 +394,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;
-	printf("XER   : 0x%08" PRIx32 "\n", regs->xer);
-#endif
+	ram_getxer(thread, &regs->xer);
+	printf("XER   : 0x%08" PRIx64 "\n", regs->xer);
 
 	printf("GPRS  :\n");
 	for (i = 0; i < 32; i++) {
diff --git a/libpdbg/chip.h b/libpdbg/chip.h
new file mode 100644
index 0000000..52f3486
--- /dev/null
+++ b/libpdbg/chip.h
@@ -0,0 +1,24 @@ 
+/* Copyright 2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LIBPDBG_CHIP_H
+#define __LIBPDBG_CHIP_H
+
+uint64_t mfspr(uint64_t reg, uint64_t spr) __attribute__ ((visibility("hidden")));
+uint64_t mtspr(uint64_t spr, uint64_t reg) __attribute__ ((visibility("hidden")));
+int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes,
+		uint64_t *results, int len, unsigned int lpar) __attribute__
+		((visibility("hidden")));
+#endif
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index e626786..2e55060 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -108,7 +108,7 @@  struct thread_regs {
 	uint64_t ctr;
 	uint64_t tar;
 	uint32_t cr;
-	uint32_t xer;
+	uint64_t xer;
 	uint64_t gprs[32];
 
 	uint64_t lpcr;
@@ -151,6 +151,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..4735c55 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -67,9 +67,10 @@ 
 #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/p8chip.c b/libpdbg/p8chip.c
index cb5a46b..89ecfd6 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -83,9 +83,61 @@ 
 #define EX_PM_GP0_REG			0xf0100
 #define  SPECIAL_WKUP_DONE		PPC_BIT(31)
 
+/* p8 specific opcodes for instruction ramming*/
+#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
+
 /* How long (in us) to wait for a special wakeup to complete */
 #define SPECIAL_WKUP_TIMEOUT		10
 
+#include "chip.h"
+
+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 int assert_special_wakeup(struct core *chip)
 {
 	int i = 0;
@@ -386,6 +438,38 @@  static int p8_ram_destroy(struct thread *thread)
 	return 0;
 }
 
+static int p8_ram_getxer(struct pdbg_target *thread, uint64_t *value)
+{
+	uint64_t opcodes[] = {mfxerf(0, 0), mtspr(277, 0), mfxerf(0, 1),
+			      mtspr(277, 0), mfxerf(0, 2), mtspr(277, 0),
+			      mfxerf(0, 3), mtspr(277, 0)};
+	uint64_t results[] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+	/* On POWER8 we can't get xer with getspr. We seem to only be able to
+	 * get and set IBM bits 32-34 and 44-56.
+	 */
+	PR_WARNING("Can only get/set IBM bits 32-34 and 44-56 of the XER register\n");
+
+
+	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
+
+	*value = results[1] | results[3] | results[5] | results[7];
+	return 0;
+}
+
+static int p8_ram_putxer(struct pdbg_target *thread, uint64_t value)
+{
+	uint64_t fields[] = {value, value, value, value, 0};
+	uint64_t opcodes[] = {mfspr(0, 277), mtxerf(0, 0), mtxerf(0, 1), mtxerf(0, 2), mtxerf(0, 3)};
+
+	/* We seem to only be able to get and set IBM bits 32-34 and 44-56.*/
+	PR_WARNING("Can only set IBM bits 32-34 and 44-56 of the XER register\n");
+
+	CHECK_ERR(ram_instructions(thread, opcodes, fields, ARRAY_SIZE(opcodes), 0));
+
+	return 0;
+}
+
 /*
  * Initialise all viable threads for ramming on the given core.
  */
@@ -413,6 +497,8 @@  static struct thread p8_thread = {
 	.ram_setup = p8_ram_setup,
 	.ram_instruction = p8_ram_instruction,
 	.ram_destroy = p8_ram_destroy,
+	.ram_getxer = p8_ram_getxer,
+	.ram_putxer = p8_ram_putxer,
 };
 DECLARE_HW_UNIT(p8_thread);
 
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index 189d80a..f126968 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -292,7 +292,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;
@@ -307,7 +306,18 @@  static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
 		break;
 
 	case MFSPR_OPCODE:
-		switch(MFSPR_SPR(opcode)) {
+		switch(MXSPR_SPR(opcode)) {
+		case 1: /* XER */
+			predecode = 4;
+			break;
+		default:
+			predecode = 0;
+			break;
+		}
+		break;
+
+	case MTSPR_OPCODE:
+		switch(MXSPR_SPR(opcode)) {
 		case 1: /* XER */
 			predecode = 4;
 			break;
@@ -395,6 +405,21 @@  static int p9_ram_destroy(struct thread *thread)
 	return 0;
 }
 
+static int p9_ram_getxer(struct pdbg_target *thread, uint64_t *value)
+{
+	CHECK_ERR(ram_getspr(thread, 1, value));
+
+	return 0;
+}
+
+static int p9_ram_putxer(struct pdbg_target *thread, uint64_t value)
+{
+	CHECK_ERR(ram_putspr(thread, 1, value));
+
+	return 0;
+
+}
+
 static struct thread p9_thread = {
 	.target = {
 		.name = "POWER9 Thread",
@@ -410,6 +435,8 @@  static struct thread p9_thread = {
 	.ram_setup = p9_ram_setup,
 	.ram_instruction = p9_ram_instruction,
 	.ram_destroy = p9_ram_destroy,
+	.ram_getxer = p9_ram_getxer,
+	.ram_putxer = p9_ram_putxer,
 };
 DECLARE_HW_UNIT(p9_thread);
 
diff --git a/libpdbg/target.h b/libpdbg/target.h
index 9f055ac..8bad405 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -153,6 +153,8 @@  struct thread {
 	int (*ram_setup)(struct thread *);
 	int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch);
 	int (*ram_destroy)(struct thread *);
+	int (*ram_getxer)(struct pdbg_target *, uint64_t *value);
+	int (*ram_putxer)(struct pdbg_target *, uint64_t value);
 };
 #define target_to_thread(x) container_of(x, struct thread, target)