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 29*b7b8410aSAlexander Graf __weak void board_quiesce_devices(void) 30*b7b8410aSAlexander Graf { 31*b7b8410aSAlexander Graf } 32*b7b8410aSAlexander Graf 330d0ba59cSSimon Glass void bootm_announce_and_cleanup(void) 340d0ba59cSSimon Glass { 350d0ba59cSSimon Glass printf("\nStarting kernel ...\n\n"); 360d0ba59cSSimon Glass 370d0ba59cSSimon Glass #ifdef CONFIG_SYS_COREBOOT 380d0ba59cSSimon Glass timestamp_add_now(TS_U_BOOT_START_KERNEL); 390d0ba59cSSimon Glass #endif 400d0ba59cSSimon Glass bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 410d0ba59cSSimon Glass #ifdef CONFIG_BOOTSTAGE_REPORT 420d0ba59cSSimon Glass bootstage_report(); 430d0ba59cSSimon Glass #endif 440d0ba59cSSimon Glass } 450d0ba59cSSimon Glass 460d0ba59cSSimon Glass #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) 470d0ba59cSSimon Glass int arch_fixup_memory_node(void *blob) 480d0ba59cSSimon Glass { 490d0ba59cSSimon Glass bd_t *bd = gd->bd; 500d0ba59cSSimon Glass int bank; 510d0ba59cSSimon Glass u64 start[CONFIG_NR_DRAM_BANKS]; 520d0ba59cSSimon Glass u64 size[CONFIG_NR_DRAM_BANKS]; 530d0ba59cSSimon Glass 540d0ba59cSSimon Glass for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { 550d0ba59cSSimon Glass start[bank] = bd->bi_dram[bank].start; 560d0ba59cSSimon Glass size[bank] = bd->bi_dram[bank].size; 570d0ba59cSSimon Glass } 580d0ba59cSSimon Glass 590d0ba59cSSimon Glass return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); 600d0ba59cSSimon Glass } 61fea25720SGraeme Russ #endif 62fea25720SGraeme Russ 630d0ba59cSSimon Glass /* Subcommand: PREP */ 640d0ba59cSSimon Glass static int boot_prep_linux(bootm_headers_t *images) 650d0ba59cSSimon Glass { 660d0ba59cSSimon Glass char *cmd_line_dest = NULL; 670d0ba59cSSimon Glass image_header_t *hdr; 680d0ba59cSSimon Glass int is_zimage = 0; 690d0ba59cSSimon Glass void *data = NULL; 700d0ba59cSSimon Glass size_t len; 710d0ba59cSSimon Glass int ret; 72fea25720SGraeme Russ 730d0ba59cSSimon Glass #ifdef CONFIG_OF_LIBFDT 740d0ba59cSSimon Glass if (images->ft_len) { 750d0ba59cSSimon Glass debug("using: FDT\n"); 760d0ba59cSSimon Glass if (image_setup_linux(images)) { 770d0ba59cSSimon Glass puts("FDT creation failed! hanging..."); 780d0ba59cSSimon Glass hang(); 790d0ba59cSSimon Glass } 800d0ba59cSSimon Glass } 810d0ba59cSSimon Glass #endif 82fea25720SGraeme Russ if (images->legacy_hdr_valid) { 83fea25720SGraeme Russ hdr = images->legacy_hdr_os; 84fea25720SGraeme Russ if (image_check_type(hdr, IH_TYPE_MULTI)) { 850d0ba59cSSimon Glass ulong os_data, os_len; 860d0ba59cSSimon Glass 87fea25720SGraeme Russ /* if multi-part image, we need to get first subimage */ 88fea25720SGraeme Russ image_multi_getimg(hdr, 0, &os_data, &os_len); 890d0ba59cSSimon Glass data = (void *)os_data; 900d0ba59cSSimon Glass len = os_len; 91fea25720SGraeme Russ } else { 92fea25720SGraeme Russ /* otherwise get image data */ 930d0ba59cSSimon Glass data = (void *)image_get_data(hdr); 940d0ba59cSSimon Glass len = image_get_data_size(hdr); 95fea25720SGraeme Russ } 960d0ba59cSSimon Glass is_zimage = 1; 97fea25720SGraeme Russ #if defined(CONFIG_FIT) 980d0ba59cSSimon Glass } else if (images->fit_uname_os && is_zimage) { 99fea25720SGraeme Russ ret = fit_image_get_data(images->fit_hdr_os, 1000d0ba59cSSimon Glass images->fit_noffset_os, 1010d0ba59cSSimon Glass (const void **)&data, &len); 102fea25720SGraeme Russ if (ret) { 103fea25720SGraeme Russ puts("Can't get image data/size!\n"); 104fea25720SGraeme Russ goto error; 105fea25720SGraeme Russ } 1060d0ba59cSSimon Glass is_zimage = 1; 107fea25720SGraeme Russ #endif 1080d0ba59cSSimon Glass } 1090d0ba59cSSimon Glass 1100d0ba59cSSimon Glass if (is_zimage) { 11176539383SSimon Glass ulong load_address; 1120d0ba59cSSimon Glass char *base_ptr; 1130d0ba59cSSimon Glass 1140d0ba59cSSimon Glass base_ptr = (char *)load_zimage(data, len, &load_address); 11576539383SSimon Glass images->os.load = load_address; 1160d0ba59cSSimon Glass cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET; 1170d0ba59cSSimon Glass images->ep = (ulong)base_ptr; 1180d0ba59cSSimon Glass } else if (images->ep) { 1190d0ba59cSSimon Glass cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET; 120fea25720SGraeme Russ } else { 1212c363cb0SSimon Glass printf("## Kernel loading failed (missing x86 kernel setup) ...\n"); 122fea25720SGraeme Russ goto error; 123fea25720SGraeme Russ } 124fea25720SGraeme Russ 1250d0ba59cSSimon Glass printf("Setup at %#08lx\n", images->ep); 1260d0ba59cSSimon Glass ret = setup_zimage((void *)images->ep, cmd_line_dest, 12769370d14SGabe Black 0, images->rd_start, 1280d0ba59cSSimon Glass images->rd_end - images->rd_start); 1290d0ba59cSSimon Glass 1300d0ba59cSSimon Glass if (ret) { 13169370d14SGabe Black printf("## Setting up boot parameters failed ...\n"); 1320d0ba59cSSimon Glass return 1; 133fea25720SGraeme Russ } 134fea25720SGraeme Russ 1350d0ba59cSSimon Glass return 0; 136fea25720SGraeme Russ 137fea25720SGraeme Russ error: 138fea25720SGraeme Russ return 1; 139fea25720SGraeme Russ } 1400d0ba59cSSimon Glass 14176539383SSimon Glass int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) 14276539383SSimon Glass { 14376539383SSimon Glass bootm_announce_and_cleanup(); 14476539383SSimon Glass 14576539383SSimon Glass #ifdef CONFIG_SYS_COREBOOT 14676539383SSimon Glass timestamp_add_now(TS_U_BOOT_START_KERNEL); 14776539383SSimon Glass #endif 14876539383SSimon Glass if (image_64bit) { 14961643ae6SSimon Glass if (!cpu_has_64bit()) { 15061643ae6SSimon Glass puts("Cannot boot 64-bit kernel on 32-bit machine\n"); 15161643ae6SSimon Glass return -EFAULT; 15261643ae6SSimon Glass } 15361643ae6SSimon Glass return cpu_jump_to_64bit(setup_base, load_address); 15476539383SSimon Glass } else { 15576539383SSimon Glass /* 15676539383SSimon Glass * Set %ebx, %ebp, and %edi to 0, %esi to point to the 15776539383SSimon Glass * boot_params structure, and then jump to the kernel. We 15876539383SSimon Glass * assume that %cs is 0x10, 4GB flat, and read/execute, and 15976539383SSimon Glass * the data segments are 0x18, 4GB flat, and read/write. 160a187559eSBin Meng * U-Boot is setting them up that way for itself in 16176539383SSimon Glass * arch/i386/cpu/cpu.c. 162e49cceacSSimon Glass * 163e49cceacSSimon Glass * Note that we cannot currently boot a kernel while running as 164e49cceacSSimon Glass * an EFI application. Please use the payload option for that. 16576539383SSimon Glass */ 166e49cceacSSimon Glass #ifndef CONFIG_EFI_APP 16776539383SSimon Glass __asm__ __volatile__ ( 16876539383SSimon Glass "movl $0, %%ebp\n" 16976539383SSimon Glass "cli\n" 17076539383SSimon Glass "jmp *%[kernel_entry]\n" 17176539383SSimon Glass :: [kernel_entry]"a"(load_address), 17276539383SSimon Glass [boot_params] "S"(setup_base), 17376539383SSimon Glass "b"(0), "D"(0) 17476539383SSimon Glass ); 175e49cceacSSimon Glass #endif 17676539383SSimon Glass } 17776539383SSimon Glass 17876539383SSimon Glass /* We can't get to here */ 17976539383SSimon Glass return -EFAULT; 18076539383SSimon Glass } 18176539383SSimon Glass 1820d0ba59cSSimon Glass /* Subcommand: GO */ 1830d0ba59cSSimon Glass static int boot_jump_linux(bootm_headers_t *images) 1840d0ba59cSSimon Glass { 1850d0ba59cSSimon Glass debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", 1860d0ba59cSSimon Glass images->ep, images->os.load); 1870d0ba59cSSimon Glass 18861643ae6SSimon Glass return boot_linux_kernel(images->ep, images->os.load, 18961643ae6SSimon Glass images->os.arch == IH_ARCH_X86_64); 1900d0ba59cSSimon Glass } 1910d0ba59cSSimon Glass 1920d0ba59cSSimon Glass int do_bootm_linux(int flag, int argc, char * const argv[], 1930d0ba59cSSimon Glass bootm_headers_t *images) 1940d0ba59cSSimon Glass { 1950d0ba59cSSimon Glass /* No need for those on x86 */ 1960d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 1970d0ba59cSSimon Glass return -1; 1980d0ba59cSSimon Glass 1990d0ba59cSSimon Glass if (flag & BOOTM_STATE_OS_PREP) 2000d0ba59cSSimon Glass return boot_prep_linux(images); 2010d0ba59cSSimon Glass 20276539383SSimon Glass if (flag & BOOTM_STATE_OS_GO) 20376539383SSimon Glass return boot_jump_linux(images); 2040d0ba59cSSimon Glass 2050d0ba59cSSimon Glass return boot_jump_linux(images); 2060d0ba59cSSimon Glass } 207