uboot/arch/sandbox/cpu/os.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011 The Chromium OS Authors.
   4 */
   5
   6#define _GNU_SOURCE
   7
   8#include <dirent.h>
   9#include <errno.h>
  10#include <fcntl.h>
  11#include <getopt.h>
  12#include <setjmp.h>
  13#include <signal.h>
  14#include <stdio.h>
  15#include <stdint.h>
  16#include <stdlib.h>
  17#include <string.h>
  18#include <termios.h>
  19#include <time.h>
  20#include <ucontext.h>
  21#include <unistd.h>
  22#include <sys/mman.h>
  23#include <sys/stat.h>
  24#include <sys/time.h>
  25#include <sys/types.h>
  26#include <linux/compiler_attributes.h>
  27#include <linux/types.h>
  28
  29#include <asm/getopt.h>
  30#include <asm/sections.h>
  31#include <asm/state.h>
  32#include <os.h>
  33#include <rtc_def.h>
  34
  35/* Environment variable for time offset */
  36#define ENV_TIME_OFFSET "UBOOT_SB_TIME_OFFSET"
  37
  38/* Operating System Interface */
  39
  40struct os_mem_hdr {
  41        size_t length;          /* number of bytes in the block */
  42};
  43
  44ssize_t os_read(int fd, void *buf, size_t count)
  45{
  46        return read(fd, buf, count);
  47}
  48
  49ssize_t os_write(int fd, const void *buf, size_t count)
  50{
  51        return write(fd, buf, count);
  52}
  53
  54off_t os_lseek(int fd, off_t offset, int whence)
  55{
  56        if (whence == OS_SEEK_SET)
  57                whence = SEEK_SET;
  58        else if (whence == OS_SEEK_CUR)
  59                whence = SEEK_CUR;
  60        else if (whence == OS_SEEK_END)
  61                whence = SEEK_END;
  62        else
  63                os_exit(1);
  64        return lseek(fd, offset, whence);
  65}
  66
  67int os_open(const char *pathname, int os_flags)
  68{
  69        int flags;
  70
  71        switch (os_flags & OS_O_MASK) {
  72        case OS_O_RDONLY:
  73        default:
  74                flags = O_RDONLY;
  75                break;
  76
  77        case OS_O_WRONLY:
  78                flags = O_WRONLY;
  79                break;
  80
  81        case OS_O_RDWR:
  82                flags = O_RDWR;
  83                break;
  84        }
  85
  86        if (os_flags & OS_O_CREAT)
  87                flags |= O_CREAT;
  88        if (os_flags & OS_O_TRUNC)
  89                flags |= O_TRUNC;
  90        /*
  91         * During a cold reset execv() is used to relaunch the U-Boot binary.
  92         * We must ensure that all files are closed in this case.
  93         */
  94        flags |= O_CLOEXEC;
  95
  96        return open(pathname, flags, 0777);
  97}
  98
  99int os_close(int fd)
 100{
 101        /* Do not close the console input */
 102        if (fd)
 103                return close(fd);
 104        return -1;
 105}
 106
 107int os_unlink(const char *pathname)
 108{
 109        return unlink(pathname);
 110}
 111
 112void os_exit(int exit_code)
 113{
 114        exit(exit_code);
 115}
 116
 117int os_write_file(const char *fname, const void *buf, int size)
 118{
 119        int fd;
 120
 121        fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC);
 122        if (fd < 0) {
 123                printf("Cannot open file '%s'\n", fname);
 124                return -EIO;
 125        }
 126        if (os_write(fd, buf, size) != size) {
 127                printf("Cannot write to file '%s'\n", fname);
 128                os_close(fd);
 129                return -EIO;
 130        }
 131        os_close(fd);
 132
 133        return 0;
 134}
 135
 136int os_filesize(int fd)
 137{
 138        off_t size;
 139
 140        size = os_lseek(fd, 0, OS_SEEK_END);
 141        if (size < 0)
 142                return -errno;
 143        if (os_lseek(fd, 0, OS_SEEK_SET) < 0)
 144                return -errno;
 145
 146        return size;
 147}
 148
 149int os_read_file(const char *fname, void **bufp, int *sizep)
 150{
 151        off_t size;
 152        int ret = -EIO;
 153        int fd;
 154
 155        fd = os_open(fname, OS_O_RDONLY);
 156        if (fd < 0) {
 157                printf("Cannot open file '%s'\n", fname);
 158                goto err;
 159        }
 160        size = os_filesize(fd);
 161        if (size < 0) {
 162                printf("Cannot get file size of '%s'\n", fname);
 163                goto err;
 164        }
 165
 166        *bufp = os_malloc(size);
 167        if (!*bufp) {
 168                printf("Not enough memory to read file '%s'\n", fname);
 169                ret = -ENOMEM;
 170                goto err;
 171        }
 172        if (os_read(fd, *bufp, size) != size) {
 173                printf("Cannot read from file '%s'\n", fname);
 174                goto err;
 175        }
 176        os_close(fd);
 177        *sizep = size;
 178
 179        return 0;
 180err:
 181        os_close(fd);
 182        return ret;
 183}
 184
 185int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
 186{
 187        void *ptr;
 188        int size;
 189        int ifd;
 190
 191        ifd = os_open(pathname, os_flags);
 192        if (ifd < 0) {
 193                printf("Cannot open file '%s'\n", pathname);
 194                return -EIO;
 195        }
 196        size = os_filesize(ifd);
 197        if (size < 0) {
 198                printf("Cannot get file size of '%s'\n", pathname);
 199                return -EIO;
 200        }
 201
 202        ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, ifd, 0);
 203        if (ptr == MAP_FAILED) {
 204                printf("Can't map file '%s': %s\n", pathname, strerror(errno));
 205                return -EPERM;
 206        }
 207
 208        *bufp = ptr;
 209        *sizep = size;
 210
 211        return 0;
 212}
 213
 214/* Restore tty state when we exit */
 215static struct termios orig_term;
 216static bool term_setup;
 217static bool term_nonblock;
 218
 219void os_fd_restore(void)
 220{
 221        if (term_setup) {
 222                int flags;
 223
 224                tcsetattr(0, TCSANOW, &orig_term);
 225                if (term_nonblock) {
 226                        flags = fcntl(0, F_GETFL, 0);
 227                        fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
 228                }
 229                term_setup = false;
 230        }
 231}
 232
 233static void os_sigint_handler(int sig)
 234{
 235        os_fd_restore();
 236        signal(SIGINT, SIG_DFL);
 237        raise(SIGINT);
 238}
 239
 240static void os_signal_handler(int sig, siginfo_t *info, void *con)
 241{
 242        ucontext_t __maybe_unused *context = con;
 243        unsigned long pc;
 244
 245#if defined(__x86_64__)
 246        pc = context->uc_mcontext.gregs[REG_RIP];
 247#elif defined(__aarch64__)
 248        pc = context->uc_mcontext.pc;
 249#elif defined(__riscv)
 250        pc = context->uc_mcontext.__gregs[REG_PC];
 251#else
 252        const char msg[] =
 253                "\nUnsupported architecture, cannot read program counter\n";
 254
 255        os_write(1, msg, sizeof(msg));
 256        pc = 0;
 257#endif
 258
 259        os_signal_action(sig, pc);
 260}
 261
 262int os_setup_signal_handlers(void)
 263{
 264        struct sigaction act;
 265
 266        act.sa_sigaction = os_signal_handler;
 267        sigemptyset(&act.sa_mask);
 268        act.sa_flags = SA_SIGINFO;
 269        if (sigaction(SIGILL, &act, NULL) ||
 270            sigaction(SIGBUS, &act, NULL) ||
 271            sigaction(SIGSEGV, &act, NULL))
 272                return -1;
 273        return 0;
 274}
 275
 276/* Put tty into raw mode so <tab> and <ctrl+c> work */
 277void os_tty_raw(int fd, bool allow_sigs)
 278{
 279        struct termios term;
 280        int flags;
 281
 282        if (term_setup)
 283                return;
 284
 285        /* If not a tty, don't complain */
 286        if (tcgetattr(fd, &orig_term))
 287                return;
 288
 289        term = orig_term;
 290        term.c_iflag = IGNBRK | IGNPAR;
 291        term.c_oflag = OPOST | ONLCR;
 292        term.c_cflag = CS8 | CREAD | CLOCAL;
 293        term.c_lflag = allow_sigs ? ISIG : 0;
 294        if (tcsetattr(fd, TCSANOW, &term))
 295                return;
 296
 297        flags = fcntl(fd, F_GETFL, 0);
 298        if (!(flags & O_NONBLOCK)) {
 299                if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
 300                        return;
 301                term_nonblock = true;
 302        }
 303
 304        term_setup = true;
 305        atexit(os_fd_restore);
 306        signal(SIGINT, os_sigint_handler);
 307}
 308
 309/*
 310 * Provide our own malloc so we don't use space in the sandbox ram_buf for
 311 * allocations that are internal to sandbox, or need to be done before U-Boot's
 312 * malloc() is ready.
 313 */
 314void *os_malloc(size_t length)
 315{
 316        int page_size = getpagesize();
 317        struct os_mem_hdr *hdr;
 318
 319        if (!length)
 320                return NULL;
 321        /*
 322         * Use an address that is hopefully available to us so that pointers
 323         * to this memory are fairly obvious. If we end up with a different
 324         * address, that's fine too.
 325         */
 326        hdr = mmap((void *)0x10000000, length + page_size,
 327                   PROT_READ | PROT_WRITE | PROT_EXEC,
 328                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 329        if (hdr == MAP_FAILED)
 330                return NULL;
 331        hdr->length = length;
 332
 333        return (void *)hdr + page_size;
 334}
 335
 336void os_free(void *ptr)
 337{
 338        int page_size = getpagesize();
 339        struct os_mem_hdr *hdr;
 340
 341        if (ptr) {
 342                hdr = ptr - page_size;
 343                munmap(hdr, hdr->length + page_size);
 344        }
 345}
 346
 347/* These macros are from kernel.h but not accessible in this file */
 348#define ALIGN(x, a)             __ALIGN_MASK((x), (typeof(x))(a) - 1)
 349#define __ALIGN_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 350
 351/*
 352 * Provide our own malloc so we don't use space in the sandbox ram_buf for
 353 * allocations that are internal to sandbox, or need to be done before U-Boot's
 354 * malloc() is ready.
 355 */
 356void *os_realloc(void *ptr, size_t length)
 357{
 358        int page_size = getpagesize();
 359        struct os_mem_hdr *hdr;
 360        void *new_ptr;
 361
 362        /* Reallocating a NULL pointer is just an alloc */
 363        if (!ptr)
 364                return os_malloc(length);
 365
 366        /* Changing a length to 0 is just a free */
 367        if (length) {
 368                os_free(ptr);
 369                return NULL;
 370        }
 371
 372        /*
 373         * If the new size is the same number of pages as the old, nothing to
 374         * do. There isn't much point in shrinking things
 375         */
 376        hdr = ptr - page_size;
 377        if (ALIGN(length, page_size) <= ALIGN(hdr->length, page_size))
 378                return ptr;
 379
 380        /* We have to grow it, so allocate something new */
 381        new_ptr = os_malloc(length);
 382        memcpy(new_ptr, ptr, hdr->length);
 383        os_free(ptr);
 384
 385        return new_ptr;
 386}
 387
 388void os_usleep(unsigned long usec)
 389{
 390        usleep(usec);
 391}
 392
 393uint64_t __attribute__((no_instrument_function)) os_get_nsec(void)
 394{
 395#if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK)
 396        struct timespec tp;
 397        if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) {
 398                struct timeval tv;
 399
 400                gettimeofday(&tv, NULL);
 401                tp.tv_sec = tv.tv_sec;
 402                tp.tv_nsec = tv.tv_usec * 1000;
 403        }
 404        return tp.tv_sec * 1000000000ULL + tp.tv_nsec;
 405#else
 406        struct timeval tv;
 407        gettimeofday(&tv, NULL);
 408        return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
 409#endif
 410}
 411
 412static char *short_opts;
 413static struct option *long_opts;
 414
 415int os_parse_args(struct sandbox_state *state, int argc, char *argv[])
 416{
 417        struct sandbox_cmdline_option **sb_opt =
 418                __u_boot_sandbox_option_start();
 419        size_t num_options = __u_boot_sandbox_option_count();
 420        size_t i;
 421
 422        int hidden_short_opt;
 423        size_t si;
 424
 425        int c;
 426
 427        if (short_opts || long_opts)
 428                return 1;
 429
 430        state->argc = argc;
 431        state->argv = argv;
 432
 433        /* dynamically construct the arguments to the system getopt_long */
 434        short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1);
 435        long_opts = os_malloc(sizeof(*long_opts) * (num_options + 1));
 436        if (!short_opts || !long_opts)
 437                return 1;
 438
 439        /*
 440         * getopt_long requires "val" to be unique (since that is what the
 441         * func returns), so generate unique values automatically for flags
 442         * that don't have a short option.  pick 0x100 as that is above the
 443         * single byte range (where ASCII/ISO-XXXX-X charsets live).
 444         */
 445        hidden_short_opt = 0x100;
 446        si = 0;
 447        for (i = 0; i < num_options; ++i) {
 448                long_opts[i].name = sb_opt[i]->flag;
 449                long_opts[i].has_arg = sb_opt[i]->has_arg ?
 450                        required_argument : no_argument;
 451                long_opts[i].flag = NULL;
 452
 453                if (sb_opt[i]->flag_short) {
 454                        short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short;
 455                        if (long_opts[i].has_arg == required_argument)
 456                                short_opts[si++] = ':';
 457                } else
 458                        long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++;
 459        }
 460        short_opts[si] = '\0';
 461
 462        /* we need to handle output ourselves since u-boot provides printf */
 463        opterr = 0;
 464
 465        memset(&long_opts[num_options], '\0', sizeof(*long_opts));
 466        /*
 467         * walk all of the options the user gave us on the command line,
 468         * figure out what u-boot option structure they belong to (via
 469         * the unique short val key), and call the appropriate callback.
 470         */
 471        while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
 472                for (i = 0; i < num_options; ++i) {
 473                        if (sb_opt[i]->flag_short == c) {
 474                                if (sb_opt[i]->callback(state, optarg)) {
 475                                        state->parse_err = sb_opt[i]->flag;
 476                                        return 0;
 477                                }
 478                                break;
 479                        }
 480                }
 481                if (i == num_options) {
 482                        /*
 483                         * store the faulting flag for later display.  we have to
 484                         * store the flag itself as the getopt parsing itself is
 485                         * tricky: need to handle the following flags (assume all
 486                         * of the below are unknown):
 487                         *   -a        optopt='a' optind=<next>
 488                         *   -abbbb    optopt='a' optind=<this>
 489                         *   -aaaaa    optopt='a' optind=<this>
 490                         *   --a       optopt=0   optind=<this>
 491                         * as you can see, it is impossible to determine the exact
 492                         * faulting flag without doing the parsing ourselves, so
 493                         * we just report the specific flag that failed.
 494                         */
 495                        if (optopt) {
 496                                static char parse_err[3] = { '-', 0, '\0', };
 497                                parse_err[1] = optopt;
 498                                state->parse_err = parse_err;
 499                        } else
 500                                state->parse_err = argv[optind - 1];
 501                        break;
 502                }
 503        }
 504
 505        return 0;
 506}
 507
 508void os_dirent_free(struct os_dirent_node *node)
 509{
 510        struct os_dirent_node *next;
 511
 512        while (node) {
 513                next = node->next;
 514                os_free(node);
 515                node = next;
 516        }
 517}
 518
 519int os_dirent_ls(const char *dirname, struct os_dirent_node **headp)
 520{
 521        struct dirent *entry;
 522        struct os_dirent_node *head, *node, *next;
 523        struct stat buf;
 524        DIR *dir;
 525        int ret;
 526        char *fname;
 527        char *old_fname;
 528        int len;
 529        int dirlen;
 530
 531        *headp = NULL;
 532        dir = opendir(dirname);
 533        if (!dir)
 534                return -1;
 535
 536        /* Create a buffer upfront, with typically sufficient size */
 537        dirlen = strlen(dirname) + 2;
 538        len = dirlen + 256;
 539        fname = os_malloc(len);
 540        if (!fname) {
 541                ret = -ENOMEM;
 542                goto done;
 543        }
 544
 545        for (node = head = NULL;; node = next) {
 546                errno = 0;
 547                entry = readdir(dir);
 548                if (!entry) {
 549                        ret = errno;
 550                        break;
 551                }
 552                next = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1);
 553                if (!next) {
 554                        os_dirent_free(head);
 555                        ret = -ENOMEM;
 556                        goto done;
 557                }
 558                if (dirlen + strlen(entry->d_name) > len) {
 559                        len = dirlen + strlen(entry->d_name);
 560                        old_fname = fname;
 561                        fname = os_realloc(fname, len);
 562                        if (!fname) {
 563                                os_free(old_fname);
 564                                os_free(next);
 565                                os_dirent_free(head);
 566                                ret = -ENOMEM;
 567                                goto done;
 568                        }
 569                }
 570                next->next = NULL;
 571                strcpy(next->name, entry->d_name);
 572                switch (entry->d_type) {
 573                case DT_REG:
 574                        next->type = OS_FILET_REG;
 575                        break;
 576                case DT_DIR:
 577                        next->type = OS_FILET_DIR;
 578                        break;
 579                case DT_LNK:
 580                        next->type = OS_FILET_LNK;
 581                        break;
 582                default:
 583                        next->type = OS_FILET_UNKNOWN;
 584                }
 585                next->size = 0;
 586                snprintf(fname, len, "%s/%s", dirname, next->name);
 587                if (!stat(fname, &buf))
 588                        next->size = buf.st_size;
 589                if (node)
 590                        node->next = next;
 591                else
 592                        head = next;
 593        }
 594        *headp = head;
 595
 596done:
 597        closedir(dir);
 598        os_free(fname);
 599        return ret;
 600}
 601
 602const char *os_dirent_typename[OS_FILET_COUNT] = {
 603        "   ",
 604        "SYM",
 605        "DIR",
 606        "???",
 607};
 608
 609const char *os_dirent_get_typename(enum os_dirent_t type)
 610{
 611        if (type >= OS_FILET_REG && type < OS_FILET_COUNT)
 612                return os_dirent_typename[type];
 613
 614        return os_dirent_typename[OS_FILET_UNKNOWN];
 615}
 616
 617int os_get_filesize(const char *fname, loff_t *size)
 618{
 619        struct stat buf;
 620        int ret;
 621
 622        ret = stat(fname, &buf);
 623        if (ret)
 624                return ret;
 625        *size = buf.st_size;
 626        return 0;
 627}
 628
 629void os_putc(int ch)
 630{
 631        putchar(ch);
 632}
 633
 634void os_puts(const char *str)
 635{
 636        while (*str)
 637                os_putc(*str++);
 638}
 639
 640int os_write_ram_buf(const char *fname)
 641{
 642        struct sandbox_state *state = state_get_current();
 643        int fd, ret;
 644
 645        fd = open(fname, O_CREAT | O_WRONLY, 0777);
 646        if (fd < 0)
 647                return -ENOENT;
 648        ret = write(fd, state->ram_buf, state->ram_size);
 649        close(fd);
 650        if (ret != state->ram_size)
 651                return -EIO;
 652
 653        return 0;
 654}
 655
 656int os_read_ram_buf(const char *fname)
 657{
 658        struct sandbox_state *state = state_get_current();
 659        int fd, ret;
 660        loff_t size;
 661
 662        ret = os_get_filesize(fname, &size);
 663        if (ret < 0)
 664                return ret;
 665        if (size != state->ram_size)
 666                return -ENOSPC;
 667        fd = open(fname, O_RDONLY);
 668        if (fd < 0)
 669                return -ENOENT;
 670
 671        ret = read(fd, state->ram_buf, state->ram_size);
 672        close(fd);
 673        if (ret != state->ram_size)
 674                return -EIO;
 675
 676        return 0;
 677}
 678
 679static int make_exec(char *fname, const void *data, int size)
 680{
 681        int fd;
 682
 683        strcpy(fname, "/tmp/u-boot.jump.XXXXXX");
 684        fd = mkstemp(fname);
 685        if (fd < 0)
 686                return -ENOENT;
 687        if (write(fd, data, size) < 0)
 688                return -EIO;
 689        close(fd);
 690        if (chmod(fname, 0777))
 691                return -ENOEXEC;
 692
 693        return 0;
 694}
 695
 696/**
 697 * add_args() - Allocate a new argv with the given args
 698 *
 699 * This is used to create a new argv array with all the old arguments and some
 700 * new ones that are passed in
 701 *
 702 * @argvp:  Returns newly allocated args list
 703 * @add_args: Arguments to add, each a string
 704 * @count: Number of arguments in @add_args
 705 * @return 0 if OK, -ENOMEM if out of memory
 706 */
 707static int add_args(char ***argvp, char *add_args[], int count)
 708{
 709        char **argv, **ap;
 710        int argc;
 711
 712        for (argc = 0; (*argvp)[argc]; argc++)
 713                ;
 714
 715        argv = os_malloc((argc + count + 1) * sizeof(char *));
 716        if (!argv) {
 717                printf("Out of memory for %d argv\n", count);
 718                return -ENOMEM;
 719        }
 720        for (ap = *argvp, argc = 0; *ap; ap++) {
 721                char *arg = *ap;
 722
 723                /* Drop args that we don't want to propagate */
 724                if (*arg == '-' && strlen(arg) == 2) {
 725                        switch (arg[1]) {
 726                        case 'j':
 727                        case 'm':
 728                                ap++;
 729                                continue;
 730                        }
 731                } else if (!strcmp(arg, "--rm_memory")) {
 732                        continue;
 733                }
 734                argv[argc++] = arg;
 735        }
 736
 737        memcpy(argv + argc, add_args, count * sizeof(char *));
 738        argv[argc + count] = NULL;
 739
 740        *argvp = argv;
 741        return 0;
 742}
 743
 744/**
 745 * os_jump_to_file() - Jump to a new program
 746 *
 747 * This saves the memory buffer, sets up arguments to the new process, then
 748 * execs it.
 749 *
 750 * @fname: Filename to exec
 751 * @return does not return on success, any return value is an error
 752 */
 753static int os_jump_to_file(const char *fname, bool delete_it)
 754{
 755        struct sandbox_state *state = state_get_current();
 756        char mem_fname[30];
 757        int fd, err;
 758        char *extra_args[5];
 759        char **argv = state->argv;
 760        int argc;
 761#ifdef DEBUG
 762        int i;
 763#endif
 764
 765        strcpy(mem_fname, "/tmp/u-boot.mem.XXXXXX");
 766        fd = mkstemp(mem_fname);
 767        if (fd < 0)
 768                return -ENOENT;
 769        close(fd);
 770        err = os_write_ram_buf(mem_fname);
 771        if (err)
 772                return err;
 773
 774        os_fd_restore();
 775
 776        argc = 0;
 777        if (delete_it) {
 778                extra_args[argc++] = "-j";
 779                extra_args[argc++] = (char *)fname;
 780        }
 781        extra_args[argc++] = "-m";
 782        extra_args[argc++] = mem_fname;
 783        if (state->ram_buf_rm)
 784                extra_args[argc++] = "--rm_memory";
 785        err = add_args(&argv, extra_args, argc);
 786        if (err)
 787                return err;
 788        argv[0] = (char *)fname;
 789
 790#ifdef DEBUG
 791        for (i = 0; argv[i]; i++)
 792                printf("%d %s\n", i, argv[i]);
 793#endif
 794
 795        if (state_uninit())
 796                os_exit(2);
 797
 798        err = execv(fname, argv);
 799        os_free(argv);
 800        if (err) {
 801                perror("Unable to run image");
 802                printf("Image filename '%s'\n", fname);
 803                return err;
 804        }
 805
 806        if (delete_it)
 807                return unlink(fname);
 808
 809        return -EFAULT;
 810}
 811
 812int os_jump_to_image(const void *dest, int size)
 813{
 814        char fname[30];
 815        int err;
 816
 817        err = make_exec(fname, dest, size);
 818        if (err)
 819                return err;
 820
 821        return os_jump_to_file(fname, true);
 822}
 823
 824int os_find_u_boot(char *fname, int maxlen, bool use_img,
 825                   const char *cur_prefix, const char *next_prefix)
 826{
 827        struct sandbox_state *state = state_get_current();
 828        const char *progname = state->argv[0];
 829        int len = strlen(progname);
 830        char subdir[10];
 831        char *suffix;
 832        char *p;
 833        int fd;
 834
 835        if (len >= maxlen || len < 4)
 836                return -ENOSPC;
 837
 838        strcpy(fname, progname);
 839        suffix = fname + len - 4;
 840
 841        /* Change the existing suffix to the new one */
 842        if (*suffix != '-')
 843                return -EINVAL;
 844
 845        if (*next_prefix)
 846                strcpy(suffix + 1, next_prefix);  /* e.g. "-tpl" to "-spl" */
 847        else
 848                *suffix = '\0';  /* e.g. "-spl" to "" */
 849        fd = os_open(fname, O_RDONLY);
 850        if (fd >= 0) {
 851                close(fd);
 852                return 0;
 853        }
 854
 855        /*
 856         * We didn't find it, so try looking for 'u-boot-xxx' in the xxx/
 857         * directory. Replace the old dirname with the new one.
 858         */
 859        snprintf(subdir, sizeof(subdir), "/%s/", cur_prefix);
 860        p = strstr(fname, subdir);
 861        if (p) {
 862                if (*next_prefix)
 863                        /* e.g. ".../tpl/u-boot-spl"  to "../spl/u-boot-spl" */
 864                        memcpy(p + 1, next_prefix, strlen(next_prefix));
 865                else
 866                        /* e.g. ".../spl/u-boot" to ".../u-boot" */
 867                        strcpy(p, p + 1 + strlen(cur_prefix));
 868                if (use_img)
 869                        strcat(p, ".img");
 870
 871                fd = os_open(fname, O_RDONLY);
 872                if (fd >= 0) {
 873                        close(fd);
 874                        return 0;
 875                }
 876        }
 877
 878        return -ENOENT;
 879}
 880
 881int os_spl_to_uboot(const char *fname)
 882{
 883        struct sandbox_state *state = state_get_current();
 884
 885        /* U-Boot will delete ram buffer after read: "--rm_memory"*/
 886        state->ram_buf_rm = true;
 887
 888        return os_jump_to_file(fname, false);
 889}
 890
 891long os_get_time_offset(void)
 892{
 893        const char *offset;
 894
 895        offset = getenv(ENV_TIME_OFFSET);
 896        if (offset)
 897                return strtol(offset, NULL, 0);
 898        return 0;
 899}
 900
 901void os_set_time_offset(long offset)
 902{
 903        char buf[21];
 904        int ret;
 905
 906        snprintf(buf, sizeof(buf), "%ld", offset);
 907        ret = setenv(ENV_TIME_OFFSET, buf, true);
 908        if (ret)
 909                printf("Could not set environment variable %s\n",
 910                       ENV_TIME_OFFSET);
 911}
 912
 913void os_localtime(struct rtc_time *rt)
 914{
 915        time_t t = time(NULL);
 916        struct tm *tm;
 917
 918        tm = localtime(&t);
 919        rt->tm_sec = tm->tm_sec;
 920        rt->tm_min = tm->tm_min;
 921        rt->tm_hour = tm->tm_hour;
 922        rt->tm_mday = tm->tm_mday;
 923        rt->tm_mon = tm->tm_mon + 1;
 924        rt->tm_year = tm->tm_year + 1900;
 925        rt->tm_wday = tm->tm_wday;
 926        rt->tm_yday = tm->tm_yday;
 927        rt->tm_isdst = tm->tm_isdst;
 928}
 929
 930void os_abort(void)
 931{
 932        abort();
 933}
 934
 935int os_mprotect_allow(void *start, size_t len)
 936{
 937        int page_size = getpagesize();
 938
 939        /* Move start to the start of a page, len to the end */
 940        start = (void *)(((ulong)start) & ~(page_size - 1));
 941        len = (len + page_size * 2) & ~(page_size - 1);
 942
 943        return mprotect(start, len, PROT_READ | PROT_WRITE);
 944}
 945
 946void *os_find_text_base(void)
 947{
 948        char line[500];
 949        void *base = NULL;
 950        int len;
 951        int fd;
 952
 953        /*
 954         * This code assumes that the first line of /proc/self/maps holds
 955         * information about the text, for example:
 956         *
 957         * 5622d9907000-5622d9a55000 r-xp 00000000 08:01 15067168   u-boot
 958         *
 959         * The first hex value is assumed to be the address.
 960         *
 961         * This is tested in Linux 4.15.
 962         */
 963        fd = open("/proc/self/maps", O_RDONLY);
 964        if (fd == -1)
 965                return NULL;
 966        len = read(fd, line, sizeof(line));
 967        if (len > 0) {
 968                char *end = memchr(line, '-', len);
 969
 970                if (end) {
 971                        uintptr_t addr;
 972
 973                        *end = '\0';
 974                        if (sscanf(line, "%zx", &addr) == 1)
 975                                base = (void *)addr;
 976                }
 977        }
 978        close(fd);
 979
 980        return base;
 981}
 982
 983void os_relaunch(char *argv[])
 984{
 985        execv(argv[0], argv);
 986        os_exit(1);
 987}
 988