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 290d0ba59cSSimon Glass /* 300d0ba59cSSimon Glass * Implement a weak default function for boards that optionally 310d0ba59cSSimon Glass * need to clean up the system before jumping to the kernel. 320d0ba59cSSimon Glass */ 330d0ba59cSSimon Glass __weak void board_final_cleanup(void) 34fea25720SGraeme Russ { 350d0ba59cSSimon Glass } 36fea25720SGraeme Russ 370d0ba59cSSimon Glass void bootm_announce_and_cleanup(void) 380d0ba59cSSimon Glass { 390d0ba59cSSimon Glass printf("\nStarting kernel ...\n\n"); 400d0ba59cSSimon Glass 410d0ba59cSSimon Glass #ifdef CONFIG_SYS_COREBOOT 420d0ba59cSSimon Glass timestamp_add_now(TS_U_BOOT_START_KERNEL); 430d0ba59cSSimon Glass #endif 440d0ba59cSSimon Glass bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 450d0ba59cSSimon Glass #ifdef CONFIG_BOOTSTAGE_REPORT 460d0ba59cSSimon Glass bootstage_report(); 470d0ba59cSSimon Glass #endif 480d0ba59cSSimon Glass board_final_cleanup(); 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) 1030d0ba59cSSimon Glass } else if (images->fit_uname_os && is_zimage) { 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 } 15861643ae6SSimon Glass return cpu_jump_to_64bit(setup_base, load_address); 15976539383SSimon Glass } else { 16076539383SSimon Glass /* 16176539383SSimon Glass * Set %ebx, %ebp, and %edi to 0, %esi to point to the 16276539383SSimon Glass * boot_params structure, and then jump to the kernel. We 16376539383SSimon Glass * assume that %cs is 0x10, 4GB flat, and read/execute, and 16476539383SSimon Glass * the data segments are 0x18, 4GB flat, and read/write. 16576539383SSimon Glass * U-boot is setting them up that way for itself in 16676539383SSimon Glass * arch/i386/cpu/cpu.c. 167*e49cceacSSimon Glass * 168*e49cceacSSimon Glass * Note that we cannot currently boot a kernel while running as 169*e49cceacSSimon Glass * an EFI application. Please use the payload option for that. 17076539383SSimon Glass */ 171*e49cceacSSimon Glass #ifndef CONFIG_EFI_APP 17276539383SSimon Glass __asm__ __volatile__ ( 17376539383SSimon Glass "movl $0, %%ebp\n" 17476539383SSimon Glass "cli\n" 17576539383SSimon Glass "jmp *%[kernel_entry]\n" 17676539383SSimon Glass :: [kernel_entry]"a"(load_address), 17776539383SSimon Glass [boot_params] "S"(setup_base), 17876539383SSimon Glass "b"(0), "D"(0) 17976539383SSimon Glass ); 180*e49cceacSSimon Glass #endif 18176539383SSimon Glass } 18276539383SSimon Glass 18376539383SSimon Glass /* We can't get to here */ 18476539383SSimon Glass return -EFAULT; 18576539383SSimon Glass } 18676539383SSimon Glass 1870d0ba59cSSimon Glass /* Subcommand: GO */ 1880d0ba59cSSimon Glass static int boot_jump_linux(bootm_headers_t *images) 1890d0ba59cSSimon Glass { 1900d0ba59cSSimon Glass debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", 1910d0ba59cSSimon Glass images->ep, images->os.load); 1920d0ba59cSSimon Glass 19361643ae6SSimon Glass return boot_linux_kernel(images->ep, images->os.load, 19461643ae6SSimon Glass images->os.arch == IH_ARCH_X86_64); 1950d0ba59cSSimon Glass } 1960d0ba59cSSimon Glass 1970d0ba59cSSimon Glass int do_bootm_linux(int flag, int argc, char * const argv[], 1980d0ba59cSSimon Glass bootm_headers_t *images) 1990d0ba59cSSimon Glass { 2000d0ba59cSSimon Glass /* No need for those on x86 */ 2010d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 2020d0ba59cSSimon Glass return -1; 2030d0ba59cSSimon Glass 2040d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_PREP) 2050d0ba59cSSimon Glass return boot_prep_linux(images); 2060d0ba59cSSimon Glass 20776539383SSimon Glass if (flag & BOOTM_STATE_OS_GO) 20876539383SSimon Glass return boot_jump_linux(images); 2090d0ba59cSSimon Glass 2100d0ba59cSSimon Glass return boot_jump_linux(images); 2110d0ba59cSSimon Glass } 212