#include "target/target.h"
#include "target/target_type.h"
#include "target/register.h"
+#include <target/smp.h>
#include "rtos.h"
#include "helper/log.h"
#include "helper/types.h"
/* determine the number of "threads" */
if (target->smp) {
- for (head = target->head; head; head = head->next) {
+ foreach_smp_target(head, target->smp_targets) {
struct target *curr = head->target;
if (!target_was_examined(curr))
if (target->smp) {
/* loop over all threads */
- for (head = target->head; head; head = head->next) {
+ foreach_smp_target(head, target->smp_targets) {
struct target *curr = head->target;
if (!target_was_examined(curr))
if (!target)
return NULL;
if (target->smp) {
- for (struct target_list *head = target->head; head; head = head->next) {
+ struct target_list *head;
+ foreach_smp_target(head, target->smp_targets) {
if (thread_id == threadid_from_target(head->target))
return head->target;
}
#include "rtos.h"
#include "rtos_standard_stackings.h"
#include <target/register.h>
+#include <target/smp.h>
#include "server/gdb_server.h"
#define LINUX_USER_KERNEL_BORDER 0xc0000000
/* search target to perform the access */
struct reg **gdb_reg_list;
struct target_list *head;
- head = target->head;
found = 0;
- do {
+ foreach_smp_target(head, target->smp_targets) {
if (head->target->coreid == next->core_id) {
target = head->target;
found = 1;
break;
}
- head = head->next;
- } while (head);
+ }
if (found == 0) {
LOG_ERROR
static int get_current(struct target *target, int create)
{
struct target_list *head;
- head = target->head;
uint8_t *buf;
uint32_t val;
uint32_t ti_addr;
ctt = ctt->next;
}
- while (head) {
+ foreach_smp_target(head, target->smp_targets) {
struct reg **reg_list;
int reg_list_size;
int retval;
}
free(reg_list);
- head = head->next;
}
free(buffer);
struct linux_os *os_linux =
(struct linux_os *)rtos->rtos_specific_params;
struct current_thread *ct;
- head = target->head;
- while (head) {
+ foreach_smp_target(head, target->smp_targets) {
if (head->target->rtos != rtos) {
struct linux_os *smp_os_linux =
(struct linux_os *)head->target->rtos->rtos_specific_params;
os_linux->nr_cpus++;
free(smp_os_linux);
}
-
- head = head->next;
}
return ERROR_OK;
*combined_list_size = 0;
struct target_list *head;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
struct reg **reg_list = NULL;
int reg_list_size;
int result = target_get_gdb_reg_list_noread(head->target, ®_list,
}
/* Now warn the user about any registers that weren't found in every target. */
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
struct reg **reg_list = NULL;
int reg_list_size;
int result = target_get_gdb_reg_list_noread(head->target, ®_list,
/* initialize all targets gdb service with the same pointer */
{
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if (curr != target)
curr->gdb_service = gdb_service;
- head = head->next;
}
}
return ret;
static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first)
{
int retval = ERROR_OK;
- struct target_list *head = target->head;
+ struct target_list *head;
struct target *first = NULL;
LOG_DEBUG("target %s exc %i", target_name(target), exc_target);
- while (head) {
+ foreach_smp_target(head, target->smp_targets) {
struct target *curr = head->target;
struct armv8_common *armv8 = target_to_armv8(curr);
- head = head->next;
if (exc_target && curr == target)
continue;
struct target_list *head;
struct target *curr;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
int halted;
curr = head->target;
}
/* poll all targets in the group, but skip the target that serves GDB */
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
curr = head->target;
/* skip calling context */
if (curr == target)
struct target *first = NULL;
uint64_t address;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
struct target *curr = head->target;
/* skip calling target */
struct target *curr = target;
bool all_resumed = true;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
uint32_t prsr;
int resumed;
struct target_list *head;
bool all_resumed = true;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
uint32_t prsr;
int resumed;
#include "arm_opcodes.h"
#include "target.h"
#include "target_type.h"
+#include "smp.h"
static void armv7a_show_fault_registers(struct target *target)
{
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
{
struct armv7a_l2x_cache *l2x_cache;
- struct target_list *head = target->head;
- struct target *curr;
+ struct target_list *head;
struct armv7a_common *armv7a = target_to_armv7a(target);
l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
/* initialize all target in this cluster (smp target)
* l2 cache must be configured after smp declaration */
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if (curr != target) {
armv7a = target_to_armv7a(curr);
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
LOG_ERROR("smp target : outer cache already initialized\n");
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
}
- head = head->next;
}
return JIM_OK;
}
#include "armv7a_cache.h"
#include <helper/time_support.h>
#include "arm_opcodes.h"
+#include "smp.h"
static int armv7a_l1_d_cache_sanity_check(struct target *target)
{
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if (curr->state == TARGET_HALTED)
retval = armv7a_l1_d_cache_clean_inval_all(curr);
-
- head = head->next;
}
} else
retval = armv7a_l1_d_cache_clean_inval_all(target);
#include <helper/time_support.h>
#include "target.h"
#include "target_type.h"
+#include "smp.h"
static int arm7a_l2x_sanity_check(struct target *target)
{
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
{
struct armv7a_l2x_cache *l2x_cache;
- struct target_list *head = target->head;
- struct target *curr;
+ struct target_list *head;
struct armv7a_common *armv7a = target_to_armv7a(target);
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
/* initialize all targets in this cluster (smp target)
* l2 cache must be configured after smp declaration */
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if (curr != target) {
armv7a = target_to_armv7a(curr);
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
}
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
}
- head = head->next;
}
return ERROR_OK;
}
#include "armv8_cache.h"
#include "armv8_dpm.h"
#include "armv8_opcodes.h"
+#include "smp.h"
/* CLIDR cache types */
#define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4
/* look if all the other target have been flushed in order to flush level
* 2 */
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if (curr->state == TARGET_HALTED) {
LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid);
retval = _armv8_flush_all_data(curr);
}
- head = head->next;
}
} else
retval = _armv8_flush_all_data(target);
#include "target.h"
#include <helper/log.h>
#include "breakpoints.h"
+#include "smp.h"
static const char * const breakpoint_type_strings[] = {
"hardware",
uint32_t length,
enum breakpoint_type type)
{
- int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- if (type == BKPT_SOFT)
+
+ if (type == BKPT_SOFT) {
+ head = list_first_entry(target->smp_targets, struct target_list, lh);
return breakpoint_add_internal(head->target, address, length, type);
+ }
- while (head) {
- curr = head->target;
- retval = breakpoint_add_internal(curr, address, length, type);
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
+ int retval = breakpoint_add_internal(curr, address, length, type);
if (retval != ERROR_OK)
return retval;
- head = head->next;
}
- return retval;
+
+ return ERROR_OK;
} else {
return breakpoint_add_internal(target, address, length, type);
}
uint32_t length,
enum breakpoint_type type)
{
- int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
- retval = context_breakpoint_add_internal(curr, asid, length, type);
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
+ int retval = context_breakpoint_add_internal(curr, asid, length, type);
if (retval != ERROR_OK)
return retval;
- head = head->next;
}
- return retval;
+
+ return ERROR_OK;
} else {
return context_breakpoint_add_internal(target, asid, length, type);
}
uint32_t length,
enum breakpoint_type type)
{
- int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
- retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
+ int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
if (retval != ERROR_OK)
return retval;
- head = head->next;
}
- return retval;
+
+ return ERROR_OK;
} else
return hybrid_breakpoint_add_internal(target, address, asid, length, type);
}
if (target->smp) {
unsigned int num_breakpoints = 0;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
num_breakpoints += breakpoint_remove_internal(curr, address);
- head = head->next;
}
if (!num_breakpoints)
LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
{
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
breakpoint_remove_all_internal(curr);
- head = head->next;
}
} else {
breakpoint_remove_all_internal(target);
{
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
breakpoint_clear_target_internal(curr);
- head = head->next;
}
} else {
breakpoint_clear_target_internal(target);
int watchpoint_add(struct target *target, target_addr_t address,
uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
{
- int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head != (struct target_list *)NULL) {
- curr = head->target;
- retval = watchpoint_add_internal(curr, address, length, rw, value,
- mask);
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
+ int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
if (retval != ERROR_OK)
return retval;
- head = head->next;
}
- return retval;
+
+ return ERROR_OK;
} else {
return watchpoint_add_internal(target, address, length, rw, value,
mask);
if (target->smp) {
unsigned int num_watchpoints = 0;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
num_watchpoints += watchpoint_remove_internal(curr, address);
- head = head->next;
}
if (num_watchpoints == 0)
LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
static struct target *get_cortex_a(struct target *target, int32_t coreid)
{
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
return curr;
- head = head->next;
}
return target;
}
{
int retval = 0;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_HALTED)
&& target_was_examined(curr))
retval += cortex_a_halt(curr);
- head = head->next;
}
return retval;
}
if (target->gdb_service)
gdb_target = target->gdb_service->target;
- foreach_smp_target(head, target->head) {
+ foreach_smp_target(head, target->smp_targets) {
curr = head->target;
/* skip calling context */
if (curr == target)
{
int retval = 0;
struct target_list *head;
- struct target *curr;
target_addr_t address;
- head = target->head;
- while (head) {
- curr = head->target;
+
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_RUNNING)
&& target_was_examined(curr)) {
/* resume current address , not in step mode */
handle_breakpoints, 0);
retval += cortex_a_internal_restart(curr);
}
- head = head->next;
-
}
return retval;
}
static struct target *get_mips_m4k(struct target *target, int32_t coreid)
{
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
return curr;
- head = head->next;
}
return target;
}
{
int retval = ERROR_OK;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
+
+ foreach_smp_target(head, target->smp_targets) {
int ret = ERROR_OK;
- curr = head->target;
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_HALTED))
ret = mips_m4k_halt(curr);
LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid);
retval = ret;
}
- head = head->next;
}
return retval;
}
{
int retval = ERROR_OK;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head) {
+ foreach_smp_target(head, target->smp_targets) {
int ret = ERROR_OK;
- curr = head->target;
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_RUNNING)) {
/* resume current address , not in step mode */
ret = mips_m4k_internal_restore(curr, 1, address,
retval = ret;
}
}
- head = head->next;
}
return retval;
}
#include "target/target.h"
#include "target/algorithm.h"
#include "target/target_type.h"
+#include <target/smp.h>
#include "jtag/jtag.h"
#include "target/register.h"
#include "target/breakpoints.h"
int result = ERROR_OK;
if (target->smp) {
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ struct target_list *tlist;
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (halt_prep(t) != ERROR_OK)
result = ERROR_FAIL;
}
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
riscv_info_t *i = riscv_info(t);
if (i->prepped) {
}
}
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (halt_finish(t) != ERROR_OK)
return ERROR_FAIL;
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
int result = ERROR_OK;
if (target->smp && !single_hart) {
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ struct target_list *tlist;
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (resume_prep(t, current, address, handle_breakpoints,
debug_execution) != ERROR_OK)
result = ERROR_FAIL;
}
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
riscv_info_t *i = riscv_info(t);
if (i->prepped) {
}
}
- for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (resume_finish(t) != ERROR_OK)
return ERROR_FAIL;
unsigned halts_discovered = 0;
unsigned should_remain_halted = 0;
unsigned should_resume = 0;
- unsigned i = 0;
- for (struct target_list *list = target->head; list;
- list = list->next, i++) {
+ struct target_list *list;
+ foreach_smp_target(list, target->smp_targets) {
struct target *t = list->target;
riscv_info_t *r = riscv_info(t);
enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
}
/* Sample memory if any target is running. */
- for (struct target_list *list = target->head; list;
- list = list->next, i++) {
+ foreach_smp_target(list, target->smp_targets) {
struct target *t = list->target;
if (t->state == TARGET_RUNNING) {
sample_memory(target);
}
if (!strcmp(CMD_ARGV[0], "on")) {
- foreach_smp_target(head, target->head)
+ foreach_smp_target(head, target->smp_targets)
head->target->smp = 1;
return ERROR_OK;
}
if (!strcmp(CMD_ARGV[0], "off")) {
- foreach_smp_target(head, target->head)
+ foreach_smp_target(head, target->smp_targets)
head->target->smp = 0;
/* fixes the target display to the debugger */
- if (target->head)
+ if (!list_empty(target->smp_targets))
target->gdb_service->target = target;
return ERROR_OK;
{
struct target *target = get_current_target(CMD_CTX);
int retval = ERROR_OK;
- struct target_list *head;
- head = target->head;
- if (head) {
+ if (!list_empty(target->smp_targets)) {
if (CMD_ARGC == 1) {
int coreid = 0;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid);
#ifndef OPENOCD_TARGET_SMP_H
#define OPENOCD_TARGET_SMP_H
+#include <helper/list.h>
#include "server/server.h"
#define foreach_smp_target(pos, head) \
- for (pos = head; (pos); pos = pos->next)
+ list_for_each_entry(pos, head, lh)
extern const struct command_registration smp_command_handlers[];
#include "rtos/rtos.h"
#include "transport/transport.h"
#include "arm_cti.h"
+#include "smp.h"
/* default halt wait timeout (ms) */
#define DEFAULT_HALT_TIMEOUT 5000
static LIST_HEAD(target_reset_callback_list);
static LIST_HEAD(target_trace_callback_list);
static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL;
+static LIST_HEAD(empty_smp_targets);
static const struct jim_nvp nvp_assert[] = {
{ .name = "assert", NVP_ASSERT },
/* release the targets SMP list */
if (target->smp) {
- struct target_list *head = target->head;
- while (head) {
- struct target_list *pos = head->next;
+ struct target_list *head, *tmp;
+
+ list_for_each_entry_safe(head, tmp, target->smp_targets, lh) {
+ list_del(&head->lh);
head->target->smp = 0;
free(head);
- head = pos;
}
+ if (target->smp_targets != &empty_smp_targets)
+ free(target->smp_targets);
target->smp = 0;
}
return JIM_ERR;
}
+ /* set empty smp cluster */
+ target->smp_targets = &empty_smp_targets;
+
/* set target number */
target->target_number = new_target_number();
const char *targetname;
int retval, len;
struct target *target = NULL;
- struct target_list *head, *curr, *new;
- curr = NULL;
- head = NULL;
+ struct target_list *head, *new;
retval = 0;
LOG_DEBUG("%d", argc);
* argv[3] ...
*/
+ struct list_head *lh = malloc(sizeof(*lh));
+ if (!lh) {
+ LOG_ERROR("Out of memory");
+ return JIM_ERR;
+ }
+ INIT_LIST_HEAD(lh);
+
for (i = 1; i < argc; i++) {
targetname = Jim_GetString(argv[i], &len);
if (target) {
new = malloc(sizeof(struct target_list));
new->target = target;
- new->next = NULL;
- if (!head) {
- head = new;
- curr = head;
- } else {
- curr->next = new;
- curr = new;
- }
+ list_add_tail(&new->lh, lh);
}
}
/* now parse the list of cpu and put the target in smp mode*/
- curr = head;
-
- while (curr) {
- target = curr->target;
+ foreach_smp_target(head, lh) {
+ target = head->target;
target->smp = 1;
- target->head = head;
- curr = curr->next;
+ target->smp_targets = lh;
}
if (target && target->rtos)
* and must be detected when symbols are offered */
struct backoff_timer backoff;
int smp; /* add some target attributes for smp support */
- struct target_list *head;
+ struct list_head *smp_targets; /* list all targets in this smp group/cluster
+ * The head of the list is shared between the
+ * cluster, thus here there is a pointer */
/* the gdb service is there in case of smp, we have only one gdb server
* for all smp target
* the target attached to the gdb is changing dynamically by changing
};
struct target_list {
+ struct list_head lh;
struct target *target;
- struct target_list *next;
};
struct gdb_fileio_info {