diff mbox series

[7/9] libpdbg: Rearrange thread procedures for register access

Message ID 20200622004501.12889-8-amitay@ozlabs.org
State New
Headers show
Series Make register access into thread procedures | expand

Checks

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

Commit Message

Amitay Isaacs June 22, 2020, 12:44 a.m. UTC
This moves libpdbg thread api to thread.c.  Also, the implementation
based ramming instructions moves to the specific thread drivers.

Signed-off-by: Amitay Isaacs <amitay@ozlabs.org>
---
 Makefile.am      |   3 +-
 libpdbg/chip.c   | 318 +++++++--------------------------------------
 libpdbg/chip.h   |  19 +++
 libpdbg/hwunit.h |   2 -
 libpdbg/p8chip.c |  17 ++-
 libpdbg/p9chip.c |  21 ++-
 libpdbg/thread.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 429 insertions(+), 279 deletions(-)
 create mode 100644 libpdbg/thread.c

Comments

Alistair Popple June 22, 2020, 8:16 a.m. UTC | #1
On Monday, 22 June 2020 10:44:59 AM AEST Amitay Isaacs wrote:
> +int thread_getregs(struct pdbg_target *target, struct thread_regs *regs)
> +{
> +       struct thread *thread;
> +
> +       assert(pdbg_target_is_class(target, "thread"));
> +       thread = target_to_thread(target);
> +
> +       if (thread->getregs)
> +               return thread->getregs(thread, regs);
> +
> +       PR_ERROR("Not implemented on the backend\n");
> +       return -1;
> +}

I was almost going to say that this isn't a thread specific operation and 
should be kept as a generic library function that just goes and calls 
getreg(blah) one by one. But it seems the SBEFIFO has a method to get a heap 
of registers at once, and it would be possible to develop more efficient 
implementations of this for instruction ramming too so guess it makes sense to 
have this as a thread specific call back like the rest.

- Alistair
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index f51afb3..4247913 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -207,7 +207,8 @@  libpdbg_la_SOURCES = \
 	libpdbg/sbefifo.c \
 	libpdbg/sprs.h \
 	libpdbg/target.c \
-	libpdbg/target.h
+	libpdbg/target.h \
+	libpdbg/thread.c
 
 libpdbg_la_CFLAGS = -Wall -Werror
 libpdbg_la_LIBADD = libcronus.la libsbefifo.la
diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 58eedeb..a5afe5c 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -26,6 +26,7 @@ 
 #include "bitutils.h"
 #include "debug.h"
 #include "sprs.h"
+#include "chip.h"
 
 uint64_t mfspr(uint64_t reg, uint64_t spr)
 {
@@ -107,166 +108,6 @@  static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra)
 	return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2);
 }
 
-struct thread_state thread_status(struct pdbg_target *target)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-	return thread->status;
-}
-
-/*
- * Single step the thread count instructions.
- */
-int thread_step(struct pdbg_target *target, int count)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-	return thread->step(thread, count);
-}
-
-int thread_start(struct pdbg_target *target)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-	return thread->start(thread);
-}
-
-int thread_stop(struct pdbg_target *target)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-	return thread->stop(thread);
-}
-
-int thread_sreset(struct pdbg_target *target)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-	return thread->sreset(thread);
-}
-
-int thread_step_all(void)
-{
-	struct pdbg_target *target, *thread;
-	int rc = 0, count = 0;
-
-	pdbg_for_each_class_target("pib", target) {
-		struct pib *pib = target_to_pib(target);
-
-		if (!pib->thread_step_all)
-			break;
-
-		rc |= pib->thread_step_all(pib, 1);
-		count++;
-	}
-
-	if (count > 0)
-		return rc;
-
-	pdbg_for_each_class_target("thread", thread) {
-		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
-			continue;
-
-		rc |= thread_step(thread, 1);
-	}
-
-	return rc;
-}
-
-int thread_start_all(void)
-{
-	struct pdbg_target *target, *thread;
-	int rc = 0, count = 0;
-
-	pdbg_for_each_class_target("pib", target) {
-		struct pib *pib = target_to_pib(target);
-
-		if (!pib->thread_start_all)
-			break;
-
-		rc |= pib->thread_start_all(pib);
-		count++;
-	}
-
-	if (count > 0)
-		return rc;
-
-	pdbg_for_each_class_target("thread", thread) {
-		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
-			continue;
-
-		rc |= thread_start(thread);
-	}
-
-	return rc;
-}
-
-int thread_stop_all(void)
-{
-	struct pdbg_target *target, *thread;
-	int rc = 0, count = 0;
-
-	pdbg_for_each_class_target("pib", target) {
-		struct pib *pib = target_to_pib(target);
-
-		if (!pib->thread_stop_all)
-			break;
-
-		rc |= pib->thread_stop_all(pib);
-		count++;
-	}
-
-	if (count > 0)
-		return rc;
-
-	pdbg_for_each_class_target("thread", thread) {
-		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
-			continue;
-
-		rc |= thread_stop(thread);
-	}
-
-	return rc;
-}
-
-int thread_sreset_all(void)
-{
-	struct pdbg_target *target, *thread;
-	int rc = 0, count = 0;
-
-	pdbg_for_each_class_target("pib", target) {
-		struct pib *pib = target_to_pib(target);
-
-		if (!pib->thread_sreset_all)
-			break;
-
-		rc |= pib->thread_sreset_all(pib);
-		count++;
-	}
-
-	if (count > 0)
-		return rc;
-
-	pdbg_for_each_class_target("thread", thread) {
-		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
-			continue;
-
-		rc |= thread_sreset(thread);
-	}
-
-	return rc;
-}
-
 /*
  * RAMs the opcodes in *opcodes and store the results of each opcode
  * into *results. *results must point to an array the same size as
@@ -336,40 +177,30 @@  int ram_instructions(struct thread *thread, uint64_t *opcodes,
 /*
  * Get gpr value. Chip must be stopped.
  */
-int thread_getgpr(struct pdbg_target *target, int gpr, uint64_t *value)
+int ram_getgpr(struct thread *thread, int gpr, uint64_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mtspr(277, gpr)};
 	uint64_t results[] = {0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	*value = results[0];
 	return 0;
 }
 
-int thread_putgpr(struct pdbg_target *target, int gpr, uint64_t value)
+int ram_putgpr(struct thread *thread, int gpr, uint64_t value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(gpr, 277)};
 	uint64_t results[] = {value};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
-
 	return 0;
 }
 
-int thread_getnia(struct pdbg_target *target, uint64_t *value)
+int ram_getnia(struct thread *thread, uint64_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfnia(0), mtspr(277, 0)};
 	uint64_t results[] = {0, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	*value = results[1];
 	return 0;
@@ -382,9 +213,8 @@  int thread_getnia(struct pdbg_target *target, uint64_t *value)
  * This is a hack and should be made much cleaner once we have target
  * specific putspr commands.
  */
-int thread_putnia(struct pdbg_target *target, uint64_t value)
+int ram_putnia(struct thread *thread, uint64_t value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {	mfspr(1, 8),	/* mflr r1 */
 				mfspr(0, 277),	/* value -> r0 */
 				mtspr(8, 0),	/* mtlr r0 */
@@ -392,53 +222,41 @@  int thread_putnia(struct pdbg_target *target, uint64_t value)
 				mtspr(8, 1), };	/* mtlr r1 */
 	uint64_t results[] = {0, value, 0, 0, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	return 0;
 }
 
-int thread_getspr(struct pdbg_target *target, int spr, uint64_t *value)
+int ram_getspr(struct thread *thread, int spr, uint64_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(0, spr), mtspr(277, 0)};
 	uint64_t results[] = {0, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	*value = results[1];
 	return 0;
 }
 
-int thread_putspr(struct pdbg_target *target, int spr, uint64_t value)
+int ram_putspr(struct thread *thread, int spr, uint64_t value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(0, 277), mtspr(spr, 0)};
 	uint64_t results[] = {value, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	return 0;
 }
 
-int thread_getmsr(struct pdbg_target *target, uint64_t *value)
+int ram_getmsr(struct thread *thread, uint64_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfmsr(0), mtspr(277, 0)};
 	uint64_t results[] = {0, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	*value = results[1];
 	return 0;
 }
 
-int thread_getcr(struct pdbg_target *target, uint32_t *value)
+int ram_getcr(struct thread *thread, uint32_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfocrf(0, 0), mtspr(277, 0), mfocrf(0, 1), mtspr(277, 0),
 			      mfocrf(0, 2), mtspr(277, 0), mfocrf(0, 3), mtspr(277, 0),
 			      mfocrf(0, 4), mtspr(277, 0), mfocrf(0, 5), mtspr(277, 0),
@@ -447,8 +265,6 @@  int thread_getcr(struct pdbg_target *target, uint32_t *value)
 	uint32_t cr_field, cr = 0;
 	int i;
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	for (i = 1; i < 16; i += 2) {
 		cr_field = results[i];
@@ -460,70 +276,36 @@  int thread_getcr(struct pdbg_target *target, uint32_t *value)
 	return 0;
 }
 
-int thread_putcr(struct pdbg_target *target, uint32_t value)
+int ram_putcr(struct thread *thread, uint32_t value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(0, 277), mtocrf(0, 0), mtocrf(1, 0),
 			      mtocrf(2, 0), mtocrf(3, 0), mtocrf(4, 0),
 			      mtocrf(5, 0), mtocrf(6, 0), mtocrf(7, 0)};
 	uint64_t results[] = {value};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
-
 	return 0;
 }
 
-int thread_putmsr(struct pdbg_target *target, uint64_t value)
+int ram_putmsr(struct thread *thread, uint64_t value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(0, 277), mtmsr(0)};
 	uint64_t results[] = {value, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	return 0;
 }
 
-int thread_getmem(struct pdbg_target *target, uint64_t addr, uint64_t *value)
+int ram_getmem(struct thread *thread, uint64_t addr, uint64_t *value)
 {
-	struct thread *thread;
 	uint64_t opcodes[] = {mfspr(0, 277), mfspr(1, 277), ld(0, 0, 1), mtspr(277, 0)};
 	uint64_t results[] = {0xdeaddeaddeaddead, addr, 0, 0};
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
 	CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0));
 	*value = results[3];
 	return 0;
 }
 
-int thread_getxer(struct pdbg_target *target, uint64_t *value)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-
-	CHECK_ERR(thread->ram_getxer(thread, value));
-
-	return 0;
-}
-
-int thread_putxer(struct pdbg_target *target, uint64_t value)
-{
-	struct thread *thread;
-
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-
-	CHECK_ERR(thread->ram_putxer(thread, value));
-
-	return 0;
-}
-
 /*
  * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits.
  */
@@ -536,9 +318,8 @@  int getring(struct pdbg_target *target, uint64_t ring_addr, uint64_t ring_len, u
 	return chiplet->getring(chiplet, ring_addr, ring_len, result);
 }
 
-int thread_getregs(struct pdbg_target *target, struct thread_regs *regs)
+int ram_getregs(struct thread *thread, struct thread_regs *regs)
 {
-	struct thread *thread;
 	struct thread_regs _regs;
 	uint64_t value = 0;
 	int i;
@@ -546,9 +327,6 @@  int thread_getregs(struct pdbg_target *target, struct thread_regs *regs)
 	if (!regs)
 		regs = &_regs;
 
-	assert(pdbg_target_is_class(target, "thread"));
-	thread = target_to_thread(target);
-
 	CHECK_ERR(thread->ram_setup(thread));
 
 	/*
@@ -557,117 +335,117 @@  int thread_getregs(struct pdbg_target *target, struct thread_regs *regs)
 	 * can help to diagnose checkstop issues with ramming to print as
 	 * we go. Once it's more robust and tested, maybe.
 	 */
-	thread_getnia(target, &regs->nia);
+	ram_getnia(thread, &regs->nia);
 	printf("NIA   : 0x%016" PRIx64 "\n", regs->nia);
 
-	thread_getspr(target, SPR_CFAR, &regs->cfar);
+	ram_getspr(thread, SPR_CFAR, &regs->cfar);
 	printf("CFAR  : 0x%016" PRIx64 "\n", regs->cfar);
 
-	thread_getmsr(target, &regs->msr);
+	ram_getmsr(thread, &regs->msr);
 	printf("MSR   : 0x%016" PRIx64 "\n", regs->msr);
 
-	thread_getspr(target, SPR_LR, &regs->lr);
+	ram_getspr(thread, SPR_LR, &regs->lr);
 	printf("LR    : 0x%016" PRIx64 "\n", regs->lr);
 
-	thread_getspr(target, SPR_CTR, &regs->ctr);
+	ram_getspr(thread, SPR_CTR, &regs->ctr);
 	printf("CTR   : 0x%016" PRIx64 "\n", regs->ctr);
 
-	thread_getspr(target, 815, &regs->tar);
+	ram_getspr(thread, 815, &regs->tar);
 	printf("TAR   : 0x%016" PRIx64 "\n", regs->tar);
 
-	thread_getcr(target, &regs->cr);
+	ram_getcr(thread, &regs->cr);
 	printf("CR    : 0x%08" PRIx32 "\n", regs->cr);
 
-	thread_getxer(target, &regs->xer);
+	thread->getxer(thread, &regs->xer);
 	printf("XER   : 0x%08" PRIx64 "\n", regs->xer);
 
 	printf("GPRS  :\n");
 	for (i = 0; i < 32; i++) {
-		thread_getgpr(target, i, &regs->gprs[i]);
+		ram_getgpr(thread, i, &regs->gprs[i]);
 		printf(" 0x%016" PRIx64 "", regs->gprs[i]);
 		if (i % 4 == 3)
 			printf("\n");
 	}
 
-	thread_getspr(target, SPR_LPCR, &regs->lpcr);
+	ram_getspr(thread, SPR_LPCR, &regs->lpcr);
 	printf("LPCR  : 0x%016" PRIx64 "\n", regs->lpcr);
 
-	thread_getspr(target, SPR_PTCR, &regs->ptcr);
+	ram_getspr(thread, SPR_PTCR, &regs->ptcr);
 	printf("PTCR  : 0x%016" PRIx64 "\n", regs->ptcr);
 
-	thread_getspr(target, SPR_LPIDR, &regs->lpidr);
+	ram_getspr(thread, SPR_LPIDR, &regs->lpidr);
 	printf("LPIDR : 0x%016" PRIx64 "\n", regs->lpidr);
 
-	thread_getspr(target, SPR_PIDR, &regs->pidr);
+	ram_getspr(thread, SPR_PIDR, &regs->pidr);
 	printf("PIDR  : 0x%016" PRIx64 "\n", regs->pidr);
 
-	thread_getspr(target, SPR_HFSCR, &regs->hfscr);
+	ram_getspr(thread, SPR_HFSCR, &regs->hfscr);
 	printf("HFSCR : 0x%016" PRIx64 "\n", regs->hfscr);
 
-	thread_getspr(target, SPR_HDSISR, &value);
+	ram_getspr(thread, SPR_HDSISR, &value);
 	regs->hdsisr = value;
 	printf("HDSISR: 0x%08" PRIx32 "\n", regs->hdsisr);
 
-	thread_getspr(target, SPR_HDAR, &regs->hdar);
+	ram_getspr(thread, SPR_HDAR, &regs->hdar);
 	printf("HDAR  : 0x%016" PRIx64 "\n", regs->hdar);
 
-	thread_getspr(target, SPR_HEIR, &value);
+	ram_getspr(thread, SPR_HEIR, &value);
 	regs->heir = value;
 	printf("HEIR : 0x%016" PRIx32 "\n", regs->heir);
 
-	thread_getspr(target, SPR_HID, &regs->hid);
+	ram_getspr(thread, SPR_HID, &regs->hid);
 	printf("HID0 : 0x%016" PRIx64 "\n", regs->hid);
 
-	thread_getspr(target, SPR_HSRR0, &regs->hsrr0);
+	ram_getspr(thread, SPR_HSRR0, &regs->hsrr0);
 	printf("HSRR0 : 0x%016" PRIx64 "\n", regs->hsrr0);
 
-	thread_getspr(target, SPR_HSRR1, &regs->hsrr1);
+	ram_getspr(thread, SPR_HSRR1, &regs->hsrr1);
 	printf("HSRR1 : 0x%016" PRIx64 "\n", regs->hsrr1);
 
-	thread_getspr(target, SPR_HDEC, &regs->hdec);
+	ram_getspr(thread, SPR_HDEC, &regs->hdec);
 	printf("HDEC  : 0x%016" PRIx64 "\n", regs->hdec);
 
-	thread_getspr(target, SPR_HSPRG0, &regs->hsprg0);
+	ram_getspr(thread, SPR_HSPRG0, &regs->hsprg0);
 	printf("HSPRG0: 0x%016" PRIx64 "\n", regs->hsprg0);
 
-	thread_getspr(target, SPR_HSPRG1, &regs->hsprg1);
+	ram_getspr(thread, SPR_HSPRG1, &regs->hsprg1);
 	printf("HSPRG1: 0x%016" PRIx64 "\n", regs->hsprg1);
 
-	thread_getspr(target, SPR_FSCR, &regs->fscr);
+	ram_getspr(thread, SPR_FSCR, &regs->fscr);
 	printf("FSCR  : 0x%016" PRIx64 "\n", regs->fscr);
 
-	thread_getspr(target, SPR_DSISR, &value);
+	ram_getspr(thread, SPR_DSISR, &value);
 	regs->dsisr = value;
 	printf("DSISR : 0x%08" PRIx32 "\n", regs->dsisr);
 
-	thread_getspr(target, SPR_DAR, &regs->dar);
+	ram_getspr(thread, SPR_DAR, &regs->dar);
 	printf("DAR   : 0x%016" PRIx64 "\n", regs->dar);
 
-	thread_getspr(target, SPR_SRR0, &regs->srr0);
+	ram_getspr(thread, SPR_SRR0, &regs->srr0);
 	printf("SRR0  : 0x%016" PRIx64 "\n", regs->srr0);
 
-	thread_getspr(target, SPR_SRR1, &regs->srr1);
+	ram_getspr(thread, SPR_SRR1, &regs->srr1);
 	printf("SRR1  : 0x%016" PRIx64 "\n", regs->srr1);
 
-	thread_getspr(target, SPR_DEC, &regs->dec);
+	ram_getspr(thread, SPR_DEC, &regs->dec);
 	printf("DEC   : 0x%016" PRIx64 "\n", regs->dec);
 
-	thread_getspr(target, SPR_TB, &regs->tb);
+	ram_getspr(thread, SPR_TB, &regs->tb);
 	printf("TB    : 0x%016" PRIx64 "\n", regs->tb);
 
-	thread_getspr(target, SPR_SPRG0, &regs->sprg0);
+	ram_getspr(thread, SPR_SPRG0, &regs->sprg0);
 	printf("SPRG0 : 0x%016" PRIx64 "\n", regs->sprg0);
 
-	thread_getspr(target, SPR_SPRG1, &regs->sprg1);
+	ram_getspr(thread, SPR_SPRG1, &regs->sprg1);
 	printf("SPRG1 : 0x%016" PRIx64 "\n", regs->sprg1);
 
-	thread_getspr(target, SPR_SPRG2, &regs->sprg2);
+	ram_getspr(thread, SPR_SPRG2, &regs->sprg2);
 	printf("SPRG2 : 0x%016" PRIx64 "\n", regs->sprg2);
 
-	thread_getspr(target, SPR_SPRG3, &regs->sprg3);
+	ram_getspr(thread, SPR_SPRG3, &regs->sprg3);
 	printf("SPRG3 : 0x%016" PRIx64 "\n", regs->sprg3);
 
-	thread_getspr(target, SPR_PPR, &regs->ppr);
+	ram_getspr(thread, SPR_PPR, &regs->ppr);
 	printf("PPR   : 0x%016" PRIx64 "\n", regs->ppr);
 
 	CHECK_ERR(thread->ram_destroy(thread));
diff --git a/libpdbg/chip.h b/libpdbg/chip.h
index b3342b8..6856c64 100644
--- a/libpdbg/chip.h
+++ b/libpdbg/chip.h
@@ -24,4 +24,23 @@  uint64_t mtspr(uint64_t spr, uint64_t reg) __attribute__ ((visibility("hidden"))
 int ram_instructions(struct thread *thread, uint64_t *opcodes,
 		uint64_t *results, int len, unsigned int lpar) __attribute__
 		((visibility("hidden")));
+
+int ram_getmem(struct thread *thread, uint64_t addr, uint64_t *value);
+int ram_getregs(struct thread *thread, struct thread_regs *regs);
+
+int ram_getgpr(struct thread *thread, int gpr, uint64_t *value);
+int ram_putgpr(struct thread *thread, int gpr, uint64_t value);
+
+int ram_getnia(struct thread *thread, uint64_t *value);
+int ram_putnia(struct thread *thread, uint64_t value);
+
+int ram_getspr(struct thread *thread, int spr, uint64_t *value);
+int ram_putspr(struct thread *thread, int spr, uint64_t value);
+
+int ram_getmsr(struct thread *thread, uint64_t *value);
+int ram_putmsr(struct thread *thread, uint64_t value);
+
+int ram_getcr(struct thread *thread, uint32_t *value);
+int ram_putcr(struct thread *thread, uint32_t value);
+
 #endif
diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h
index fd643b4..691689f 100644
--- a/libpdbg/hwunit.h
+++ b/libpdbg/hwunit.h
@@ -140,8 +140,6 @@  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 thread *, uint64_t *value);
-	int (*ram_putxer)(struct thread *, uint64_t value);
 	int (*enable_attn)(struct thread *);
 
 	int (*getmem)(struct thread *, uint64_t, uint64_t *);
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index 50ab143..4179557 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -26,6 +26,7 @@ 
 #include "bitutils.h"
 #include "debug.h"
 #include "sprs.h"
+#include "chip.h"
 
 #define RAS_STATUS_TIMEOUT	100
 
@@ -655,9 +656,21 @@  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,
 	.enable_attn = p8_enable_attn,
+	.getmem = ram_getmem,
+	.getregs = ram_getregs,
+	.getgpr = ram_getgpr,
+	.putgpr = ram_putgpr,
+	.getspr = ram_getspr,
+	.putspr = ram_putspr,
+	.getmsr = ram_getmsr,
+	.putmsr = ram_putmsr,
+	.getnia = ram_getnia,
+	.putnia = ram_putnia,
+	.getxer = p8_ram_getxer,
+	.putxer = p8_ram_putxer,
+	.getcr = ram_getcr,
+	.putcr = ram_putcr,
 };
 DECLARE_HW_UNIT(p8_thread);
 
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index abd2ab2..a46d053 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -25,6 +25,7 @@ 
 #include "bitutils.h"
 #include "debug.h"
 #include "sprs.h"
+#include "chip.h"
 
 /*
  * NOTE!
@@ -407,14 +408,14 @@  static int p9_ram_destroy(struct thread *thread)
 
 static int p9_ram_getxer(struct thread *thread, uint64_t *value)
 {
-	CHECK_ERR(thread_getspr(&thread->target, SPR_XER, value));
+	CHECK_ERR(ram_getspr(thread, SPR_XER, value));
 
 	return 0;
 }
 
 static int p9_ram_putxer(struct thread *thread, uint64_t value)
 {
-	CHECK_ERR(thread_putspr(&thread->target, SPR_XER, value));
+	CHECK_ERR(ram_putspr(thread, SPR_XER, value));
 
 	return 0;
 
@@ -435,8 +436,20 @@  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,
+	.getmem = ram_getmem,
+	.getregs = ram_getregs,
+	.getgpr = ram_getgpr,
+	.putgpr = ram_putgpr,
+	.getspr = ram_getspr,
+	.putspr = ram_putspr,
+	.getmsr = ram_getmsr,
+	.putmsr = ram_putmsr,
+	.getnia = ram_getnia,
+	.putnia = ram_putnia,
+	.getxer = p9_ram_getxer,
+	.putxer = p9_ram_putxer,
+	.getcr = ram_getcr,
+	.putcr = ram_putcr,
 };
 DECLARE_HW_UNIT(p9_thread);
 
diff --git a/libpdbg/thread.c b/libpdbg/thread.c
new file mode 100644
index 0000000..193efb2
--- /dev/null
+++ b/libpdbg/thread.c
@@ -0,0 +1,328 @@ 
+/* Copyright 2020 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.
+ */
+#include <stdio.h>
+
+#include "libpdbg.h"
+#include "hwunit.h"
+#include "debug.h"
+
+struct thread_state thread_status(struct pdbg_target *target)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+	return thread->status;
+}
+
+/*
+ * Single step the thread count instructions.
+ */
+int thread_step(struct pdbg_target *target, int count)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+	return thread->step(thread, count);
+}
+
+int thread_start(struct pdbg_target *target)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+	return thread->start(thread);
+}
+
+int thread_stop(struct pdbg_target *target)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+	return thread->stop(thread);
+}
+
+int thread_sreset(struct pdbg_target *target)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+	return thread->sreset(thread);
+}
+
+int thread_step_all(void)
+{
+	struct pdbg_target *target, *thread;
+	int rc = 0, count = 0;
+
+	pdbg_for_each_class_target("pib", target) {
+		struct pib *pib = target_to_pib(target);
+
+		if (!pib->thread_step_all)
+			break;
+
+		rc |= pib->thread_step_all(pib, 1);
+		count++;
+	}
+
+	if (count > 0)
+		return rc;
+
+	pdbg_for_each_class_target("thread", thread) {
+		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
+			continue;
+
+		rc |= thread_step(thread, 1);
+	}
+
+	return rc;
+}
+
+int thread_start_all(void)
+{
+	struct pdbg_target *target, *thread;
+	int rc = 0, count = 0;
+
+	pdbg_for_each_class_target("pib", target) {
+		struct pib *pib = target_to_pib(target);
+
+		if (!pib->thread_start_all)
+			break;
+
+		rc |= pib->thread_start_all(pib);
+		count++;
+	}
+
+	if (count > 0)
+		return rc;
+
+	pdbg_for_each_class_target("thread", thread) {
+		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
+			continue;
+
+		rc |= thread_start(thread);
+	}
+
+	return rc;
+}
+
+int thread_stop_all(void)
+{
+	struct pdbg_target *target, *thread;
+	int rc = 0, count = 0;
+
+	pdbg_for_each_class_target("pib", target) {
+		struct pib *pib = target_to_pib(target);
+
+		if (!pib->thread_stop_all)
+			break;
+
+		rc |= pib->thread_stop_all(pib);
+		count++;
+	}
+
+	if (count > 0)
+		return rc;
+
+	pdbg_for_each_class_target("thread", thread) {
+		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
+			continue;
+
+		rc |= thread_stop(thread);
+	}
+
+	return rc;
+}
+
+int thread_sreset_all(void)
+{
+	struct pdbg_target *target, *thread;
+	int rc = 0, count = 0;
+
+	pdbg_for_each_class_target("pib", target) {
+		struct pib *pib = target_to_pib(target);
+
+		if (!pib->thread_sreset_all)
+			break;
+
+		rc |= pib->thread_sreset_all(pib);
+		count++;
+	}
+
+	if (count > 0)
+		return rc;
+
+	pdbg_for_each_class_target("thread", thread) {
+		if (pdbg_target_status(thread) != PDBG_TARGET_ENABLED)
+			continue;
+
+		rc |= thread_sreset(thread);
+	}
+
+	return rc;
+}
+
+int thread_getmem(struct pdbg_target *target, uint64_t addr, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	if (thread->getmem)
+		return thread->getmem(thread, addr, value);
+
+	PR_ERROR("Not implemented on the backend\n");
+	return -1;
+}
+
+int thread_getregs(struct pdbg_target *target, struct thread_regs *regs)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	if (thread->getregs)
+		return thread->getregs(thread, regs);
+
+	PR_ERROR("Not implemented on the backend\n");
+	return -1;
+}
+
+int thread_getgpr(struct pdbg_target *target, int gpr, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getgpr(thread, gpr, value);
+}
+
+int thread_putgpr(struct pdbg_target *target, int gpr, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putgpr(thread, gpr, value);
+}
+
+int thread_getspr(struct pdbg_target *target, int spr, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getspr(thread, spr, value);
+}
+
+int thread_putspr(struct pdbg_target *target, int spr, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putspr(thread, spr, value);
+}
+
+int thread_getmsr(struct pdbg_target *target, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getmsr(thread, value);
+}
+
+int thread_putmsr(struct pdbg_target *target, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putmsr(thread, value);
+}
+
+int thread_getnia(struct pdbg_target *target, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getnia(thread, value);
+}
+
+int thread_putnia(struct pdbg_target *target, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putnia(thread, value);
+}
+
+int thread_getxer(struct pdbg_target *target, uint64_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getxer(thread, value);
+}
+
+int thread_putxer(struct pdbg_target *target, uint64_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putxer(thread, value);
+}
+
+int thread_getcr(struct pdbg_target *target, uint32_t *value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->getcr(thread, value);
+}
+
+int thread_putcr(struct pdbg_target *target, uint32_t value)
+{
+	struct thread *thread;
+
+	assert(pdbg_target_is_class(target, "thread"));
+	thread = target_to_thread(target);
+
+	return thread->putcr(thread, value);
+}