uboot/arch/x86/lib/bootm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2002
   4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   5 * Marius Groeger <mgroeger@sysgo.de>
   6 *
   7 * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
   8 */
   9
  10#include <common.h>
  11#include <bootstage.h>
  12#include <command.h>
  13#include <hang.h>
  14#include <log.h>
  15#include <dm/device.h>
  16#include <dm/root.h>
  17#include <errno.h>
  18#include <fdt_support.h>
  19#include <image.h>
  20#include <u-boot/zlib.h>
  21#include <asm/bootparam.h>
  22#include <asm/cpu.h>
  23#include <asm/byteorder.h>
  24#include <asm/zimage.h>
  25#ifdef CONFIG_SYS_COREBOOT
  26#include <asm/arch/timestamp.h>
  27#endif
  28
  29DECLARE_GLOBAL_DATA_PTR;
  30
  31#define COMMAND_LINE_OFFSET 0x9000
  32
  33void bootm_announce_and_cleanup(void)
  34{
  35        printf("\nStarting kernel ...\n\n");
  36
  37#ifdef CONFIG_SYS_COREBOOT
  38        timestamp_add_now(TS_U_BOOT_START_KERNEL);
  39#endif
  40        bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
  41#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
  42        bootstage_report();
  43#endif
  44
  45        /*
  46         * Call remove function of all devices with a removal flag set.
  47         * This may be useful for last-stage operations, like cancelling
  48         * of DMA operation or releasing device internal buffers.
  49         */
  50        dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
  51}
  52
  53#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
  54int arch_fixup_memory_node(void *blob)
  55{
  56        struct bd_info  *bd = gd->bd;
  57        int bank;
  58        u64 start[CONFIG_NR_DRAM_BANKS];
  59        u64 size[CONFIG_NR_DRAM_BANKS];
  60
  61        for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
  62                start[bank] = bd->bi_dram[bank].start;
  63                size[bank] = bd->bi_dram[bank].size;
  64        }
  65
  66        return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
  67}
  68#endif
  69
  70/* Subcommand: PREP */
  71static int boot_prep_linux(bootm_headers_t *images)
  72{
  73        char *cmd_line_dest = NULL;
  74        image_header_t *hdr;
  75        int is_zimage = 0;
  76        void *data = NULL;
  77        size_t len;
  78        int ret;
  79
  80#ifdef CONFIG_OF_LIBFDT
  81        if (images->ft_len) {
  82                debug("using: FDT\n");
  83                if (image_setup_linux(images)) {
  84                        puts("FDT creation failed! hanging...");
  85                        hang();
  86                }
  87        }
  88#endif
  89        if (images->legacy_hdr_valid) {
  90                hdr = images->legacy_hdr_os;
  91                if (image_check_type(hdr, IH_TYPE_MULTI)) {
  92                        ulong os_data, os_len;
  93
  94                        /* if multi-part image, we need to get first subimage */
  95                        image_multi_getimg(hdr, 0, &os_data, &os_len);
  96                        data = (void *)os_data;
  97                        len = os_len;
  98                } else {
  99                        /* otherwise get image data */
 100                        data = (void *)image_get_data(hdr);
 101                        len = image_get_data_size(hdr);
 102                }
 103                is_zimage = 1;
 104#if defined(CONFIG_FIT)
 105        } else if (images->fit_uname_os && is_zimage) {
 106                ret = fit_image_get_data(images->fit_hdr_os,
 107                                images->fit_noffset_os,
 108                                (const void **)&data, &len);
 109                if (ret) {
 110                        puts("Can't get image data/size!\n");
 111                        goto error;
 112                }
 113                is_zimage = 1;
 114#endif
 115        }
 116
 117        if (is_zimage) {
 118                ulong load_address;
 119                char *base_ptr;
 120
 121                base_ptr = (char *)load_zimage(data, len, &load_address);
 122                if (!base_ptr) {
 123                        puts("## Kernel loading failed ...\n");
 124                        goto error;
 125                }
 126                images->os.load = load_address;
 127                cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
 128                images->ep = (ulong)base_ptr;
 129        } else if (images->ep) {
 130                cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
 131        } else {
 132                printf("## Kernel loading failed (missing x86 kernel setup) ...\n");
 133                goto error;
 134        }
 135
 136        printf("Setup at %#08lx\n", images->ep);
 137        ret = setup_zimage((void *)images->ep, cmd_line_dest,
 138                        0, images->rd_start,
 139                        images->rd_end - images->rd_start, 0);
 140
 141        if (ret) {
 142                printf("## Setting up boot parameters failed ...\n");
 143                return 1;
 144        }
 145
 146        return 0;
 147
 148error:
 149        return 1;
 150}
 151
 152int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
 153{
 154        bootm_announce_and_cleanup();
 155
 156#ifdef CONFIG_SYS_COREBOOT
 157        timestamp_add_now(TS_U_BOOT_START_KERNEL);
 158#endif
 159        if (image_64bit) {
 160                if (!cpu_has_64bit()) {
 161                        puts("Cannot boot 64-bit kernel on 32-bit machine\n");
 162                        return -EFAULT;
 163                }
 164                /* At present 64-bit U-Boot does not support booting a
 165                 * kernel.
 166                 * TODO(sjg@chromium.org): Support booting both 32-bit and
 167                 * 64-bit kernels from 64-bit U-Boot.
 168                 */
 169#if !CONFIG_IS_ENABLED(X86_64)
 170                return cpu_jump_to_64bit(setup_base, load_address);
 171#endif
 172        } else {
 173                /*
 174                * Set %ebx, %ebp, and %edi to 0, %esi to point to the
 175                * boot_params structure, and then jump to the kernel. We
 176                * assume that %cs is 0x10, 4GB flat, and read/execute, and
 177                * the data segments are 0x18, 4GB flat, and read/write.
 178                * U-Boot is setting them up that way for itself in
 179                * arch/i386/cpu/cpu.c.
 180                *
 181                * Note that we cannot currently boot a kernel while running as
 182                * an EFI application. Please use the payload option for that.
 183                */
 184#ifndef CONFIG_EFI_APP
 185                __asm__ __volatile__ (
 186                "movl $0, %%ebp\n"
 187                "cli\n"
 188                "jmp *%[kernel_entry]\n"
 189                :: [kernel_entry]"a"(load_address),
 190                [boot_params] "S"(setup_base),
 191                "b"(0), "D"(0)
 192                );
 193#endif
 194        }
 195
 196        /* We can't get to here */
 197        return -EFAULT;
 198}
 199
 200/* Subcommand: GO */
 201static int boot_jump_linux(bootm_headers_t *images)
 202{
 203        debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
 204              images->ep, images->os.load);
 205
 206        return boot_linux_kernel(images->ep, images->os.load,
 207                                 images->os.arch == IH_ARCH_X86_64);
 208}
 209
 210int do_bootm_linux(int flag, int argc, char *const argv[],
 211                   bootm_headers_t *images)
 212{
 213        /* No need for those on x86 */
 214        if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
 215                return -1;
 216
 217        if (flag & BOOTM_STATE_OS_PREP)
 218                return boot_prep_linux(images);
 219
 220        if (flag & BOOTM_STATE_OS_GO)
 221                return boot_jump_linux(images);
 222
 223        return boot_jump_linux(images);
 224}
 225