uboot/arch/sandbox/cpu/start.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011-2012 The Chromium OS Authors.
   4 */
   5
   6#include <common.h>
   7#include <command.h>
   8#include <dm/root.h>
   9#include <efi_loader.h>
  10#include <errno.h>
  11#include <init.h>
  12#include <log.h>
  13#include <os.h>
  14#include <cli.h>
  15#include <sort.h>
  16#include <asm/getopt.h>
  17#include <asm/global_data.h>
  18#include <asm/io.h>
  19#include <asm/malloc.h>
  20#include <asm/sections.h>
  21#include <asm/state.h>
  22#include <linux/ctype.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26static char **os_argv;
  27
  28/* Compare two options so that they can be sorted into alphabetical order */
  29static int h_compare_opt(const void *p1, const void *p2)
  30{
  31        const struct sandbox_cmdline_option *opt1 = p1;
  32        const struct sandbox_cmdline_option *opt2 = p2;
  33        const char *str1, *str2;
  34        char flag1[2], flag2[2];
  35
  36        opt1 = *(struct sandbox_cmdline_option **)p1;
  37        opt2 = *(struct sandbox_cmdline_option **)p2;
  38        flag1[1] = '\0';
  39        flag2[1] = '\0';
  40
  41        *flag1 = opt1->flag_short < 0x100 ? opt1->flag_short : '\0';
  42        *flag2 = opt2->flag_short < 0x100 ? opt2->flag_short : '\0';
  43
  44        str1 = *flag1 ? flag1 : opt1->flag;
  45        str2 = *flag2 ? flag2 : opt2->flag;
  46
  47        /*
  48         * Force lower-case flags to come before upper-case ones. We only
  49         * support upper-case for short flags.
  50         */
  51        if (isalpha(*str1) && isalpha(*str2) &&
  52            tolower(*str1) == tolower(*str2))
  53                return isupper(*str1) - isupper(*str2);
  54
  55        return strcasecmp(str1, str2);
  56}
  57
  58int sandbox_early_getopt_check(void)
  59{
  60        struct sandbox_state *state = state_get_current();
  61        struct sandbox_cmdline_option **sb_opt =
  62                __u_boot_sandbox_option_start();
  63        size_t num_options = __u_boot_sandbox_option_count();
  64        size_t i;
  65        int max_arg_len, max_noarg_len;
  66        struct sandbox_cmdline_option **sorted_opt;
  67        int size;
  68
  69        /* parse_err will be a string of the faulting option */
  70        if (!state->parse_err)
  71                return 0;
  72
  73        if (strcmp(state->parse_err, "help")) {
  74                printf("u-boot: error: failed while parsing option: %s\n"
  75                        "\ttry running with --help for more information.\n",
  76                        state->parse_err);
  77                os_exit(1);
  78        }
  79
  80        printf(
  81                "u-boot, a command line test interface to U-Boot\n\n"
  82                "Usage: u-boot [options]\n"
  83                "Options:\n");
  84
  85        max_arg_len = 0;
  86        for (i = 0; i < num_options; ++i)
  87                max_arg_len = max((int)strlen(sb_opt[i]->flag), max_arg_len);
  88        max_noarg_len = max_arg_len + 7;
  89
  90        /* Sort the options */
  91        size = sizeof(*sorted_opt) * num_options;
  92        sorted_opt = os_malloc(size);
  93        if (!sorted_opt) {
  94                printf("No memory to sort options\n");
  95                os_exit(1);
  96        }
  97        memcpy(sorted_opt, sb_opt, size);
  98        qsort(sorted_opt, num_options, sizeof(*sorted_opt), h_compare_opt);
  99
 100        for (i = 0; i < num_options; ++i) {
 101                struct sandbox_cmdline_option *opt = sorted_opt[i];
 102
 103                /* first output the short flag if it has one */
 104                if (opt->flag_short >= 0x100)
 105                        printf("      ");
 106                else
 107                        printf("  -%c, ", opt->flag_short);
 108
 109                /* then the long flag */
 110                if (opt->has_arg)
 111                        printf("--%-*s <arg> ", max_arg_len, opt->flag);
 112                else
 113                        printf("--%-*s", max_noarg_len, opt->flag);
 114
 115                /* finally the help text */
 116                printf("  %s\n", opt->help);
 117        }
 118
 119        os_exit(0);
 120}
 121
 122int misc_init_f(void)
 123{
 124        return sandbox_early_getopt_check();
 125}
 126
 127static int sandbox_cmdline_cb_help(struct sandbox_state *state, const char *arg)
 128{
 129        /* just flag to sandbox_early_getopt_check to show usage */
 130        return 1;
 131}
 132SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
 133
 134#ifndef CONFIG_SPL_BUILD
 135int sandbox_main_loop_init(void)
 136{
 137        struct sandbox_state *state = state_get_current();
 138
 139        /* Execute command if required */
 140        if (state->cmd || state->run_distro_boot) {
 141                int retval = 0;
 142
 143                cli_init();
 144
 145#ifdef CONFIG_CMDLINE
 146                if (state->cmd)
 147                        retval = run_command_list(state->cmd, -1, 0);
 148
 149                if (state->run_distro_boot)
 150                        retval = cli_simple_run_command("run distro_bootcmd",
 151                                                        0);
 152#endif
 153                if (!state->interactive)
 154                        os_exit(retval);
 155        }
 156
 157        return 0;
 158}
 159#endif
 160
 161static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
 162                                      const char *arg)
 163{
 164        state->run_distro_boot = true;
 165        return 0;
 166}
 167SANDBOX_CMDLINE_OPT_SHORT(boot, 'b', 0, "Run distro boot commands");
 168
 169static int sandbox_cmdline_cb_command(struct sandbox_state *state,
 170                                      const char *arg)
 171{
 172        state->cmd = arg;
 173        return 0;
 174}
 175SANDBOX_CMDLINE_OPT_SHORT(command, 'c', 1, "Execute U-Boot command");
 176
 177static int sandbox_cmdline_cb_fdt(struct sandbox_state *state, const char *arg)
 178{
 179        state->fdt_fname = arg;
 180        return 0;
 181}
 182SANDBOX_CMDLINE_OPT_SHORT(fdt, 'd', 1, "Specify U-Boot's control FDT");
 183
 184static int sandbox_cmdline_cb_default_fdt(struct sandbox_state *state,
 185                                          const char *arg)
 186{
 187        const char *fmt = "%s.dtb";
 188        char *fname;
 189        int len;
 190
 191        len = strlen(state->argv[0]) + strlen(fmt) + 1;
 192        fname = os_malloc(len);
 193        if (!fname)
 194                return -ENOMEM;
 195        snprintf(fname, len, fmt, state->argv[0]);
 196        state->fdt_fname = fname;
 197
 198        return 0;
 199}
 200SANDBOX_CMDLINE_OPT_SHORT(default_fdt, 'D', 0,
 201                "Use the default u-boot.dtb control FDT in U-Boot directory");
 202
 203static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state,
 204                                       const char *arg)
 205{
 206        const char *fmt = "/arch/sandbox/dts/test.dtb";
 207        char *p;
 208        char *fname;
 209        int len;
 210
 211        len = strlen(state->argv[0]) + strlen(fmt) + 1;
 212        fname = os_malloc(len);
 213        if (!fname)
 214                return -ENOMEM;
 215        strcpy(fname, state->argv[0]);
 216        p = strrchr(fname, '/');
 217        if (!p)
 218                p = fname + strlen(fname);
 219        len -= p - fname;
 220        snprintf(p, len, fmt);
 221        state->fdt_fname = fname;
 222
 223        return 0;
 224}
 225SANDBOX_CMDLINE_OPT_SHORT(test_fdt, 'T', 0,
 226                          "Use the test.dtb control FDT in U-Boot directory");
 227
 228static int sandbox_cmdline_cb_interactive(struct sandbox_state *state,
 229                                          const char *arg)
 230{
 231        state->interactive = true;
 232        return 0;
 233}
 234
 235SANDBOX_CMDLINE_OPT_SHORT(interactive, 'i', 0, "Enter interactive mode");
 236
 237static int sandbox_cmdline_cb_jump(struct sandbox_state *state,
 238                                   const char *arg)
 239{
 240        /* Remember to delete this U-Boot image later */
 241        state->jumped_fname = arg;
 242
 243        return 0;
 244}
 245SANDBOX_CMDLINE_OPT_SHORT(jump, 'j', 1, "Jumped from previous U-Boot");
 246
 247static int sandbox_cmdline_cb_memory(struct sandbox_state *state,
 248                                     const char *arg)
 249{
 250        int err;
 251
 252        /* For now assume we always want to write it */
 253        state->write_ram_buf = true;
 254        state->ram_buf_fname = arg;
 255
 256        err = os_read_ram_buf(arg);
 257        if (err) {
 258                printf("Failed to read RAM buffer '%s': %d\n", arg, err);
 259                return err;
 260        }
 261        state->ram_buf_read = true;
 262
 263        return 0;
 264}
 265SANDBOX_CMDLINE_OPT_SHORT(memory, 'm', 1,
 266                          "Read/write ram_buf memory contents from file");
 267
 268static int sandbox_cmdline_cb_rm_memory(struct sandbox_state *state,
 269                                        const char *arg)
 270{
 271        state->ram_buf_rm = true;
 272
 273        return 0;
 274}
 275SANDBOX_CMDLINE_OPT(rm_memory, 0, "Remove memory file after reading");
 276
 277static int sandbox_cmdline_cb_state(struct sandbox_state *state,
 278                                    const char *arg)
 279{
 280        state->state_fname = arg;
 281        return 0;
 282}
 283SANDBOX_CMDLINE_OPT_SHORT(state, 's', 1, "Specify the sandbox state FDT");
 284
 285static int sandbox_cmdline_cb_read(struct sandbox_state *state,
 286                                   const char *arg)
 287{
 288        state->read_state = true;
 289        return 0;
 290}
 291SANDBOX_CMDLINE_OPT_SHORT(read, 'r', 0, "Read the state FDT on startup");
 292
 293static int sandbox_cmdline_cb_write(struct sandbox_state *state,
 294                                    const char *arg)
 295{
 296        state->write_state = true;
 297        return 0;
 298}
 299SANDBOX_CMDLINE_OPT_SHORT(write, 'w', 0, "Write state FDT on exit");
 300
 301static int sandbox_cmdline_cb_ignore_missing(struct sandbox_state *state,
 302                                             const char *arg)
 303{
 304        state->ignore_missing_state_on_read = true;
 305        return 0;
 306}
 307SANDBOX_CMDLINE_OPT_SHORT(ignore_missing, 'n', 0,
 308                          "Ignore missing state on read");
 309
 310static int sandbox_cmdline_cb_show_lcd(struct sandbox_state *state,
 311                                       const char *arg)
 312{
 313        state->show_lcd = true;
 314        return 0;
 315}
 316SANDBOX_CMDLINE_OPT_SHORT(show_lcd, 'l', 0,
 317                          "Show the sandbox LCD display");
 318
 319static int sandbox_cmdline_cb_double_lcd(struct sandbox_state *state,
 320                                         const char *arg)
 321{
 322        state->double_lcd = true;
 323
 324        return 0;
 325}
 326SANDBOX_CMDLINE_OPT_SHORT(double_lcd, 'K', 0,
 327                          "Double the LCD display size in each direction");
 328
 329static const char *term_args[STATE_TERM_COUNT] = {
 330        "raw-with-sigs",
 331        "raw",
 332        "cooked",
 333};
 334
 335static int sandbox_cmdline_cb_terminal(struct sandbox_state *state,
 336                                       const char *arg)
 337{
 338        int i;
 339
 340        for (i = 0; i < STATE_TERM_COUNT; i++) {
 341                if (!strcmp(arg, term_args[i])) {
 342                        state->term_raw = i;
 343                        return 0;
 344                }
 345        }
 346
 347        printf("Unknown terminal setting '%s' (", arg);
 348        for (i = 0; i < STATE_TERM_COUNT; i++)
 349                printf("%s%s", i ? ", " : "", term_args[i]);
 350        puts(")\n");
 351
 352        return 1;
 353}
 354SANDBOX_CMDLINE_OPT_SHORT(terminal, 't', 1,
 355                          "Set terminal to raw/cooked mode");
 356
 357static int sandbox_cmdline_cb_verbose(struct sandbox_state *state,
 358                                      const char *arg)
 359{
 360        state->show_test_output = true;
 361        return 0;
 362}
 363SANDBOX_CMDLINE_OPT_SHORT(verbose, 'v', 0, "Show test output");
 364
 365static int sandbox_cmdline_cb_log_level(struct sandbox_state *state,
 366                                        const char *arg)
 367{
 368        state->default_log_level = simple_strtol(arg, NULL, 10);
 369
 370        return 0;
 371}
 372SANDBOX_CMDLINE_OPT_SHORT(log_level, 'L', 1,
 373                          "Set log level (0=panic, 7=debug)");
 374
 375static int sandbox_cmdline_cb_unittests(struct sandbox_state *state,
 376                                        const char *arg)
 377{
 378        state->run_unittests = true;
 379
 380        return 0;
 381}
 382SANDBOX_CMDLINE_OPT_SHORT(unittests, 'u', 0, "Run unit tests");
 383
 384static int sandbox_cmdline_cb_select_unittests(struct sandbox_state *state,
 385                                               const char *arg)
 386{
 387        state->select_unittests = arg;
 388
 389        return 0;
 390}
 391SANDBOX_CMDLINE_OPT_SHORT(select_unittests, 'k', 1, "Select unit tests to run");
 392
 393static int sandbox_cmdline_cb_signals(struct sandbox_state *state,
 394                                      const char *arg)
 395{
 396        state->handle_signals = true;
 397
 398        return 0;
 399}
 400SANDBOX_CMDLINE_OPT_SHORT(signals, 'S', 0,
 401                          "Handle signals (such as SIGSEGV) in sandbox");
 402
 403static int sandbox_cmdline_cb_autoboot_keyed(struct sandbox_state *state,
 404                                             const char *arg)
 405{
 406        state->autoboot_keyed = true;
 407
 408        return 0;
 409}
 410SANDBOX_CMDLINE_OPT(autoboot_keyed, 0, "Allow keyed autoboot");
 411
 412static void setup_ram_buf(struct sandbox_state *state)
 413{
 414        /* Zero the RAM buffer if we didn't read it, to keep valgrind happy */
 415        if (!state->ram_buf_read)
 416                memset(state->ram_buf, '\0', state->ram_size);
 417
 418        gd->arch.ram_buf = state->ram_buf;
 419        gd->ram_size = state->ram_size;
 420}
 421
 422void state_show(struct sandbox_state *state)
 423{
 424        char **p;
 425
 426        printf("Arguments:\n");
 427        for (p = state->argv; *p; p++)
 428                printf("%s ", *p);
 429        printf("\n");
 430}
 431
 432void __efi_runtime EFIAPI efi_reset_system(
 433                enum efi_reset_type reset_type,
 434                efi_status_t reset_status,
 435                unsigned long data_size, void *reset_data)
 436{
 437        if (reset_type == EFI_RESET_SHUTDOWN)
 438                sandbox_exit();
 439        else
 440                sandbox_reset();
 441}
 442
 443void sandbox_reset(void)
 444{
 445        /* Do this here while it still has an effect */
 446        os_fd_restore();
 447        if (state_uninit())
 448                os_exit(2);
 449
 450        /* Restart U-Boot */
 451        os_relaunch(os_argv);
 452}
 453
 454int main(int argc, char *argv[])
 455{
 456        struct sandbox_state *state;
 457        void * text_base;
 458        gd_t data;
 459        int size;
 460        int ret;
 461
 462        text_base = os_find_text_base();
 463
 464        /*
 465         * This must be the first invocation of os_malloc() to have
 466         * state->ram_buf in the low 4 GiB.
 467         */
 468        ret = state_init();
 469        if (ret)
 470                goto err;
 471
 472        /*
 473         * Copy argv[] so that we can pass the arguments in the original
 474         * sequence when resetting the sandbox.
 475         */
 476        size = sizeof(char *) * (argc + 1);
 477        os_argv = os_malloc(size);
 478        if (!os_argv)
 479                os_exit(1);
 480        memcpy(os_argv, argv, size);
 481
 482        memset(&data, '\0', sizeof(data));
 483        gd = &data;
 484        gd->arch.text_base = text_base;
 485
 486        state = state_get_current();
 487        if (os_parse_args(state, argc, argv))
 488                return 1;
 489
 490        /* Remove old memory file if required */
 491        if (state->ram_buf_rm && state->ram_buf_fname) {
 492                os_unlink(state->ram_buf_fname);
 493                state->write_ram_buf = false;
 494                state->ram_buf_fname = NULL;
 495        }
 496
 497        ret = sandbox_read_state(state, state->state_fname);
 498        if (ret)
 499                goto err;
 500
 501        if (state->handle_signals) {
 502                ret = os_setup_signal_handlers();
 503                if (ret)
 504                        goto err;
 505        }
 506
 507#if CONFIG_VAL(SYS_MALLOC_F_LEN)
 508        gd->malloc_base = CONFIG_MALLOC_F_ADDR;
 509#endif
 510#if CONFIG_IS_ENABLED(LOG)
 511        gd->default_log_level = state->default_log_level;
 512#endif
 513        setup_ram_buf(state);
 514
 515        /*
 516         * Set up the relocation offset here, since sandbox symbols are always
 517         * relocated by the OS before sandbox is entered.
 518         */
 519        gd->reloc_off = (ulong)gd->arch.text_base;
 520
 521        /* sandbox test: log functions called before log_init in board_init_f */
 522        log_debug("debug: %s\n", __func__);
 523
 524        /* Do pre- and post-relocation init */
 525        board_init_f(0);
 526
 527        board_init_r(gd->new_gd, 0);
 528
 529        /* NOTREACHED - board_init_r() does not return */
 530        return 0;
 531
 532err:
 533        printf("Error %d\n", ret);
 534        return 1;
 535}
 536