uboot/boot/bootm_os.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000-2009
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <bootm.h>
   9#include <bootstage.h>
  10#include <cpu_func.h>
  11#include <efi_loader.h>
  12#include <env.h>
  13#include <fdt_support.h>
  14#include <image.h>
  15#include <lmb.h>
  16#include <log.h>
  17#include <asm/global_data.h>
  18#include <linux/libfdt.h>
  19#include <malloc.h>
  20#include <mapmem.h>
  21#include <vxworks.h>
  22#include <tee/optee.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26static int do_bootm_standalone(int flag, int argc, char *const argv[],
  27                               bootm_headers_t *images)
  28{
  29        char *s;
  30        int (*appl)(int, char *const[]);
  31
  32        /* Don't start if "autostart" is set to "no" */
  33        s = env_get("autostart");
  34        if ((s != NULL) && !strcmp(s, "no")) {
  35                env_set_hex("filesize", images->os.image_len);
  36                return 0;
  37        }
  38        appl = (int (*)(int, char * const []))images->ep;
  39        appl(argc, argv);
  40        return 0;
  41}
  42
  43/*******************************************************************/
  44/* OS booting routines */
  45/*******************************************************************/
  46
  47#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
  48static void copy_args(char *dest, int argc, char *const argv[], char delim)
  49{
  50        int i;
  51
  52        for (i = 0; i < argc; i++) {
  53                if (i > 0)
  54                        *dest++ = delim;
  55                strcpy(dest, argv[i]);
  56                dest += strlen(argv[i]);
  57        }
  58}
  59#endif
  60
  61static void __maybe_unused fit_unsupported_reset(const char *msg)
  62{
  63        if (CONFIG_IS_ENABLED(FIT_VERBOSE)) {
  64                printf("! FIT images not supported for '%s' - must reset board to recover!\n",
  65                       msg);
  66        }
  67}
  68
  69#ifdef CONFIG_BOOTM_NETBSD
  70static int do_bootm_netbsd(int flag, int argc, char *const argv[],
  71                           bootm_headers_t *images)
  72{
  73        void (*loader)(struct bd_info *, image_header_t *, char *, char *);
  74        image_header_t *os_hdr, *hdr;
  75        ulong kernel_data, kernel_len;
  76        char *cmdline;
  77
  78        if (flag != BOOTM_STATE_OS_GO)
  79                return 0;
  80
  81#if defined(CONFIG_FIT)
  82        if (!images->legacy_hdr_valid) {
  83                fit_unsupported_reset("NetBSD");
  84                return 1;
  85        }
  86#endif
  87        hdr = images->legacy_hdr_os;
  88
  89        /*
  90         * Booting a (NetBSD) kernel image
  91         *
  92         * This process is pretty similar to a standalone application:
  93         * The (first part of an multi-) image must be a stage-2 loader,
  94         * which in turn is responsible for loading & invoking the actual
  95         * kernel.  The only differences are the parameters being passed:
  96         * besides the board info strucure, the loader expects a command
  97         * line, the name of the console device, and (optionally) the
  98         * address of the original image header.
  99         */
 100        os_hdr = NULL;
 101        if (image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
 102                image_multi_getimg(hdr, 1, &kernel_data, &kernel_len);
 103                if (kernel_len)
 104                        os_hdr = hdr;
 105        }
 106
 107        if (argc > 0) {
 108                ulong len;
 109                int   i;
 110
 111                for (i = 0, len = 0; i < argc; i += 1)
 112                        len += strlen(argv[i]) + 1;
 113                cmdline = malloc(len);
 114                copy_args(cmdline, argc, argv, ' ');
 115        } else {
 116                cmdline = env_get("bootargs");
 117                if (cmdline == NULL)
 118                        cmdline = "";
 119        }
 120
 121        loader = (void (*)(struct bd_info *, image_header_t *, char *, char *))images->ep;
 122
 123        printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
 124               (ulong)loader);
 125
 126        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 127
 128        /*
 129         * NetBSD Stage-2 Loader Parameters:
 130         *   arg[0]: pointer to board info data
 131         *   arg[1]: image load address
 132         *   arg[2]: char pointer to the console device to use
 133         *   arg[3]: char pointer to the boot arguments
 134         */
 135        (*loader)(gd->bd, os_hdr, "", cmdline);
 136
 137        return 1;
 138}
 139#endif /* CONFIG_BOOTM_NETBSD*/
 140
 141#ifdef CONFIG_BOOTM_RTEMS
 142static int do_bootm_rtems(int flag, int argc, char *const argv[],
 143                          bootm_headers_t *images)
 144{
 145        void (*entry_point)(struct bd_info *);
 146
 147        if (flag != BOOTM_STATE_OS_GO)
 148                return 0;
 149
 150#if defined(CONFIG_FIT)
 151        if (!images->legacy_hdr_valid) {
 152                fit_unsupported_reset("RTEMS");
 153                return 1;
 154        }
 155#endif
 156
 157        entry_point = (void (*)(struct bd_info *))images->ep;
 158
 159        printf("## Transferring control to RTEMS (at address %08lx) ...\n",
 160               (ulong)entry_point);
 161
 162        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 163
 164        /*
 165         * RTEMS Parameters:
 166         *   r3: ptr to board info data
 167         */
 168        (*entry_point)(gd->bd);
 169
 170        return 1;
 171}
 172#endif /* CONFIG_BOOTM_RTEMS */
 173
 174#if defined(CONFIG_BOOTM_OSE)
 175static int do_bootm_ose(int flag, int argc, char *const argv[],
 176                        bootm_headers_t *images)
 177{
 178        void (*entry_point)(void);
 179
 180        if (flag != BOOTM_STATE_OS_GO)
 181                return 0;
 182
 183#if defined(CONFIG_FIT)
 184        if (!images->legacy_hdr_valid) {
 185                fit_unsupported_reset("OSE");
 186                return 1;
 187        }
 188#endif
 189
 190        entry_point = (void (*)(void))images->ep;
 191
 192        printf("## Transferring control to OSE (at address %08lx) ...\n",
 193               (ulong)entry_point);
 194
 195        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 196
 197        /*
 198         * OSE Parameters:
 199         *   None
 200         */
 201        (*entry_point)();
 202
 203        return 1;
 204}
 205#endif /* CONFIG_BOOTM_OSE */
 206
 207#if defined(CONFIG_BOOTM_PLAN9)
 208static int do_bootm_plan9(int flag, int argc, char *const argv[],
 209                          bootm_headers_t *images)
 210{
 211        void (*entry_point)(void);
 212        char *s;
 213
 214        if (flag != BOOTM_STATE_OS_GO)
 215                return 0;
 216
 217#if defined(CONFIG_FIT)
 218        if (!images->legacy_hdr_valid) {
 219                fit_unsupported_reset("Plan 9");
 220                return 1;
 221        }
 222#endif
 223
 224        /* See README.plan9 */
 225        s = env_get("confaddr");
 226        if (s != NULL) {
 227                char *confaddr = (char *)hextoul(s, NULL);
 228
 229                if (argc > 0) {
 230                        copy_args(confaddr, argc, argv, '\n');
 231                } else {
 232                        s = env_get("bootargs");
 233                        if (s != NULL)
 234                                strcpy(confaddr, s);
 235                }
 236        }
 237
 238        entry_point = (void (*)(void))images->ep;
 239
 240        printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
 241               (ulong)entry_point);
 242
 243        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 244
 245        /*
 246         * Plan 9 Parameters:
 247         *   None
 248         */
 249        (*entry_point)();
 250
 251        return 1;
 252}
 253#endif /* CONFIG_BOOTM_PLAN9 */
 254
 255#if defined(CONFIG_BOOTM_VXWORKS) && \
 256        (defined(CONFIG_PPC) || defined(CONFIG_ARM))
 257
 258static void do_bootvx_fdt(bootm_headers_t *images)
 259{
 260#if defined(CONFIG_OF_LIBFDT)
 261        int ret;
 262        char *bootline;
 263        ulong of_size = images->ft_len;
 264        char **of_flat_tree = &images->ft_addr;
 265        struct lmb *lmb = &images->lmb;
 266
 267        if (*of_flat_tree) {
 268                boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
 269
 270                ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
 271                if (ret)
 272                        return;
 273
 274                /* Update ethernet nodes */
 275                fdt_fixup_ethernet(*of_flat_tree);
 276
 277                ret = fdt_add_subnode(*of_flat_tree, 0, "chosen");
 278                if ((ret >= 0 || ret == -FDT_ERR_EXISTS)) {
 279                        bootline = env_get("bootargs");
 280                        if (bootline) {
 281                                ret = fdt_find_and_setprop(*of_flat_tree,
 282                                                "/chosen", "bootargs",
 283                                                bootline,
 284                                                strlen(bootline) + 1, 1);
 285                                if (ret < 0) {
 286                                        printf("## ERROR: %s : %s\n", __func__,
 287                                               fdt_strerror(ret));
 288                                        return;
 289                                }
 290                        }
 291                } else {
 292                        printf("## ERROR: %s : %s\n", __func__,
 293                               fdt_strerror(ret));
 294                        return;
 295                }
 296        }
 297#endif
 298
 299        boot_prep_vxworks(images);
 300
 301        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 302
 303#if defined(CONFIG_OF_LIBFDT)
 304        printf("## Starting vxWorks at 0x%08lx, device tree at 0x%08lx ...\n",
 305               (ulong)images->ep, (ulong)*of_flat_tree);
 306#else
 307        printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
 308#endif
 309
 310        boot_jump_vxworks(images);
 311
 312        puts("## vxWorks terminated\n");
 313}
 314
 315static int do_bootm_vxworks_legacy(int flag, int argc, char *const argv[],
 316                                   bootm_headers_t *images)
 317{
 318        if (flag != BOOTM_STATE_OS_GO)
 319                return 0;
 320
 321#if defined(CONFIG_FIT)
 322        if (!images->legacy_hdr_valid) {
 323                fit_unsupported_reset("VxWorks");
 324                return 1;
 325        }
 326#endif
 327
 328        do_bootvx_fdt(images);
 329
 330        return 1;
 331}
 332
 333int do_bootm_vxworks(int flag, int argc, char *const argv[],
 334                     bootm_headers_t *images)
 335{
 336        char *bootargs;
 337        int pos;
 338        unsigned long vxflags;
 339        bool std_dtb = false;
 340
 341        /* get bootargs env */
 342        bootargs = env_get("bootargs");
 343
 344        if (bootargs != NULL) {
 345                for (pos = 0; pos < strlen(bootargs); pos++) {
 346                        /* find f=0xnumber flag */
 347                        if ((bootargs[pos] == '=') && (pos >= 1) &&
 348                            (bootargs[pos - 1] == 'f')) {
 349                                vxflags = hextoul(&bootargs[pos + 1], NULL);
 350                                if (vxflags & VXWORKS_SYSFLG_STD_DTB)
 351                                        std_dtb = true;
 352                        }
 353                }
 354        }
 355
 356        if (std_dtb) {
 357                if (flag & BOOTM_STATE_OS_PREP)
 358                        printf("   Using standard DTB\n");
 359                return do_bootm_linux(flag, argc, argv, images);
 360        } else {
 361                if (flag & BOOTM_STATE_OS_PREP)
 362                        printf("   !!! WARNING !!! Using legacy DTB\n");
 363                return do_bootm_vxworks_legacy(flag, argc, argv, images);
 364        }
 365}
 366#endif
 367
 368#if defined(CONFIG_CMD_ELF)
 369static int do_bootm_qnxelf(int flag, int argc, char *const argv[],
 370                           bootm_headers_t *images)
 371{
 372        char *local_args[2];
 373        char str[16];
 374        int dcache;
 375
 376        if (flag != BOOTM_STATE_OS_GO)
 377                return 0;
 378
 379#if defined(CONFIG_FIT)
 380        if (!images->legacy_hdr_valid) {
 381                fit_unsupported_reset("QNX");
 382                return 1;
 383        }
 384#endif
 385
 386        sprintf(str, "%lx", images->ep); /* write entry-point into string */
 387        local_args[0] = argv[0];
 388        local_args[1] = str;    /* and provide it via the arguments */
 389
 390        /*
 391         * QNX images require the data cache is disabled.
 392         */
 393        dcache = dcache_status();
 394        if (dcache)
 395                dcache_disable();
 396
 397        do_bootelf(NULL, 0, 2, local_args);
 398
 399        if (dcache)
 400                dcache_enable();
 401
 402        return 1;
 403}
 404#endif
 405
 406#ifdef CONFIG_INTEGRITY
 407static int do_bootm_integrity(int flag, int argc, char *const argv[],
 408                              bootm_headers_t *images)
 409{
 410        void (*entry_point)(void);
 411
 412        if (flag != BOOTM_STATE_OS_GO)
 413                return 0;
 414
 415#if defined(CONFIG_FIT)
 416        if (!images->legacy_hdr_valid) {
 417                fit_unsupported_reset("INTEGRITY");
 418                return 1;
 419        }
 420#endif
 421
 422        entry_point = (void (*)(void))images->ep;
 423
 424        printf("## Transferring control to INTEGRITY (at address %08lx) ...\n",
 425               (ulong)entry_point);
 426
 427        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 428
 429        /*
 430         * INTEGRITY Parameters:
 431         *   None
 432         */
 433        (*entry_point)();
 434
 435        return 1;
 436}
 437#endif
 438
 439#ifdef CONFIG_BOOTM_OPENRTOS
 440static int do_bootm_openrtos(int flag, int argc, char *const argv[],
 441                             bootm_headers_t *images)
 442{
 443        void (*entry_point)(void);
 444
 445        if (flag != BOOTM_STATE_OS_GO)
 446                return 0;
 447
 448        entry_point = (void (*)(void))images->ep;
 449
 450        printf("## Transferring control to OpenRTOS (at address %08lx) ...\n",
 451                (ulong)entry_point);
 452
 453        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 454
 455        /*
 456         * OpenRTOS Parameters:
 457         *   None
 458         */
 459        (*entry_point)();
 460
 461        return 1;
 462}
 463#endif
 464
 465#ifdef CONFIG_BOOTM_OPTEE
 466static int do_bootm_tee(int flag, int argc, char *const argv[],
 467                        bootm_headers_t *images)
 468{
 469        int ret;
 470
 471        /* Verify OS type */
 472        if (images->os.os != IH_OS_TEE) {
 473                return 1;
 474        };
 475
 476        /* Validate OPTEE header */
 477        ret = optee_verify_bootm_image(images->os.image_start,
 478                                       images->os.load,
 479                                       images->os.image_len);
 480        if (ret)
 481                return ret;
 482
 483        /* Locate FDT etc */
 484        ret = bootm_find_images(flag, argc, argv, 0, 0);
 485        if (ret)
 486                return ret;
 487
 488        /* From here we can run the regular linux boot path */
 489        return do_bootm_linux(flag, argc, argv, images);
 490}
 491#endif
 492
 493#ifdef CONFIG_BOOTM_EFI
 494static int do_bootm_efi(int flag, int argc, char *const argv[],
 495                        bootm_headers_t *images)
 496{
 497        int ret;
 498        efi_status_t efi_ret;
 499        void *image_buf;
 500
 501        if (flag != BOOTM_STATE_OS_GO)
 502                return 0;
 503
 504        /* Locate FDT, if provided */
 505        ret = bootm_find_images(flag, argc, argv, 0, 0);
 506        if (ret)
 507                return ret;
 508
 509        /* Initialize EFI drivers */
 510        efi_ret = efi_init_obj_list();
 511        if (efi_ret != EFI_SUCCESS) {
 512                printf("## Failed to initialize UEFI sub-system: r = %lu\n",
 513                       efi_ret & ~EFI_ERROR_MASK);
 514                return 1;
 515        }
 516
 517        /* Install device tree */
 518        efi_ret = efi_install_fdt(images->ft_len
 519                                  ? images->ft_addr : EFI_FDT_USE_INTERNAL);
 520        if (efi_ret != EFI_SUCCESS) {
 521                printf("## Failed to install device tree: r = %lu\n",
 522                       efi_ret & ~EFI_ERROR_MASK);
 523                return 1;
 524        }
 525
 526        /* Run EFI image */
 527        printf("## Transferring control to EFI (at address %08lx) ...\n",
 528               images->ep);
 529        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 530
 531        /* We expect to return */
 532        images->os.type = IH_TYPE_STANDALONE;
 533
 534        image_buf = map_sysmem(images->ep, images->os.image_len);
 535
 536        efi_ret = efi_run_image(image_buf, images->os.image_len);
 537        if (efi_ret != EFI_SUCCESS)
 538                return 1;
 539        return 0;
 540}
 541#endif
 542
 543static boot_os_fn *boot_os[] = {
 544        [IH_OS_U_BOOT] = do_bootm_standalone,
 545#ifdef CONFIG_BOOTM_LINUX
 546        [IH_OS_LINUX] = do_bootm_linux,
 547#endif
 548#ifdef CONFIG_BOOTM_NETBSD
 549        [IH_OS_NETBSD] = do_bootm_netbsd,
 550#endif
 551#ifdef CONFIG_BOOTM_RTEMS
 552        [IH_OS_RTEMS] = do_bootm_rtems,
 553#endif
 554#if defined(CONFIG_BOOTM_OSE)
 555        [IH_OS_OSE] = do_bootm_ose,
 556#endif
 557#if defined(CONFIG_BOOTM_PLAN9)
 558        [IH_OS_PLAN9] = do_bootm_plan9,
 559#endif
 560#if defined(CONFIG_BOOTM_VXWORKS) && \
 561        (defined(CONFIG_PPC) || defined(CONFIG_ARM) || defined(CONFIG_RISCV))
 562        [IH_OS_VXWORKS] = do_bootm_vxworks,
 563#endif
 564#if defined(CONFIG_CMD_ELF)
 565        [IH_OS_QNX] = do_bootm_qnxelf,
 566#endif
 567#ifdef CONFIG_INTEGRITY
 568        [IH_OS_INTEGRITY] = do_bootm_integrity,
 569#endif
 570#ifdef CONFIG_BOOTM_OPENRTOS
 571        [IH_OS_OPENRTOS] = do_bootm_openrtos,
 572#endif
 573#ifdef CONFIG_BOOTM_OPTEE
 574        [IH_OS_TEE] = do_bootm_tee,
 575#endif
 576#ifdef CONFIG_BOOTM_EFI
 577        [IH_OS_EFI] = do_bootm_efi,
 578#endif
 579};
 580
 581/* Allow for arch specific config before we boot */
 582__weak void arch_preboot_os(void)
 583{
 584        /* please define platform specific arch_preboot_os() */
 585}
 586
 587/* Allow for board specific config before we boot */
 588__weak void board_preboot_os(void)
 589{
 590        /* please define board specific board_preboot_os() */
 591}
 592
 593int boot_selected_os(int argc, char *const argv[], int state,
 594                     bootm_headers_t *images, boot_os_fn *boot_fn)
 595{
 596        arch_preboot_os();
 597        board_preboot_os();
 598        boot_fn(state, argc, argv, images);
 599
 600        /* Stand-alone may return when 'autostart' is 'no' */
 601        if (images->os.type == IH_TYPE_STANDALONE ||
 602            IS_ENABLED(CONFIG_SANDBOX) ||
 603            state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
 604                return 0;
 605        bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
 606        debug("\n## Control returned to monitor - resetting...\n");
 607
 608        return BOOTM_ERR_RESET;
 609}
 610
 611boot_os_fn *bootm_os_get_boot_func(int os)
 612{
 613#ifdef CONFIG_NEEDS_MANUAL_RELOC
 614        static bool relocated;
 615
 616        if (!relocated) {
 617                int i;
 618
 619                /* relocate boot function table */
 620                for (i = 0; i < ARRAY_SIZE(boot_os); i++)
 621                        if (boot_os[i] != NULL)
 622                                boot_os[i] += gd->reloc_off;
 623
 624                relocated = true;
 625        }
 626#endif
 627        return boot_os[os];
 628}
 629