diff options
-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); |