diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2018-05-03 16:27:01 +1000 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2018-05-18 11:19:21 +1000 |
commit | 18de4ba00b600e40fd49aaaea8d0bf118b8a90e5 (patch) | |
tree | cd29bdf448e6f42c9d2eb5fd1ad6c54c8229571d | |
parent | acf6c036e30815c1e326c4ecdf478eaed89a9f29 (diff) | |
download | pdbg-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.c | 169 | ||||
-rw-r--r-- | libpdbg/libpdbg.h | 38 | ||||
-rw-r--r-- | libpdbg/operations.h | 5 | ||||
-rw-r--r-- | libpdbg/p8chip.c | 10 | ||||
-rw-r--r-- | libpdbg/p9chip.c | 24 | ||||
-rw-r--r-- | libpdbg/target.h | 1 | ||||
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/thread.c | 18 | ||||
-rw-r--r-- | src/thread.h | 1 |
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, ®s->nia); + printf("NIA : 0x%016" PRIx64 "\n", regs->nia); + + ram_getspr(thread, 28, ®s->cfar); + printf("CFAR : 0x%016" PRIx64 "\n", regs->cfar); + + ram_getmsr(thread, ®s->msr); + printf("MSR : 0x%016" PRIx64 "\n", regs->msr); + + ram_getspr(thread, 8, ®s->lr); + printf("LR : 0x%016" PRIx64 "\n", regs->lr); + + ram_getspr(thread, 9, ®s->ctr); + printf("CTR : 0x%016" PRIx64 "\n", regs->ctr); + + ram_getspr(thread, 815, ®s->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, ®s->gprs[i]); + printf(" 0x%016" PRIx64 "", regs->gprs[i]); + if (i % 4 == 3) + printf("\n"); + } + + ram_getspr(thread, 318, ®s->lpcr); + printf("LPCR : 0x%016" PRIx64 "\n", regs->lpcr); + + ram_getspr(thread, 464, ®s->ptcr); + printf("PTCR : 0x%016" PRIx64 "\n", regs->lpcr); + + ram_getspr(thread, 319, ®s->lpidr); + printf("LPIDR : 0x%016" PRIx64 "\n", regs->lpidr); + + ram_getspr(thread, 48, ®s->pidr); + printf("PIDR : 0x%016" PRIx64 "\n", regs->pidr); + + ram_getspr(thread, 190, ®s->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, ®s->hdar); + printf("HDAR : 0x%016" PRIx64 "\n", regs->hdar); + + ram_getspr(thread, 314, ®s->hsrr0); + printf("HSRR0 : 0x%016" PRIx64 "\n", regs->hsrr0); + + ram_getspr(thread, 315, ®s->hsrr1); + printf("HSRR1 : 0x%016" PRIx64 "\n", regs->hsrr1); + + ram_getspr(thread, 310, ®s->hdec); + printf("HDEC : 0x%016" PRIx64 "\n", regs->hdec); + + ram_getspr(thread, 304, ®s->hsprg0); + printf("HSPRG0: 0x%016" PRIx64 "\n", regs->hsprg0); + + ram_getspr(thread, 305, ®s->hsprg1); + printf("HSPRG1: 0x%016" PRIx64 "\n", regs->hsprg1); + + ram_getspr(thread, 153, ®s->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, ®s->dar); + printf("DAR : 0x%016" PRIx64 "\n", regs->dar); + + ram_getspr(thread, 26, ®s->srr0); + printf("SRR0 : 0x%016" PRIx64 "\n", regs->srr0); + + ram_getspr(thread, 27, ®s->srr1); + printf("SRR1 : 0x%016" PRIx64 "\n", regs->srr1); + + ram_getspr(thread, 22, ®s->dec); + printf("DEC : 0x%016" PRIx64 "\n", regs->dec); + + ram_getspr(thread, 268, ®s->tb); + printf("TB : 0x%016" PRIx64 "\n", regs->tb); + + ram_getspr(thread, 272, ®s->sprg0); + printf("SPRG0 : 0x%016" PRIx64 "\n", regs->sprg0); + + ram_getspr(thread, 273, ®s->sprg1); + printf("SPRG1 : 0x%016" PRIx64 "\n", regs->sprg1); + + ram_getspr(thread, 274, ®s->sprg2); + printf("SPRG2 : 0x%016" PRIx64 "\n", regs->sprg2); + + ram_getspr(thread, 275, ®s->sprg3); + printf("SPRG3 : 0x%016" PRIx64 "\n", regs->sprg3); + + ram_getspr(thread, 896, ®s->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 *); @@ -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, ®s) ? 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[]); |