summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpdbg/chip.c55
-rw-r--r--libpdbg/operations.h1
-rw-r--r--src/main.c30
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);
diff --git a/src/main.c b/src/main.c
index 6b86f3f..d478988 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
OpenPOWER on IntegriCloud