[Pdbg] [PATCH] WIP: POWER8 SRESET

Alistair Popple alistair at popple.id.au
Thu Mar 7 16:13:18 AEDT 2019


SRESET on POWER8 is made more complex because it can only be run if a
thread is in a powersave state. This makes getting an active thread
into SRESET hard because we need to emulate what the processor does
using instruction ramming.

This patch aims to implement this sequence. If a thread is in a nap
state it will just use the direct controls, however if it is in an
active state it will quiesce the thread and use instruction ramming to
put the thread at the 0x100 sreset exception vector.

Signed-off-by: Alistair Popple <alistair at popple.id.au>
---
 libpdbg/chip.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 libpdbg/p8chip.c | 25 +++++++++++++++++++------
 src/thread.c     |  6 ++++++
 3 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 5b67c7b..8698e9b 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -534,3 +534,45 @@ int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs)
 
 	return 0;
 }
+
+#define SPR_SRR0 0x01a
+#define SPR_SRR1 0x01b
+#define SRESET_SRR1 0x9000000000101001ull
+
+#define MSR_HV          PPC_BIT(3)      /* Hypervisor mode */
+#define MSR_EE          PPC_BIT(48)     /* External Int. Enable */
+#define MSR_FE0         PPC_BIT(52)     /* FP Exception 0 */
+#define MSR_FE1         PPC_BIT(55)     /* FP Exception 1 */
+#define MSR_IR          PPC_BIT(58)     /* Instructions reloc */
+#define MSR_DR          PPC_BIT(59)     /* Data reloc */
+#define MSR_RI          PPC_BIT(62)     /* Recoverable Interrupt */
+
+int emulate_sreset(struct thread *thread)
+{
+	uint64_t opcodes[] = {
+		mfmsr(0), mtspr(277, 0),		/* Get MSR */
+		mfnia(0), mtspr(277, 0),		/* Get NIA */
+		mfspr(0, 277), mtmsr(0),		/* Put modified MSR back */
+		mfspr(0, 277), mtspr(SPR_SRR0, 0),	/* Set SRR0 to NIA */
+		mfspr(0, 277), mtspr(SPR_SRR1, 0),	/* Set SRR1 to SRESET value */
+		mfspr(0, 277), mtnia(0),		/* Set NIA */
+	};
+	uint64_t results[] = {
+		0, 0,
+		0, 0,
+		0, 0,
+		0, 0,					/* SRR0 */
+		SRESET_SRR1, 0,		      		/* SRR1 SRESET value */
+		0x100, 0,				/* Set NIA = 0x100 */
+	};
+
+	/* RAM first 4 opcodes */
+	CHECK_ERR(ram_instructions(&thread->target, opcodes, results, 4, 0));
+
+	/* Set MSR, SRR0 = NIA and ram remaining instructions*/
+	results[4] = (results[1] & ~(MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE | MSR_RI)) | MSR_HV;
+	results[6] = results[3];
+	CHECK_ERR(ram_instructions(&thread->target, &opcodes[4], &results[4], ARRAY_SIZE(opcodes) - 4, 0));
+
+	return 0;
+}
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index 914c335..e51684a 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -29,6 +29,8 @@
 #define RAS_STATUS_TIMEOUT	100
 
 #define DIRECT_CONTROLS_REG    		0x0
+#define  DIRECT_CONTROL_PRENAP		PPC_BIT(47)
+#define  DIRECT_CONTROL_SRESET		PPC_BIT(60)
 #define  DIRECT_CONTROL_SP_STEP		PPC_BIT(61)
 #define  DIRECT_CONTROL_SP_START 	PPC_BIT(62)
 #define  DIRECT_CONTROL_SP_STOP 	PPC_BIT(63)
@@ -337,12 +339,6 @@ static int p8_thread_start(struct thread *thread)
 	return 0;
 }
 
-static int p8_thread_sreset(struct thread *thread)
-{
-	/* Broken on p8 */
-	return 1;
-}
-
 static int p8_ram_setup(struct thread *thread)
 {
 	struct pdbg_target *target;
@@ -440,6 +436,23 @@ static int p8_ram_destroy(struct thread *thread)
 	return 0;
 }
 
+int emulate_sreset(struct thread *thread);
+static int p8_thread_sreset(struct thread *thread)
+{
+	if (!p8_ram_setup(thread)) {
+		/* Thread was active, emulate the sreset */
+		emulate_sreset(thread);
+		p8_ram_destroy(thread);
+		p8_thread_start(thread);
+	} else {
+		/* Use direct controls */
+		CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_PRENAP));
+		CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SRESET));
+	}
+
+	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),
diff --git a/src/thread.c b/src/thread.c
index 1fd448d..63966f6 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -295,6 +295,12 @@ static int thread_sreset(void)
 	for_each_path_target_class("thread", target) {
 		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
 			continue;
+		ram_stop_thread(target);
+	}
+
+	for_each_path_target_class("thread", target) {
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
 
 		ram_sreset_thread(target);
 		count++;
-- 
2.11.0



More information about the Pdbg mailing list