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 *name, const void *buf, int size) 102 { 103 char fname[256]; 104 int fd; 105 106 fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC); 107 if (fd < 0) { 108 printf("Cannot open file '%s'\n", fname); 109 return -EIO; 110 } 111 if (os_write(fd, buf, size) != size) { 112 printf("Cannot write to file '%s'\n", fname); 113 return -EIO; 114 } 115 os_close(fd); 116 printf("Write '%s', size %#x (%d)\n", name, size, size); 117 118 return 0; 119 } 120 121 /* Restore tty state when we exit */ 122 static struct termios orig_term; 123 static bool term_setup; 124 static bool term_nonblock; 125 126 void os_fd_restore(void) 127 { 128 if (term_setup) { 129 int flags; 130 131 tcsetattr(0, TCSANOW, &orig_term); 132 if (term_nonblock) { 133 flags = fcntl(0, F_GETFL, 0); 134 fcntl(0, F_SETFL, flags & ~O_NONBLOCK); 135 } 136 term_setup = false; 137 } 138 } 139 140 /* Put tty into raw mode so <tab> and <ctrl+c> work */ 141 void os_tty_raw(int fd, bool allow_sigs) 142 { 143 struct termios term; 144 int flags; 145 146 if (term_setup) 147 return; 148 149 /* If not a tty, don't complain */ 150 if (tcgetattr(fd, &orig_term)) 151 return; 152 153 term = orig_term; 154 term.c_iflag = IGNBRK | IGNPAR; 155 term.c_oflag = OPOST | ONLCR; 156 term.c_cflag = CS8 | CREAD | CLOCAL; 157 term.c_lflag = allow_sigs ? ISIG : 0; 158 if (tcsetattr(fd, TCSANOW, &term)) 159 return; 160 161 flags = fcntl(fd, F_GETFL, 0); 162 if (!(flags & O_NONBLOCK)) { 163 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) 164 return; 165 term_nonblock = true; 166 } 167 168 term_setup = true; 169 atexit(os_fd_restore); 170 } 171 172 void *os_malloc(size_t length) 173 { 174 struct os_mem_hdr *hdr; 175 int page_size = getpagesize(); 176 177 /* 178 * Use an address that is hopefully available to us so that pointers 179 * to this memory are fairly obvious. If we end up with a different 180 * address, that's fine too. 181 */ 182 hdr = mmap((void *)0x10000000, length + page_size, 183 PROT_READ | PROT_WRITE | PROT_EXEC, 184 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 185 if (hdr == MAP_FAILED) 186 return NULL; 187 hdr->length = length; 188 189 return (void *)hdr + page_size; 190 } 191 192 void os_free(void *ptr) 193 { 194 struct os_mem_hdr *hdr = ptr; 195 196 hdr--; 197 if (ptr) 198 munmap(hdr, hdr->length + sizeof(*hdr)); 199 } 200 201 void *os_realloc(void *ptr, size_t length) 202 { 203 struct os_mem_hdr *hdr = ptr; 204 void *buf = NULL; 205 206 hdr--; 207 if (length != 0) { 208 buf = os_malloc(length); 209 if (!buf) 210 return buf; 211 if (ptr) { 212 if (length > hdr->length) 213 length = hdr->length; 214 memcpy(buf, ptr, length); 215 } 216 } 217 os_free(ptr); 218 219 return buf; 220 } 221 222 void os_usleep(unsigned long usec) 223 { 224 usleep(usec); 225 } 226 227 uint64_t __attribute__((no_instrument_function)) os_get_nsec(void) 228 { 229 #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) 230 struct timespec tp; 231 if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) { 232 struct timeval tv; 233 234 gettimeofday(&tv, NULL); 235 tp.tv_sec = tv.tv_sec; 236 tp.tv_nsec = tv.tv_usec * 1000; 237 } 238 return tp.tv_sec * 1000000000ULL + tp.tv_nsec; 239 #else 240 struct timeval tv; 241 gettimeofday(&tv, NULL); 242 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; 243 #endif 244 } 245 246 static char *short_opts; 247 static struct option *long_opts; 248 249 int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) 250 { 251 struct sandbox_cmdline_option **sb_opt = __u_boot_sandbox_option_start; 252 size_t num_options = __u_boot_sandbox_option_count(); 253 size_t i; 254 255 int hidden_short_opt; 256 size_t si; 257 258 int c; 259 260 if (short_opts || long_opts) 261 return 1; 262 263 state->argc = argc; 264 state->argv = argv; 265 266 /* dynamically construct the arguments to the system getopt_long */ 267 short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1); 268 long_opts = os_malloc(sizeof(*long_opts) * num_options); 269 if (!short_opts || !long_opts) 270 return 1; 271 272 /* 273 * getopt_long requires "val" to be unique (since that is what the 274 * func returns), so generate unique values automatically for flags 275 * that don't have a short option. pick 0x100 as that is above the 276 * single byte range (where ASCII/ISO-XXXX-X charsets live). 277 */ 278 hidden_short_opt = 0x100; 279 si = 0; 280 for (i = 0; i < num_options; ++i) { 281 long_opts[i].name = sb_opt[i]->flag; 282 long_opts[i].has_arg = sb_opt[i]->has_arg ? 283 required_argument : no_argument; 284 long_opts[i].flag = NULL; 285 286 if (sb_opt[i]->flag_short) { 287 short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short; 288 if (long_opts[i].has_arg == required_argument) 289 short_opts[si++] = ':'; 290 } else 291 long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++; 292 } 293 short_opts[si] = '\0'; 294 295 /* we need to handle output ourselves since u-boot provides printf */ 296 opterr = 0; 297 298 /* 299 * walk all of the options the user gave us on the command line, 300 * figure out what u-boot option structure they belong to (via 301 * the unique short val key), and call the appropriate callback. 302 */ 303 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { 304 for (i = 0; i < num_options; ++i) { 305 if (sb_opt[i]->flag_short == c) { 306 if (sb_opt[i]->callback(state, optarg)) { 307 state->parse_err = sb_opt[i]->flag; 308 return 0; 309 } 310 break; 311 } 312 } 313 if (i == num_options) { 314 /* 315 * store the faulting flag for later display. we have to 316 * store the flag itself as the getopt parsing itself is 317 * tricky: need to handle the following flags (assume all 318 * of the below are unknown): 319 * -a optopt='a' optind=<next> 320 * -abbbb optopt='a' optind=<this> 321 * -aaaaa optopt='a' optind=<this> 322 * --a optopt=0 optind=<this> 323 * as you can see, it is impossible to determine the exact 324 * faulting flag without doing the parsing ourselves, so 325 * we just report the specific flag that failed. 326 */ 327 if (optopt) { 328 static char parse_err[3] = { '-', 0, '\0', }; 329 parse_err[1] = optopt; 330 state->parse_err = parse_err; 331 } else 332 state->parse_err = argv[optind - 1]; 333 break; 334 } 335 } 336 337 return 0; 338 } 339 340 void os_dirent_free(struct os_dirent_node *node) 341 { 342 struct os_dirent_node *next; 343 344 while (node) { 345 next = node->next; 346 free(node); 347 node = next; 348 } 349 } 350 351 int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) 352 { 353 struct dirent *entry; 354 struct os_dirent_node *head, *node, *next; 355 struct stat buf; 356 DIR *dir; 357 int ret; 358 char *fname; 359 char *old_fname; 360 int len; 361 int dirlen; 362 363 *headp = NULL; 364 dir = opendir(dirname); 365 if (!dir) 366 return -1; 367 368 /* Create a buffer upfront, with typically sufficient size */ 369 dirlen = strlen(dirname) + 2; 370 len = dirlen + 256; 371 fname = malloc(len); 372 if (!fname) { 373 ret = -ENOMEM; 374 goto done; 375 } 376 377 for (node = head = NULL;; node = next) { 378 errno = 0; 379 entry = readdir(dir); 380 if (!entry) { 381 ret = errno; 382 break; 383 } 384 next = malloc(sizeof(*node) + strlen(entry->d_name) + 1); 385 if (!next) { 386 os_dirent_free(head); 387 ret = -ENOMEM; 388 goto done; 389 } 390 if (dirlen + strlen(entry->d_name) > len) { 391 len = dirlen + strlen(entry->d_name); 392 old_fname = fname; 393 fname = realloc(fname, len); 394 if (!fname) { 395 free(old_fname); 396 free(next); 397 os_dirent_free(head); 398 ret = -ENOMEM; 399 goto done; 400 } 401 } 402 next->next = NULL; 403 strcpy(next->name, entry->d_name); 404 switch (entry->d_type) { 405 case DT_REG: 406 next->type = OS_FILET_REG; 407 break; 408 case DT_DIR: 409 next->type = OS_FILET_DIR; 410 break; 411 case DT_LNK: 412 next->type = OS_FILET_LNK; 413 break; 414 default: 415 next->type = OS_FILET_UNKNOWN; 416 } 417 next->size = 0; 418 snprintf(fname, len, "%s/%s", dirname, next->name); 419 if (!stat(fname, &buf)) 420 next->size = buf.st_size; 421 if (node) 422 node->next = next; 423 else 424 head = next; 425 } 426 *headp = head; 427 428 done: 429 closedir(dir); 430 free(fname); 431 return ret; 432 } 433 434 const char *os_dirent_typename[OS_FILET_COUNT] = { 435 " ", 436 "SYM", 437 "DIR", 438 "???", 439 }; 440 441 const char *os_dirent_get_typename(enum os_dirent_t type) 442 { 443 if (type >= OS_FILET_REG && type < OS_FILET_COUNT) 444 return os_dirent_typename[type]; 445 446 return os_dirent_typename[OS_FILET_UNKNOWN]; 447 } 448 449 int os_get_filesize(const char *fname, loff_t *size) 450 { 451 struct stat buf; 452 int ret; 453 454 ret = stat(fname, &buf); 455 if (ret) 456 return ret; 457 *size = buf.st_size; 458 return 0; 459 } 460 461 void os_putc(int ch) 462 { 463 putchar(ch); 464 } 465 466 void os_puts(const char *str) 467 { 468 while (*str) 469 os_putc(*str++); 470 } 471 472 int os_write_ram_buf(const char *fname) 473 { 474 struct sandbox_state *state = state_get_current(); 475 int fd, ret; 476 477 fd = open(fname, O_CREAT | O_WRONLY, 0777); 478 if (fd < 0) 479 return -ENOENT; 480 ret = write(fd, state->ram_buf, state->ram_size); 481 close(fd); 482 if (ret != state->ram_size) 483 return -EIO; 484 485 return 0; 486 } 487 488 int os_read_ram_buf(const char *fname) 489 { 490 struct sandbox_state *state = state_get_current(); 491 int fd, ret; 492 loff_t size; 493 494 ret = os_get_filesize(fname, &size); 495 if (ret < 0) 496 return ret; 497 if (size != state->ram_size) 498 return -ENOSPC; 499 fd = open(fname, O_RDONLY); 500 if (fd < 0) 501 return -ENOENT; 502 503 ret = read(fd, state->ram_buf, state->ram_size); 504 close(fd); 505 if (ret != state->ram_size) 506 return -EIO; 507 508 return 0; 509 } 510 511 static int make_exec(char *fname, const void *data, int size) 512 { 513 int fd; 514 515 strcpy(fname, "/tmp/u-boot.jump.XXXXXX"); 516 fd = mkstemp(fname); 517 if (fd < 0) 518 return -ENOENT; 519 if (write(fd, data, size) < 0) 520 return -EIO; 521 close(fd); 522 if (chmod(fname, 0777)) 523 return -ENOEXEC; 524 525 return 0; 526 } 527 528 static int add_args(char ***argvp, const char *add_args[], int count) 529 { 530 char **argv; 531 int argc; 532 533 for (argv = *argvp, argc = 0; (*argvp)[argc]; argc++) 534 ; 535 536 argv = malloc((argc + count + 1) * sizeof(char *)); 537 if (!argv) { 538 printf("Out of memory for %d argv\n", count); 539 return -ENOMEM; 540 } 541 memcpy(argv, *argvp, argc * sizeof(char *)); 542 memcpy(argv + argc, add_args, count * sizeof(char *)); 543 argv[argc + count] = NULL; 544 545 *argvp = argv; 546 return 0; 547 } 548 549 int os_jump_to_image(const void *dest, int size) 550 { 551 struct sandbox_state *state = state_get_current(); 552 char fname[30], mem_fname[30]; 553 int fd, err; 554 const char *extra_args[5]; 555 char **argv = state->argv; 556 #ifdef DEBUG 557 int argc, i; 558 #endif 559 560 err = make_exec(fname, dest, size); 561 if (err) 562 return err; 563 564 strcpy(mem_fname, "/tmp/u-boot.mem.XXXXXX"); 565 fd = mkstemp(mem_fname); 566 if (fd < 0) 567 return -ENOENT; 568 close(fd); 569 err = os_write_ram_buf(mem_fname); 570 if (err) 571 return err; 572 573 os_fd_restore(); 574 575 extra_args[0] = "-j"; 576 extra_args[1] = fname; 577 extra_args[2] = "-m"; 578 extra_args[3] = mem_fname; 579 extra_args[4] = "--rm_memory"; 580 err = add_args(&argv, extra_args, 581 sizeof(extra_args) / sizeof(extra_args[0])); 582 if (err) 583 return err; 584 585 #ifdef DEBUG 586 for (i = 0; argv[i]; i++) 587 printf("%d %s\n", i, argv[i]); 588 #endif 589 590 if (state_uninit()) 591 os_exit(2); 592 593 err = execv(fname, argv); 594 free(argv); 595 if (err) 596 return err; 597 598 return unlink(fname); 599 } 600 601 int os_find_u_boot(char *fname, int maxlen) 602 { 603 struct sandbox_state *state = state_get_current(); 604 const char *progname = state->argv[0]; 605 int len = strlen(progname); 606 const char *suffix; 607 char *p; 608 int fd; 609 610 if (len >= maxlen || len < 4) 611 return -ENOSPC; 612 613 strcpy(fname, progname); 614 suffix = fname + len - 4; 615 616 /* If we are TPL, boot to SPL */ 617 if (!strcmp(suffix, "-tpl")) { 618 fname[len - 3] = 's'; 619 fd = os_open(fname, O_RDONLY); 620 if (fd >= 0) { 621 close(fd); 622 return 0; 623 } 624 625 /* Look for 'u-boot-tpl' in the tpl/ directory */ 626 p = strstr(fname, "/tpl/"); 627 if (p) { 628 p[1] = 's'; 629 fd = os_open(fname, O_RDONLY); 630 if (fd >= 0) { 631 close(fd); 632 return 0; 633 } 634 } 635 return -ENOENT; 636 } 637 638 /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ 639 if (!strcmp(suffix, "-spl")) { 640 fname[len - 4] = '\0'; 641 fd = os_open(fname, O_RDONLY); 642 if (fd >= 0) { 643 close(fd); 644 return 0; 645 } 646 } 647 648 /* Look for 'u-boot' in the parent directory of spl/ */ 649 p = strstr(fname, "/spl/"); 650 if (p) { 651 strcpy(p, p + 4); 652 fd = os_open(fname, O_RDONLY); 653 if (fd >= 0) { 654 close(fd); 655 return 0; 656 } 657 } 658 659 return -ENOENT; 660 } 661 662 int os_spl_to_uboot(const char *fname) 663 { 664 struct sandbox_state *state = state_get_current(); 665 char *argv[state->argc + 1]; 666 int ret; 667 668 memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1)); 669 argv[0] = (char *)fname; 670 ret = execv(fname, argv); 671 if (ret) 672 return ret; 673 674 return unlink(fname); 675 } 676 677 void os_localtime(struct rtc_time *rt) 678 { 679 time_t t = time(NULL); 680 struct tm *tm; 681 682 tm = localtime(&t); 683 rt->tm_sec = tm->tm_sec; 684 rt->tm_min = tm->tm_min; 685 rt->tm_hour = tm->tm_hour; 686 rt->tm_mday = tm->tm_mday; 687 rt->tm_mon = tm->tm_mon + 1; 688 rt->tm_year = tm->tm_year + 1900; 689 rt->tm_wday = tm->tm_wday; 690 rt->tm_yday = tm->tm_yday; 691 rt->tm_isdst = tm->tm_isdst; 692 } 693 694 void os_abort(void) 695 { 696 abort(); 697 } 698 699 int os_mprotect_allow(void *start, size_t len) 700 { 701 int page_size = getpagesize(); 702 703 /* Move start to the start of a page, len to the end */ 704 start = (void *)(((ulong)start) & ~(page_size - 1)); 705 len = (len + page_size * 2) & ~(page_size - 1); 706 707 return mprotect(start, len, PROT_READ | PROT_WRITE); 708 } 709