1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2011 The Chromium OS Authors. 4 */ 5 6 #include <dirent.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <getopt.h> 10 #include <setjmp.h> 11 #include <stdio.h> 12 #include <stdint.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <termios.h> 16 #include <time.h> 17 #include <unistd.h> 18 #include <sys/mman.h> 19 #include <sys/stat.h> 20 #include <sys/time.h> 21 #include <sys/types.h> 22 #include <linux/types.h> 23 24 #include <asm/getopt.h> 25 #include <asm/sections.h> 26 #include <asm/state.h> 27 #include <os.h> 28 #include <rtc_def.h> 29 30 /* Operating System Interface */ 31 32 struct os_mem_hdr { 33 size_t length; /* number of bytes in the block */ 34 }; 35 36 ssize_t os_read(int fd, void *buf, size_t count) 37 { 38 return read(fd, buf, count); 39 } 40 41 ssize_t os_write(int fd, const void *buf, size_t count) 42 { 43 return write(fd, buf, count); 44 } 45 46 off_t os_lseek(int fd, off_t offset, int whence) 47 { 48 if (whence == OS_SEEK_SET) 49 whence = SEEK_SET; 50 else if (whence == OS_SEEK_CUR) 51 whence = SEEK_CUR; 52 else if (whence == OS_SEEK_END) 53 whence = SEEK_END; 54 else 55 os_exit(1); 56 return lseek(fd, offset, whence); 57 } 58 59 int os_open(const char *pathname, int os_flags) 60 { 61 int flags; 62 63 switch (os_flags & OS_O_MASK) { 64 case OS_O_RDONLY: 65 default: 66 flags = O_RDONLY; 67 break; 68 69 case OS_O_WRONLY: 70 flags = O_WRONLY; 71 break; 72 73 case OS_O_RDWR: 74 flags = O_RDWR; 75 break; 76 } 77 78 if (os_flags & OS_O_CREAT) 79 flags |= O_CREAT; 80 if (os_flags & OS_O_TRUNC) 81 flags |= O_TRUNC; 82 83 return open(pathname, flags, 0777); 84 } 85 86 int os_close(int fd) 87 { 88 return close(fd); 89 } 90 91 int os_unlink(const char *pathname) 92 { 93 return unlink(pathname); 94 } 95 96 void os_exit(int exit_code) 97 { 98 exit(exit_code); 99 } 100 101 int os_write_file(const char *fname, const void *buf, int size) 102 { 103 int fd; 104 105 fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC); 106 if (fd < 0) { 107 printf("Cannot open file '%s'\n", fname); 108 return -EIO; 109 } 110 if (os_write(fd, buf, size) != size) { 111 printf("Cannot write to file '%s'\n", fname); 112 os_close(fd); 113 return -EIO; 114 } 115 os_close(fd); 116 117 return 0; 118 } 119 120 int os_read_file(const char *fname, void **bufp, int *sizep) 121 { 122 off_t size; 123 int ret = -EIO; 124 int fd; 125 126 fd = os_open(fname, OS_O_RDONLY); 127 if (fd < 0) { 128 printf("Cannot open file '%s'\n", fname); 129 goto err; 130 } 131 size = os_lseek(fd, 0, OS_SEEK_END); 132 if (size < 0) { 133 printf("Cannot seek to end of file '%s'\n", fname); 134 goto err; 135 } 136 if (os_lseek(fd, 0, OS_SEEK_SET) < 0) { 137 printf("Cannot seek to start of file '%s'\n", fname); 138 goto err; 139 } 140 *bufp = os_malloc(size); 141 if (!*bufp) { 142 printf("Not enough memory to read file '%s'\n", fname); 143 ret = -ENOMEM; 144 goto err; 145 } 146 if (os_read(fd, *bufp, size) != size) { 147 printf("Cannot read from file '%s'\n", fname); 148 goto err; 149 } 150 os_close(fd); 151 *sizep = size; 152 153 return 0; 154 err: 155 os_close(fd); 156 return ret; 157 } 158 159 /* Restore tty state when we exit */ 160 static struct termios orig_term; 161 static bool term_setup; 162 static bool term_nonblock; 163 164 void os_fd_restore(void) 165 { 166 if (term_setup) { 167 int flags; 168 169 tcsetattr(0, TCSANOW, &orig_term); 170 if (term_nonblock) { 171 flags = fcntl(0, F_GETFL, 0); 172 fcntl(0, F_SETFL, flags & ~O_NONBLOCK); 173 } 174 term_setup = false; 175 } 176 } 177 178 /* Put tty into raw mode so <tab> and <ctrl+c> work */ 179 void os_tty_raw(int fd, bool allow_sigs) 180 { 181 struct termios term; 182 int flags; 183 184 if (term_setup) 185 return; 186 187 /* If not a tty, don't complain */ 188 if (tcgetattr(fd, &orig_term)) 189 return; 190 191 term = orig_term; 192 term.c_iflag = IGNBRK | IGNPAR; 193 term.c_oflag = OPOST | ONLCR; 194 term.c_cflag = CS8 | CREAD | CLOCAL; 195 term.c_lflag = allow_sigs ? ISIG : 0; 196 if (tcsetattr(fd, TCSANOW, &term)) 197 return; 198 199 flags = fcntl(fd, F_GETFL, 0); 200 if (!(flags & O_NONBLOCK)) { 201 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) 202 return; 203 term_nonblock = true; 204 } 205 206 term_setup = true; 207 atexit(os_fd_restore); 208 } 209 210 void *os_malloc(size_t length) 211 { 212 struct os_mem_hdr *hdr; 213 int page_size = getpagesize(); 214 215 /* 216 * Use an address that is hopefully available to us so that pointers 217 * to this memory are fairly obvious. If we end up with a different 218 * address, that's fine too. 219 */ 220 hdr = mmap((void *)0x10000000, length + page_size, 221 PROT_READ | PROT_WRITE | PROT_EXEC, 222 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 223 if (hdr == MAP_FAILED) 224 return NULL; 225 hdr->length = length; 226 227 return (void *)hdr + page_size; 228 } 229 230 void os_free(void *ptr) 231 { 232 struct os_mem_hdr *hdr = ptr; 233 234 hdr--; 235 if (ptr) 236 munmap(hdr, hdr->length + sizeof(*hdr)); 237 } 238 239 void *os_realloc(void *ptr, size_t length) 240 { 241 struct os_mem_hdr *hdr = ptr; 242 void *buf = NULL; 243 244 hdr--; 245 if (length != 0) { 246 buf = os_malloc(length); 247 if (!buf) 248 return buf; 249 if (ptr) { 250 if (length > hdr->length) 251 length = hdr->length; 252 memcpy(buf, ptr, length); 253 } 254 } 255 os_free(ptr); 256 257 return buf; 258 } 259 260 void os_usleep(unsigned long usec) 261 { 262 usleep(usec); 263 } 264 265 uint64_t __attribute__((no_instrument_function)) os_get_nsec(void) 266 { 267 #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) 268 struct timespec tp; 269 if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) { 270 struct timeval tv; 271 272 gettimeofday(&tv, NULL); 273 tp.tv_sec = tv.tv_sec; 274 tp.tv_nsec = tv.tv_usec * 1000; 275 } 276 return tp.tv_sec * 1000000000ULL + tp.tv_nsec; 277 #else 278 struct timeval tv; 279 gettimeofday(&tv, NULL); 280 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; 281 #endif 282 } 283 284 static char *short_opts; 285 static struct option *long_opts; 286 287 int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) 288 { 289 struct sandbox_cmdline_option **sb_opt = __u_boot_sandbox_option_start; 290 size_t num_options = __u_boot_sandbox_option_count(); 291 size_t i; 292 293 int hidden_short_opt; 294 size_t si; 295 296 int c; 297 298 if (short_opts || long_opts) 299 return 1; 300 301 state->argc = argc; 302 state->argv = argv; 303 304 /* dynamically construct the arguments to the system getopt_long */ 305 short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1); 306 long_opts = os_malloc(sizeof(*long_opts) * num_options); 307 if (!short_opts || !long_opts) 308 return 1; 309 310 /* 311 * getopt_long requires "val" to be unique (since that is what the 312 * func returns), so generate unique values automatically for flags 313 * that don't have a short option. pick 0x100 as that is above the 314 * single byte range (where ASCII/ISO-XXXX-X charsets live). 315 */ 316 hidden_short_opt = 0x100; 317 si = 0; 318 for (i = 0; i < num_options; ++i) { 319 long_opts[i].name = sb_opt[i]->flag; 320 long_opts[i].has_arg = sb_opt[i]->has_arg ? 321 required_argument : no_argument; 322 long_opts[i].flag = NULL; 323 324 if (sb_opt[i]->flag_short) { 325 short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short; 326 if (long_opts[i].has_arg == required_argument) 327 short_opts[si++] = ':'; 328 } else 329 long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++; 330 } 331 short_opts[si] = '\0'; 332 333 /* we need to handle output ourselves since u-boot provides printf */ 334 opterr = 0; 335 336 /* 337 * walk all of the options the user gave us on the command line, 338 * figure out what u-boot option structure they belong to (via 339 * the unique short val key), and call the appropriate callback. 340 */ 341 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { 342 for (i = 0; i < num_options; ++i) { 343 if (sb_opt[i]->flag_short == c) { 344 if (sb_opt[i]->callback(state, optarg)) { 345 state->parse_err = sb_opt[i]->flag; 346 return 0; 347 } 348 break; 349 } 350 } 351 if (i == num_options) { 352 /* 353 * store the faulting flag for later display. we have to 354 * store the flag itself as the getopt parsing itself is 355 * tricky: need to handle the following flags (assume all 356 * of the below are unknown): 357 * -a optopt='a' optind=<next> 358 * -abbbb optopt='a' optind=<this> 359 * -aaaaa optopt='a' optind=<this> 360 * --a optopt=0 optind=<this> 361 * as you can see, it is impossible to determine the exact 362 * faulting flag without doing the parsing ourselves, so 363 * we just report the specific flag that failed. 364 */ 365 if (optopt) { 366 static char parse_err[3] = { '-', 0, '\0', }; 367 parse_err[1] = optopt; 368 state->parse_err = parse_err; 369 } else 370 state->parse_err = argv[optind - 1]; 371 break; 372 } 373 } 374 375 return 0; 376 } 377 378 void os_dirent_free(struct os_dirent_node *node) 379 { 380 struct os_dirent_node *next; 381 382 while (node) { 383 next = node->next; 384 os_free(node); 385 node = next; 386 } 387 } 388 389 int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) 390 { 391 struct dirent *entry; 392 struct os_dirent_node *head, *node, *next; 393 struct stat buf; 394 DIR *dir; 395 int ret; 396 char *fname; 397 char *old_fname; 398 int len; 399 int dirlen; 400 401 *headp = NULL; 402 dir = opendir(dirname); 403 if (!dir) 404 return -1; 405 406 /* Create a buffer upfront, with typically sufficient size */ 407 dirlen = strlen(dirname) + 2; 408 len = dirlen + 256; 409 fname = os_malloc(len); 410 if (!fname) { 411 ret = -ENOMEM; 412 goto done; 413 } 414 415 for (node = head = NULL;; node = next) { 416 errno = 0; 417 entry = readdir(dir); 418 if (!entry) { 419 ret = errno; 420 break; 421 } 422 next = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1); 423 if (!next) { 424 os_dirent_free(head); 425 ret = -ENOMEM; 426 goto done; 427 } 428 if (dirlen + strlen(entry->d_name) > len) { 429 len = dirlen + strlen(entry->d_name); 430 old_fname = fname; 431 fname = os_realloc(fname, len); 432 if (!fname) { 433 os_free(old_fname); 434 os_free(next); 435 os_dirent_free(head); 436 ret = -ENOMEM; 437 goto done; 438 } 439 } 440 next->next = NULL; 441 strcpy(next->name, entry->d_name); 442 switch (entry->d_type) { 443 case DT_REG: 444 next->type = OS_FILET_REG; 445 break; 446 case DT_DIR: 447 next->type = OS_FILET_DIR; 448 break; 449 case DT_LNK: 450 next->type = OS_FILET_LNK; 451 break; 452 default: 453 next->type = OS_FILET_UNKNOWN; 454 } 455 next->size = 0; 456 snprintf(fname, len, "%s/%s", dirname, next->name); 457 if (!stat(fname, &buf)) 458 next->size = buf.st_size; 459 if (node) 460 node->next = next; 461 else 462 head = next; 463 } 464 *headp = head; 465 466 done: 467 closedir(dir); 468 os_free(fname); 469 return ret; 470 } 471 472 const char *os_dirent_typename[OS_FILET_COUNT] = { 473 " ", 474 "SYM", 475 "DIR", 476 "???", 477 }; 478 479 const char *os_dirent_get_typename(enum os_dirent_t type) 480 { 481 if (type >= OS_FILET_REG && type < OS_FILET_COUNT) 482 return os_dirent_typename[type]; 483 484 return os_dirent_typename[OS_FILET_UNKNOWN]; 485 } 486 487 int os_get_filesize(const char *fname, loff_t *size) 488 { 489 struct stat buf; 490 int ret; 491 492 ret = stat(fname, &buf); 493 if (ret) 494 return ret; 495 *size = buf.st_size; 496 return 0; 497 } 498 499 void os_putc(int ch) 500 { 501 putchar(ch); 502 } 503 504 void os_puts(const char *str) 505 { 506 while (*str) 507 os_putc(*str++); 508 } 509 510 int os_write_ram_buf(const char *fname) 511 { 512 struct sandbox_state *state = state_get_current(); 513 int fd, ret; 514 515 fd = open(fname, O_CREAT | O_WRONLY, 0777); 516 if (fd < 0) 517 return -ENOENT; 518 ret = write(fd, state->ram_buf, state->ram_size); 519 close(fd); 520 if (ret != state->ram_size) 521 return -EIO; 522 523 return 0; 524 } 525 526 int os_read_ram_buf(const char *fname) 527 { 528 struct sandbox_state *state = state_get_current(); 529 int fd, ret; 530 loff_t size; 531 532 ret = os_get_filesize(fname, &size); 533 if (ret < 0) 534 return ret; 535 if (size != state->ram_size) 536 return -ENOSPC; 537 fd = open(fname, O_RDONLY); 538 if (fd < 0) 539 return -ENOENT; 540 541 ret = read(fd, state->ram_buf, state->ram_size); 542 close(fd); 543 if (ret != state->ram_size) 544 return -EIO; 545 546 return 0; 547 } 548 549 static int make_exec(char *fname, const void *data, int size) 550 { 551 int fd; 552 553 strcpy(fname, "/tmp/u-boot.jump.XXXXXX"); 554 fd = mkstemp(fname); 555 if (fd < 0) 556 return -ENOENT; 557 if (write(fd, data, size) < 0) 558 return -EIO; 559 close(fd); 560 if (chmod(fname, 0777)) 561 return -ENOEXEC; 562 563 return 0; 564 } 565 566 /** 567 * add_args() - Allocate a new argv with the given args 568 * 569 * This is used to create a new argv array with all the old arguments and some 570 * new ones that are passed in 571 * 572 * @argvp: Returns newly allocated args list 573 * @add_args: Arguments to add, each a string 574 * @count: Number of arguments in @add_args 575 * @return 0 if OK, -ENOMEM if out of memory 576 */ 577 static int add_args(char ***argvp, char *add_args[], int count) 578 { 579 char **argv, **ap; 580 int argc; 581 582 for (argc = 0; (*argvp)[argc]; argc++) 583 ; 584 585 argv = os_malloc((argc + count + 1) * sizeof(char *)); 586 if (!argv) { 587 printf("Out of memory for %d argv\n", count); 588 return -ENOMEM; 589 } 590 for (ap = *argvp, argc = 0; *ap; ap++) { 591 char *arg = *ap; 592 593 /* Drop args that we don't want to propagate */ 594 if (*arg == '-' && strlen(arg) == 2) { 595 switch (arg[1]) { 596 case 'j': 597 case 'm': 598 ap++; 599 continue; 600 } 601 } else if (!strcmp(arg, "--rm_memory")) { 602 ap++; 603 continue; 604 } 605 argv[argc++] = arg; 606 } 607 608 memcpy(argv + argc, add_args, count * sizeof(char *)); 609 argv[argc + count] = NULL; 610 611 *argvp = argv; 612 return 0; 613 } 614 615 /** 616 * os_jump_to_file() - Jump to a new program 617 * 618 * This saves the memory buffer, sets up arguments to the new process, then 619 * execs it. 620 * 621 * @fname: Filename to exec 622 * @return does not return on success, any return value is an error 623 */ 624 static int os_jump_to_file(const char *fname) 625 { 626 struct sandbox_state *state = state_get_current(); 627 char mem_fname[30]; 628 int fd, err; 629 char *extra_args[5]; 630 char **argv = state->argv; 631 int argc; 632 #ifdef DEBUG 633 int i; 634 #endif 635 636 strcpy(mem_fname, "/tmp/u-boot.mem.XXXXXX"); 637 fd = mkstemp(mem_fname); 638 if (fd < 0) 639 return -ENOENT; 640 close(fd); 641 err = os_write_ram_buf(mem_fname); 642 if (err) 643 return err; 644 645 os_fd_restore(); 646 647 extra_args[0] = "-j"; 648 extra_args[1] = (char *)fname; 649 extra_args[2] = "-m"; 650 extra_args[3] = mem_fname; 651 argc = 4; 652 if (state->ram_buf_rm) 653 extra_args[argc++] = "--rm_memory"; 654 err = add_args(&argv, extra_args, argc); 655 if (err) 656 return err; 657 argv[0] = (char *)fname; 658 659 #ifdef DEBUG 660 for (i = 0; argv[i]; i++) 661 printf("%d %s\n", i, argv[i]); 662 #endif 663 664 if (state_uninit()) 665 os_exit(2); 666 667 err = execv(fname, argv); 668 os_free(argv); 669 if (err) { 670 perror("Unable to run image"); 671 printf("Image filename '%s'\n", mem_fname); 672 return err; 673 } 674 675 return unlink(fname); 676 } 677 678 int os_jump_to_image(const void *dest, int size) 679 { 680 char fname[30]; 681 int err; 682 683 err = make_exec(fname, dest, size); 684 if (err) 685 return err; 686 687 return os_jump_to_file(fname); 688 } 689 690 int os_find_u_boot(char *fname, int maxlen) 691 { 692 struct sandbox_state *state = state_get_current(); 693 const char *progname = state->argv[0]; 694 int len = strlen(progname); 695 const char *suffix; 696 char *p; 697 int fd; 698 699 if (len >= maxlen || len < 4) 700 return -ENOSPC; 701 702 strcpy(fname, progname); 703 suffix = fname + len - 4; 704 705 /* If we are TPL, boot to SPL */ 706 if (!strcmp(suffix, "-tpl")) { 707 fname[len - 3] = 's'; 708 fd = os_open(fname, O_RDONLY); 709 if (fd >= 0) { 710 close(fd); 711 return 0; 712 } 713 714 /* Look for 'u-boot-tpl' in the tpl/ directory */ 715 p = strstr(fname, "/tpl/"); 716 if (p) { 717 p[1] = 's'; 718 fd = os_open(fname, O_RDONLY); 719 if (fd >= 0) { 720 close(fd); 721 return 0; 722 } 723 } 724 return -ENOENT; 725 } 726 727 /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ 728 if (!strcmp(suffix, "-spl")) { 729 fname[len - 4] = '\0'; 730 fd = os_open(fname, O_RDONLY); 731 if (fd >= 0) { 732 close(fd); 733 return 0; 734 } 735 } 736 737 /* Look for 'u-boot' in the parent directory of spl/ */ 738 p = strstr(fname, "/spl/"); 739 if (p) { 740 strcpy(p, p + 4); 741 fd = os_open(fname, O_RDONLY); 742 if (fd >= 0) { 743 close(fd); 744 return 0; 745 } 746 } 747 748 return -ENOENT; 749 } 750 751 int os_spl_to_uboot(const char *fname) 752 { 753 return os_jump_to_file(fname); 754 } 755 756 void os_localtime(struct rtc_time *rt) 757 { 758 time_t t = time(NULL); 759 struct tm *tm; 760 761 tm = localtime(&t); 762 rt->tm_sec = tm->tm_sec; 763 rt->tm_min = tm->tm_min; 764 rt->tm_hour = tm->tm_hour; 765 rt->tm_mday = tm->tm_mday; 766 rt->tm_mon = tm->tm_mon + 1; 767 rt->tm_year = tm->tm_year + 1900; 768 rt->tm_wday = tm->tm_wday; 769 rt->tm_yday = tm->tm_yday; 770 rt->tm_isdst = tm->tm_isdst; 771 } 772 773 void os_abort(void) 774 { 775 abort(); 776 } 777 778 int os_mprotect_allow(void *start, size_t len) 779 { 780 int page_size = getpagesize(); 781 782 /* Move start to the start of a page, len to the end */ 783 start = (void *)(((ulong)start) & ~(page_size - 1)); 784 len = (len + page_size * 2) & ~(page_size - 1); 785 786 return mprotect(start, len, PROT_READ | PROT_WRITE); 787 } 788