gdb_server, target: Add target_address_bits()
[fw/openocd] / src / target / target.c
index bf3669192ea7dc92f65ed2848d89fcfde0b19b62..5295dd626815ee86dacb4698218014c0b8303168 100644 (file)
@@ -251,6 +251,7 @@ static const Jim_Nvp nvp_target_debug_reason[] = {
        { .name = "single-step"              , .value = DBG_REASON_SINGLESTEP },
        { .name = "target-not-halted"        , .value = DBG_REASON_NOTHALTED  },
        { .name = "program-exit"             , .value = DBG_REASON_EXIT },
+       { .name = "exception-catch"          , .value = DBG_REASON_EXC_CATCH },
        { .name = "undefined"                , .value = DBG_REASON_UNDEFINED },
        { .name = NULL, .value = -1 },
 };
@@ -517,9 +518,7 @@ struct target *get_target_by_num(int num)
 
 struct target *get_current_target(struct command_context *cmd_ctx)
 {
-       struct target *target = cmd_ctx->current_target_override
-               ? cmd_ctx->current_target_override
-               : cmd_ctx->current_target;
+       struct target *target = get_current_target_or_null(cmd_ctx);
 
        if (target == NULL) {
                LOG_ERROR("BUG: current_target out of bounds");
@@ -529,6 +528,13 @@ struct target *get_current_target(struct command_context *cmd_ctx)
        return target;
 }
 
+struct target *get_current_target_or_null(struct command_context *cmd_ctx)
+{
+       return cmd_ctx->current_target_override
+               ? cmd_ctx->current_target_override
+               : cmd_ctx->current_target;
+}
+
 int target_poll(struct target *target)
 {
        int retval;
@@ -1047,6 +1053,9 @@ int target_run_flash_async_algorithm(struct target *target,
                retval = target_write_u32(target, wp_addr, wp);
                if (retval != ERROR_OK)
                        break;
+
+               /* Avoid GDB timeouts */
+               keep_alive();
        }
 
        if (retval != ERROR_OK) {
@@ -1248,6 +1257,22 @@ int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno,
        return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c);
 }
 
+target_addr_t target_address_max(struct target *target)
+{
+       unsigned bits = target_address_bits(target);
+       if (sizeof(target_addr_t) * 8 == bits)
+               return (target_addr_t) -1;
+       else
+               return (((target_addr_t) 1) << bits) - 1;
+}
+
+unsigned target_address_bits(struct target *target)
+{
+       if (target->type->address_bits)
+               return target->type->address_bits(target);
+       return 32;
+}
+
 int target_profiling(struct target *target, uint32_t *samples,
                        uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
 {
@@ -1349,7 +1374,7 @@ static int target_init(struct command_context *cmd_ctx)
                return retval;
 
        retval = target_register_timer_callback(&handle_target,
-                       polling_interval, 1, cmd_ctx->interp);
+                       polling_interval, TARGET_TIMER_TYPE_PERIODIC, cmd_ctx->interp);
        if (ERROR_OK != retval)
                return retval;
 
@@ -1452,7 +1477,8 @@ int target_register_trace_callback(int (*callback)(struct target *target,
        return ERROR_OK;
 }
 
-int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
+int target_register_timer_callback(int (*callback)(void *priv),
+               unsigned int time_ms, enum target_timer_type type, void *priv)
 {
        struct target_timer_callback **callbacks_p = &target_timer_callbacks;
 
@@ -1467,7 +1493,7 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int
 
        (*callbacks_p) = malloc(sizeof(struct target_timer_callback));
        (*callbacks_p)->callback = callback;
-       (*callbacks_p)->periodic = periodic;
+       (*callbacks_p)->type = type;
        (*callbacks_p)->time_ms = time_ms;
        (*callbacks_p)->removed = false;
 
@@ -1617,7 +1643,7 @@ static int target_call_timer_callback(struct target_timer_callback *cb,
 {
        cb->callback(cb->priv);
 
-       if (cb->periodic)
+       if (cb->type == TARGET_TIMER_TYPE_PERIODIC)
                return target_timer_callback_periodic_restart(cb, now);
 
        return target_unregister_timer_callback(cb->callback, cb->priv);
@@ -1651,7 +1677,7 @@ static int target_call_timer_callbacks_check_time(int checktime)
                }
 
                bool call_it = (*callback)->callback &&
-                       ((!checktime && (*callback)->periodic) ||
+                       ((!checktime && (*callback)->type == TARGET_TIMER_TYPE_PERIODIC) ||
                         timeval_compare(&now, &(*callback)->when) >= 0);
 
                if (call_it)
@@ -1911,6 +1937,65 @@ int target_free_working_area(struct target *target, struct working_area *area)
        return target_free_working_area_restore(target, area, 1);
 }
 
+/* free resources and restore memory, if restoring memory fails,
+ * free up resources anyway
+ */
+static void target_free_all_working_areas_restore(struct target *target, int restore)
+{
+       struct working_area *c = target->working_areas;
+
+       LOG_DEBUG("freeing all working areas");
+
+       /* Loop through all areas, restoring the allocated ones and marking them as free */
+       while (c) {
+               if (!c->free) {
+                       if (restore)
+                               target_restore_working_area(target, c);
+                       c->free = true;
+                       *c->user = NULL; /* Same as above */
+                       c->user = NULL;
+               }
+               c = c->next;
+       }
+
+       /* Run a merge pass to combine all areas into one */
+       target_merge_working_areas(target);
+
+       print_wa_layout(target);
+}
+
+void target_free_all_working_areas(struct target *target)
+{
+       target_free_all_working_areas_restore(target, 1);
+
+       /* Now we have none or only one working area marked as free */
+       if (target->working_areas) {
+               /* Free the last one to allow on-the-fly moving and resizing */
+               free(target->working_areas->backup);
+               free(target->working_areas);
+               target->working_areas = NULL;
+       }
+}
+
+/* Find the largest number of bytes that can be allocated */
+uint32_t target_get_working_area_avail(struct target *target)
+{
+       struct working_area *c = target->working_areas;
+       uint32_t max_size = 0;
+
+       if (c == NULL)
+               return target->working_area_size;
+
+       while (c) {
+               if (c->free && max_size < c->size)
+                       max_size = c->size;
+
+               c = c->next;
+       }
+
+       return max_size;
+}
+
 static void target_destroy(struct target *target)
 {
        if (target->type->deinit_target)
@@ -1930,11 +2015,6 @@ static void target_destroy(struct target *target)
        }
 
        target_free_all_working_areas(target);
-       /* Now we have none or only one working area marked as free */
-       if (target->working_areas) {
-               free(target->working_areas->backup);
-               free(target->working_areas);
-       }
 
        /* release the targets SMP list */
        if (target->smp) {
@@ -1985,57 +2065,6 @@ void target_quit(void)
        all_targets = NULL;
 }
 
-/* free resources and restore memory, if restoring memory fails,
- * free up resources anyway
- */
-static void target_free_all_working_areas_restore(struct target *target, int restore)
-{
-       struct working_area *c = target->working_areas;
-
-       LOG_DEBUG("freeing all working areas");
-
-       /* Loop through all areas, restoring the allocated ones and marking them as free */
-       while (c) {
-               if (!c->free) {
-                       if (restore)
-                               target_restore_working_area(target, c);
-                       c->free = true;
-                       *c->user = NULL; /* Same as above */
-                       c->user = NULL;
-               }
-               c = c->next;
-       }
-
-       /* Run a merge pass to combine all areas into one */
-       target_merge_working_areas(target);
-
-       print_wa_layout(target);
-}
-
-void target_free_all_working_areas(struct target *target)
-{
-       target_free_all_working_areas_restore(target, 1);
-}
-
-/* Find the largest number of bytes that can be allocated */
-uint32_t target_get_working_area_avail(struct target *target)
-{
-       struct working_area *c = target->working_areas;
-       uint32_t max_size = 0;
-
-       if (c == NULL)
-               return target->working_area_size;
-
-       while (c) {
-               if (c->free && max_size < c->size)
-                       max_size = c->size;
-
-               c = c->next;
-       }
-
-       return max_size;
-}
-
 int target_arch_state(struct target *target)
 {
        int retval;
@@ -3708,38 +3737,31 @@ static int handle_bp_command_set(struct command_context *cmd_ctx,
 
        if (asid == 0) {
                retval = breakpoint_add(target, addr, length, hw);
+               /* error is always logged in breakpoint_add(), do not print it again */
                if (ERROR_OK == retval)
                        command_print(cmd_ctx, "breakpoint set at " TARGET_ADDR_FMT "", addr);
-               else {
-                       LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used");
-                       return retval;
-               }
+
        } else if (addr == 0) {
                if (target->type->add_context_breakpoint == NULL) {
-                       LOG_WARNING("Context breakpoint not available");
-                       return ERROR_OK;
+                       LOG_ERROR("Context breakpoint not available");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
                retval = context_breakpoint_add(target, asid, length, hw);
+               /* error is always logged in context_breakpoint_add(), do not print it again */
                if (ERROR_OK == retval)
                        command_print(cmd_ctx, "Context breakpoint set at 0x%8.8" PRIx32 "", asid);
-               else {
-                       LOG_ERROR("Failure setting breakpoint, the same address(CONTEXTID) is already used");
-                       return retval;
-               }
+
        } else {
                if (target->type->add_hybrid_breakpoint == NULL) {
-                       LOG_WARNING("Hybrid breakpoint not available");
-                       return ERROR_OK;
+                       LOG_ERROR("Hybrid breakpoint not available");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
                retval = hybrid_breakpoint_add(target, addr, asid, length, hw);
+               /* error is always logged in hybrid_breakpoint_add(), do not print it again */
                if (ERROR_OK == retval)
                        command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid);
-               else {
-                       LOG_ERROR("Failure setting breakpoint, the same address is already used");
-                       return retval;
-               }
        }
-       return ERROR_OK;
+       return retval;
 }
 
 COMMAND_HANDLER(handle_bp_command)
@@ -5871,8 +5893,7 @@ static const struct command_registration target_subcommand_handlers[] = {
        },
        {
                .name = "create",
-               /* REVISIT this should be COMMAND_CONFIG ... */
-               .mode = COMMAND_ANY,
+               .mode = COMMAND_CONFIG,
                .jim_handler = jim_target_create,
                .usage = "name type '-chain-position' name [options ...]",
                .help = "Creates and selects a new target",