+// 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>
return read(fd, buf, count);
}
-ssize_t os_read_no_block(int fd, void *buf, size_t count)
-{
- const int flags = fcntl(fd, F_GETFL, 0);
-
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- return os_read(fd, buf, count);
-}
-
ssize_t os_write(int fd, const void *buf, size_t count)
{
return write(fd, buf, count);
if (os_flags & OS_O_CREAT)
flags |= O_CREAT;
+ if (os_flags & OS_O_TRUNC)
+ flags |= O_TRUNC;
return open(pathname, flags, 0777);
}
exit(exit_code);
}
+int os_write_file(const char *fname, const void *buf, int size)
+{
+ int fd;
+
+ fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC);
+ if (fd < 0) {
+ printf("Cannot open file '%s'\n", fname);
+ return -EIO;
+ }
+ if (os_write(fd, buf, size) != size) {
+ printf("Cannot write to file '%s'\n", fname);
+ os_close(fd);
+ return -EIO;
+ }
+ os_close(fd);
+
+ return 0;
+}
+
+int os_read_file(const char *fname, void **bufp, int *sizep)
+{
+ off_t size;
+ int ret = -EIO;
+ int fd;
+
+ fd = os_open(fname, OS_O_RDONLY);
+ if (fd < 0) {
+ printf("Cannot open file '%s'\n", fname);
+ goto err;
+ }
+ size = os_lseek(fd, 0, OS_SEEK_END);
+ if (size < 0) {
+ printf("Cannot seek to end of file '%s'\n", fname);
+ goto err;
+ }
+ if (os_lseek(fd, 0, OS_SEEK_SET) < 0) {
+ printf("Cannot seek to start of file '%s'\n", fname);
+ goto err;
+ }
+ *bufp = os_malloc(size);
+ if (!*bufp) {
+ printf("Not enough memory to read file '%s'\n", fname);
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (os_read(fd, *bufp, size) != size) {
+ printf("Cannot read from file '%s'\n", fname);
+ goto err;
+ }
+ os_close(fd);
+ *sizep = size;
+
+ return 0;
+err:
+ os_close(fd);
+ return ret;
+}
+
/* Restore tty state when we exit */
static struct termios orig_term;
static bool term_setup;
+static bool term_nonblock;
void os_fd_restore(void)
{
if (term_setup) {
+ int flags;
+
tcsetattr(0, TCSANOW, &orig_term);
+ if (term_nonblock) {
+ flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+ }
term_setup = false;
}
}
void os_tty_raw(int fd, bool allow_sigs)
{
struct termios term;
+ int flags;
if (term_setup)
return;
if (tcsetattr(fd, TCSANOW, &term))
return;
+ flags = fcntl(fd, F_GETFL, 0);
+ if (!(flags & O_NONBLOCK)) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ return;
+ term_nonblock = true;
+ }
+
term_setup = true;
atexit(os_fd_restore);
}
void *os_malloc(size_t length)
{
struct os_mem_hdr *hdr;
+ int page_size = getpagesize();
- hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE,
+ /*
+ * Use an address that is hopefully available to us so that pointers
+ * to this memory are fairly obvious. If we end up with a different
+ * address, that's fine too.
+ */
+ hdr = mmap((void *)0x10000000, length + page_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (hdr == MAP_FAILED)
return NULL;
hdr->length = length;
- return hdr + 1;
+ return (void *)hdr + page_size;
}
void os_free(void *ptr)
while (node) {
next = node->next;
- free(node);
+ os_free(node);
node = next;
}
}
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;
- fname = malloc(len);
+ /* Create a buffer upfront, with typically sufficient size */
+ dirlen = strlen(dirname) + 2;
+ len = dirlen + 256;
+ fname = os_malloc(len);
if (!fname) {
ret = -ENOMEM;
goto done;
}
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 = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1);
if (!next) {
os_dirent_free(head);
ret = -ENOMEM;
goto done;
}
+ if (dirlen + strlen(entry->d_name) > len) {
+ len = dirlen + strlen(entry->d_name);
+ old_fname = fname;
+ fname = os_realloc(fname, len);
+ if (!fname) {
+ os_free(old_fname);
+ os_free(next);
+ os_dirent_free(head);
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
next->next = NULL;
- strcpy(next->name, entry.d_name);
- switch (entry.d_type) {
+ 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);
+ os_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];
return 0;
}
-static int add_args(char ***argvp, const char *add_args[], int count)
+/**
+ * add_args() - Allocate a new argv with the given args
+ *
+ * This is used to create a new argv array with all the old arguments and some
+ * new ones that are passed in
+ *
+ * @argvp: Returns newly allocated args list
+ * @add_args: Arguments to add, each a string
+ * @count: Number of arguments in @add_args
+ * @return 0 if OK, -ENOMEM if out of memory
+ */
+static int add_args(char ***argvp, char *add_args[], int count)
{
- char **argv;
+ char **argv, **ap;
int argc;
- for (argv = *argvp, argc = 0; (*argvp)[argc]; argc++)
+ for (argc = 0; (*argvp)[argc]; argc++)
;
- argv = malloc((argc + count + 1) * sizeof(char *));
+ argv = os_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 *));
+ for (ap = *argvp, argc = 0; *ap; ap++) {
+ char *arg = *ap;
+
+ /* Drop args that we don't want to propagate */
+ if (*arg == '-' && strlen(arg) == 2) {
+ switch (arg[1]) {
+ case 'j':
+ case 'm':
+ ap++;
+ continue;
+ }
+ } else if (!strcmp(arg, "--rm_memory")) {
+ ap++;
+ continue;
+ }
+ argv[argc++] = arg;
+ }
+
memcpy(argv + argc, add_args, count * sizeof(char *));
argv[argc + count] = NULL;
return 0;
}
-int os_jump_to_image(const void *dest, int size)
+/**
+ * os_jump_to_file() - Jump to a new program
+ *
+ * This saves the memory buffer, sets up arguments to the new process, then
+ * execs it.
+ *
+ * @fname: Filename to exec
+ * @return does not return on success, any return value is an error
+ */
+static int os_jump_to_file(const char *fname)
{
struct sandbox_state *state = state_get_current();
- char fname[30], mem_fname[30];
+ char mem_fname[30];
int fd, err;
- const char *extra_args[5];
+ char *extra_args[5];
char **argv = state->argv;
+ int argc;
#ifdef DEBUG
- int argc, i;
+ int 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)
os_fd_restore();
extra_args[0] = "-j";
- extra_args[1] = fname;
+ extra_args[1] = (char *)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]));
+ argc = 4;
+ if (state->ram_buf_rm)
+ extra_args[argc++] = "--rm_memory";
+ err = add_args(&argv, extra_args, argc);
if (err)
return err;
+ argv[0] = (char *)fname;
#ifdef DEBUG
for (i = 0; argv[i]; i++)
os_exit(2);
err = execv(fname, argv);
- free(argv);
- if (err)
+ os_free(argv);
+ if (err) {
+ perror("Unable to run image");
+ printf("Image filename '%s'\n", mem_fname);
return err;
+ }
return unlink(fname);
}
+int os_jump_to_image(const void *dest, int size)
+{
+ char fname[30];
+ int err;
+
+ err = make_exec(fname, dest, size);
+ if (err)
+ return err;
+
+ return os_jump_to_file(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);
+ const char *suffix;
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")) {
+ suffix = fname + len - 4;
+
+ /* If we are TPL, boot to SPL */
+ if (!strcmp(suffix, "-tpl")) {
+ fname[len - 3] = 's';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+
+ /* Look for 'u-boot-tpl' in the tpl/ directory */
+ p = strstr(fname, "/tpl/");
+ if (p) {
+ p[1] = 's';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+ return -ENOENT;
+ }
+
+ /* Look for 'u-boot' in the same directory as 'u-boot-spl' */
+ if (!strcmp(suffix, "-spl")) {
fname[len - 4] = '\0';
fd = os_open(fname, O_RDONLY);
if (fd >= 0) {
}
/* Look for 'u-boot' in the parent directory of spl/ */
- p = strstr(fname, "/spl/");
+ p = strstr(fname, "spl/");
if (p) {
- strcpy(p, p + 4);
+ /* Remove the "spl" characters */
+ memmove(p, p + 4, strlen(p + 4) + 1);
fd = os_open(fname, O_RDONLY);
if (fd >= 0) {
close(fd);
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);
+ return os_jump_to_file(fname);
}
void os_localtime(struct rtc_time *rt)
rt->tm_yday = tm->tm_yday;
rt->tm_isdst = tm->tm_isdst;
}
+
+void os_abort(void)
+{
+ abort();
+}
+
+int os_mprotect_allow(void *start, size_t len)
+{
+ int page_size = getpagesize();
+
+ /* Move start to the start of a page, len to the end */
+ start = (void *)(((ulong)start) & ~(page_size - 1));
+ len = (len + page_size * 2) & ~(page_size - 1);
+
+ return mprotect(start, len, PROT_READ | PROT_WRITE);
+}