1 /* Copyright (C) 2011 2 * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de> 3 * - Added prep subcommand support 4 * - Reorganized source - modeled after powerpc version 5 * 6 * (C) Copyright 2002 7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 8 * Marius Groeger <mgroeger@sysgo.de> 9 * 10 * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) 11 * 12 * SPDX-License-Identifier: GPL-2.0+ 13 */ 14 15 #include <common.h> 16 #include <command.h> 17 #include <image.h> 18 #include <u-boot/zlib.h> 19 #include <asm/byteorder.h> 20 #include <libfdt.h> 21 #include <fdt_support.h> 22 #include <asm/bootm.h> 23 #include <linux/compiler.h> 24 25 DECLARE_GLOBAL_DATA_PTR; 26 27 static struct tag *params; 28 29 static ulong get_sp(void) 30 { 31 ulong ret; 32 33 asm("mov %0, sp" : "=r"(ret) : ); 34 return ret; 35 } 36 37 void arch_lmb_reserve(struct lmb *lmb) 38 { 39 ulong sp; 40 41 /* 42 * Booting a (Linux) kernel image 43 * 44 * Allocate space for command line and board info - the 45 * address should be as high as possible within the reach of 46 * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused 47 * memory, which means far enough below the current stack 48 * pointer. 49 */ 50 sp = get_sp(); 51 debug("## Current stack ends at 0x%08lx ", sp); 52 53 /* adjust sp by 4K to be safe */ 54 sp -= 4096; 55 lmb_reserve(lmb, sp, 56 gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); 57 } 58 59 /** 60 * announce_and_cleanup() - Print message and prepare for kernel boot 61 * 62 * @fake: non-zero to do everything except actually boot 63 */ 64 static void announce_and_cleanup(int fake) 65 { 66 printf("\nStarting kernel ...%s\n\n", fake ? 67 "(fake run for tracing)" : ""); 68 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 69 #ifdef CONFIG_BOOTSTAGE_FDT 70 if (flag == BOOTM_STATE_OS_FAKE_GO) 71 bootstage_fdt_add_report(); 72 #endif 73 #ifdef CONFIG_BOOTSTAGE_REPORT 74 bootstage_report(); 75 #endif 76 77 #ifdef CONFIG_USB_DEVICE 78 udc_disconnect(); 79 #endif 80 cleanup_before_linux(); 81 } 82 83 static void setup_start_tag (bd_t *bd) 84 { 85 params = (struct tag *)bd->bi_boot_params; 86 87 params->hdr.tag = ATAG_CORE; 88 params->hdr.size = tag_size (tag_core); 89 90 params->u.core.flags = 0; 91 params->u.core.pagesize = 0; 92 params->u.core.rootdev = 0; 93 94 params = tag_next (params); 95 } 96 97 static void setup_memory_tags(bd_t *bd) 98 { 99 int i; 100 101 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 102 params->hdr.tag = ATAG_MEM; 103 params->hdr.size = tag_size (tag_mem32); 104 105 params->u.mem.start = bd->bi_dram[i].start; 106 params->u.mem.size = bd->bi_dram[i].size; 107 108 params = tag_next (params); 109 } 110 } 111 112 static void setup_commandline_tag(bd_t *bd, char *commandline) 113 { 114 char *p; 115 116 if (!commandline) 117 return; 118 119 /* eat leading white space */ 120 for (p = commandline; *p == ' '; p++); 121 122 /* skip non-existent command lines so the kernel will still 123 * use its default command line. 124 */ 125 if (*p == '\0') 126 return; 127 128 params->hdr.tag = ATAG_CMDLINE; 129 params->hdr.size = 130 (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2; 131 132 strcpy (params->u.cmdline.cmdline, p); 133 134 params = tag_next (params); 135 } 136 137 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) 138 { 139 /* an ATAG_INITRD node tells the kernel where the compressed 140 * ramdisk can be found. ATAG_RDIMG is a better name, actually. 141 */ 142 params->hdr.tag = ATAG_INITRD2; 143 params->hdr.size = tag_size (tag_initrd); 144 145 params->u.initrd.start = initrd_start; 146 params->u.initrd.size = initrd_end - initrd_start; 147 148 params = tag_next (params); 149 } 150 151 static void setup_serial_tag(struct tag **tmp) 152 { 153 struct tag *params = *tmp; 154 struct tag_serialnr serialnr; 155 156 get_board_serial(&serialnr); 157 params->hdr.tag = ATAG_SERIAL; 158 params->hdr.size = tag_size (tag_serialnr); 159 params->u.serialnr.low = serialnr.low; 160 params->u.serialnr.high= serialnr.high; 161 params = tag_next (params); 162 *tmp = params; 163 } 164 165 static void setup_revision_tag(struct tag **in_params) 166 { 167 u32 rev = 0; 168 169 rev = get_board_rev(); 170 params->hdr.tag = ATAG_REVISION; 171 params->hdr.size = tag_size (tag_revision); 172 params->u.revision.rev = rev; 173 params = tag_next (params); 174 } 175 176 static void setup_end_tag(bd_t *bd) 177 { 178 params->hdr.tag = ATAG_NONE; 179 params->hdr.size = 0; 180 } 181 182 __weak void setup_board_tags(struct tag **in_params) {} 183 184 /* Subcommand: PREP */ 185 static void boot_prep_linux(bootm_headers_t *images) 186 { 187 char *commandline = getenv("bootargs"); 188 189 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { 190 #ifdef CONFIG_OF_LIBFDT 191 debug("using: FDT\n"); 192 if (image_setup_linux(images)) { 193 printf("FDT creation failed! hanging..."); 194 hang(); 195 } 196 #endif 197 } else if (BOOTM_ENABLE_TAGS) { 198 debug("using: ATAGS\n"); 199 setup_start_tag(gd->bd); 200 if (BOOTM_ENABLE_SERIAL_TAG) 201 setup_serial_tag(¶ms); 202 if (BOOTM_ENABLE_CMDLINE_TAG) 203 setup_commandline_tag(gd->bd, commandline); 204 if (BOOTM_ENABLE_REVISION_TAG) 205 setup_revision_tag(¶ms); 206 if (BOOTM_ENABLE_MEMORY_TAGS) 207 setup_memory_tags(gd->bd); 208 if (BOOTM_ENABLE_INITRD_TAG) { 209 if (images->rd_start && images->rd_end) { 210 setup_initrd_tag(gd->bd, images->rd_start, 211 images->rd_end); 212 } 213 } 214 setup_board_tags(¶ms); 215 setup_end_tag(gd->bd); 216 } else { 217 printf("FDT and ATAGS support not compiled in - hanging\n"); 218 hang(); 219 } 220 } 221 222 /* Subcommand: GO */ 223 static void boot_jump_linux(bootm_headers_t *images, int flag) 224 { 225 unsigned long machid = gd->bd->bi_arch_number; 226 char *s; 227 void (*kernel_entry)(int zero, int arch, uint params); 228 unsigned long r2; 229 int fake = (flag & BOOTM_STATE_OS_FAKE_GO); 230 231 kernel_entry = (void (*)(int, int, uint))images->ep; 232 233 s = getenv("machid"); 234 if (s) { 235 strict_strtoul(s, 16, &machid); 236 printf("Using machid 0x%lx from environment\n", machid); 237 } 238 239 debug("## Transferring control to Linux (at address %08lx)" \ 240 "...\n", (ulong) kernel_entry); 241 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 242 announce_and_cleanup(fake); 243 244 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 245 r2 = (unsigned long)images->ft_addr; 246 else 247 r2 = gd->bd->bi_boot_params; 248 249 if (!fake) 250 kernel_entry(0, machid, r2); 251 } 252 253 /* Main Entry point for arm bootm implementation 254 * 255 * Modeled after the powerpc implementation 256 * DIFFERENCE: Instead of calling prep and go at the end 257 * they are called if subcommand is equal 0. 258 */ 259 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 260 { 261 /* No need for those on ARM */ 262 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 263 return -1; 264 265 if (flag & BOOTM_STATE_OS_PREP) { 266 boot_prep_linux(images); 267 return 0; 268 } 269 270 if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { 271 boot_jump_linux(images, flag); 272 return 0; 273 } 274 275 boot_prep_linux(images); 276 boot_jump_linux(images, flag); 277 return 0; 278 } 279 280 #ifdef CONFIG_CMD_BOOTZ 281 282 struct zimage_header { 283 uint32_t code[9]; 284 uint32_t zi_magic; 285 uint32_t zi_start; 286 uint32_t zi_end; 287 }; 288 289 #define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818 290 291 int bootz_setup(ulong image, ulong *start, ulong *end) 292 { 293 struct zimage_header *zi; 294 295 zi = (struct zimage_header *)map_sysmem(image, 0); 296 if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) { 297 puts("Bad Linux ARM zImage magic!\n"); 298 return 1; 299 } 300 301 *start = zi->zi_start; 302 *end = zi->zi_end; 303 304 printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start, 305 *end); 306 307 return 0; 308 } 309 310 #endif /* CONFIG_CMD_BOOTZ */ 311