+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
/***************************************************************************
* Copyright (C) 2018 by Liviu Ionescu *
* <ilg@livius.net> *
* *
* Copyright (C) 2016 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> *
- * *
- * 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, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
static int semihosting_common_fileio_end(struct target *target, int result,
int fileio_errno, bool ctrl_c);
-static int semihosting_read_fields(struct target *target, size_t number,
- uint8_t *fields);
-static int semihosting_write_fields(struct target *target, size_t number,
- uint8_t *fields);
-static uint64_t semihosting_get_field(struct target *target, size_t index,
- uint8_t *fields);
-static void semihosting_set_field(struct target *target, uint64_t value,
- size_t index,
- uint8_t *fields);
-
/* Attempts to include gdb_server.h failed. */
extern int gdb_actual_connections;
semihosting->result = -1;
semihosting->sys_errno = -1;
semihosting->cmdline = NULL;
+ semihosting->basedir = NULL;
/* If possible, update it in setup(). */
semihosting->setup_time = clock();
semihosting->setup = setup;
semihosting->post_result = post_result;
+ semihosting->user_command_extension = NULL;
target->semihosting = semihosting;
semihosting->sys_errno = EINVAL;
break;
}
- uint8_t *fn = malloc(len+1);
+ size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0;
+ uint8_t *fn = malloc(basedir_len + len + 2);
if (!fn) {
semihosting->result = -1;
semihosting->sys_errno = ENOMEM;
} else {
- retval = target_read_memory(target, addr, 1, len, fn);
+ if (basedir_len > 0) {
+ strcpy((char *)fn, semihosting->basedir);
+ if (fn[basedir_len - 1] != '/')
+ fn[basedir_len++] = '/';
+ }
+ retval = target_read_memory(target, addr, 1, len, fn + basedir_len);
if (retval != ERROR_OK) {
free(fn);
return retval;
}
- fn[len] = 0;
+ fn[basedir_len + len] = 0;
/* TODO: implement the :semihosting-features special file.
* */
if (semihosting->is_fileio) {
* Return
* On exit, the RETURN REGISTER contains the return status.
*/
- {
- assert(!semihosting_user_op_params);
+ if (semihosting->user_command_extension) {
+ retval = semihosting->user_command_extension(target);
+ if (retval != ERROR_NOT_IMPLEMENTED)
+ break;
+ /* If custom user command not handled, we are looking for the TCL handler */
+ }
+ assert(!semihosting_user_op_params);
retval = semihosting_read_fields(target, 2, fields);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read fields for user defined command"
target_handle_event(target, semihosting->op);
free(semihosting_user_op_params);
semihosting_user_op_params = NULL;
-
semihosting->result = 0;
break;
- }
-
case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
/*
*/
switch (semihosting->op) {
case SEMIHOSTING_SYS_WRITE: /* 0x05 */
+ case SEMIHOSTING_SYS_READ: /* 0x06 */
if (result < 0)
- semihosting->result = fileio_info->param_3;
+ semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */
else
- semihosting->result = 0;
- break;
-
- case SEMIHOSTING_SYS_READ: /* 0x06 */
- if (result == (int)fileio_info->param_3)
- semihosting->result = 0;
- if (result <= 0)
- semihosting->result = fileio_info->param_3;
+ semihosting->result = (int64_t)fileio_info->param_3 - result;
break;
case SEMIHOSTING_SYS_SEEK: /* 0x0a */
return semihosting->post_result(target);
}
+/* -------------------------------------------------------------------------
+ * Utility functions. */
+
/**
* Read all fields of a command from target to buffer.
*/
-static int semihosting_read_fields(struct target *target, size_t number,
+int semihosting_read_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
/**
* Write all fields of a command from buffer to target.
*/
-static int semihosting_write_fields(struct target *target, size_t number,
+int semihosting_write_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
/**
* Extract a field from the buffer, considering register size and endianness.
*/
-static uint64_t semihosting_get_field(struct target *target, size_t index,
+uint64_t semihosting_get_field(struct target *target, size_t index,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
/**
* Store a field in the buffer, considering register size and endianness.
*/
-static void semihosting_set_field(struct target *target, uint64_t value,
+void semihosting_set_field(struct target *target, uint64_t value,
size_t index,
uint8_t *fields)
{
{
struct target *target = get_current_target(CMD_CTX);
- if (target == NULL) {
+ if (!target) {
LOG_ERROR("No target selected");
return ERROR_FAIL;
}
return ERROR_OK;
}
+COMMAND_HANDLER(handle_common_semihosting_basedir_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+
+ if (CMD_ARGC > 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (!target) {
+ LOG_ERROR("No target selected");
+ return ERROR_FAIL;
+ }
+
+ struct semihosting *semihosting = target->semihosting;
+ if (!semihosting) {
+ command_print(CMD, "semihosting not supported for current target");
+ return ERROR_FAIL;
+ }
+
+ if (!semihosting->is_active) {
+ command_print(CMD, "semihosting not yet enabled for current target");
+ return ERROR_FAIL;
+ }
+
+ if (CMD_ARGC > 0) {
+ free(semihosting->basedir);
+ semihosting->basedir = strdup(CMD_ARGV[0]);
+ if (!semihosting->basedir) {
+ command_print(CMD, "semihosting failed to allocate memory for basedir!");
+ return ERROR_FAIL;
+ }
+ }
+
+ command_print(CMD, "semihosting base dir: %s",
+ semihosting->basedir ? semihosting->basedir : "");
+
+ return ERROR_OK;
+}
+
const struct command_registration semihosting_common_handlers[] = {
{
.name = "semihosting",
.usage = "",
.help = "read parameters in semihosting-user-cmd-0x10X callbacks",
},
+ {
+ .name = "semihosting_basedir",
+ .handler = handle_common_semihosting_basedir_command,
+ .mode = COMMAND_EXEC,
+ .usage = "[dir]",
+ .help = "set the base directory for semihosting I/O operations",
+ },
COMMAND_REGISTRATION_DONE
};