target/xtensa: add file-IO support
- Manual integration of File-IO support from xt0.2 release - Verified with applications linked using gdbio LSP - No new clang static analysis warnings Signed-off-by: Ian Thompson <ianst@cadence.com> Change-Id: Iedc5f885b2548097ef4f11ae1a675b5944f5fdf0 Reviewed-on: https://review.openocd.org/c/openocd/+/7550 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
df12552b5b
commit
2dd34cbe0b
|
@ -8,4 +8,6 @@ noinst_LTLIBRARIES += %D%/libxtensa.la
|
|||
%D%/xtensa_chip.h \
|
||||
%D%/xtensa_debug_module.c \
|
||||
%D%/xtensa_debug_module.h \
|
||||
%D%/xtensa_fileio.c \
|
||||
%D%/xtensa_fileio.h \
|
||||
%D%/xtensa_regs.h
|
||||
|
|
|
@ -1544,6 +1544,7 @@ int xtensa_prepare_resume(struct target *target,
|
|||
LOG_TARGET_WARNING(target, "target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
xtensa->halt_request = false;
|
||||
|
||||
if (address && !current) {
|
||||
xtensa_reg_set(target, XT_REG_IDX_PC, address);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <target/arm_adi_v5.h>
|
||||
#include <rtos/rtos.h>
|
||||
#include "xtensa_chip.h"
|
||||
#include "xtensa_fileio.h"
|
||||
|
||||
int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
|
||||
struct xtensa_debug_module_config *dm_cfg)
|
||||
|
@ -30,7 +31,10 @@ int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
|
|||
|
||||
int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target)
|
||||
{
|
||||
return xtensa_target_init(cmd_ctx, target);
|
||||
int ret = xtensa_target_init(cmd_ctx, target);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
return xtensa_fileio_init(target);
|
||||
}
|
||||
|
||||
int xtensa_chip_arch_state(struct target *target)
|
||||
|
@ -45,10 +49,12 @@ static int xtensa_chip_poll(struct target *target)
|
|||
|
||||
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
|
||||
/*Call any event callbacks that are applicable */
|
||||
if (old_state == TARGET_DEBUG_RUNNING)
|
||||
if (old_state == TARGET_DEBUG_RUNNING) {
|
||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
||||
else
|
||||
} else {
|
||||
xtensa_fileio_detect_proc(target);
|
||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -193,4 +199,7 @@ struct target_type xtensa_chip_target = {
|
|||
.gdb_query_custom = xtensa_gdb_query_custom,
|
||||
|
||||
.commands = xtensa_command_handlers,
|
||||
|
||||
.get_gdb_fileio_info = xtensa_get_gdb_fileio_info,
|
||||
.gdb_fileio_end = xtensa_gdb_fileio_end,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Xtensa Target File-I/O Support for OpenOCD *
|
||||
* Copyright (C) 2020-2023 Cadence Design Systems, Inc. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "xtensa_chip.h"
|
||||
#include "xtensa_fileio.h"
|
||||
#include "xtensa.h"
|
||||
|
||||
#define XTENSA_SYSCALL(x) XT_INS_BREAK(x, 1, 14)
|
||||
#define XTENSA_SYSCALL_SZ 3
|
||||
#define XTENSA_SYSCALL_LEN_MAX 255
|
||||
|
||||
|
||||
int xtensa_fileio_init(struct target *target)
|
||||
{
|
||||
char *idmem = malloc(XTENSA_SYSCALL_LEN_MAX + 1);
|
||||
target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
|
||||
if (!idmem || !target->fileio_info) {
|
||||
LOG_TARGET_ERROR(target, "Out of memory!");
|
||||
free(idmem);
|
||||
free(target->fileio_info);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
target->fileio_info->identifier = idmem;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for and processes an Xtensa File-IO request.
|
||||
*
|
||||
* Return ERROR_OK if request was found and handled; or
|
||||
* return ERROR_FAIL if no request was detected.
|
||||
*/
|
||||
int xtensa_fileio_detect_proc(struct target *target)
|
||||
{
|
||||
struct xtensa *xtensa = target_to_xtensa(target);
|
||||
int retval;
|
||||
|
||||
xtensa_reg_val_t dbg_cause = xtensa_cause_get(target);
|
||||
if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0 || xtensa->halt_request)
|
||||
return ERROR_FAIL;
|
||||
|
||||
uint8_t brk_insn_buf[sizeof(uint32_t)] = {0};
|
||||
xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
|
||||
retval = target_read_memory(target,
|
||||
pc,
|
||||
XTENSA_SYSCALL_SZ,
|
||||
1,
|
||||
(uint8_t *)brk_insn_buf);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to read break instruction!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (buf_get_u32(brk_insn_buf, 0, 32) != XTENSA_SYSCALL(xtensa))
|
||||
return ERROR_FAIL;
|
||||
|
||||
LOG_TARGET_DEBUG(target, "File-I/O: syscall breakpoint found at 0x%x", pc);
|
||||
xtensa->proc_syscall = true;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
|
||||
{
|
||||
/* fill syscall parameters to file-I/O info */
|
||||
if (!fileio_info) {
|
||||
LOG_ERROR("File-I/O data structure uninitialized");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct xtensa *xtensa = target_to_xtensa(target);
|
||||
if (!xtensa->proc_syscall)
|
||||
return ERROR_FAIL;
|
||||
|
||||
xtensa_reg_val_t syscall = xtensa_reg_get(target, XTENSA_SYSCALL_OP_REG);
|
||||
xtensa_reg_val_t arg0 = xtensa_reg_get(target, XT_REG_IDX_A6);
|
||||
xtensa_reg_val_t arg1 = xtensa_reg_get(target, XT_REG_IDX_A3);
|
||||
xtensa_reg_val_t arg2 = xtensa_reg_get(target, XT_REG_IDX_A4);
|
||||
xtensa_reg_val_t arg3 = xtensa_reg_get(target, XT_REG_IDX_A5);
|
||||
int retval = ERROR_OK;
|
||||
|
||||
LOG_TARGET_DEBUG(target, "File-I/O: syscall 0x%x 0x%x 0x%x 0x%x 0x%x",
|
||||
syscall, arg0, arg1, arg2, arg3);
|
||||
|
||||
switch (syscall) {
|
||||
case XTENSA_SYSCALL_OPEN:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "open");
|
||||
fileio_info->param_1 = arg0; // pathp
|
||||
fileio_info->param_2 = arg3; // len
|
||||
fileio_info->param_3 = arg1; // flags
|
||||
fileio_info->param_4 = arg2; // mode
|
||||
break;
|
||||
case XTENSA_SYSCALL_CLOSE:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "close");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
break;
|
||||
case XTENSA_SYSCALL_READ:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "read");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
fileio_info->param_2 = arg1; // bufp
|
||||
fileio_info->param_3 = arg2; // count
|
||||
break;
|
||||
case XTENSA_SYSCALL_WRITE:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "write");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
fileio_info->param_2 = arg1; // bufp
|
||||
fileio_info->param_3 = arg2; // count
|
||||
break;
|
||||
case XTENSA_SYSCALL_LSEEK:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "lseek");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
fileio_info->param_2 = arg1; // offset
|
||||
fileio_info->param_3 = arg2; // flags
|
||||
break;
|
||||
case XTENSA_SYSCALL_RENAME:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "rename");
|
||||
fileio_info->param_1 = arg0; // old pathp
|
||||
fileio_info->param_2 = arg3; // old len
|
||||
fileio_info->param_3 = arg1; // new pathp
|
||||
fileio_info->param_4 = arg2; // new len
|
||||
break;
|
||||
case XTENSA_SYSCALL_UNLINK:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unlink");
|
||||
fileio_info->param_1 = arg0; // pathnamep
|
||||
fileio_info->param_2 = arg1; // len
|
||||
break;
|
||||
case XTENSA_SYSCALL_STAT:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "stat");
|
||||
fileio_info->param_1 = arg0; // pathnamep
|
||||
fileio_info->param_2 = arg2; // len
|
||||
fileio_info->param_3 = arg1; // bufp
|
||||
break;
|
||||
case XTENSA_SYSCALL_FSTAT:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "fstat");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
fileio_info->param_2 = arg1; // bufp
|
||||
break;
|
||||
case XTENSA_SYSCALL_GETTIMEOFDAY:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "gettimeofday");
|
||||
fileio_info->param_1 = arg0; // tvp
|
||||
fileio_info->param_2 = arg1; // tzp
|
||||
break;
|
||||
case XTENSA_SYSCALL_ISATTY:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "isatty");
|
||||
fileio_info->param_1 = arg0; // fd
|
||||
break;
|
||||
case XTENSA_SYSCALL_SYSTEM:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "system");
|
||||
fileio_info->param_1 = arg0; // cmdp
|
||||
fileio_info->param_2 = arg1; // len
|
||||
break;
|
||||
default:
|
||||
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unknown");
|
||||
LOG_TARGET_DEBUG(target, "File-I/O: syscall unknown (%d), pc=0x%08X",
|
||||
syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
|
||||
LOG_INFO("File-I/O: syscall unknown (%d), pc=0x%08X",
|
||||
syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
|
||||
{
|
||||
struct xtensa *xtensa = target_to_xtensa(target);
|
||||
if (!xtensa->proc_syscall)
|
||||
return ERROR_FAIL;
|
||||
|
||||
LOG_TARGET_DEBUG(target, "File-I/O: syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s",
|
||||
retcode, fileio_errno, ctrl_c ? "true" : "false");
|
||||
|
||||
/* If interrupt was requested before FIO completion (ERRNO==4), halt and repeat
|
||||
* syscall. Otherwise, set File-I/O Ax and underlying ARx registers, increment PC.
|
||||
* NOTE: sporadic cases of ((ERRNO==4) && !ctrl_c) were observed; most have ctrl_c.
|
||||
*/
|
||||
if (fileio_errno != 4) {
|
||||
xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_RETVAL_REG, retcode);
|
||||
xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_ERRNO_REG, fileio_errno);
|
||||
|
||||
xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
|
||||
xtensa_reg_set(target, XT_REG_IDX_PC, pc + XTENSA_SYSCALL_SZ);
|
||||
}
|
||||
|
||||
xtensa->proc_syscall = false;
|
||||
xtensa->halt_request = true;
|
||||
return ctrl_c ? ERROR_FAIL : ERROR_OK;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Xtensa Target File-I/O Support for OpenOCD *
|
||||
* Copyright (C) 2020-2023 Cadence Design Systems, Inc. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_XTENSA_FILEIO_H
|
||||
#define OPENOCD_TARGET_XTENSA_FILEIO_H
|
||||
|
||||
#include <target/target.h>
|
||||
#include <helper/command.h>
|
||||
#include "xtensa.h"
|
||||
|
||||
#define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2
|
||||
#define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2
|
||||
#define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3
|
||||
|
||||
#define XTENSA_SYSCALL_OPEN (-2)
|
||||
#define XTENSA_SYSCALL_CLOSE (-3)
|
||||
#define XTENSA_SYSCALL_READ (-4)
|
||||
#define XTENSA_SYSCALL_WRITE (-5)
|
||||
#define XTENSA_SYSCALL_LSEEK (-6)
|
||||
#define XTENSA_SYSCALL_RENAME (-7)
|
||||
#define XTENSA_SYSCALL_UNLINK (-8)
|
||||
#define XTENSA_SYSCALL_STAT (-9)
|
||||
#define XTENSA_SYSCALL_FSTAT (-10)
|
||||
#define XTENSA_SYSCALL_GETTIMEOFDAY (-11)
|
||||
#define XTENSA_SYSCALL_ISATTY (-12)
|
||||
#define XTENSA_SYSCALL_SYSTEM (-13)
|
||||
|
||||
int xtensa_fileio_init(struct target *target);
|
||||
int xtensa_fileio_detect_proc(struct target *target);
|
||||
int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
|
||||
int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
|
||||
|
||||
#endif /* OPENOCD_TARGET_XTENSA_FILEIO_H */
|
Loading…
Reference in New Issue