* Copyright (C) 2011 by Broadcom Corporation *
* Evan Hunter - ehunter@broadcom.com *
* *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * michel.jaouen@stericsson.com : smp minimum support *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
#include <target/image.h>
#include <jtag/jtag.h>
#include "rtos/rtos.h"
+#include "target/smp.h"
/**
int closed;
int busy;
int noack_mode;
- bool sync; /* set flag to true if you want the next stepi to return immediately.
+ bool sync; /* set flag to true if you want the next stepi to return immediately.
allowing GDB to pick up a fresh set of register values from the target
without modifying the target state. */
/* We delay reporting memory write errors until next step/continue or memory
"ocd_gdb_restart %s",
target_name(target));
break;
+
+ case 'j':
+ /* packet supported only by smp target i.e cortex_a.c*/
+ /* handle smp packet replying coreid played to gbd */
+ gdb_read_smp_packet(
+ connection, target,
+ packet, packet_size);
+ break;
+
+ case 'J':
+ /* packet supported only by smp target i.e cortex_a.c */
+ /* handle smp packet setting coreid to be played at next
+ * resume to gdb */
+ gdb_write_smp_packet(
+ connection, target,
+ packet, packet_size);
+ break;
+
default:
/* ignore unknown packets */
LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
static int gdb_target_start(struct target *target, const char *port)
{
- struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service));
+
+ struct gdb_service *gdb_service;
+ int ret;
+ gdb_service = malloc(sizeof(struct gdb_service));
+
if (NULL == gdb_service)
return -ENOMEM;
gdb_service->target = target;
+ gdb_service->core[0] = -1;
+ gdb_service->core[1] = -1;
+ target->gdb_service = gdb_service;
- return add_service("gdb",
+ ret = add_service("gdb",
port, 1, &gdb_new_connection, &gdb_input,
&gdb_connection_closed, gdb_service);
+ /* initialialize all targets gdb service with the same pointer */
+ {
+ struct target_list *head;
+ struct target *curr;
+ head = target->head;
+ while(head != (struct target_list*)NULL)
+ {
+ curr = head->target;
+ if (curr != target) curr->gdb_service = gdb_service;
+ head = head->next;
+ }
+ }
+ return ret;
}
static int gdb_target_add_one(struct target *target)
{
+ /* one gdb instance per smp list */
+ if ((target->smp) && (target->gdb_service)) return ERROR_OK;
int retval = gdb_target_start(target, gdb_port_next);
- if (retval == ERROR_OK)
+ if (retval == ERROR_OK)
{
long portnumber;
/* If we can parse the port number
#define GDB_SERVER_H
struct image;
+struct reg;
#include <target/target.h>
#define GDB_BUFFER_SIZE 16384
-struct gdb_service
-{
- struct target *target;
-};
-
int gdb_target_add_all(struct target *target);
int gdb_register_commands(struct command_context *command_context);
breakpoints.c \
target.c \
target_request.c \
- testee.c
+ testee.c \
+ smp.c
ARMV4_5_SRC = \
armv4_5.c \
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * michel.jaouen@stericsson.com : smp minimum support *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
// monotonic counter/id-number for breakpoints and watch points
static int bpwp_unique_id;
-int breakpoint_add(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type)
+int breakpoint_add_internal(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
+ char *reason;
int retval;
int n;
(*breakpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_breakpoint(target, *breakpoint_p);
- if (retval != ERROR_OK)
- {
- LOG_ERROR("could not add breakpoint");
+ switch (retval) {
+ case ERROR_OK:
+ break;
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+ reason = "resource not available";
+ goto fail;
+ case ERROR_TARGET_NOT_HALTED:
+ reason = "target running";
+ goto fail;
+ default:
+ reason = "unknown reason";
+fail:
+ LOG_ERROR("can't add breakpoint: %s", reason);
free((*breakpoint_p)->orig_instr);
free(*breakpoint_p);
*breakpoint_p = NULL;
return ERROR_OK;
}
+int breakpoint_add(struct target *target, uint32_t address, 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 != (struct target_list*)NULL)
+ {
+ curr = head->target;
+ retval = breakpoint_add_internal(curr, address,length, type);
+ if (retval != ERROR_OK) return retval;
+ head = head->next;
+ }
+ return retval;
+ }
+ else
+ return(breakpoint_add_internal(target, address, length, type));
+
+}
+
/* free up a breakpoint */
static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
{
free(breakpoint);
}
-void breakpoint_remove(struct target *target, uint32_t address)
+void breakpoint_remove_internal(struct target *target, uint32_t address)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
}
}
+void breakpoint_remove(struct target *target, uint32_t address)
+{
+ if ((target->smp))
+ {
+ struct target_list *head;
+ struct target *curr;
+ head = target->head;
+ while(head != (struct target_list*)NULL)
+ {
+ curr = head->target;
+ breakpoint_remove_internal(curr, address);
+ head = head->next;
+ }
+ }
+ else breakpoint_remove_internal(target, address);
+}
-void breakpoint_clear_target(struct target *target)
+void breakpoint_clear_target_internal(struct target *target)
{
struct breakpoint *breakpoint;
}
}
+void breakpoint_clear_target(struct target *target)
+{
+ if (target->smp)
+ {
+ struct target_list *head;
+ struct target *curr;
+ head = target->head;
+ while(head != (struct target_list*)NULL)
+ {
+ curr = head->target;
+ breakpoint_clear_target_internal(curr);
+ head = head->next;
+ }
+ }
+ else breakpoint_clear_target_internal(target);
+
+}
+
+
struct breakpoint* breakpoint_find(struct target *target, uint32_t address)
{
struct breakpoint *breakpoint = target->breakpoints;
struct watchpoint *watchpoint = target->watchpoints;
struct watchpoint **watchpoint_p = &target->watchpoints;
int retval;
+ char *reason;
while (watchpoint)
{
(*watchpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_watchpoint(target, *watchpoint_p);
- if (retval != ERROR_OK)
- {
- LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32,
+ switch (retval) {
+ case ERROR_OK:
+ break;
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+ reason = "resource not available";
+ goto bye;
+ case ERROR_TARGET_NOT_HALTED:
+ reason = "target running";
+ goto bye;
+ default:
+ reason = "unrecognized error";
+bye:
+ LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
watchpoint_rw_strings[(*watchpoint_p)->rw],
- address);
+ address, reason);
free (*watchpoint_p);
*watchpoint_p = NULL;
return retval;
--- /dev/null
+/***************************************************************************
+ * *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "server/server.h"
+#include <helper/types.h>
+
+#include "target/target.h"
+
+#include "server/gdb_server.h"
+#include "smp.h"
+
+
+/* implementation of new packet in gdb interface for smp feature */
+/* */
+/* j : smp status request */
+/* J : smp set request */
+/* */
+/* jc :read core id displayed by gdb connection */
+/* reply XXXXXXXX core id is int32_t , 8 hex digits */
+/* */
+/* Reply ENN error not supported (target not smp) */
+/* */
+/* JcXX set core id displayed at next gdb continue */
+/* maximum 8 bytes described core id int32_t (8 hex digits) */
+/* (core id -1 , reserved for returning to normal continue mode) */
+/* Reply ENN error not supported(target not smp,core id out of range) */
+/* Reply OK : for success */
+/* */
+/* handling of this packet within gdb can be done by the creation */
+/* internal variable by mean of function allocate_computed_value */
+/* set $_core 1 => Jc01 packet is sent */
+/* print $_core => jc packet is sent and result is affected in $ */
+/* Another way to test this packet is the usage of maintenance packet */
+/* maint packet Jc01 */
+/* maint packet jc */
+
+static const char DIGITS[16] = "0123456789abcdef";
+
+
+/* packet j :smp status request */
+int gdb_read_smp_packet(struct connection *connection,
+ struct target *target, char *packet, int packet_size)
+{
+ uint32_t len = sizeof(int32_t);
+ uint8_t *buffer;
+ char *hex_buffer;
+ int retval = ERROR_OK;
+ if (target->smp)
+ {
+ if (strstr(packet, "jc"))
+ {
+ hex_buffer = malloc(len * 2 + 1);
+ buffer = (uint8_t *)&target->gdb_service->core[0];
+ uint32_t i;
+ for (i = 0; i < 4; i++)
+ {
+ uint8_t t = buffer[i];
+ hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
+ hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
+ }
+
+ gdb_put_packet(connection, hex_buffer, len * 2);
+
+ free(hex_buffer);
+ }
+ }
+ else
+ retval = gdb_put_packet(connection,"E01",3);
+ return retval;
+}
+
+/* J : smp set request */
+int gdb_write_smp_packet(struct connection *connection,
+ struct target *target, char *packet, int packet_size)
+{
+ char *separator;
+ int coreid = 0;
+ int retval = ERROR_OK;
+
+ /* skip command character */
+ if (target->smp)
+ {
+ if (strstr(packet, "Jc"))
+ {
+ packet+=2;
+ coreid = strtoul(packet, &separator, 16);
+ target->gdb_service->core[1] = coreid;
+ gdb_put_packet(connection, "OK", 2);
+ }
+ }
+ else
+ {
+ retval = gdb_put_packet(connection,"E01",3);
+ }
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "server/server.h"
+int gdb_read_smp_packet(struct connection *connection,
+ struct target *target, char *packet, int packet_size);
+int gdb_write_smp_packet(struct connection *connection,
+ struct target *target, char *packet, int packet_size);
+
* Copyright (C) 2011 by Broadcom Corporation *
* Evan Hunter - ehunter@broadcom.com *
* *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * michel.jaouen@stericsson.com : smp minimum support *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
int target_add_breakpoint(struct target *target,
struct breakpoint *breakpoint)
{
- if (target->state != TARGET_HALTED) {
+ if ((target->state != TARGET_HALTED)&&(breakpoint->type!=BKPT_HARD)) {
LOG_WARNING("target %s is not halted", target->cmd_name);
return ERROR_TARGET_NOT_HALTED;
}
/* loop for more e*/
break;
+
case TCFG_ENDIAN:
if (goi->isconfigure) {
e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n);
if (e != JIM_OK) {
return e;
}
- target->coreid = (int)w;
+ target->coreid = (int32_t)w;
} else {
if (goi->argc != 0) {
goto no_params;
return JIM_OK;
}
+static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ const char *targetname;
+ int retval,len;
+ struct target *target;
+ struct target_list *head, *curr, *new;
+ curr = (struct target_list*) NULL;
+ head = (struct target_list*) NULL;
+ new = (struct target_list*) NULL;
+
+ retval = 0;
+ LOG_DEBUG("%d",argc);
+ /* argv[1] = target to associate in smp
+ * argv[2] = target to assoicate in smp
+ * argv[3] ...
+ */
+
+ for(i=1;i<argc;i++)
+ {
+
+ targetname = Jim_GetString(argv[i], &len);
+ target = get_target(targetname);
+ LOG_DEBUG("%s ",targetname);
+ if (target)
+ {
+ new=malloc(sizeof(struct target_list));
+ new->target = target;
+ new->next = (struct target_list*)NULL;
+ if (head == (struct target_list*)NULL)
+ {
+ head = new;
+ curr = head;
+ }
+ else
+ {
+ curr->next = new;
+ curr = new;
+ }
+ }
+ }
+ /* now parse the list of cpu and put the target in smp mode*/
+ curr=head;
+
+ while(curr!=(struct target_list *)NULL)
+ {
+ target=curr->target;
+ target->smp = 1;
+ target->head = head;
+ curr=curr->next;
+ }
+ return retval;
+}
+
+
static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_GetOptInfo goi;
.help = "Returns the number of targets as an integer "
"(DEPRECATED)",
},
+ {
+ .name = "smp",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_target_smp,
+ .usage = "targetname1 targetname2 ...",
+ .help = "gather several target in a smp list"
+ },
+
COMMAND_REGISTRATION_DONE
};
* Copyright (C) 2011 by Broadcom Corporation *
* Evan Hunter - ehunter@broadcom.com *
* *
+ * Copyright (C) ST-Ericsson SA 2011 *
+ * michel.jaouen@stericsson.com : smp minimum support *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
struct watchpoint;
struct mem_param;
struct reg_param;
-
+struct target_list;
/*
* TARGET_UNKNOWN = 0: we don't know anything about the target yet
struct working_area **user;
struct working_area *next;
};
+
+struct gdb_service
+{
+ struct target *target;
+ /* field for smp display */
+ /* element 0 coreid currently displayed ( 1 till n) */
+ /* element 1 coreid to be displayed at next resume 1 till n 0 means resume
+ * all cores
+ core displayed */
+ int32_t core[2];
+};
// target_type.h contains the full definitionof struct targe_type
struct target
const char *cmd_name; /* tcl Name of target */
int target_number; /* DO NOT USE! field to be removed in 2010 */
struct jtag_tap *tap; /* where on the jtag chain is this */
- int coreid; /* which device on the TAP? */
+ int32_t coreid; /* which device on the TAP? */
const char *variant; /* what variant of this chip is it? */
/**
struct rtos *rtos; /* Instance of Real Time Operating System support */
bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto"
* and must be detected when symbols are offered */
+
+ int smp; /* add some target attributes for smp support */
+ struct target_list *head;
+ /* 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
+ * gdb_service->target pointer */
+ struct gdb_service *gdb_service;
+};
+
+
+struct target_list {
+ struct target *target;
+ struct target_list *next;
};
/** Returns the instance-specific name of the specified target. */