semihosting: add custom user command handler
authorErhan Kurubas <erhan.kurubas@espressif.com>
Tue, 5 Apr 2022 11:26:08 +0000 (14:26 +0300)
committerAntonio Borneo <borneo.antonio@gmail.com>
Fri, 24 Jun 2022 21:47:43 +0000 (21:47 +0000)
Custom user syscalls can be handled with target events in the TCL scripts.
This patch gives another opportunity to handle custom syscalls in the c files.
Besides that some utility functions are also exported for the custom handlers.

Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>
Change-Id: Ice13d527540a0de0b2a8abda912ae3dcff3834b7
Reviewed-on: https://review.openocd.org/c/openocd/+/6889
Tested-by: jenkins
Reviewed-by: Ian Thompson <ianst@cadence.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
src/target/semihosting_common.c
src/target/semihosting_common.h

index 0a60eb12118203d9a21a43445d18767c4643aeb2..d54c341ac90eff2951e56d7a34a7504eee987256 100644 (file)
@@ -103,16 +103,6 @@ static int semihosting_common_fileio_info(struct target *target,
 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;
 
@@ -166,6 +156,7 @@ int semihosting_common_init(struct target *target, void *setup,
 
        semihosting->setup = setup;
        semihosting->post_result = post_result;
+       semihosting->user_command_extension = NULL;
 
        target->semihosting = semihosting;
 
@@ -1467,9 +1458,14 @@ int semihosting_common(struct target *target)
                         * 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"
@@ -1507,11 +1503,8 @@ int semihosting_common(struct target *target)
                        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 */
                /*
@@ -1670,10 +1663,13 @@ static int semihosting_common_fileio_end(struct target *target, int result,
        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;
@@ -1685,7 +1681,7 @@ static int semihosting_read_fields(struct target *target, size_t number,
 /**
  * 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;
@@ -1697,7 +1693,7 @@ static int semihosting_write_fields(struct target *target, size_t number,
 /**
  * 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;
@@ -1710,7 +1706,7 @@ static uint64_t semihosting_get_field(struct target *target, size_t index,
 /**
  * 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)
 {
index 404080f023401b81f0871c58900afc286c5e17f5..1b7169030200eecf29958b6e4212e0481954bdd6 100644 (file)
@@ -179,6 +179,13 @@ struct semihosting {
        /** Base directory for semihosting I/O operations. */
        char *basedir;
 
+       /**
+        * Target's extension of semihosting user commands.
+        * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise
+        * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK.
+        */
+       int (*user_command_extension)(struct target *target);
+
        int (*setup)(struct target *target, int enable);
        int (*post_result)(struct target *target);
 };
@@ -187,4 +194,15 @@ int semihosting_common_init(struct target *target, void *setup,
        void *post_result);
 int semihosting_common(struct target *target);
 
+/* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */
+int semihosting_read_fields(struct target *target, size_t number,
+       uint8_t *fields);
+int semihosting_write_fields(struct target *target, size_t number,
+       uint8_t *fields);
+uint64_t semihosting_get_field(struct target *target, size_t index,
+       uint8_t *fields);
+void semihosting_set_field(struct target *target, uint64_t value,
+       size_t index,
+       uint8_t *fields);
+
 #endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */