On 10/14/25 12:03, Andrew Goodbody wrote: > The sys call SYS_READ was being used in a way that did not allow for > file sizes > 2^31. Fixing this required changing the signature of the > function to allow file sizes up to 2^32 - 2 and also being able to > return errors that could be tested for. > > Signed-off-by: Andrew Goodbody <[email protected]> > --- > common/spl/spl_semihosting.c | 7 ++++--- > drivers/serial/serial_semihosting.c | 6 ++++-- > fs/semihostingfs.c | 9 +++++---- > include/semihosting.h | 8 ++++---- > lib/semihosting.c | 22 ++++++++++++++++++---- > 5 files changed, 35 insertions(+), 17 deletions(-) > > diff --git a/common/spl/spl_semihosting.c b/common/spl/spl_semihosting.c > index > f36863fe48d25859ee9af67a67140893b6e9e262..cff6f5351e265136b3effe483fd5d641fdd109f8 > 100644 > --- a/common/spl/spl_semihosting.c > +++ b/common/spl/spl_semihosting.c > @@ -13,13 +13,14 @@ static ulong smh_fit_read(struct spl_load_info *load, > ulong file_offset, > ulong size, void *buf) > { > long fd = *(long *)load->priv; > - ulong ret; > + long ret; > + size_t bytes_read; > > if (smh_seek(fd, file_offset)) > return 0; > > - ret = smh_read(fd, buf, size); > - return ret < 0 ? 0 : ret; > + ret = smh_read(fd, buf, size, &bytes_read); > + return ret < 0 ? 0 : bytes_read; > } > > static int spl_smh_load_image(struct spl_image_info *spl_image, > diff --git a/drivers/serial/serial_semihosting.c > b/drivers/serial/serial_semihosting.c > index > 56a5ec72428afdd97eccad739a46189380ba3e76..017b1f8eda84f5c25e09be7e970d0ebfdbf2ace0 > 100644 > --- a/drivers/serial/serial_semihosting.c > +++ b/drivers/serial/serial_semihosting.c > @@ -25,11 +25,12 @@ static int smh_serial_getc(struct udevice *dev) > { > char ch = 0; > struct smh_serial_priv *priv = dev_get_priv(dev); > + size_t bytes_read; > > if (priv->infd < 0) > return smh_getc(); > > - smh_read(priv->infd, &ch, sizeof(ch)); > + smh_read(priv->infd, &ch, sizeof(ch), &bytes_read); > return ch; > } > > @@ -140,11 +141,12 @@ static void smh_serial_setbrg(void) > static int smh_serial_getc(void) > { > char ch = 0; > + size_t bytes_read; > > if (infd < 0) > return smh_getc(); > > - smh_read(infd, &ch, sizeof(ch)); > + smh_read(infd, &ch, sizeof(ch), &bytes_read); > return ch; > } > > diff --git a/fs/semihostingfs.c b/fs/semihostingfs.c > index > 77e39ca407e4d240a1fd573497c5b6b908816454..15f58d578b65f7dbbadce19093546f5bdb46c0c3 > 100644 > --- a/fs/semihostingfs.c > +++ b/fs/semihostingfs.c > @@ -23,7 +23,8 @@ int smh_fs_set_blk_dev(struct blk_desc *rbdd, struct > disk_partition *info) > static int smh_fs_read_at(const char *filename, loff_t pos, void *buffer, > loff_t maxsize, loff_t *actread) > { > - long fd, size, ret; > + long fd, ret; > + size_t size; > > fd = smh_open(filename, MODE_READ | MODE_BINARY); > if (fd < 0) > @@ -43,10 +44,10 @@ static int smh_fs_read_at(const char *filename, loff_t > pos, void *buffer, > maxsize = size; > } > > - size = smh_read(fd, buffer, maxsize); > + ret = smh_read(fd, buffer, maxsize, &size); > smh_close(fd); > - if (size < 0) > - return size; > + if (ret < 0) > + return ret; > > *actread = size; > return 0; > diff --git a/include/semihosting.h b/include/semihosting.h > index > 4e844cbad87bb1ae6bb365f87f3e7a8aeea445f4..42832d86c711ff04e91b6b739c80629253f6d30a > 100644 > --- a/include/semihosting.h > +++ b/include/semihosting.h > @@ -95,12 +95,12 @@ long smh_open(const char *fname, enum smh_open_mode mode); > * @fd: A file descriptor returned from smh_open() > * @memp: Pointer to a buffer of memory of at least @len bytes > * @len: The number of bytes to read > + * @read_len: Pointer which will be updated with actual bytes read on > success, > + * with 0 indicating %EOF > * > - * Return: > - * * The number of bytes read on success, with 0 indicating %EOF > - * * A negative error on failure > + * Return: 0 on success or negative error on failure > */ > -long smh_read(long fd, void *memp, size_t len); > +long smh_read(long fd, void *memp, size_t len, size_t *read_len); > > /** > * smh_write() - Write data to a file > diff --git a/lib/semihosting.c b/lib/semihosting.c > index > 9be5bffd30124777c4f8110065e6cca5640312ac..e49b16b0aa34ab04b6c8949a3e7cab539fdbef82 > 100644 > --- a/lib/semihosting.c > +++ b/lib/semihosting.c > @@ -93,9 +93,9 @@ struct smh_rdwr_s { > size_t len; > }; > > -long smh_read(long fd, void *memp, size_t len) > +long smh_read(long fd, void *memp, size_t len, size_t *read_len) > { > - long ret; > + size_t ret; > struct smh_rdwr_s read; > > debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len); > @@ -105,9 +105,23 @@ long smh_read(long fd, void *memp, size_t len) > read.len = len; > > ret = smh_trap(SYSREAD, &read); > - if (ret < 0) > + if (!ret) { > + /* Success */ > + *read_len = len; > + return 0; > + } else if (ret == len) { > + /* EOF */ > + *read_len = 0; > + return 0; > + } else if ((long)ret == -1) { > + *read_len = 0; > return smh_errno(); > - return len - ret; > + } else { > + /* Partial success */ > + *read_len = len - ret; > + return 0; > + } > +
There is no point. When are you going to read 3 GiB of file all at once on a 32-bit system? Any sane user will read multiple times into smaller buffers. So the correct fix is to add if (len > LONG_MAX) return -EOVERFLOW; to the beginning. --Sean

