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