diff mbox series

[v2,06/16] libpdbg: Add in getxer and putxer functions

Message ID 20180907064015.1058-7-rashmica.g@gmail.com
State Accepted
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 fail Test build-multiarch on branch master

Commit Message

Rashmica Gupta Sept. 7, 2018, 6:40 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
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 1008e6a..68d158c 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -107,7 +107,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;
@@ -150,6 +150,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 722b53a..971a3f6 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -64,9 +64,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)