summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2016-11-30 15:56:22 +1100
committerAlistair Popple <alistair@popple.id.au>2016-11-30 15:56:22 +1100
commitc305fd7f346a98ff5f24a1797146cd9e41e5a327 (patch)
treefda0cc3643b93ad79f5f3d0d46b7869f0e322834
parent9092af83c8fb59d86a209e203186e0f979f81d0d (diff)
downloadpdbg-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.c16
-rw-r--r--libpdbg/operations.h1
-rw-r--r--libpdbg/target.c1
-rw-r--r--src/main.c79
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);
diff --git a/src/main.c b/src/main.c
index 7134fa6..82f6653 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
OpenPOWER on IntegriCloud