diff options
author | Alistair Popple <alistair@popple.id.au> | 2016-11-30 15:56:22 +1100 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2016-11-30 15:56:22 +1100 |
commit | c305fd7f346a98ff5f24a1797146cd9e41e5a327 (patch) | |
tree | fda0cc3643b93ad79f5f3d0d46b7869f0e322834 | |
parent | 9092af83c8fb59d86a209e203186e0f979f81d0d (diff) | |
download | pdbg-c305fd7f346a98ff5f24a1797146cd9e41e5a327.tar.gz pdbg-c305fd7f346a98ff5f24a1797146cd9e41e5a327.zip |
Fix thread status checks during instruction ramming
Instructions can only be rammed into a thread is all threads on a
chiplet are quiesced or sleeping. This was not properly enforced which
leads to system checkstops when ramming threads if the chip isn't
fully quiesced. This adds a check to ensure all threads are quiesced.
It also changes the startchip/stopchip behaviour to stop all threads
on the given chiplet regards of which threads are selected.
Signed-off-by: Alistair Popple <alistair@popple.id.au>
-rw-r--r-- | libpdbg/chip.c | 16 | ||||
-rw-r--r-- | libpdbg/operations.h | 1 | ||||
-rw-r--r-- | libpdbg/target.c | 1 | ||||
-rw-r--r-- | src/main.c | 79 |
4 files changed, 66 insertions, 31 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c index 39a5194..14c92b3 100644 --- a/libpdbg/chip.c +++ b/libpdbg/chip.c @@ -172,7 +172,7 @@ uint64_t chiplet_thread_status(struct target *thread) static uint64_t get_thread_status(struct target *thread) { - uint64_t val, mode_reg, thread_status = 0; + uint64_t val, mode_reg, thread_status = thread->status; /* Need to activete debug mode to get complete status */ CHECK_ERR(read_target(thread, RAS_MODE_REG, &mode_reg)); @@ -182,11 +182,8 @@ static uint64_t get_thread_status(struct target *thread) /* Read status */ CHECK_ERR(read_target(thread, RAS_STATUS_REG, &val)); - if (val & RAS_STATUS_THREAD_ACTIVE) - thread_status |= THREAD_STATUS_ACTIVE; - - if (val & RAS_STATUS_TS_QUIESCE) - thread_status |= THREAD_STATUS_QUIESCE; + thread_status = SETFIELD(THREAD_STATUS_ACTIVE, thread_status, !!(val & RAS_STATUS_THREAD_ACTIVE)); + thread_status = SETFIELD(THREAD_STATUS_QUIESCE, thread_status, !!(val & RAS_STATUS_TS_QUIESCE)); /* Read POW status */ CHECK_ERR(read_target(thread, POW_STATUS_REG, &val)); @@ -235,10 +232,6 @@ int ram_stop_thread(struct target *thread) uint64_t val; struct target *chip = thread->next; - /* Skip inactive threads */ - if (!GETFIELD(THREAD_STATUS_ACTIVE, thread->status)) - return -1; - do { /* Quiese active thread */ CHECK_ERR(write_target(thread, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STOP)); @@ -278,9 +271,6 @@ int ram_start_thread(struct target *thread) struct target *chip = thread->next; int thread_id = (thread->base >> 4) & 0x7; - if (!GETFIELD(THREAD_STATUS_ACTIVE, thread->status)) - return -1; - /* Activate thread */ CHECK_ERR(write_target(thread, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_START)); diff --git a/libpdbg/operations.h b/libpdbg/operations.h index a60a4ea..b57aa79 100644 --- a/libpdbg/operations.h +++ b/libpdbg/operations.h @@ -44,6 +44,7 @@ int adu_getmem(struct target *target, uint64_t addr, uint8_t *output, uint64_t s int adu_putmem(struct target *target, uint64_t start_addr, uint8_t *input, uint64_t size); /* Functions to ram instructions */ +#define THREAD_STATUS_DISABLED PPC_BIT(0) #define THREAD_STATUS_ACTIVE PPC_BIT(63) #define THREAD_STATUS_STATE PPC_BITMASK(61, 62) #define THREAD_STATUS_DOZE PPC_BIT(62) diff --git a/libpdbg/target.c b/libpdbg/target.c index 97641ee..228e778 100644 --- a/libpdbg/target.c +++ b/libpdbg/target.c @@ -16,6 +16,7 @@ void target_init(struct target *target, const char *name, uint64_t base, target->write = write; target->destroy = destroy; target->next = next; + target->status = 0; list_head_init(&target->children); @@ -430,8 +430,9 @@ static int backend_init(void) for_each_chiplet(chiplet) { thread_count += thread_target_probe(chiplet, target, MAX_TARGETS - target_count); for (i = 0; j < thread_count; i++, j++) { - if (chip[chiplet->next->index][chiplet->index][j]) - target_class_add(&threads, target, i); + target_class_add(&threads, target, i); + if (!chip[chiplet->next->index][chiplet->index][j]) + target->status |= THREAD_STATUS_DISABLED; target++; } } @@ -509,6 +510,24 @@ static int for_each_class_call(struct target_class *class, int (*filter)(struct int rc, count = 0; list_for_each(&class->targets, target, class_link) + if ((!filter || filter(target, priv)) && !(target->status & THREAD_STATUS_DISABLED)) { + count++; + if((rc = cb(target, addr, data))) + return rc; + } + + return count; +} + +/* Same as above but calls cb() on all targets rather than just active ones */ +static int for_each_class_call_all(struct target_class *class, int (*filter)(struct target *, void *), + int (*cb)(struct target *, uint64_t, uint64_t *), + void *priv, uint64_t addr, uint64_t *data) +{ + struct target *target; + int rc, count = 0; + + list_for_each(&class->targets, target, class_link) if (!filter || filter(target, priv)) { count++; if((rc = cb(target, addr, data))) @@ -599,13 +618,16 @@ static int putaddr(struct target *target, uint64_t addr, uint64_t *data) return rc; } +#define START_CHIP 1 +#define STEP_CHIP 2 +#define STOP_CHIP 3 static int startstopstep_thread(struct target *thread, uint64_t action, uint64_t *data) { uint64_t status; - if (action == 1) + if (action == START_CHIP) return ram_start_thread(thread); - else if (action == 2) { + else if (action == STEP_CHIP) { status = chiplet_thread_status(thread); if (!(GETFIELD(THREAD_STATUS_QUIESCE, status) && GETFIELD(THREAD_STATUS_ACTIVE, status))) { PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); @@ -624,11 +646,24 @@ 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, data); + if (action == STEP_CHIP) + for_each_class_call(&threads, filter_parent, startstopstep_thread, chiplet, action, data); + else + for_each_class_call_all(&threads, filter_parent, startstopstep_thread, chiplet, action, data); return 0; } +static int check_thread_status(struct target *thread, uint64_t unused, uint64_t *unused1) +{ + uint64_t status = chiplet_thread_status(thread); + + if (status & THREAD_STATUS_QUIESCE) + return 0; + else + return -1; +} + #define REG_MEM -3ULL #define REG_MSR -2ULL #define REG_NIA -1ULL @@ -636,13 +671,17 @@ static int startstopstep_chip(struct target *chiplet, uint64_t action, uint64_t static int putreg(struct target *thread, uint64_t reg, uint64_t *data) { - uint64_t status = chiplet_thread_status(thread); + struct target *chiplet = thread->next; - if (status != (THREAD_STATUS_QUIESCE | THREAD_STATUS_ACTIVE)) { - PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); + if (for_each_class_call_all(&threads, filter_parent, check_thread_status, chiplet, 0, NULL) < 0) { + PR_ERROR("Not all threads are quiesced. Use the stopchip command" + " first to ensure all chiplet threads are quiesced\n"); + return -1; + } - /* Return 0 so we continue stepping other threads if requested */ - return 0; + if (!((thread->status & THREAD_STATUS_ACTIVE) && (thread->status & THREAD_STATUS_QUIESCE))) { + PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); + return -1; } if (reg == REG_NIA) @@ -673,14 +712,18 @@ 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); + struct target *chiplet = thread->next; uint64_t addr = *data; - if (status != (THREAD_STATUS_QUIESCE | THREAD_STATUS_ACTIVE)) { - PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); + if (for_each_class_call_all(&threads, filter_parent, check_thread_status, chiplet, 0, NULL) < 0) { + PR_ERROR("Not all threads are quiesced. Use the stopchip command" + " first to ensure all chiplet threads are quiesced.\n"); + return -1; + } - /* Return 0 so we continue stepping other threads if requested */ - return 0; + if (!((thread->status & THREAD_STATUS_ACTIVE) && (thread->status & THREAD_STATUS_QUIESCE))) { + PR_ERROR("Thread %d not stopped. Use stopchip first.\n", thread->index); + return -1; } if (reg == REG_NIA) @@ -824,13 +867,13 @@ int main(int argc, char *argv[]) printf("\nA - Active\nS - Sleep\nN - Nap\nD - Doze\nQ - Quiesced/Stopped\nU - Unknown\n"); break; case STARTCHIP: - rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, 1, NULL); + rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, START_CHIP, NULL); break; case STEP: - rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, 2, &cmd_args[0]); + rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, STEP_CHIP, &cmd_args[0]); break; case STOPCHIP: - rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, 0, NULL); + rc = for_each_class_call(&chiplets, NULL, startstopstep_chip, NULL, STOP_CHIP, NULL); break; case PROBE: rc = 1; |