1fea25720SGraeme Russ /* 2fea25720SGraeme Russ * (C) Copyright 2002 3fea25720SGraeme Russ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 4fea25720SGraeme Russ * Marius Groeger <mgroeger@sysgo.de> 5fea25720SGraeme Russ * 6fea25720SGraeme Russ * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) 7fea25720SGraeme Russ * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 9fea25720SGraeme Russ */ 10fea25720SGraeme Russ 11fea25720SGraeme Russ #include <common.h> 12fea25720SGraeme Russ #include <command.h> 1376539383SSimon Glass #include <errno.h> 140d0ba59cSSimon Glass #include <fdt_support.h> 15fea25720SGraeme Russ #include <image.h> 16fea25720SGraeme Russ #include <u-boot/zlib.h> 1769370d14SGabe Black #include <asm/bootparam.h> 1861643ae6SSimon Glass #include <asm/cpu.h> 19fea25720SGraeme Russ #include <asm/byteorder.h> 20fea25720SGraeme Russ #include <asm/zimage.h> 210d0ba59cSSimon Glass #ifdef CONFIG_SYS_COREBOOT 220d0ba59cSSimon Glass #include <asm/arch/timestamp.h> 230d0ba59cSSimon Glass #endif 24fea25720SGraeme Russ 258b097916SSimon Glass DECLARE_GLOBAL_DATA_PTR; 268b097916SSimon Glass 2769370d14SGabe Black #define COMMAND_LINE_OFFSET 0x9000 2869370d14SGabe Black 2963c09417SMasahiro Yamada int arch_fixup_fdt(void *blob) 3063c09417SMasahiro Yamada { 3163c09417SMasahiro Yamada return 0; 3263c09417SMasahiro Yamada } 3363c09417SMasahiro Yamada 34b7b8410aSAlexander Graf __weak void board_quiesce_devices(void) 35b7b8410aSAlexander Graf { 36b7b8410aSAlexander Graf } 37b7b8410aSAlexander Graf 380d0ba59cSSimon Glass void bootm_announce_and_cleanup(void) 390d0ba59cSSimon Glass { 400d0ba59cSSimon Glass printf("\nStarting kernel ...\n\n"); 410d0ba59cSSimon Glass 420d0ba59cSSimon Glass #ifdef CONFIG_SYS_COREBOOT 430d0ba59cSSimon Glass timestamp_add_now(TS_U_BOOT_START_KERNEL); 440d0ba59cSSimon Glass #endif 450d0ba59cSSimon Glass bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 460d0ba59cSSimon Glass #ifdef CONFIG_BOOTSTAGE_REPORT 470d0ba59cSSimon Glass bootstage_report(); 480d0ba59cSSimon Glass #endif 490d0ba59cSSimon Glass } 500d0ba59cSSimon Glass 510d0ba59cSSimon Glass #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) 520d0ba59cSSimon Glass int arch_fixup_memory_node(void *blob) 530d0ba59cSSimon Glass { 540d0ba59cSSimon Glass bd_t *bd = gd->bd; 550d0ba59cSSimon Glass int bank; 560d0ba59cSSimon Glass u64 start[CONFIG_NR_DRAM_BANKS]; 570d0ba59cSSimon Glass u64 size[CONFIG_NR_DRAM_BANKS]; 580d0ba59cSSimon Glass 590d0ba59cSSimon Glass for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { 600d0ba59cSSimon Glass start[bank] = bd->bi_dram[bank].start; 610d0ba59cSSimon Glass size[bank] = bd->bi_dram[bank].size; 620d0ba59cSSimon Glass } 630d0ba59cSSimon Glass 640d0ba59cSSimon Glass return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); 650d0ba59cSSimon Glass } 66fea25720SGraeme Russ #endif 67fea25720SGraeme Russ 680d0ba59cSSimon Glass /* Subcommand: PREP */ 690d0ba59cSSimon Glass static int boot_prep_linux(bootm_headers_t *images) 700d0ba59cSSimon Glass { 710d0ba59cSSimon Glass char *cmd_line_dest = NULL; 720d0ba59cSSimon Glass image_header_t *hdr; 730d0ba59cSSimon Glass int is_zimage = 0; 740d0ba59cSSimon Glass void *data = NULL; 750d0ba59cSSimon Glass size_t len; 760d0ba59cSSimon Glass int ret; 77fea25720SGraeme Russ 780d0ba59cSSimon Glass #ifdef CONFIG_OF_LIBFDT 790d0ba59cSSimon Glass if (images->ft_len) { 800d0ba59cSSimon Glass debug("using: FDT\n"); 810d0ba59cSSimon Glass if (image_setup_linux(images)) { 820d0ba59cSSimon Glass puts("FDT creation failed! hanging..."); 830d0ba59cSSimon Glass hang(); 840d0ba59cSSimon Glass } 850d0ba59cSSimon Glass } 860d0ba59cSSimon Glass #endif 87fea25720SGraeme Russ if (images->legacy_hdr_valid) { 88fea25720SGraeme Russ hdr = images->legacy_hdr_os; 89fea25720SGraeme Russ if (image_check_type(hdr, IH_TYPE_MULTI)) { 900d0ba59cSSimon Glass ulong os_data, os_len; 910d0ba59cSSimon Glass 92fea25720SGraeme Russ /* if multi-part image, we need to get first subimage */ 93fea25720SGraeme Russ image_multi_getimg(hdr, 0, &os_data, &os_len); 940d0ba59cSSimon Glass data = (void *)os_data; 950d0ba59cSSimon Glass len = os_len; 96fea25720SGraeme Russ } else { 97fea25720SGraeme Russ /* otherwise get image data */ 980d0ba59cSSimon Glass data = (void *)image_get_data(hdr); 990d0ba59cSSimon Glass len = image_get_data_size(hdr); 100fea25720SGraeme Russ } 1010d0ba59cSSimon Glass is_zimage = 1; 102fea25720SGraeme Russ #if defined(CONFIG_FIT) 103*13c531e5SStefan Roese } else if (images->fit_uname_os) { 104fea25720SGraeme Russ ret = fit_image_get_data(images->fit_hdr_os, 1050d0ba59cSSimon Glass images->fit_noffset_os, 1060d0ba59cSSimon Glass (const void **)&data, &len); 107fea25720SGraeme Russ if (ret) { 108fea25720SGraeme Russ puts("Can't get image data/size!\n"); 109fea25720SGraeme Russ goto error; 110fea25720SGraeme Russ } 1110d0ba59cSSimon Glass is_zimage = 1; 112fea25720SGraeme Russ #endif 1130d0ba59cSSimon Glass } 1140d0ba59cSSimon Glass 1150d0ba59cSSimon Glass if (is_zimage) { 11676539383SSimon Glass ulong load_address; 1170d0ba59cSSimon Glass char *base_ptr; 1180d0ba59cSSimon Glass 1190d0ba59cSSimon Glass base_ptr = (char *)load_zimage(data, len, &load_address); 12076539383SSimon Glass images->os.load = load_address; 1210d0ba59cSSimon Glass cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET; 1220d0ba59cSSimon Glass images->ep = (ulong)base_ptr; 1230d0ba59cSSimon Glass } else if (images->ep) { 1240d0ba59cSSimon Glass cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET; 125fea25720SGraeme Russ } else { 1262c363cb0SSimon Glass printf("## Kernel loading failed (missing x86 kernel setup) ...\n"); 127fea25720SGraeme Russ goto error; 128fea25720SGraeme Russ } 129fea25720SGraeme Russ 1300d0ba59cSSimon Glass printf("Setup at %#08lx\n", images->ep); 1310d0ba59cSSimon Glass ret = setup_zimage((void *)images->ep, cmd_line_dest, 13269370d14SGabe Black 0, images->rd_start, 1330d0ba59cSSimon Glass images->rd_end - images->rd_start); 1340d0ba59cSSimon Glass 1350d0ba59cSSimon Glass if (ret) { 13669370d14SGabe Black printf("## Setting up boot parameters failed ...\n"); 1370d0ba59cSSimon Glass return 1; 138fea25720SGraeme Russ } 139fea25720SGraeme Russ 1400d0ba59cSSimon Glass return 0; 141fea25720SGraeme Russ 142fea25720SGraeme Russ error: 143fea25720SGraeme Russ return 1; 144fea25720SGraeme Russ } 1450d0ba59cSSimon Glass 14676539383SSimon Glass int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) 14776539383SSimon Glass { 14876539383SSimon Glass bootm_announce_and_cleanup(); 14976539383SSimon Glass 15076539383SSimon Glass #ifdef CONFIG_SYS_COREBOOT 15176539383SSimon Glass timestamp_add_now(TS_U_BOOT_START_KERNEL); 15276539383SSimon Glass #endif 15376539383SSimon Glass if (image_64bit) { 15461643ae6SSimon Glass if (!cpu_has_64bit()) { 15561643ae6SSimon Glass puts("Cannot boot 64-bit kernel on 32-bit machine\n"); 15661643ae6SSimon Glass return -EFAULT; 15761643ae6SSimon Glass } 15823b89d4dSSimon Glass /* At present 64-bit U-Boot does not support booting a 15923b89d4dSSimon Glass * kernel. 16023b89d4dSSimon Glass * TODO(sjg@chromium.org): Support booting both 32-bit and 16123b89d4dSSimon Glass * 64-bit kernels from 64-bit U-Boot. 16223b89d4dSSimon Glass */ 16323b89d4dSSimon Glass #if !CONFIG_IS_ENABLED(X86_64) 16461643ae6SSimon Glass return cpu_jump_to_64bit(setup_base, load_address); 16523b89d4dSSimon Glass #endif 16676539383SSimon Glass } else { 16776539383SSimon Glass /* 16876539383SSimon Glass * Set %ebx, %ebp, and %edi to 0, %esi to point to the 16976539383SSimon Glass * boot_params structure, and then jump to the kernel. We 17076539383SSimon Glass * assume that %cs is 0x10, 4GB flat, and read/execute, and 17176539383SSimon Glass * the data segments are 0x18, 4GB flat, and read/write. 172a187559eSBin Meng * U-Boot is setting them up that way for itself in 17376539383SSimon Glass * arch/i386/cpu/cpu.c. 174e49cceacSSimon Glass * 175e49cceacSSimon Glass * Note that we cannot currently boot a kernel while running as 176e49cceacSSimon Glass * an EFI application. Please use the payload option for that. 17776539383SSimon Glass */ 178e49cceacSSimon Glass #ifndef CONFIG_EFI_APP 17976539383SSimon Glass __asm__ __volatile__ ( 18076539383SSimon Glass "movl $0, %%ebp\n" 18176539383SSimon Glass "cli\n" 18276539383SSimon Glass "jmp *%[kernel_entry]\n" 18376539383SSimon Glass :: [kernel_entry]"a"(load_address), 18476539383SSimon Glass [boot_params] "S"(setup_base), 18576539383SSimon Glass "b"(0), "D"(0) 18676539383SSimon Glass ); 187e49cceacSSimon Glass #endif 18876539383SSimon Glass } 18976539383SSimon Glass 19076539383SSimon Glass /* We can't get to here */ 19176539383SSimon Glass return -EFAULT; 19276539383SSimon Glass } 19376539383SSimon Glass 1940d0ba59cSSimon Glass /* Subcommand: GO */ 1950d0ba59cSSimon Glass static int boot_jump_linux(bootm_headers_t *images) 1960d0ba59cSSimon Glass { 1970d0ba59cSSimon Glass debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", 1980d0ba59cSSimon Glass images->ep, images->os.load); 1990d0ba59cSSimon Glass 20061643ae6SSimon Glass return boot_linux_kernel(images->ep, images->os.load, 20161643ae6SSimon Glass images->os.arch == IH_ARCH_X86_64); 2020d0ba59cSSimon Glass } 2030d0ba59cSSimon Glass 2040d0ba59cSSimon Glass int do_bootm_linux(int flag, int argc, char * const argv[], 2050d0ba59cSSimon Glass bootm_headers_t *images) 2060d0ba59cSSimon Glass { 2070d0ba59cSSimon Glass /* No need for those on x86 */ 2080d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 2090d0ba59cSSimon Glass return -1; 2100d0ba59cSSimon Glass 2110d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_PREP) 2120d0ba59cSSimon Glass return boot_prep_linux(images); 2130d0ba59cSSimon Glass 21476539383SSimon Glass if (flag & BOOTM_STATE_OS_GO) 21576539383SSimon Glass return boot_jump_linux(images); 2160d0ba59cSSimon Glass 2170d0ba59cSSimon Glass return boot_jump_linux(images); 2180d0ba59cSSimon Glass } 219