- /* resume execution to the original mode */
- buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, result);
- armv4_5->core_cache->reg_list[0].dirty = 1;
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, lr);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, spsr);
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
- armv4_5->core_mode = spsr & 0x1f;
- if (spsr & 0x20)
- armv4_5->core_state = ARM_STATE_THUMB;
- return target_resume(target, 1, 0, 0, 0);
+ return ERROR_OK;
+}
+
+static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
+{
+ struct arm *arm = target_to_arm(target);
+
+ /* To avoid uneccessary duplication, semihosting prepares the
+ * fileio_info structure out-of-band when the target halts. See
+ * do_semihosting for more detail.
+ */
+ if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
+{
+ struct arm *arm = target_to_arm(target);
+ struct gdb_fileio_info *fileio_info = target->fileio_info;
+
+ /* clear pending status */
+ arm->semihosting_hit_fileio = false;
+
+ arm->semihosting_result = result;
+ arm->semihosting_errno = fileio_errno;
+
+ /* Some fileio results do not match up with what the semihosting
+ * operation expects; for these operations, we munge the results
+ * below:
+ */
+ switch (arm->semihosting_op) {
+ case 0x05: /* SYS_WRITE */
+ if (result < 0)
+ arm->semihosting_result = fileio_info->param_3;
+ else
+ arm->semihosting_result = 0;
+ break;
+
+ case 0x06: /* SYS_READ */
+ if (result == (int)fileio_info->param_3)
+ arm->semihosting_result = 0;
+ if (result <= 0)
+ arm->semihosting_result = fileio_info->param_3;
+ break;
+
+ case 0x0a: /* SYS_SEEK */
+ if (result > 0)
+ arm->semihosting_result = 0;
+ break;
+ }
+
+ return post_result(target);
+}
+
+/**
+ * Initialize ARM semihosting support.
+ *
+ * @param target Pointer to the ARM target to initialize.
+ * @return An error status if there is a problem during initialization.
+ */
+int arm_semihosting_init(struct target *target)
+{
+ target->fileio_info = malloc(sizeof(*target->fileio_info));
+ if (target->fileio_info == NULL) {
+ LOG_ERROR("out of memory");
+ return ERROR_FAIL;
+ }
+
+ target->type->get_gdb_fileio_info = get_gdb_fileio_info;
+ target->type->gdb_fileio_end = gdb_fileio_end;
+
+ return ERROR_OK;