This is an automated email from Gerrit. Alamy Liu ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/3294
-- gerrit commit ec4d3e6f0cc219aab3dcdfbc4bab8c70ce274e02 Author: Alamy Liu <[email protected]> Date: Fri Aug 21 13:18:28 2015 -0700 64-bit: add target64.c for 64-bit functions Change-Id: Ibb5cc9fad948eefd5a0bfe727caca19ab4eed44e Signed-off-by: Alamy Liu <[email protected]> diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 65d92f6..cf9a309 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -86,6 +86,7 @@ ARMV7_SRC = \ cortex_a.c ARMV8_SRC = \ + target64.c \ aarch64.c \ armv8.c diff --git a/src/target/target64.c b/src/target/target64.c new file mode 100644 index 0000000..fbc5768 --- /dev/null +++ b/src/target/target64.c @@ -0,0 +1,660 @@ +/*************************************************************************** + * Copyright (C) 2015 by Alamy Liu * + * [email protected] * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <flash/common.h> +#include <helper/time_support.h> +#include <helper/binarybuffer.h> + +#include "register.h" + +#include "target.h" +#include "target_type.h" +#include "target_type64.h" +//#include "target_request.h" +//#include "breakpoints.h" + + +/* 64-bit targets */ +extern struct target_type_64 aarch64_target; + +static struct target_type_64 *target_types_64[] = { + &aarch64_target, + NULL, +}; + +/** + * Executes a target-specific native code algorithm in the target. + * It differs from target_run_algorithm in that the algorithm is asynchronous. + * Because of this it requires an compliant algorithm: + * see contrib/loaders/flash/stm32f1x.S for example. + * + * @param target used to run the algorithm + */ + +int target_run_flash_async_algorithm_64(struct target *target, + const uint8_t *buffer, uint32_t count, int block_size, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uintmax_t buffer_start, uintmax_t buffer_size, + uintmax_t entry_point, uintmax_t exit_point, void *arch_info) +{ + int retval; + int timeout = 0; + + const uint8_t *buffer_orig = buffer; + + /* Set up working area. First word is write pointer, second word is read pointer, + * rest is fifo data area. */ + uintmax_t wp_addr = buffer_start; + uintmax_t rp_addr = buffer_start + 4; /* Alamy: 4/8 ? */ + uintmax_t fifo_start_addr = buffer_start + 8; /* Alamy: ? */ + uintmax_t fifo_end_addr = buffer_start + buffer_size; + + uintmax_t wp = fifo_start_addr; + uintmax_t rp = fifo_start_addr; + + /* validate block_size is 2^n */ + assert(!block_size || !(block_size & (block_size - 1))); + + retval = target_write_u32(target, wp_addr, wp); /* Alamy: write_u64 ? */ + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, rp_addr, rp); /* Alamy: write_u64 ? */ + if (retval != ERROR_OK) + return retval; + + /* Start up algorithm on target and let it idle while writing the first chunk */ + retval = target_start_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, + exit_point, + arch_info); + + if (retval != ERROR_OK) { + LOG_ERROR("error starting target flash write algorithm"); + return retval; + } + + while (count > 0) { + + retval = target_read_u64(target, rp_addr, &rp); + if (retval != ERROR_OK) { + LOG_ERROR("failed to get read pointer"); + break; + } + + LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%.*" PRIXMAX " rp 0x%.*" PRIXMAX, + (size_t) (buffer - buffer_orig), count, + addr_fmt_width(target), wp, + addr_fmt_width(target), rp); + + if (rp == 0) { + LOG_ERROR("flash write algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { + LOG_ERROR("corrupted fifo read pointer 0x%.*" PRIXMAX, + addr_fmt_width(target), rp); + break; + } + + /* Count the number of bytes available in the fifo without + * crossing the wrap around. Make sure to not fill it completely, + * because that would make wp == rp and that's the empty condition. */ + uint32_t thisrun_bytes; + if (rp > wp) + thisrun_bytes = rp - wp - block_size; + else if (rp > fifo_start_addr) + thisrun_bytes = fifo_end_addr - wp; + else + thisrun_bytes = fifo_end_addr - wp - block_size; + + if (thisrun_bytes == 0) { + /* Throttle polling a bit if transfer is (much) faster than flash + * programming. The exact delay shouldn't matter as long as it's + * less than buffer size / flash speed. This is very unlikely to + * run when using high latency connections such as USB. */ + alive_sleep(10); + + /* to stop an infinite loop on some targets check and increment a timeout + * this issue was observed on a stellaris using the new ICDI interface */ + if (timeout++ >= 500) { + LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); + return ERROR_FLASH_OPERATION_FAILED; + } + continue; + } + + /* reset our timeout */ + timeout = 0; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_bytes > count * block_size) + thisrun_bytes = count * block_size; + + /* Write data to fifo */ + retval = target_write_buffer(target, wp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / block_size; + wp += thisrun_bytes; + if (wp >= fifo_end_addr) + wp = fifo_start_addr; + + /* Store updated write pointer to target */ + retval = target_write_u64(target, wp_addr, wp); + if (retval != ERROR_OK) + break; + } + + if (retval != ERROR_OK) { + /* abort flash write algorithm on target */ + target_write_u64(target, wp_addr, 0); + } + + int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, + 10000, + arch_info); + + if (retval2 != ERROR_OK) { + LOG_ERROR("error waiting for target flash write algorithm"); + retval = retval2; + } + + return retval; +} + + +static int default_examine_64(struct target *target) +{ + target_set_examined(target); + return ERROR_OK; +} + +/* no check by default */ +static int default_check_reset_64(struct target *target) +{ + return ERROR_OK; +} + +static int identity_virt2phys_64(struct target *target, + uint64_t virtual, uint64_t *physical) +{ + *physical = virtual; + return ERROR_OK; +} + +static int no_mmu_64(struct target *target, int *enabled) +{ + *enabled = 0; + return ERROR_OK; +} + +static int target_read_buffer_default_64( + struct target *target, + uint64_t address, + uint32_t count, + uint8_t *buffer) +{ + uint32_t size; + + /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + * will have something to do with the size we leave to it. */ + for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + if (address & size) { + int retval = target_read_memory(target, address, size, 1, buffer); + if (retval != ERROR_OK) + return retval; + address += size; + count -= size; + buffer += size; + } + } + + /* Read the data with as large access size as possible. */ + for (; size > 0; size /= 2) { + uint32_t aligned = count - count % size; + if (aligned > 0) { + int retval = target_read_memory(target, address, size, aligned / size, buffer); + if (retval != ERROR_OK) + return retval; + address += aligned; + count -= aligned; + buffer += aligned; + } + } + + return ERROR_OK; +} + +static int target_write_buffer_default_64( + struct target *target, + uint64_t address, + uint32_t count, + const uint8_t *buffer) +{ + uint32_t size; + + /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + * will have something to do with the size we leave to it. */ + for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + if (address & size) { + int retval = target_write_memory(target, address, size, 1, buffer); + if (retval != ERROR_OK) + return retval; + address += size; + count -= size; + buffer += size; + } + } + + /* Write the data with as large access size as possible. */ + for (; size > 0; size /= 2) { + uint32_t aligned = count - count % size; + if (aligned > 0) { + int retval = target_write_memory(target, address, size, aligned / size, buffer); + if (retval != ERROR_OK) + return retval; + address += aligned; + count -= aligned; + buffer += aligned; + } + } + + return ERROR_OK; +} + +static int target_get_gdb_fileio_info_default_64(struct target *target, + struct gdb_fileio_info *fileio_info) +{ + /* If target does not support semi-hosting function, target + has no need to provide .get_gdb_fileio_info callback. + It just return ERROR_FAIL and gdb_server will return "Txx" + as target halted every time. */ + return ERROR_FAIL; +} + +static int target_gdb_fileio_end_default_64(struct target *target, + int retcode, int fileio_errno, bool ctrl_c) +{ + return ERROR_OK; +} + +static int target_profiling_default_64(struct target *target, uint64_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +{ + struct timeval timeout, now; + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + LOG_INFO("Starting profiling. Halting and resuming the" + " target as often as we can..."); + + uint32_t sample_count = 0; + /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ + struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1); /* ERROR */ + + int retval = ERROR_OK; + for (;;) { + target_poll(target); + if (target->state == TARGET_HALTED) { + uint32_t t = buf_get_u32(reg->value, 0, 32); /* ERROR */ + samples[sample_count++] = t; + /* current pc, addr = 0, do not handle breakpoints, not debugging */ + retval = target_resume(target, 1, 0, 0, 0); + target_poll(target); + alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ + } else if (target->state == TARGET_RUNNING) { + /* We want to quickly sample the PC. */ + retval = target_halt(target); + } else { + LOG_INFO("Target not halted or running"); + retval = ERROR_OK; + break; + } + + if (retval != ERROR_OK) + break; + + gettimeofday(&now, NULL); + if ((sample_count >= max_num_samples) || + ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { + LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); + break; + } + } + + *num_samples = sample_count; + return retval; +} + +/* Duplicated from target.c */ +static inline void target_reset_examined(struct target *target) +{ + target->examined = false; +} + +#if 0 +static int target_create_64(Jim_GetOptInfo *goi) +{ + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + char *cp2; + int e; + int x; + struct target *target; + struct command_context *cmd_ctx; + + cmd_ctx = current_command_context(goi->interp); + assert(cmd_ctx != NULL); + + if (goi->argc < 3) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); + return JIM_ERR; + } + + /* COMMAND */ + Jim_GetOpt_Obj(goi, &new_cmd); + /* does this command exist? */ + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + if (cmd) { + cp = Jim_GetString(new_cmd, NULL); + Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); + return JIM_ERR; + } + + /* TYPE */ + e = Jim_GetOpt_String(goi, &cp2, NULL); + if (e != JIM_OK) + return e; + cp = cp2; + struct transport *tr = get_current_transport(); + if (tr->override_target) { + e = tr->override_target(&cp); + if (e != ERROR_OK) { + LOG_ERROR("The selected transport doesn't support this target"); + return JIM_ERR; + } + LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); + } + /* now does target type exist */ + for (x = 0 ; target_types[x] ; x++) { + if (0 == strcmp(cp, target_types[x]->name)) { + /* found */ + break; + } + + /* check for deprecated name */ + if (target_types[x]->deprecated_name) { + if (0 == strcmp(cp, target_types[x]->deprecated_name)) { + /* found */ + LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name); + break; + } + } + } + if (target_types[x] == NULL) { + Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); + for (x = 0 ; target_types[x] ; x++) { + if (target_types[x + 1]) { + Jim_AppendStrings(goi->interp, + Jim_GetResult(goi->interp), + target_types[x]->name, + ", ", NULL); + } else { + Jim_AppendStrings(goi->interp, + Jim_GetResult(goi->interp), + " or ", + target_types[x]->name, NULL); + } + } + return JIM_ERR; + } + + /* Create it */ + target = calloc(1, sizeof(struct target)); + /* set target number */ + target->target_number = new_target_number(); + cmd_ctx->current_target = target->target_number; + + /* allocate memory for each unique target type */ + target->type = calloc(1, sizeof(struct target_type)); + /* target->type64 = calloc(1, sizeof(struct target_type64)); */ /* Alamy */ + + memcpy(target->type, target_types[x], sizeof(struct target_type)); + + /* will be set by "-endian" */ + target->endianness = TARGET_ENDIAN_UNKNOWN; + + /* default to first core, override with -coreid */ + target->coreid = 0; + + target->working_area = 0x0; + target->working_area_size = 0x0; + target->working_areas = NULL; + target->backup_working_area = 0; + + target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; + target->reg_cache = NULL; + target->breakpoints = NULL; + target->watchpoints = NULL; + target->next = NULL; + target->arch_info = NULL; + + target->display = 1; + + target->halt_issued = false; + + /* initialize trace information */ + target->trace_info = malloc(sizeof(struct trace)); + target->trace_info->num_trace_points = 0; + target->trace_info->trace_points_size = 0; + target->trace_info->trace_points = NULL; + target->trace_info->trace_history_size = 0; + target->trace_info->trace_history = NULL; + target->trace_info->trace_history_pos = 0; + target->trace_info->trace_history_overflowed = 0; + + target->dbgmsg = NULL; + target->dbg_msg_enabled = 0; + + target->endianness = TARGET_ENDIAN_UNKNOWN; + + target->rtos = NULL; + target->rtos_auto_detect = false; + + /* Do the rest as "configure" options */ + goi->isconfigure = 1; + e = target_configure(goi, target); + + if (target->tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); + e = JIM_ERR; + } + + if (e != JIM_OK) { + free(target->type); + free(target); + return e; + } + + if (target->endianness == TARGET_ENDIAN_UNKNOWN) { + /* default endian to little if not specified */ + target->endianness = TARGET_LITTLE_ENDIAN; + } + + cp = Jim_GetString(new_cmd, NULL); + target->cmd_name = strdup(cp); + + /* create the target specific commands */ + if (target->type->commands) { + e = register_commands(cmd_ctx, NULL, target->type->commands); + if (ERROR_OK != e) + LOG_ERROR("unable to register '%s' commands", cp); + } + if (target->type->target_create) + (*(target->type->target_create))(target, goi->interp); + + /* append to end of list */ + { + struct target **tpp; + tpp = &(all_targets); + while (*tpp) + tpp = &((*tpp)->next); + *tpp = target; + } + + /* now - create the new target name command */ + const struct command_registration target_subcommands[] = { + { + .chain = target_instance_command_handlers, + }, + { + .chain = target->type->commands, + }, + COMMAND_REGISTRATION_DONE + }; + const struct command_registration target_commands[] = { + { + .name = cp, + .mode = COMMAND_ANY, + .help = "target command group", + .usage = "", + .chain = target_subcommands, + }, + COMMAND_REGISTRATION_DONE + }; + e = register_commands(cmd_ctx, NULL, target_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, cp); + assert(c); + command_set_handler_data(c, target); + + return (ERROR_OK == e) ? JIM_OK : JIM_ERR; +} +#endif + +int target_init_one_64( + struct command_context *cmd_ctx, + struct target *target) +{ + target_reset_examined(target); + + struct target_type_64 *type64 = target->type64; + if (type64->examine == NULL) + type64->examine = default_examine_64; + + if (type64->check_reset == NULL) + type64->check_reset = default_check_reset_64; + + assert(type64->init_target != NULL); + + int retval = type64->init_target(cmd_ctx, target); + if (ERROR_OK != retval) { + LOG_ERROR("target '%s' init failed", target_name(target)); + return retval; + } + + /* Sanity-check MMU support ... stub in what we must, to help + * implement it in stages, but warn if we need to do so. + */ + if (type64->mmu) { + if (type64->virt2phys == NULL) { + LOG_ERROR("type '%s' is missing virt2phys", type64->name); + type64->virt2phys = identity_virt2phys_64; + } + } else { + /* Make sure no-MMU targets all behave the same: make no + * distinction between physical and virtual addresses, and + * ensure that virt2phys() is always an identity mapping. + */ + if (type64->write_phys_memory || type64->read_phys_memory || type64->virt2phys) + LOG_WARNING("type '%s' has bad MMU hooks", type64->name); + + type64->mmu = no_mmu_64; + type64->write_phys_memory = type64->write_memory; + type64->read_phys_memory = type64->read_memory; + type64->virt2phys = identity_virt2phys_64; + } + + if (type64->read_buffer == NULL) + type64->read_buffer = target_read_buffer_default_64; + + if (type64->write_buffer == NULL) + type64->write_buffer = target_write_buffer_default_64; + + if (type64->get_gdb_fileio_info == NULL) + type64->get_gdb_fileio_info = target_get_gdb_fileio_info_default_64; + + if (type64->gdb_fileio_end == NULL) + type64->gdb_fileio_end = target_gdb_fileio_end_default_64; + + if (type64->profiling == NULL) + type64->profiling = target_profiling_default_64; + + return ERROR_OK; +} + +/* Looking for target in 64-bit target type table */ +struct target_type_64 *scan_target_type_64(Jim_GetOptInfo *goi, const char *cp) +{ + int i; + + for (i = 0; target_types_64[i]; i++) { + if (0 == strcmp(cp, target_types_64[i]->name)) + return target_types_64[i]; /* found */ + } + + /* Not found with target name */ + Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); + for (i = 0; target_types_64[i]; i++) { + if (target_types_64[i + 1]) { + Jim_AppendStrings(goi->interp, + Jim_GetResult(goi->interp), + target_types_64[i]->name, + ", ", NULL); + } else { + Jim_AppendStrings(goi->interp, + Jim_GetResult(goi->interp), + " or ", + target_types_64[i]->name, NULL); + } + } + + return NULL; +} + + -- ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
