Remove FSF address from GPL notices
[openocd.git] / src / target / target.c
index fb141789e74e65812dba4059523b9a378f978973..d6558c49a92e3a4474d7613df807c8f00fa51719 100644 (file)
@@ -34,9 +34,7 @@
  *   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.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -104,6 +102,7 @@ extern struct target_type nds32_v3_target;
 extern struct target_type nds32_v3m_target;
 extern struct target_type or1k_target;
 extern struct target_type quark_x10xx_target;
+extern struct target_type quark_d20xx_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -133,6 +132,7 @@ static struct target_type *target_types[] = {
        &nds32_v3m_target,
        &or1k_target,
        &quark_x10xx_target,
+       &quark_d20xx_target,
        NULL,
 };
 
@@ -140,6 +140,7 @@ struct target *all_targets;
 static struct target_event_callback *target_event_callbacks;
 static struct target_timer_callback *target_timer_callbacks;
 LIST_HEAD(target_reset_callback_list);
+LIST_HEAD(target_trace_callback_list);
 static const int polling_interval = 100;
 
 static const Jim_Nvp nvp_assert[] = {
@@ -217,6 +218,8 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" },
        { .value = TARGET_EVENT_GDB_FLASH_ERASE_END  , .name = "gdb-flash-erase-end" },
 
+       { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
+
        { .name = NULL, .value = -1 }
 };
 
@@ -484,7 +487,7 @@ struct target *get_target(const char *id)
 }
 
 /* returns a pointer to the n-th configured target */
-static struct target *get_target_by_num(int num)
+struct target *get_target_by_num(int num)
 {
        struct target *target = all_targets;
 
@@ -685,7 +688,15 @@ static int default_check_reset(struct target *target)
 
 int target_examine_one(struct target *target)
 {
-       return target->type->examine(target);
+       target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
+
+       int retval = target->type->examine(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
+
+       return ERROR_OK;
 }
 
 static int jtag_enable_callback(enum jtag_event event, void *priv)
@@ -697,15 +708,7 @@ static int jtag_enable_callback(enum jtag_event event, void *priv)
 
        jtag_unregister_event_callback(jtag_enable_callback, target);
 
-       target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
-
-       int retval = target_examine_one(target);
-       if (retval != ERROR_OK)
-               return retval;
-
-       target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
-
-       return retval;
+       return target_examine_one(target);
 }
 
 /* Targets that correctly implement init + examine, i.e.
@@ -726,13 +729,9 @@ int target_examine(void)
                        continue;
                }
 
-               target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
-
                retval = target_examine_one(target);
                if (retval != ERROR_OK)
                        return retval;
-
-               target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
        }
        return retval;
 }
@@ -940,7 +939,7 @@ int target_run_flash_async_algorithm(struct target *target,
                        break;
                }
 
-               if ((rp & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) {
+               if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) {
                        LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp);
                        break;
                }
@@ -1023,6 +1022,10 @@ int target_read_memory(struct target *target,
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
+       if (!target->type->read_memory) {
+               LOG_ERROR("Target %s doesn't support read_memory", target_name(target));
+               return ERROR_FAIL;
+       }
        return target->type->read_memory(target, address, size, count, buffer);
 }
 
@@ -1033,6 +1036,10 @@ int target_read_phys_memory(struct target *target,
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
+       if (!target->type->read_phys_memory) {
+               LOG_ERROR("Target %s doesn't support read_phys_memory", target_name(target));
+               return ERROR_FAIL;
+       }
        return target->type->read_phys_memory(target, address, size, count, buffer);
 }
 
@@ -1043,6 +1050,10 @@ int target_write_memory(struct target *target,
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
+       if (!target->type->write_memory) {
+               LOG_ERROR("Target %s doesn't support write_memory", target_name(target));
+               return ERROR_FAIL;
+       }
        return target->type->write_memory(target, address, size, count, buffer);
 }
 
@@ -1053,6 +1064,10 @@ int target_write_phys_memory(struct target *target,
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
+       if (!target->type->write_phys_memory) {
+               LOG_ERROR("Target %s doesn't support write_phys_memory", target_name(target));
+               return ERROR_FAIL;
+       }
        return target->type->write_phys_memory(target, address, size, count, buffer);
 }
 
@@ -1174,20 +1189,6 @@ static void target_reset_examined(struct target *target)
        target->examined = false;
 }
 
-static int err_read_phys_memory(struct target *target, uint32_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
-{
-       LOG_ERROR("Not implemented: %s", __func__);
-       return ERROR_FAIL;
-}
-
-static int err_write_phys_memory(struct target *target, uint32_t address,
-               uint32_t size, uint32_t count, const uint8_t *buffer)
-{
-       LOG_ERROR("Not implemented: %s", __func__);
-       return ERROR_FAIL;
-}
-
 static int handle_target(void *priv);
 
 static int target_init_one(struct command_context *cmd_ctx,
@@ -1214,16 +1215,6 @@ static int target_init_one(struct command_context *cmd_ctx,
         * implement it in stages, but warn if we need to do so.
         */
        if (type->mmu) {
-               if (type->write_phys_memory == NULL) {
-                       LOG_ERROR("type '%s' is missing write_phys_memory",
-                                       type->name);
-                       type->write_phys_memory = err_write_phys_memory;
-               }
-               if (type->read_phys_memory == NULL) {
-                       LOG_ERROR("type '%s' is missing read_phys_memory",
-                                       type->name);
-                       type->read_phys_memory = err_read_phys_memory;
-               }
                if (type->virt2phys == NULL) {
                        LOG_ERROR("type '%s' is missing virt2phys", type->name);
                        type->virt2phys = identity_virt2phys;
@@ -1360,6 +1351,28 @@ int target_register_reset_callback(int (*callback)(struct target *target,
        return ERROR_OK;
 }
 
+int target_register_trace_callback(int (*callback)(struct target *target,
+               size_t len, uint8_t *data, void *priv), void *priv)
+{
+       struct target_trace_callback *entry;
+
+       if (callback == NULL)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       entry = malloc(sizeof(struct target_trace_callback));
+       if (entry == NULL) {
+               LOG_ERROR("error allocating buffer for trace callback entry");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       entry->callback = callback;
+       entry->priv = priv;
+       list_add(&entry->list, &target_trace_callback_list);
+
+
+       return ERROR_OK;
+}
+
 int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
 {
        struct target_timer_callback **callbacks_p = &target_timer_callbacks;
@@ -1378,6 +1391,7 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int
        (*callbacks_p)->callback = callback;
        (*callbacks_p)->periodic = periodic;
        (*callbacks_p)->time_ms = time_ms;
+       (*callbacks_p)->removed = false;
 
        gettimeofday(&now, NULL);
        (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
@@ -1436,26 +1450,39 @@ int target_unregister_reset_callback(int (*callback)(struct target *target,
        return ERROR_OK;
 }
 
-int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+int target_unregister_trace_callback(int (*callback)(struct target *target,
+               size_t len, uint8_t *data, void *priv), void *priv)
 {
-       struct target_timer_callback **p = &target_timer_callbacks;
-       struct target_timer_callback *c = target_timer_callbacks;
+       struct target_trace_callback *entry;
 
        if (callback == NULL)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       while (c) {
-               struct target_timer_callback *next = c->next;
+       list_for_each_entry(entry, &target_trace_callback_list, list) {
+               if (entry->callback == callback && entry->priv == priv) {
+                       list_del(&entry->list);
+                       free(entry);
+                       break;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+{
+       if (callback == NULL)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       for (struct target_timer_callback *c = target_timer_callbacks;
+            c; c = c->next) {
                if ((c->callback == callback) && (c->priv == priv)) {
-                       *p = next;
-                       free(c);
+                       c->removed = true;
                        return ERROR_OK;
-               } else
-                       p = &(c->next);
-               c = next;
+               }
        }
 
-       return ERROR_OK;
+       return ERROR_FAIL;
 }
 
 int target_call_event_callbacks(struct target *target, enum target_event event)
@@ -1495,6 +1522,16 @@ int target_call_reset_callbacks(struct target *target, enum target_reset_mode re
        return ERROR_OK;
 }
 
+int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data)
+{
+       struct target_trace_callback *callback;
+
+       list_for_each_entry(callback, &target_trace_callback_list, list)
+               callback->callback(target, len, data, callback->priv);
+
+       return ERROR_OK;
+}
+
 static int target_timer_callback_periodic_restart(
                struct target_timer_callback *cb, struct timeval *now)
 {
@@ -1522,31 +1559,44 @@ static int target_call_timer_callback(struct target_timer_callback *cb,
 
 static int target_call_timer_callbacks_check_time(int checktime)
 {
+       static bool callback_processing;
+
+       /* Do not allow nesting */
+       if (callback_processing)
+               return ERROR_OK;
+
+       callback_processing = true;
+
        keep_alive();
 
        struct timeval now;
        gettimeofday(&now, NULL);
 
-       struct target_timer_callback *callback = target_timer_callbacks;
-       while (callback) {
-               /* cleaning up may unregister and free this callback */
-               struct target_timer_callback *next_callback = callback->next;
+       /* Store an address of the place containing a pointer to the
+        * next item; initially, that's a standalone "root of the
+        * list" variable. */
+       struct target_timer_callback **callback = &target_timer_callbacks;
+       while (*callback) {
+               if ((*callback)->removed) {
+                       struct target_timer_callback *p = *callback;
+                       *callback = (*callback)->next;
+                       free(p);
+                       continue;
+               }
 
-               bool call_it = callback->callback &&
-                       ((!checktime && callback->periodic) ||
-                         now.tv_sec > callback->when.tv_sec ||
-                        (now.tv_sec == callback->when.tv_sec &&
-                         now.tv_usec >= callback->when.tv_usec));
+               bool call_it = (*callback)->callback &&
+                       ((!checktime && (*callback)->periodic) ||
+                        now.tv_sec > (*callback)->when.tv_sec ||
+                        (now.tv_sec == (*callback)->when.tv_sec &&
+                         now.tv_usec >= (*callback)->when.tv_usec));
 
-               if (call_it) {
-                       int retval = target_call_timer_callback(callback, &now);
-                       if (retval != ERROR_OK)
-                               return retval;
-               }
+               if (call_it)
+                       target_call_timer_callback(*callback, &now);
 
-               callback = next_callback;
+               callback = &(*callback)->next;
        }
 
+       callback_processing = false;
        return ERROR_OK;
 }
 
@@ -1796,6 +1846,31 @@ int target_free_working_area(struct target *target, struct working_area *area)
        return target_free_working_area_restore(target, area, 1);
 }
 
+void target_quit(void)
+{
+       struct target_event_callback *pe = target_event_callbacks;
+       while (pe) {
+               struct target_event_callback *t = pe->next;
+               free(pe);
+               pe = t;
+       }
+       target_event_callbacks = NULL;
+
+       struct target_timer_callback *pt = target_timer_callbacks;
+       while (pt) {
+               struct target_timer_callback *t = pt->next;
+               free(pt);
+               pt = t;
+       }
+       target_timer_callbacks = NULL;
+
+       for (struct target *target = all_targets;
+            target; target = target->next) {
+               if (target->type->deinit_target)
+                       target->type->deinit_target(target);
+       }
+}
+
 /* free resources and restore memory, if restoring memory fails,
  * free up resources anyway
  */
@@ -1855,7 +1930,8 @@ int target_arch_state(struct target *target)
                return ERROR_OK;
        }
 
-       LOG_USER("target state: %s", target_state_name(target));
+       LOG_USER("%s: target state: %s", target_name(target),
+                target_state_name(target));
 
        if (target->state != TARGET_HALTED)
                return ERROR_OK;
@@ -2491,29 +2567,27 @@ static int handle_target(void *priv)
                                        target->backoff.times *= 2;
                                        target->backoff.times++;
                                }
-                               LOG_USER("Polling target %s failed, GDB will be halted. Polling again in %dms",
-                                               target_name(target),
-                                               target->backoff.times * polling_interval);
 
                                /* Tell GDB to halt the debugger. This allows the user to
                                 * run monitor commands to handle the situation.
                                 */
                                target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
-                               return retval;
                        }
-                       /* Since we succeeded, we reset backoff count */
                        if (target->backoff.times > 0) {
-                               LOG_USER("Polling target %s succeeded again, trying to reexamine", target_name(target));
+                               LOG_USER("Polling target %s failed, trying to reexamine", target_name(target));
                                target_reset_examined(target);
                                retval = target_examine_one(target);
                                /* Target examination could have failed due to unstable connection,
                                 * but we set the examined flag anyway to repoll it later */
                                if (retval != ERROR_OK) {
                                        target->examined = true;
+                                       LOG_USER("Examination failed, GDB will be halted. Polling again in %dms",
+                                                target->backoff.times * polling_interval);
                                        return retval;
                                }
                        }
 
+                       /* Since we succeeded, we reset backoff count */
                        target->backoff.times = 0;
                }
        }
@@ -3145,7 +3219,7 @@ COMMAND_HANDLER(handle_load_image_command)
 
 COMMAND_HANDLER(handle_dump_image_command)
 {
-       struct fileio fileio;
+       struct fileio *fileio;
        uint8_t *buffer;
        int retval, retvaltemp;
        uint32_t address, size;
@@ -3178,7 +3252,7 @@ COMMAND_HANDLER(handle_dump_image_command)
                if (retval != ERROR_OK)
                        break;
 
-               retval = fileio_write(&fileio, this_run_size, buffer, &size_written);
+               retval = fileio_write(fileio, this_run_size, buffer, &size_written);
                if (retval != ERROR_OK)
                        break;
 
@@ -3189,16 +3263,16 @@ COMMAND_HANDLER(handle_dump_image_command)
        free(buffer);
 
        if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
-               int filesize;
-               retval = fileio_size(&fileio, &filesize);
+               size_t filesize;
+               retval = fileio_size(fileio, &filesize);
                if (retval != ERROR_OK)
                        return retval;
                command_print(CMD_CTX,
-                               "dumped %ld bytes in %fs (%0.3f KiB/s)", (long)filesize,
+                               "dumped %zu bytes in %fs (%0.3f KiB/s)", filesize,
                                duration_elapsed(&bench), duration_kbps(&bench, filesize));
        }
 
-       retvaltemp = fileio_close(&fileio);
+       retvaltemp = fileio_close(fileio);
        if (retvaltemp != ERROR_OK)
                return retvaltemp;
 
@@ -4844,10 +4918,7 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        struct target *target = Jim_CmdPrivData(goi.interp);
        if (!target->tap->enabled)
                return jim_target_tap_disabled(interp);
-       if (!(target_was_examined(target))) {
-               LOG_ERROR("Target not examined yet");
-               return ERROR_TARGET_NOT_EXAMINED;
-       }
+
        if (!target->type->assert_reset || !target->type->deassert_reset) {
                Jim_SetResultFormatted(interp,
                                "No target-specific reset for %s",
@@ -5110,7 +5181,6 @@ static int target_create(Jim_GetOptInfo *goi)
        Jim_Obj *new_cmd;
        Jim_Cmd *cmd;
        const char *cp;
-       char *cp2;
        int e;
        int x;
        struct target *target;
@@ -5135,10 +5205,9 @@ static int target_create(Jim_GetOptInfo *goi)
        }
 
        /* TYPE */
-       e = Jim_GetOpt_String(goi, &cp2, NULL);
+       e = Jim_GetOpt_String(goi, &cp, NULL);
        if (e != JIM_OK)
                return e;
-       cp = cp2;
        struct transport *tr = get_current_transport();
        if (tr->override_target) {
                e = tr->override_target(&cp);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)