+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2011 The Chromium OS Authors.
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <setjmp.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <asm/sections.h>
#include <asm/state.h>
#include <os.h>
+#include <rtc_def.h>
/* Operating System Interface */
return close(fd);
}
+int os_unlink(const char *pathname)
+{
+ return unlink(pathname);
+}
+
void os_exit(int exit_code)
{
exit(exit_code);
/* Restore tty state when we exit */
static struct termios orig_term;
+static bool term_setup;
-static void os_fd_restore(void)
+void os_fd_restore(void)
{
- tcsetattr(0, TCSANOW, &orig_term);
+ if (term_setup) {
+ tcsetattr(0, TCSANOW, &orig_term);
+ term_setup = false;
+ }
}
/* Put tty into raw mode so <tab> and <ctrl+c> work */
-void os_tty_raw(int fd)
+void os_tty_raw(int fd, bool allow_sigs)
{
- static int setup = 0;
struct termios term;
- if (setup)
+ if (term_setup)
return;
- setup = 1;
/* If not a tty, don't complain */
if (tcgetattr(fd, &orig_term))
term.c_iflag = IGNBRK | IGNPAR;
term.c_oflag = OPOST | ONLCR;
term.c_cflag = CS8 | CREAD | CLOCAL;
- term.c_lflag = 0;
+ term.c_lflag = allow_sigs ? ISIG : 0;
if (tcsetattr(fd, TCSANOW, &term))
return;
+ term_setup = true;
atexit(os_fd_restore);
}
return hdr + 1;
}
-void *os_free(void *ptr)
+void os_free(void *ptr)
{
struct os_mem_hdr *hdr = ptr;
int os_dirent_ls(const char *dirname, struct os_dirent_node **headp)
{
- struct dirent entry, *result;
+ struct dirent *entry;
struct os_dirent_node *head, *node, *next;
struct stat buf;
DIR *dir;
int ret;
char *fname;
+ char *old_fname;
int len;
+ int dirlen;
*headp = NULL;
dir = opendir(dirname);
if (!dir)
return -1;
- /* Create a buffer for the maximum filename length */
- len = sizeof(entry.d_name) + strlen(dirname) + 2;
+ /* Create a buffer upfront, with typically sufficient size */
+ dirlen = strlen(dirname) + 2;
+ len = dirlen + 256;
fname = malloc(len);
if (!fname) {
ret = -ENOMEM;
}
for (node = head = NULL;; node = next) {
- ret = readdir_r(dir, &entry, &result);
- if (ret || !result)
+ errno = 0;
+ entry = readdir(dir);
+ if (!entry) {
+ ret = errno;
break;
- next = malloc(sizeof(*node) + strlen(entry.d_name) + 1);
+ }
+ next = malloc(sizeof(*node) + strlen(entry->d_name) + 1);
if (!next) {
os_dirent_free(head);
ret = -ENOMEM;
goto done;
}
- strcpy(next->name, entry.d_name);
- switch (entry.d_type) {
+ if (dirlen + strlen(entry->d_name) > len) {
+ len = dirlen + strlen(entry->d_name);
+ old_fname = fname;
+ fname = realloc(fname, len);
+ if (!fname) {
+ free(old_fname);
+ free(next);
+ os_dirent_free(head);
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ next->next = NULL;
+ strcpy(next->name, entry->d_name);
+ switch (entry->d_type) {
case DT_REG:
next->type = OS_FILET_REG;
break;
case DT_LNK:
next->type = OS_FILET_LNK;
break;
+ default:
+ next->type = OS_FILET_UNKNOWN;
}
next->size = 0;
snprintf(fname, len, "%s/%s", dirname, next->name);
next->size = buf.st_size;
if (node)
node->next = next;
- if (!head)
- head = node;
+ else
+ head = next;
}
*headp = head;
done:
closedir(dir);
+ free(fname);
return ret;
}
const char *os_dirent_get_typename(enum os_dirent_t type)
{
- if (type >= 0 && type < OS_FILET_COUNT)
+ if (type >= OS_FILET_REG && type < OS_FILET_COUNT)
return os_dirent_typename[type];
return os_dirent_typename[OS_FILET_UNKNOWN];
}
-ssize_t os_get_filesize(const char *fname)
+int os_get_filesize(const char *fname, loff_t *size)
{
struct stat buf;
int ret;
ret = stat(fname, &buf);
if (ret)
return ret;
- return buf.st_size;
+ *size = buf.st_size;
+ return 0;
}
void os_putc(int ch)
{
struct sandbox_state *state = state_get_current();
int fd, ret;
- int size;
+ loff_t size;
- size = os_get_filesize(fname);
- if (size < 0)
- return -ENOENT;
+ ret = os_get_filesize(fname, &size);
+ if (ret < 0)
+ return ret;
if (size != state->ram_size)
return -ENOSPC;
fd = open(fname, O_RDONLY);
return 0;
}
+
+static int make_exec(char *fname, const void *data, int size)
+{
+ int fd;
+
+ strcpy(fname, "/tmp/u-boot.jump.XXXXXX");
+ fd = mkstemp(fname);
+ if (fd < 0)
+ return -ENOENT;
+ if (write(fd, data, size) < 0)
+ return -EIO;
+ close(fd);
+ if (chmod(fname, 0777))
+ return -ENOEXEC;
+
+ return 0;
+}
+
+static int add_args(char ***argvp, const char *add_args[], int count)
+{
+ char **argv;
+ int argc;
+
+ for (argv = *argvp, argc = 0; (*argvp)[argc]; argc++)
+ ;
+
+ argv = malloc((argc + count + 1) * sizeof(char *));
+ if (!argv) {
+ printf("Out of memory for %d argv\n", count);
+ return -ENOMEM;
+ }
+ memcpy(argv, *argvp, argc * sizeof(char *));
+ memcpy(argv + argc, add_args, count * sizeof(char *));
+ argv[argc + count] = NULL;
+
+ *argvp = argv;
+ return 0;
+}
+
+int os_jump_to_image(const void *dest, int size)
+{
+ struct sandbox_state *state = state_get_current();
+ char fname[30], mem_fname[30];
+ int fd, err;
+ const char *extra_args[5];
+ char **argv = state->argv;
+#ifdef DEBUG
+ int argc, i;
+#endif
+
+ err = make_exec(fname, dest, size);
+ if (err)
+ return err;
+
+ strcpy(mem_fname, "/tmp/u-boot.mem.XXXXXX");
+ fd = mkstemp(mem_fname);
+ if (fd < 0)
+ return -ENOENT;
+ close(fd);
+ err = os_write_ram_buf(mem_fname);
+ if (err)
+ return err;
+
+ os_fd_restore();
+
+ extra_args[0] = "-j";
+ extra_args[1] = fname;
+ extra_args[2] = "-m";
+ extra_args[3] = mem_fname;
+ extra_args[4] = "--rm_memory";
+ err = add_args(&argv, extra_args,
+ sizeof(extra_args) / sizeof(extra_args[0]));
+ if (err)
+ return err;
+
+#ifdef DEBUG
+ for (i = 0; argv[i]; i++)
+ printf("%d %s\n", i, argv[i]);
+#endif
+
+ if (state_uninit())
+ os_exit(2);
+
+ err = execv(fname, argv);
+ free(argv);
+ if (err)
+ return err;
+
+ return unlink(fname);
+}
+
+int os_find_u_boot(char *fname, int maxlen)
+{
+ struct sandbox_state *state = state_get_current();
+ const char *progname = state->argv[0];
+ int len = strlen(progname);
+ char *p;
+ int fd;
+
+ if (len >= maxlen || len < 4)
+ return -ENOSPC;
+
+ /* Look for 'u-boot' in the same directory as 'u-boot-spl' */
+ strcpy(fname, progname);
+ if (!strcmp(fname + len - 4, "-spl")) {
+ fname[len - 4] = '\0';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+
+ /* Look for 'u-boot' in the parent directory of spl/ */
+ p = strstr(fname, "/spl/");
+ if (p) {
+ strcpy(p, p + 4);
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int os_spl_to_uboot(const char *fname)
+{
+ struct sandbox_state *state = state_get_current();
+ char *argv[state->argc + 1];
+ int ret;
+
+ memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1));
+ argv[0] = (char *)fname;
+ ret = execv(fname, argv);
+ if (ret)
+ return ret;
+
+ return unlink(fname);
+}
+
+void os_localtime(struct rtc_time *rt)
+{
+ time_t t = time(NULL);
+ struct tm *tm;
+
+ tm = localtime(&t);
+ rt->tm_sec = tm->tm_sec;
+ rt->tm_min = tm->tm_min;
+ rt->tm_hour = tm->tm_hour;
+ rt->tm_mday = tm->tm_mday;
+ rt->tm_mon = tm->tm_mon + 1;
+ rt->tm_year = tm->tm_year + 1900;
+ rt->tm_wday = tm->tm_wday;
+ rt->tm_yday = tm->tm_yday;
+ rt->tm_isdst = tm->tm_isdst;
+}
+
+int os_setjmp(ulong *jmp, int size)
+{
+ jmp_buf dummy;
+
+ /*
+ * We cannot rely on the struct name that jmp_buf uses, so use a
+ * local variable here
+ */
+ if (size < sizeof(dummy)) {
+ printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n",
+ size, sizeof(jmp_buf));
+ return -ENOSPC;
+ }
+
+ return setjmp((struct __jmp_buf_tag *)jmp);
+}
+
+void os_longjmp(ulong *jmp, int ret)
+{
+ longjmp((struct __jmp_buf_tag *)jmp, ret);
+}