diff options
author | Alistair Popple <alistair@popple.id.au> | 2016-11-22 12:46:35 +1100 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2016-11-22 12:51:27 +1100 |
commit | adf7f8391b4e429668fdb9e8834de9a0570d533d (patch) | |
tree | 8cba0452a65f8cc9dfeaa3e73d34ec3c9b8f73da | |
parent | 749351433237295a86afcf451b947bc6621b946f (diff) | |
download | pdbg-adf7f8391b4e429668fdb9e8834de9a0570d533d.tar.gz pdbg-adf7f8391b4e429668fdb9e8834de9a0570d533d.zip |
libpdbg/chip.c: Add command to read virtual addresses
Adds a command to read a 64-bit word from a given virtual address. The
address is read in the current thread context and may cause an
exception. In the case of exception it will be raised on the host when
thread execution is resumed.
Signed-off-by: Alistair Popple <alistair@popple.id.au>
-rw-r--r-- | libpdbg/chip.c | 55 | ||||
-rw-r--r-- | libpdbg/operations.h | 1 | ||||
-rw-r--r-- | src/main.c | 30 |
3 files changed, 68 insertions, 18 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c index 9a0b963..39a5194 100644 --- a/libpdbg/chip.c +++ b/libpdbg/chip.c @@ -77,6 +77,7 @@ #define MTMSR_OPCODE 0x7c000124UL #define MFSPR_OPCODE 0x7c0002a6UL #define MTSPR_OPCODE 0x7c0003a6UL +#define LD_OPCODE 0xe8000000UL static uint64_t mfspr(uint64_t reg, uint64_t spr) { @@ -126,6 +127,14 @@ static uint64_t mtmsr(uint64_t reg) return MTMSR_OPCODE | (reg << 21); } +static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra) +{ + if ((rt > 31) | (ra > 31) | (ds > 0x3fff)) + PR_ERROR("Invalid register specified\n"); + + return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2); +} + static int assert_special_wakeup(struct target *chip) { int i = 0; @@ -295,10 +304,11 @@ int ram_start_thread(struct target *thread) static int ram_instructions(struct target *thread, uint64_t *opcodes, uint64_t *results, int len, unsigned int lpar) { - uint64_t ram_mode, val, opcode, r0 = 0; + uint64_t ram_mode, val, opcode, r0 = 0, r1 = 0; struct target *chiplet = thread->next; int thread_id = (thread->base >> 4) & 0x7; int i; + int exception = 0; /* Activate RAM mode */ CHECK_ERR(read_target(chiplet, RAM_MODE_REG, &ram_mode)); @@ -313,17 +323,23 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes, CHECK_ERR(write_target(chiplet, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR)); /* RAM instructions */ - for (i = -1; i <= len; i++) { - if (i < 0) + for (i = -2; i < len + 2; i++) { + if (i == -2) + opcode = mtspr(277, 1); + else if (i == -1) /* Save r0 (assumes opcodes don't touch other registers) */ opcode = mtspr(277, 0); else if (i < len) { CHECK_ERR(write_target(chiplet, SCR0_REG, results[i])); opcode = opcodes[i]; - } else if (i >= len) { + } else if (i == len) { /* Restore r0 */ CHECK_ERR(write_target(chiplet, SCR0_REG, r0)); opcode = mfspr(0, 277); + } else if (i == len + 1) { + /* Restore r1 */ + CHECK_ERR(write_target(chiplet, SCR0_REG, r1)); + opcode = mfspr(0, 277); } /* ram instruction */ @@ -334,14 +350,23 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes, /* wait for completion */ do { CHECK_ERR(read_target(chiplet, RAM_STATUS_REG, &val)); - } while (!val); - - if (!(val & RAM_STATUS)) - PR_ERROR("RAMMING failed with status 0x%llx\n", val); + } while (!((val & PPC_BIT(1)) || ((val & PPC_BIT(2)) && (val & PPC_BIT(3))))); + + if (!(val & PPC_BIT(1))) { + exception = GETFIELD(PPC_BITMASK(2,3), val) == 0x3; + if (exception) { + /* Skip remaining instructions */ + i = len - 1; + continue; + } else + PR_ERROR("RAMMING failed with status 0x%llx\n", val); + } /* Save the results */ CHECK_ERR(read_target(chiplet, SCR0_REG, &val)); - if (i < 0) + if (i == -2) + r1 = val; + else if (i == -1) r0 = val; else if (i < len) results[i] = val; @@ -351,7 +376,7 @@ static int ram_instructions(struct target *thread, uint64_t *opcodes, ram_mode &= ~RAM_MODE_ENABLE; CHECK_ERR(write_target(chiplet, RAM_MODE_REG, ram_mode)); - return 0; + return exception; } /* @@ -434,6 +459,16 @@ int ram_putmsr(struct target *thread, uint64_t value) return 0; } +int ram_getmem(struct target *thread, uint64_t addr, uint64_t *value) +{ + uint64_t opcodes[] = {mfspr(0, 277), mfspr(1, 277), ld(0, 0, 1), mtspr(277, 0)}; + uint64_t results[] = {0xdeaddeaddeaddead, addr, 0, 0}; + + CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); + *value = results[3]; + return 0; +} + int thread_target_init(struct target *thread, const char *name, uint64_t thread_id, struct target *next) { target_init(thread, name, 0x13000 | (thread_id << 4), NULL, NULL, NULL, next); diff --git a/libpdbg/operations.h b/libpdbg/operations.h index 8e3033d..cb20a75 100644 --- a/libpdbg/operations.h +++ b/libpdbg/operations.h @@ -58,6 +58,7 @@ int ram_getspr(struct target *thread, int spr, uint64_t *value); int ram_putspr(struct target *thread, int spr, uint64_t value); int ram_getmsr(struct target *thread, uint64_t *value); int ram_putmsr(struct target *thread, uint64_t value); +int ram_getmem(struct target *thread, uint64_t addr, uint64_t *value); uint64_t chiplet_thread_status(struct target *thread); int ram_stop_thread(struct target *thread); int ram_step_thread(struct target *thread, int count); @@ -36,7 +36,7 @@ enum command { GETCFAM = 1, PUTCFAM, GETSCOM, PUTSCOM, \ GETMEM, PUTMEM, GETGPR, GETNIA, GETSPR, \ GETMSR, PUTGPR, PUTNIA, PUTSPR, PUTMSR, \ STOPCHIP, STARTCHIP, THREADSTATUS, STEP, \ - PROBE }; + PROBE, GETVMEM }; #define MAX_CMD_ARGS 2 enum command cmd = 0; @@ -113,6 +113,7 @@ static void print_usage(char *pname) printf("\tgetscom <address>\n"); printf("\tputscom <address> <value>\n"); printf("\tgetmem <address> <count>\n"); + printf("\tgetvmem <virtual address>\n"); printf("\tgetgpr <gpr>\n"); printf("\tputgpr <gpr> <value>\n"); printf("\tgetnia\n"); @@ -167,6 +168,9 @@ enum command parse_cmd(char *optarg) } else if (strcmp(optarg, "putmsr") == 0) { cmd = PUTMSR; cmd_arg_count = 1; + } else if (strcmp(optarg, "getvmem") == 0) { + cmd = GETVMEM; + cmd_arg_count = 1; } else if (strcmp(optarg, "startchip") == 0) { cmd = STARTCHIP; cmd_arg_count = 0; @@ -616,11 +620,12 @@ static int startstopstep_thread(struct target *thread, uint64_t action, uint64_t */ static int startstopstep_chip(struct target *chiplet, uint64_t action, uint64_t *data) { - for_each_class_call(&threads, filter_parent, startstopstep_thread, chiplet, action, NULL); + for_each_class_call(&threads, filter_parent, startstopstep_thread, chiplet, action, data); return 0; } +#define REG_MEM -3ULL #define REG_MSR -2ULL #define REG_NIA -1ULL #define REG_R31 31ULL @@ -663,6 +668,7 @@ static int putreg(struct target *thread, uint64_t reg, uint64_t *data) static int getreg(struct target *thread, uint64_t reg, uint64_t *data) { uint64_t status = chiplet_thread_status(thread); + uint64_t addr = *data; if (status != (THREAD_STATUS_QUIESCE | THREAD_STATUS_ACTIVE)) { PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); @@ -671,17 +677,22 @@ static int getreg(struct target *thread, uint64_t reg, uint64_t *data) return 0; } - if (reg == REG_NIA) + if (reg == REG_NIA) if (ram_getnia(thread, data)) PR_ERROR("Error reading register\n"); else printf("c%02d:t%d:nia = 0x%016llx\n", thread->next->index, thread->index, *data); - else if (reg == REG_MSR) - if (ram_getmsr(thread, data)) - PR_ERROR("Error reading register\n"); - else + else if (reg == REG_MSR) + if (ram_getmsr(thread, data)) + PR_ERROR("Error reading register\n"); + else printf("c%02d:t%d:msr = 0x%016llx\n", thread->next->index, thread->index, *data); - else if (reg <= REG_R31) + else if (reg == REG_MEM) + if (ram_getmem(thread, addr, data)) + PR_ERROR("Page fault reading memory\n"); + else + printf("c%02d:t%d:0x%016llx = 0x%016llx\n", thread->next->index, thread->index, addr, *data); + else if (reg <= REG_R31) if (ram_getgpr(thread, reg, data)) PR_ERROR("Error reading register\n"); else @@ -757,6 +768,9 @@ int main(int argc, char *argv[]) case PUTMSR: rc = for_each_class_call(&threads, NULL, putreg, NULL, REG_MSR, &cmd_args[0]); break; + case GETVMEM: + rc = for_each_class_call(&threads, NULL, getreg, NULL, REG_MEM, &cmd_args[0]); + break; case THREADSTATUS: printf(" t: 0 1 2 3 4 5 6 7\n"); rc = for_each_class_call(&chiplets, NULL, print_chiplet_thread_status, NULL, 0, 0); |