1 /* 2 * (C) Copyright 2002 3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 4 * Marius Groeger <mgroeger@sysgo.de> 5 * 6 * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <errno.h> 14 #include <fdt_support.h> 15 #include <image.h> 16 #include <u-boot/zlib.h> 17 #include <asm/bootparam.h> 18 #include <asm/byteorder.h> 19 #include <asm/zimage.h> 20 #ifdef CONFIG_SYS_COREBOOT 21 #include <asm/arch/timestamp.h> 22 #endif 23 24 #define COMMAND_LINE_OFFSET 0x9000 25 26 /* 27 * Implement a weak default function for boards that optionally 28 * need to clean up the system before jumping to the kernel. 29 */ 30 __weak void board_final_cleanup(void) 31 { 32 } 33 34 void bootm_announce_and_cleanup(void) 35 { 36 printf("\nStarting kernel ...\n\n"); 37 38 #ifdef CONFIG_SYS_COREBOOT 39 timestamp_add_now(TS_U_BOOT_START_KERNEL); 40 #endif 41 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 42 #ifdef CONFIG_BOOTSTAGE_REPORT 43 bootstage_report(); 44 #endif 45 board_final_cleanup(); 46 } 47 48 #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) 49 int arch_fixup_memory_node(void *blob) 50 { 51 bd_t *bd = gd->bd; 52 int bank; 53 u64 start[CONFIG_NR_DRAM_BANKS]; 54 u64 size[CONFIG_NR_DRAM_BANKS]; 55 56 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { 57 start[bank] = bd->bi_dram[bank].start; 58 size[bank] = bd->bi_dram[bank].size; 59 } 60 61 return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); 62 } 63 #endif 64 65 /* Subcommand: PREP */ 66 static int boot_prep_linux(bootm_headers_t *images) 67 { 68 char *cmd_line_dest = NULL; 69 image_header_t *hdr; 70 int is_zimage = 0; 71 void *data = NULL; 72 size_t len; 73 int ret; 74 75 #ifdef CONFIG_OF_LIBFDT 76 if (images->ft_len) { 77 debug("using: FDT\n"); 78 if (image_setup_linux(images)) { 79 puts("FDT creation failed! hanging..."); 80 hang(); 81 } 82 } 83 #endif 84 if (images->legacy_hdr_valid) { 85 hdr = images->legacy_hdr_os; 86 if (image_check_type(hdr, IH_TYPE_MULTI)) { 87 ulong os_data, os_len; 88 89 /* if multi-part image, we need to get first subimage */ 90 image_multi_getimg(hdr, 0, &os_data, &os_len); 91 data = (void *)os_data; 92 len = os_len; 93 } else { 94 /* otherwise get image data */ 95 data = (void *)image_get_data(hdr); 96 len = image_get_data_size(hdr); 97 } 98 is_zimage = 1; 99 #if defined(CONFIG_FIT) 100 } else if (images->fit_uname_os && is_zimage) { 101 ret = fit_image_get_data(images->fit_hdr_os, 102 images->fit_noffset_os, 103 (const void **)&data, &len); 104 if (ret) { 105 puts("Can't get image data/size!\n"); 106 goto error; 107 } 108 is_zimage = 1; 109 #endif 110 } 111 112 if (is_zimage) { 113 ulong load_address; 114 char *base_ptr; 115 116 base_ptr = (char *)load_zimage(data, len, &load_address); 117 images->os.load = load_address; 118 cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET; 119 images->ep = (ulong)base_ptr; 120 } else if (images->ep) { 121 cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET; 122 } else { 123 printf("## Kernel loading failed (no setup) ...\n"); 124 goto error; 125 } 126 127 printf("Setup at %#08lx\n", images->ep); 128 ret = setup_zimage((void *)images->ep, cmd_line_dest, 129 0, images->rd_start, 130 images->rd_end - images->rd_start); 131 132 if (ret) { 133 printf("## Setting up boot parameters failed ...\n"); 134 return 1; 135 } 136 137 return 0; 138 139 error: 140 return 1; 141 } 142 143 int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) 144 { 145 bootm_announce_and_cleanup(); 146 147 #ifdef CONFIG_SYS_COREBOOT 148 timestamp_add_now(TS_U_BOOT_START_KERNEL); 149 #endif 150 if (image_64bit) { 151 /* TODO(boot 64-bit kernel) */ 152 } else { 153 /* 154 * Set %ebx, %ebp, and %edi to 0, %esi to point to the 155 * boot_params structure, and then jump to the kernel. We 156 * assume that %cs is 0x10, 4GB flat, and read/execute, and 157 * the data segments are 0x18, 4GB flat, and read/write. 158 * U-boot is setting them up that way for itself in 159 * arch/i386/cpu/cpu.c. 160 */ 161 __asm__ __volatile__ ( 162 "movl $0, %%ebp\n" 163 "cli\n" 164 "jmp *%[kernel_entry]\n" 165 :: [kernel_entry]"a"(load_address), 166 [boot_params] "S"(setup_base), 167 "b"(0), "D"(0) 168 ); 169 } 170 171 /* We can't get to here */ 172 return -EFAULT; 173 } 174 175 /* Subcommand: GO */ 176 static int boot_jump_linux(bootm_headers_t *images) 177 { 178 debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", 179 images->ep, images->os.load); 180 181 return boot_linux_kernel(images->ep, images->os.load, false); 182 } 183 184 int do_bootm_linux(int flag, int argc, char * const argv[], 185 bootm_headers_t *images) 186 { 187 /* No need for those on x86 */ 188 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 189 return -1; 190 191 if (flag & BOOTM_STATE_OS_PREP) 192 return boot_prep_linux(images); 193 194 if (flag & BOOTM_STATE_OS_GO) 195 return boot_jump_linux(images); 196 197 return boot_jump_linux(images); 198 } 199