diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c index 02cd673d47..e5f1e2aaaf 100644 --- a/target/arm/arm-semi.c +++ b/target/arm/arm-semi.c @@ -109,6 +109,7 @@ static int open_modeflags[12] = { typedef enum GuestFDType { GuestFDUnused = 0, GuestFDHost = 1, + GuestFDGDB = 2, } GuestFDType; /* @@ -172,14 +173,14 @@ static GuestFD *do_get_guestfd(int guestfd) /* * Associate the specified guest fd (which must have been * allocated via alloc_fd() and not previously used) with - * the specified host fd. + * the specified host/gdb fd. */ static void associate_guestfd(int guestfd, int hostfd) { GuestFD *gf = do_get_guestfd(guestfd); assert(gf); - gf->type = GuestFDHost; + gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost; gf->hostfd = hostfd; } @@ -376,6 +377,39 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb, return is_a64(env) ? env->xregs[0] : env->regs[0]; } +/* + * Types for functions implementing various semihosting calls + * for specific types of guest file descriptor. These must all + * do the work and return the required return value for the guest, + * setting the guest errno if appropriate. + */ +typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf); + +static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf) +{ + CPUARMState *env = &cpu->env; + + return set_swi_errno(env, close(gf->hostfd)); +} + +static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf) +{ + return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd); +} + +typedef struct GuestFDFunctions { + sys_closefn *closefn; +} GuestFDFunctions; + +static const GuestFDFunctions guestfd_fns[] = { + [GuestFDHost] = { + .closefn = host_closefn, + }, + [GuestFDGDB] = { + .closefn = gdb_closefn, + }, +}; + /* Read the input value from the argument block; fail the semihosting * call if the memory read fails. */ @@ -485,11 +519,7 @@ target_ulong do_arm_semihosting(CPUARMState *env) return set_swi_errno(env, -1); } - if (use_gdb_syscalls()) { - ret = arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd); - } else { - ret = set_swi_errno(env, close(gf->hostfd)); - } + ret = guestfd_fns[gf->type].closefn(cpu, gf); dealloc_guestfd(arg0); return ret; case TARGET_SYS_WRITEC: