X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=arch%2Fx86%2Flib%2Fbootm.c;h=783be691aff9afd9c83fb3895f9151a20d03854e;hb=8a8c0352556cb63c941d9bf1ff58d45c4d27d61d;hp=bac7b4f0cfb8a3b629e11010073509a2b463191b;hpb=4ebbba442587cb03590c0747fd1fea16a158f15c;p=u-boot diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index bac7b4f0cf..783be691af 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -5,96 +5,207 @@ * * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include +#include #include #include +#include +#include #include #include +#ifdef CONFIG_SYS_COREBOOT +#include +#endif -/*cmd_boot.c*/ -int do_bootm_linux(int flag, int argc, char * const argv[], - bootm_headers_t *images) +DECLARE_GLOBAL_DATA_PTR; + +#define COMMAND_LINE_OFFSET 0x9000 + +/* + * Implement a weak default function for boards that optionally + * need to clean up the system before jumping to the kernel. + */ +__weak void board_final_cleanup(void) { - void *base_ptr = NULL; - ulong os_data, os_len; - image_header_t *hdr; +} -#if defined(CONFIG_FIT) - const void *data; - size_t len; +void bootm_announce_and_cleanup(void) +{ + printf("\nStarting kernel ...\n\n"); + +#ifdef CONFIG_SYS_COREBOOT + timestamp_add_now(TS_U_BOOT_START_KERNEL); +#endif + bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); +#ifdef CONFIG_BOOTSTAGE_REPORT + bootstage_report(); #endif + board_final_cleanup(); +} - if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) - return 1; +#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) +int arch_fixup_memory_node(void *blob) +{ + bd_t *bd = gd->bd; + int bank; + u64 start[CONFIG_NR_DRAM_BANKS]; + u64 size[CONFIG_NR_DRAM_BANKS]; + + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + start[bank] = bd->bi_dram[bank].start; + size[bank] = bd->bi_dram[bank].size; + } + + return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); +} +#endif +/* Subcommand: PREP */ +static int boot_prep_linux(bootm_headers_t *images) +{ + char *cmd_line_dest = NULL; + image_header_t *hdr; + int is_zimage = 0; + void *data = NULL; + size_t len; + int ret; + +#ifdef CONFIG_OF_LIBFDT + if (images->ft_len) { + debug("using: FDT\n"); + if (image_setup_linux(images)) { + puts("FDT creation failed! hanging..."); + hang(); + } + } +#endif if (images->legacy_hdr_valid) { hdr = images->legacy_hdr_os; if (image_check_type(hdr, IH_TYPE_MULTI)) { + ulong os_data, os_len; + /* if multi-part image, we need to get first subimage */ image_multi_getimg(hdr, 0, &os_data, &os_len); + data = (void *)os_data; + len = os_len; } else { /* otherwise get image data */ - os_data = image_get_data(hdr); - os_len = image_get_data_size(hdr); + data = (void *)image_get_data(hdr); + len = image_get_data_size(hdr); } + is_zimage = 1; #if defined(CONFIG_FIT) - } else if (images->fit_uname_os) { + } else if (images->fit_uname_os && is_zimage) { ret = fit_image_get_data(images->fit_hdr_os, - images->fit_noffset_os, &data, &len); + images->fit_noffset_os, + (const void **)&data, &len); if (ret) { puts("Can't get image data/size!\n"); goto error; } - os_data = (ulong)data; - os_len = (ulong)len; + is_zimage = 1; #endif - } else { - puts("Could not find kernel image!\n"); - goto error; } -#ifdef CONFIG_CMD_ZBOOT - base_ptr = load_zimage((void *)os_data, os_len, - images->rd_start, images->rd_end - images->rd_start, 0); -#endif + if (is_zimage) { + ulong load_address; + char *base_ptr; - if (NULL == base_ptr) { - printf("## Kernel loading failed ...\n"); + base_ptr = (char *)load_zimage(data, len, &load_address); + images->os.load = load_address; + cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET; + images->ep = (ulong)base_ptr; + } else if (images->ep) { + cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET; + } else { + printf("## Kernel loading failed (missing x86 kernel setup) ...\n"); goto error; - } -#ifdef DEBUG - printf("## Transferring control to Linux (at address %08x) ...\n", - (u32)base_ptr); -#endif + printf("Setup at %#08lx\n", images->ep); + ret = setup_zimage((void *)images->ep, cmd_line_dest, + 0, images->rd_start, + images->rd_end - images->rd_start); - /* we assume that the kernel is in place */ - printf("\nStarting kernel ...\n\n"); + if (ret) { + printf("## Setting up boot parameters failed ...\n"); + return 1; + } - boot_zimage(base_ptr); - /* does not return */ + return 0; error: return 1; } + +int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) +{ + bootm_announce_and_cleanup(); + +#ifdef CONFIG_SYS_COREBOOT + timestamp_add_now(TS_U_BOOT_START_KERNEL); +#endif + if (image_64bit) { + if (!cpu_has_64bit()) { + puts("Cannot boot 64-bit kernel on 32-bit machine\n"); + return -EFAULT; + } + return cpu_jump_to_64bit(setup_base, load_address); + } else { + /* + * Set %ebx, %ebp, and %edi to 0, %esi to point to the + * boot_params structure, and then jump to the kernel. We + * assume that %cs is 0x10, 4GB flat, and read/execute, and + * the data segments are 0x18, 4GB flat, and read/write. + * U-Boot is setting them up that way for itself in + * arch/i386/cpu/cpu.c. + * + * Note that we cannot currently boot a kernel while running as + * an EFI application. Please use the payload option for that. + */ +#ifndef CONFIG_EFI_APP + __asm__ __volatile__ ( + "movl $0, %%ebp\n" + "cli\n" + "jmp *%[kernel_entry]\n" + :: [kernel_entry]"a"(load_address), + [boot_params] "S"(setup_base), + "b"(0), "D"(0) + ); +#endif + } + + /* We can't get to here */ + return -EFAULT; +} + +/* Subcommand: GO */ +static int boot_jump_linux(bootm_headers_t *images) +{ + debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", + images->ep, images->os.load); + + return boot_linux_kernel(images->ep, images->os.load, + images->os.arch == IH_ARCH_X86_64); +} + +int do_bootm_linux(int flag, int argc, char * const argv[], + bootm_headers_t *images) +{ + /* No need for those on x86 */ + if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) + return -1; + + if (flag & BOOTM_STATE_OS_PREP) + return boot_prep_linux(images); + + if (flag & BOOTM_STATE_OS_GO) + return boot_jump_linux(images); + + return boot_jump_linux(images); +}