summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-05-03 16:27:01 +1000
committerAlistair Popple <alistair@popple.id.au>2018-05-18 11:19:21 +1000
commit18de4ba00b600e40fd49aaaea8d0bf118b8a90e5 (patch)
treecd29bdf448e6f42c9d2eb5fd1ad6c54c8229571d
parentacf6c036e30815c1e326c4ecdf478eaed89a9f29 (diff)
downloadpdbg-18de4ba00b600e40fd49aaaea8d0bf118b8a90e5.tar.gz
pdbg-18de4ba00b600e40fd49aaaea8d0bf118b8a90e5.zip
pdbg: add 'regs' command
This uses ramming to pull out most registers. There are more SPRs to left to add. Ramming remains set over all register extraction, by keeping ram_is_setup target attribut. This helps to speed things up and minimise disturbance to the host. Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
-rw-r--r--libpdbg/chip.c169
-rw-r--r--libpdbg/libpdbg.h38
-rw-r--r--libpdbg/operations.h5
-rw-r--r--libpdbg/p8chip.c10
-rw-r--r--libpdbg/p9chip.c24
-rw-r--r--libpdbg/target.h1
-rw-r--r--src/main.c1
-rw-r--r--src/thread.c18
-rw-r--r--src/thread.h1
9 files changed, 265 insertions, 2 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index ebfaaa8..ee12614 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
#include <stdint.h>
+#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ccan/array_size/array_size.h>
@@ -40,6 +41,16 @@ static uint64_t mtspr(uint64_t spr, uint64_t reg)
return MTSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
}
+static uint64_t mfocrf(uint64_t reg, uint64_t cr)
+{
+ if (reg > 31)
+ PR_ERROR("Invalid register specified\n");
+ if (cr > 7)
+ PR_ERROR("Invalid register specified\n");
+
+ return MFOCRF_OPCODE | (reg << 21) | (1U << (12 + cr));
+}
+
static uint64_t mfnia(uint64_t reg)
{
if (reg > 31)
@@ -143,10 +154,15 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
int i;
int exception = 0;
struct thread *thread;
+ bool did_setup = false;
assert(!strcmp(thread_target->class, "thread"));
thread = target_to_thread(thread_target);
- CHECK_ERR(thread->ram_setup(thread));
+
+ if (!thread->ram_is_setup) {
+ CHECK_ERR(thread->ram_setup(thread));
+ did_setup = true;
+ }
/* RAM instructions */
for (i = -2; i < len + 2; i++) {
@@ -182,7 +198,8 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes
results[i] = scratch;
}
- CHECK_ERR(thread->ram_destroy(thread));
+ if (did_setup)
+ CHECK_ERR(thread->ram_destroy(thread));
return exception;
}
@@ -258,6 +275,16 @@ int ram_getmsr(struct pdbg_target *thread, uint64_t *value)
return 0;
}
+int ram_getcr(struct pdbg_target *thread, int cr, uint64_t *value)
+{
+ uint64_t opcodes[] = {mfocrf(0, cr), 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_putmsr(struct pdbg_target *thread, uint64_t value)
{
uint64_t opcodes[] = {mfspr(0, 277), mtmsr(0)};
@@ -288,3 +315,141 @@ int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t rin
chiplet = target_to_chiplet(chiplet_target);
return chiplet->getring(chiplet, ring_addr, ring_len, result);
}
+
+int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs)
+{
+ struct thread_regs _regs;
+ struct thread *t;
+ uint64_t value;
+ int i;
+
+ if (!regs)
+ regs = &_regs;
+
+ assert(!strcmp(thread->class, "thread"));
+ t = target_to_thread(thread);
+
+ CHECK_ERR(t->ram_setup(t));
+
+ /*
+ * It would be neat to do all the ramming up front, then go through
+ * and print everything out somewhere else. In practice so far it
+ * can help to diagnose checkstop issues with ramming to print as
+ * we go. Once it's more robust and tested, maybe.
+ */
+ ram_getnia(thread, &regs->nia);
+ printf("NIA : 0x%016" PRIx64 "\n", regs->nia);
+
+ ram_getspr(thread, 28, &regs->cfar);
+ printf("CFAR : 0x%016" PRIx64 "\n", regs->cfar);
+
+ ram_getmsr(thread, &regs->msr);
+ printf("MSR : 0x%016" PRIx64 "\n", regs->msr);
+
+ ram_getspr(thread, 8, &regs->lr);
+ printf("LR : 0x%016" PRIx64 "\n", regs->lr);
+
+ ram_getspr(thread, 9, &regs->ctr);
+ printf("CTR : 0x%016" PRIx64 "\n", regs->ctr);
+
+ ram_getspr(thread, 815, &regs->tar);
+ printf("TAR : 0x%016" PRIx64 "\n", regs->tar);
+
+ regs->cr = 0;
+ for (i = 0; i < 8; i++) {
+ uint64_t cr;
+ ram_getcr(thread, i, &cr);
+ regs->cr |= cr;
+ }
+ printf("CR : 0x%08" PRIx32 "\n", regs->cr);
+
+ ram_getspr(thread, 0x1, &value);
+ regs->xer = value;
+ printf("XER : 0x%08" PRIx32 "\n", regs->xer);
+
+ printf("GPRS :\n");
+ for (i = 0; i < 32; i++) {
+ ram_getgpr(thread, i, &regs->gprs[i]);
+ printf(" 0x%016" PRIx64 "", regs->gprs[i]);
+ if (i % 4 == 3)
+ printf("\n");
+ }
+
+ ram_getspr(thread, 318, &regs->lpcr);
+ printf("LPCR : 0x%016" PRIx64 "\n", regs->lpcr);
+
+ ram_getspr(thread, 464, &regs->ptcr);
+ printf("PTCR : 0x%016" PRIx64 "\n", regs->lpcr);
+
+ ram_getspr(thread, 319, &regs->lpidr);
+ printf("LPIDR : 0x%016" PRIx64 "\n", regs->lpidr);
+
+ ram_getspr(thread, 48, &regs->pidr);
+ printf("PIDR : 0x%016" PRIx64 "\n", regs->pidr);
+
+ ram_getspr(thread, 190, &regs->hfscr);
+ printf("HFSCR : 0x%016" PRIx64 "\n", regs->hfscr);
+
+ ram_getspr(thread, 306, &value);
+ regs->hdsisr = value;
+ printf("HDSISR: 0x%08" PRIx32 "\n", regs->hdsisr);
+
+ ram_getspr(thread, 307, &regs->hdar);
+ printf("HDAR : 0x%016" PRIx64 "\n", regs->hdar);
+
+ ram_getspr(thread, 314, &regs->hsrr0);
+ printf("HSRR0 : 0x%016" PRIx64 "\n", regs->hsrr0);
+
+ ram_getspr(thread, 315, &regs->hsrr1);
+ printf("HSRR1 : 0x%016" PRIx64 "\n", regs->hsrr1);
+
+ ram_getspr(thread, 310, &regs->hdec);
+ printf("HDEC : 0x%016" PRIx64 "\n", regs->hdec);
+
+ ram_getspr(thread, 304, &regs->hsprg0);
+ printf("HSPRG0: 0x%016" PRIx64 "\n", regs->hsprg0);
+
+ ram_getspr(thread, 305, &regs->hsprg1);
+ printf("HSPRG1: 0x%016" PRIx64 "\n", regs->hsprg1);
+
+ ram_getspr(thread, 153, &regs->fscr);
+ printf("FSCR : 0x%016" PRIx64 "\n", regs->fscr);
+
+ ram_getspr(thread, 18, &value);
+ regs->dsisr = value;
+ printf("DSISR : 0x%08" PRIx32 "\n", regs->dsisr);
+
+ ram_getspr(thread, 19, &regs->dar);
+ printf("DAR : 0x%016" PRIx64 "\n", regs->dar);
+
+ ram_getspr(thread, 26, &regs->srr0);
+ printf("SRR0 : 0x%016" PRIx64 "\n", regs->srr0);
+
+ ram_getspr(thread, 27, &regs->srr1);
+ printf("SRR1 : 0x%016" PRIx64 "\n", regs->srr1);
+
+ ram_getspr(thread, 22, &regs->dec);
+ printf("DEC : 0x%016" PRIx64 "\n", regs->dec);
+
+ ram_getspr(thread, 268, &regs->tb);
+ printf("TB : 0x%016" PRIx64 "\n", regs->tb);
+
+ ram_getspr(thread, 272, &regs->sprg0);
+ printf("SPRG0 : 0x%016" PRIx64 "\n", regs->sprg0);
+
+ ram_getspr(thread, 273, &regs->sprg1);
+ printf("SPRG1 : 0x%016" PRIx64 "\n", regs->sprg1);
+
+ ram_getspr(thread, 274, &regs->sprg2);
+ printf("SPRG2 : 0x%016" PRIx64 "\n", regs->sprg2);
+
+ ram_getspr(thread, 275, &regs->sprg3);
+ printf("SPRG3 : 0x%016" PRIx64 "\n", regs->sprg3);
+
+ ram_getspr(thread, 896, &regs->ppr);
+ printf("PPR : 0x%016" PRIx64 "\n", regs->ppr);
+
+ CHECK_ERR(t->ram_destroy(t));
+
+ return 0;
+}
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index 4aca740..1404041 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -90,6 +90,43 @@ int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val);
int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val);
int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data);
+struct thread_regs {
+ uint64_t nia;
+ uint64_t msr;
+ uint64_t cfar;
+ uint64_t lr;
+ uint64_t ctr;
+ uint64_t tar;
+ uint32_t cr;
+ uint32_t xer;
+ uint64_t gprs[32];
+
+ uint64_t lpcr;
+ uint64_t ptcr;
+ uint64_t lpidr;
+ uint64_t pidr;
+ uint64_t hfscr;
+ uint32_t hdsisr;
+ uint64_t hdar;
+ uint64_t hsrr0;
+ uint64_t hsrr1;
+ uint64_t hdec;
+ uint64_t hsprg0;
+ uint64_t hsprg1;
+ uint64_t fscr;
+ uint32_t dsisr;
+ uint64_t dar;
+ uint64_t srr0;
+ uint64_t srr1;
+ uint64_t dec;
+ uint64_t tb;
+ uint64_t sprg0;
+ uint64_t sprg1;
+ uint64_t sprg2;
+ uint64_t sprg3;
+ uint64_t ppr;
+};
+
int ram_putmsr(struct pdbg_target *target, uint64_t val);
int ram_putnia(struct pdbg_target *target, uint64_t val);
int ram_putspr(struct pdbg_target *target, int spr, uint64_t val);
@@ -102,6 +139,7 @@ int ram_start_thread(struct pdbg_target *target);
int ram_step_thread(struct pdbg_target *target, int steps);
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);
uint64_t thread_status(struct pdbg_target *target);
int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]);
diff --git a/libpdbg/operations.h b/libpdbg/operations.h
index 88ddce2..18a498d 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -67,8 +67,13 @@ int adu_putmem(struct pdbg_target *target, uint64_t start_addr, uint8_t *input,
#define MTMSR_OPCODE 0x7c000124UL
#define MFSPR_OPCODE 0x7c0002a6UL
#define MTSPR_OPCODE 0x7c0003a6UL
+#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 LD_OPCODE 0xe8000000UL
+#define MFSPR_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 6cae663..b256c57 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -222,6 +222,9 @@ static int p8_ram_setup(struct thread *thread)
struct core *chip = target_to_core(thread->target.parent);
uint64_t ram_mode, val;
+ if (thread->ram_is_setup)
+ return 1;
+
/* We can only ram a thread if all the threads on the core/chip are
* quiesced */
dt_for_each_compatible(&chip->target, target, "ibm,power8-thread") {
@@ -246,6 +249,8 @@ static int p8_ram_setup(struct thread *thread)
CHECK_ERR(pib_write(&chip->target, SPR_MODE_REG, val));
CHECK_ERR(pib_write(&chip->target, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR));
+ thread->ram_is_setup = true;
+
return 0;
}
@@ -254,6 +259,9 @@ static int p8_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *
struct core *chip = target_to_core(thread->target.parent);
uint64_t val;
+ if (!thread->ram_is_setup)
+ return 1;
+
CHECK_ERR(pib_write(&chip->target, SCR0_REG, *scratch));
/* ram instruction */
@@ -291,6 +299,8 @@ static int p8_ram_destroy(struct thread *thread)
ram_mode &= ~RAM_MODE_ENABLE;
CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode));
+ thread->ram_is_setup = false;
+
return 0;
}
diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c
index 7182ae1..f6fd849 100644
--- a/libpdbg/p9chip.c
+++ b/libpdbg/p9chip.c
@@ -241,6 +241,9 @@ static int p9_ram_setup(struct thread *thread)
struct core *chip = target_to_core(thread->target.parent);
uint64_t value;
+ if (thread->ram_is_setup)
+ return 1;
+
if (pdbg_expert_mode)
goto expert;
@@ -299,6 +302,8 @@ expert:
thread->status = p9_get_thread_status(thread);
+ thread->ram_is_setup = true;
+
return 0;
out_fail:
@@ -313,6 +318,9 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
uint64_t predecode, value;
int rc;
+ if (!thread->ram_is_setup)
+ return 1;
+
switch(opcode & OPCODE_MASK) {
case MTNIA_OPCODE:
predecode = 8;
@@ -330,6 +338,17 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t
predecode = 8;
break;
+ case MFSPR_OPCODE:
+ switch(MFSPR_SPR(opcode)) {
+ case 1: /* XER */
+ predecode = 4;
+ break;
+ default:
+ predecode = 0;
+ break;
+ }
+ break;
+
default:
predecode = 0;
}
@@ -392,6 +411,9 @@ static int p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *
static int p9_ram_destroy(struct thread *thread)
{
+ if (!thread->ram_is_setup)
+ return 1;
+
/* Disable ram mode */
CHECK_ERR(thread_write(thread, P9_RAM_MODEREG, 0));
@@ -402,6 +424,8 @@ static int p9_ram_destroy(struct thread *thread)
ram_nonexpert_cleanup(thread);
+ thread->ram_is_setup = false;
+
return 0;
}
diff --git a/libpdbg/target.h b/libpdbg/target.h
index 701c51f..552d1d3 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -156,6 +156,7 @@ struct thread {
/* ram_setup() should be called prior to using ram_instruction() to
* actually ram the instruction and return the result. ram_destroy()
* should be called at completion to clean-up. */
+ bool ram_is_setup;
int (*ram_setup)(struct thread *);
int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch);
int (*ram_destroy)(struct thread *);
diff --git a/src/main.c b/src/main.c
index 1bbbfb0..830062d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -107,6 +107,7 @@ static struct action actions[] = {
{ "putmem", "<address>", "Write to system memory", &handle_mem },
{ "threadstatus", "", "Print the status of a thread", &thread_status_print },
{ "sreset", "", "Reset", &thread_sreset },
+ { "regs", "", "State", &thread_state },
};
diff --git a/src/thread.c b/src/thread.c
index 13fa09d..a6e096b 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -127,6 +127,13 @@ static int sreset_thread(struct pdbg_target *thread_target, uint32_t index, uint
return ram_sreset_thread(thread_target) ? 0 : 1;
}
+static int state_thread(struct pdbg_target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1)
+{
+ struct thread_regs regs;
+
+ return ram_state_thread(thread_target, &regs) ? 0 : 1;
+}
+
int thread_start(int optind, int argc, char *argv[])
{
return for_each_target("thread", start_thread, NULL, NULL);
@@ -167,3 +174,14 @@ int thread_sreset(int optind, int argc, char *argv[])
{
return for_each_target("thread", sreset_thread, NULL, NULL);
}
+
+int thread_state(int optind, int argc, char *argv[])
+{
+ int err;
+
+ err = for_each_target("thread", state_thread, NULL, NULL);
+
+ for_each_target_release("thread");
+
+ return err;
+}
diff --git a/src/thread.h b/src/thread.h
index 01a8034..5fc2a80 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -22,3 +22,4 @@ int thread_step(int optind, int argc, char *argv[]);
int thread_stop(int optind, int argc, char *argv[]);
int thread_status_print(int optind, int argc, char *argv[]);
int thread_sreset(int optind, int argc, char *argv[]);
+int thread_state(int optind, int argc, char *argv[]);
OpenPOWER on IntegriCloud