mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-27 17:41:34 +00:00
The semihosting code exposes internal file handle handling functions to read(), open(), close() and get the length of a certain file handle. However the code using it is only interested in either reading and entire named file into memory or getting the file length of a file referred by name. No file handles are used. Thus make the file handle code internal to this file by removing these functions from the semihosting header file and staticize them. This gives us some freedom to rearrange the semihosting code without affecting the external interface. Cc: Darwin Rambo <drambo@broadcom.com> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org> Cc: Mark Hambleton <mark.hambleton@arm.com> Cc: Tom Rini <trini@ti.com> Acked-by: Steve Rae <srae@broadcom.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
238 lines
4.9 KiB
C
238 lines
4.9 KiB
C
/*
|
|
* Copyright 2014 Broadcom Corporation
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
/*
|
|
* Minimal semihosting implementation for reading files into memory. If more
|
|
* features like writing files or console output are required they can be
|
|
* added later. This code has been tested on arm64/aarch64 fastmodel only.
|
|
* An untested placeholder exists for armv7 architectures, but since they
|
|
* are commonly available in silicon now, fastmodel usage makes less sense
|
|
* for them.
|
|
*/
|
|
#include <common.h>
|
|
#include <asm/semihosting.h>
|
|
|
|
#define SYSOPEN 0x01
|
|
#define SYSCLOSE 0x02
|
|
#define SYSREAD 0x06
|
|
#define SYSFLEN 0x0C
|
|
|
|
#define MODE_READ 0x0
|
|
#define MODE_READBIN 0x1
|
|
|
|
static int smh_read(int fd, void *memp, int len);
|
|
static int smh_open(const char *fname, char *modestr);
|
|
static int smh_close(int fd);
|
|
static int smh_len_fd(int fd);
|
|
|
|
/*
|
|
* Call the handler
|
|
*/
|
|
static int smh_trap(unsigned int sysnum, void *addr)
|
|
{
|
|
register int result asm("r0");
|
|
#if defined(CONFIG_ARM64)
|
|
asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
|
|
#else
|
|
/* Note - untested placeholder */
|
|
asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Open, load a file into memory, and close it. Check that the available space
|
|
* is sufficient to store the entire file. Return the bytes actually read from
|
|
* the file as seen by the read function. The verbose flag enables some extra
|
|
* printing of successful read status.
|
|
*/
|
|
int smh_load(const char *fname, void *memp, int avail, int verbose)
|
|
{
|
|
int ret, fd, len;
|
|
|
|
ret = -1;
|
|
|
|
debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname,
|
|
avail, memp);
|
|
|
|
/* Open the file */
|
|
fd = smh_open(fname, "rb");
|
|
if (fd == -1)
|
|
return ret;
|
|
|
|
/* Get the file length */
|
|
ret = smh_len_fd(fd);
|
|
if (ret == -1) {
|
|
smh_close(fd);
|
|
return ret;
|
|
}
|
|
|
|
/* Check that the file will fit in the supplied buffer */
|
|
if (ret > avail) {
|
|
printf("%s: ERROR ret %d, avail %u\n", __func__, ret,
|
|
avail);
|
|
smh_close(fd);
|
|
return ret;
|
|
}
|
|
|
|
len = ret;
|
|
|
|
/* Read the file into the buffer */
|
|
ret = smh_read(fd, memp, len);
|
|
if (ret == 0) {
|
|
/* Print successful load information if requested */
|
|
if (verbose) {
|
|
printf("\n%s\n", fname);
|
|
printf(" 0x%8p dest\n", memp);
|
|
printf(" 0x%08x size\n", len);
|
|
printf(" 0x%08x avail\n", avail);
|
|
}
|
|
}
|
|
|
|
/* Close the file */
|
|
smh_close(fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
|
|
*/
|
|
static int smh_read(int fd, void *memp, int len)
|
|
{
|
|
int ret;
|
|
struct smh_read_s {
|
|
int fd;
|
|
void *memp;
|
|
int len;
|
|
} read;
|
|
|
|
debug("%s: fd %d, memp %p, len %d\n", __func__, fd, memp, len);
|
|
|
|
read.fd = fd;
|
|
read.memp = memp;
|
|
read.len = len;
|
|
|
|
ret = smh_trap(SYSREAD, &read);
|
|
if (ret == 0) {
|
|
return 0;
|
|
} else {
|
|
/*
|
|
* The ARM handler allows for returning partial lengths,
|
|
* but in practice this never happens so rather than create
|
|
* hard to maintain partial read loops and such, just fail
|
|
* with an error message.
|
|
*/
|
|
printf("%s: ERROR ret %d, fd %d, len %u memp %p\n",
|
|
__func__, ret, fd, len, memp);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Open a file on the host. Mode is "r" or "rb" currently. Returns a file
|
|
* descriptor or -1 on error.
|
|
*/
|
|
static int smh_open(const char *fname, char *modestr)
|
|
{
|
|
int ret, fd, mode;
|
|
struct smh_open_s {
|
|
const char *fname;
|
|
unsigned int mode;
|
|
unsigned int len;
|
|
} open;
|
|
|
|
debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
|
|
|
|
ret = -1;
|
|
|
|
/* Check the file mode */
|
|
if (!(strcmp(modestr, "r"))) {
|
|
mode = MODE_READ;
|
|
} else if (!(strcmp(modestr, "rb"))) {
|
|
mode = MODE_READBIN;
|
|
} else {
|
|
printf("%s: ERROR mode \'%s\' not supported\n", __func__,
|
|
modestr);
|
|
return ret;
|
|
}
|
|
|
|
open.fname = fname;
|
|
open.len = strlen(fname);
|
|
open.mode = mode;
|
|
|
|
/* Open the file on the host */
|
|
fd = smh_trap(SYSOPEN, &open);
|
|
if (fd == -1)
|
|
printf("%s: ERROR fd %d for file \'%s\'\n", __func__, fd,
|
|
fname);
|
|
|
|
return fd;
|
|
}
|
|
|
|
/*
|
|
* Close the file using the file descriptor
|
|
*/
|
|
static int smh_close(int fd)
|
|
{
|
|
int ret;
|
|
long fdlong;
|
|
|
|
debug("%s: fd %d\n", __func__, fd);
|
|
|
|
fdlong = (long)fd;
|
|
ret = smh_trap(SYSCLOSE, &fdlong);
|
|
if (ret == -1)
|
|
printf("%s: ERROR fd %d\n", __func__, fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Get the file length from the file descriptor
|
|
*/
|
|
static int smh_len_fd(int fd)
|
|
{
|
|
int ret;
|
|
long fdlong;
|
|
|
|
debug("%s: fd %d\n", __func__, fd);
|
|
|
|
fdlong = (long)fd;
|
|
ret = smh_trap(SYSFLEN, &fdlong);
|
|
if (ret == -1)
|
|
printf("%s: ERROR ret %d\n", __func__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Get the file length from the filename
|
|
*/
|
|
int smh_len(const char *fname)
|
|
{
|
|
int ret, fd, len;
|
|
|
|
debug("%s: file \'%s\'\n", __func__, fname);
|
|
|
|
/* Open the file */
|
|
fd = smh_open(fname, "rb");
|
|
if (fd == -1)
|
|
return fd;
|
|
|
|
/* Get the file length */
|
|
len = smh_len_fd(fd);
|
|
|
|
/* Close the file */
|
|
ret = smh_close(fd);
|
|
if (ret == -1)
|
|
return ret;
|
|
|
|
debug("%s: returning len %d\n", __func__, len);
|
|
|
|
/* Return the file length (or -1 error indication) */
|
|
return len;
|
|
}
|