The semihosting->stdin_fd is initially in blocking mode.
Due to this there is a possibility that the system software blocks
waiting for a key-press from the user. This can adversely affect
various housekeeping aspects of system software such as the
scheduling of the system software tasks/processes/threads.

Specifically, in my case I am booting the Linux kernel on RISCV
that routes all console read and write character requests to the
openSBI firmware. Since the openSBI firmware blocks waiting for a
key-press and openocd is waiting in getchar() the entire Linux
kernel scheduling is blocked due to which there are various stalls
in the kernel.

This patch introduces a new command called semihosting_stdfd that
enables us to put any of the standard input/output/error fds into
non-blocking mode. After applying this patch and running the
semihosting_std command my scheduling and kernel thread stalls were
removed and I could get the Linux bash prompt and could successfully
run shell commands and observe their outputs in semihosting console.

This same command can be extended if anyone wants to add more
controls to the semihosting standard file descriptors.

Also added documentation for this new command.

Signed-off-by: Kautuk Consul <kcon...@ventanamicro.com>
---
 doc/openocd.texi                |  7 ++++
 src/target/semihosting_common.c | 58 +++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 2a8626b80..b0bd976b0 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -9579,6 +9579,13 @@ Set the base directory for semihosting I/O, either an 
absolute path or a path re
 Use "." for the current directory.
 @end deffn
 
+@deffn {Command} {arm semihosting_stdfd} ['in'|'out'|'err'] 
['blocking'|'nonblocking']
+@cindex ARM semihosting
+Set/unset the O_NONBLOCK file status flag in the 
semihosting->std[in|out|err]_fd file descriptor. This file status
+flag affects the appropriate standard file descriptor's blocking/non-blocking 
status thus affecting the
+responsiveness of the semihosting console to inputs/outputs from/to standard 
input/output/error file descriptors.
+@end deffn
+
 @section ARMv4 and ARMv5 Architecture
 @cindex ARMv4
 @cindex ARMv5
diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index dc0dae2c8..94a4883f0 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -2038,6 +2038,57 @@ 
COMMAND_HANDLER(handle_common_semihosting_basedir_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_common_semihosting_stdfd_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+
+       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;
+       }
+
+       int flags;
+       int fd;
+
+       if (CMD_ARGC < 2 || CMD_ARGC > 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (strcmp(CMD_ARGV[0], "in") == 0)
+               fd = semihosting->stdin_fd;
+       else if (strcmp(CMD_ARGV[0], "out") == 0)
+               fd = semihosting->stdout_fd;
+       else if (strcmp(CMD_ARGV[0], "err") == 0)
+               fd = semihosting->stderr_fd;
+       else
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (strcmp(CMD_ARGV[1], "blocking") == 0) {
+               flags = fcntl(fd, F_GETFL, 0);
+               flags & O_NONBLOCK ? fcntl(fd, F_SETFL, flags & (~O_NONBLOCK)) 
: 1;
+       } else if (strcmp(CMD_ARGV[1], "nonblocking") == 0) {
+               flags = fcntl(fd, F_GETFL, 0);
+               flags & O_NONBLOCK ? 1 : fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+       } else {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       command_print(CMD, "semihosting %s standard fd set to %s",
+               CMD_ARGV[0], CMD_ARGV[1]);
+
+       return ERROR_OK;
+}
+
 const struct command_registration semihosting_common_handlers[] = {
        {
                .name = "semihosting",
@@ -2088,5 +2139,12 @@ const struct command_registration 
semihosting_common_handlers[] = {
                .usage = "[dir]",
                .help = "set the base directory for semihosting I/O operations",
        },
+       {
+               .name = "semihosting_stdfd",
+               .handler = handle_common_semihosting_stdfd_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['in'|'out'|'err'] ['blocking'|'nonblocking']",
+               .help = "control the semihosting->std*_fd file descriptor 
flags",
+       },
        COMMAND_REGISTRATION_DONE
 };
-- 
2.34.1


Reply via email to