Message ID | 20190910144428.32597-12-peter.maydell@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | target/arm: Implement semihosting v2.0 | expand |
On Tue, 10 Sep 2019 at 15:44, Peter Maydell <peter.maydell@linaro.org> wrote: > > Version 2.0 of the semihosting specification added support for > allowing a guest to detect whether the implementation supported > particular features. This works by the guest opening a magic > file ":semihosting-features", which contains a fixed set of > data with some magic numbers followed by a sequence of bytes > with feature flags. The file is expected to behave sensibly > for the various semihosting calls which operate on files > (SYS_FLEN, SYS_SEEK, etc). > @@ -586,6 +679,18 @@ target_ulong do_arm_semihosting(CPUARMState *env) > unlock_user(s, arg0, 0); > return guestfd; > } > + if (strcmp(s, ":semihosting-features") == 0) { > + unlock_user(s, arg0, 0); > + /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ > + if (arg1 != 0 && arg1 != 1) { > + dealloc_guestfd(guestfd); > + errno = EINVAL; The spec doesn't mandate any particular errno here, but EACCES would probably be better, since that's the usual error for trying to open a read-only file for writing. thanks -- PMM
Peter Maydell <peter.maydell@linaro.org> writes: > Version 2.0 of the semihosting specification added support for > allowing a guest to detect whether the implementation supported > particular features. This works by the guest opening a magic > file ":semihosting-features", which contains a fixed set of > data with some magic numbers followed by a sequence of bytes > with feature flags. The file is expected to behave sensibly > for the various semihosting calls which operate on files > (SYS_FLEN, SYS_SEEK, etc). > > Implement this as another kind of guest FD using our function > table dispatch mechanism. Initially we report no extended > features, so we have just one feature flag byte which is zero. > > Signed-off-by: Peter Maydell <peter.maydell@linaro.org> with your EACCESS suggestion: Reviewed-by: Alex Bennée <alex.bennee@linaro.org> > --- > target/arm/arm-semi.c | 107 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 106 insertions(+), 1 deletion(-) > > diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c > index f9019b00b8d..531084b7799 100644 > --- a/target/arm/arm-semi.c > +++ b/target/arm/arm-semi.c > @@ -117,6 +117,7 @@ typedef enum GuestFDType { > GuestFDUnused = 0, > GuestFDHost = 1, > GuestFDGDB = 2, > + GuestFDFeatureFile = 3, > } GuestFDType; > > /* > @@ -125,7 +126,10 @@ typedef enum GuestFDType { > */ > typedef struct GuestFD { > GuestFDType type; > - int hostfd; > + union { > + int hostfd; > + target_ulong featurefile_offset; > + }; > } GuestFD; > > static GArray *guestfd_array; > @@ -467,6 +471,87 @@ static uint32_t gdb_flenfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > gf->hostfd, arm_flen_buf(cpu)); > } > > +#define SHFB_MAGIC_0 0x53 > +#define SHFB_MAGIC_1 0x48 > +#define SHFB_MAGIC_2 0x46 > +#define SHFB_MAGIC_3 0x42 > + > +static const uint8_t featurefile_data[] = { > + SHFB_MAGIC_0, > + SHFB_MAGIC_1, > + SHFB_MAGIC_2, > + SHFB_MAGIC_3, > + 0, /* Feature byte 0 */ > +}; > + > +static void init_featurefile_guestfd(int guestfd) > +{ > + GuestFD *gf = do_get_guestfd(guestfd); > + > + assert(gf); > + gf->type = GuestFDFeatureFile; > + gf->featurefile_offset = 0; > +} > + > +static uint32_t featurefile_closefn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + /* Nothing to do */ > + return 0; > +} > + > +static uint32_t featurefile_writefn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong buf, uint32_t len) > +{ > + /* This fd can never be open for writing */ > + errno = EBADF; > + return set_swi_errno(ts, -1); > +} > + > +static uint32_t featurefile_readfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong buf, uint32_t len) > +{ > + uint32_t i; > +#ifndef CONFIG_USER_ONLY > + CPUARMState *env = &cpu->env; > +#endif > + char *s; > + > + s = lock_user(VERIFY_WRITE, buf, len, 0); > + if (!s) { > + return len; > + } > + > + for (i = 0; i < len; i++) { > + if (gf->featurefile_offset >= sizeof(featurefile_data)) { > + break; > + } > + s[i] = featurefile_data[gf->featurefile_offset]; > + gf->featurefile_offset++; > + } > + > + unlock_user(s, buf, len); > + > + /* Return number of bytes not read */ > + return len - i; > +} > + > +static uint32_t featurefile_isattyfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + return 0; > +} > + > +static uint32_t featurefile_seekfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong offset) > +{ > + gf->featurefile_offset = offset; > + return 0; > +} > + > +static uint32_t featurefile_flenfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + return sizeof(featurefile_data); > +} > + > typedef struct GuestFDFunctions { > sys_closefn *closefn; > sys_writefn *writefn; > @@ -493,6 +578,14 @@ static const GuestFDFunctions guestfd_fns[] = { > .seekfn = gdb_seekfn, > .flenfn = gdb_flenfn, > }, > + [GuestFDFeatureFile] = { > + .closefn = featurefile_closefn, > + .writefn = featurefile_writefn, > + .readfn = featurefile_readfn, > + .isattyfn = featurefile_isattyfn, > + .seekfn = featurefile_seekfn, > + .flenfn = featurefile_flenfn, > + }, > }; > > /* Read the input value from the argument block; fail the semihosting > @@ -586,6 +679,18 @@ target_ulong do_arm_semihosting(CPUARMState *env) > unlock_user(s, arg0, 0); > return guestfd; > } > + if (strcmp(s, ":semihosting-features") == 0) { > + unlock_user(s, arg0, 0); > + /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ > + if (arg1 != 0 && arg1 != 1) { > + dealloc_guestfd(guestfd); > + errno = EINVAL; > + return set_swi_errno(ts, -1); > + } > + init_featurefile_guestfd(guestfd); > + return guestfd; > + } > + > if (use_gdb_syscalls()) { > ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0, > (int)arg2+1, gdb_open_modeflags[arg1]); -- Alex Bennée
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c index f9019b00b8d..531084b7799 100644 --- a/target/arm/arm-semi.c +++ b/target/arm/arm-semi.c @@ -117,6 +117,7 @@ typedef enum GuestFDType { GuestFDUnused = 0, GuestFDHost = 1, GuestFDGDB = 2, + GuestFDFeatureFile = 3, } GuestFDType; /* @@ -125,7 +126,10 @@ typedef enum GuestFDType { */ typedef struct GuestFD { GuestFDType type; - int hostfd; + union { + int hostfd; + target_ulong featurefile_offset; + }; } GuestFD; static GArray *guestfd_array; @@ -467,6 +471,87 @@ static uint32_t gdb_flenfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) gf->hostfd, arm_flen_buf(cpu)); } +#define SHFB_MAGIC_0 0x53 +#define SHFB_MAGIC_1 0x48 +#define SHFB_MAGIC_2 0x46 +#define SHFB_MAGIC_3 0x42 + +static const uint8_t featurefile_data[] = { + SHFB_MAGIC_0, + SHFB_MAGIC_1, + SHFB_MAGIC_2, + SHFB_MAGIC_3, + 0, /* Feature byte 0 */ +}; + +static void init_featurefile_guestfd(int guestfd) +{ + GuestFD *gf = do_get_guestfd(guestfd); + + assert(gf); + gf->type = GuestFDFeatureFile; + gf->featurefile_offset = 0; +} + +static uint32_t featurefile_closefn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) +{ + /* Nothing to do */ + return 0; +} + +static uint32_t featurefile_writefn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, + target_ulong buf, uint32_t len) +{ + /* This fd can never be open for writing */ + errno = EBADF; + return set_swi_errno(ts, -1); +} + +static uint32_t featurefile_readfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, + target_ulong buf, uint32_t len) +{ + uint32_t i; +#ifndef CONFIG_USER_ONLY + CPUARMState *env = &cpu->env; +#endif + char *s; + + s = lock_user(VERIFY_WRITE, buf, len, 0); + if (!s) { + return len; + } + + for (i = 0; i < len; i++) { + if (gf->featurefile_offset >= sizeof(featurefile_data)) { + break; + } + s[i] = featurefile_data[gf->featurefile_offset]; + gf->featurefile_offset++; + } + + unlock_user(s, buf, len); + + /* Return number of bytes not read */ + return len - i; +} + +static uint32_t featurefile_isattyfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) +{ + return 0; +} + +static uint32_t featurefile_seekfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, + target_ulong offset) +{ + gf->featurefile_offset = offset; + return 0; +} + +static uint32_t featurefile_flenfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) +{ + return sizeof(featurefile_data); +} + typedef struct GuestFDFunctions { sys_closefn *closefn; sys_writefn *writefn; @@ -493,6 +578,14 @@ static const GuestFDFunctions guestfd_fns[] = { .seekfn = gdb_seekfn, .flenfn = gdb_flenfn, }, + [GuestFDFeatureFile] = { + .closefn = featurefile_closefn, + .writefn = featurefile_writefn, + .readfn = featurefile_readfn, + .isattyfn = featurefile_isattyfn, + .seekfn = featurefile_seekfn, + .flenfn = featurefile_flenfn, + }, }; /* Read the input value from the argument block; fail the semihosting @@ -586,6 +679,18 @@ target_ulong do_arm_semihosting(CPUARMState *env) unlock_user(s, arg0, 0); return guestfd; } + if (strcmp(s, ":semihosting-features") == 0) { + unlock_user(s, arg0, 0); + /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ + if (arg1 != 0 && arg1 != 1) { + dealloc_guestfd(guestfd); + errno = EINVAL; + return set_swi_errno(ts, -1); + } + init_featurefile_guestfd(guestfd); + return guestfd; + } + if (use_gdb_syscalls()) { ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0, (int)arg2+1, gdb_open_modeflags[arg1]);
Version 2.0 of the semihosting specification added support for allowing a guest to detect whether the implementation supported particular features. This works by the guest opening a magic file ":semihosting-features", which contains a fixed set of data with some magic numbers followed by a sequence of bytes with feature flags. The file is expected to behave sensibly for the various semihosting calls which operate on files (SYS_FLEN, SYS_SEEK, etc). Implement this as another kind of guest FD using our function table dispatch mechanism. Initially we report no extended features, so we have just one feature flag byte which is zero. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/arm-semi.c | 107 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-)