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 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include <common.h> 25 #include <command.h> 26 #include <image.h> 27 #include <u-boot/zlib.h> 28 #include <asm/byteorder.h> 29 #include <fdt.h> 30 #include <libfdt.h> 31 #include <fdt_support.h> 32 33 DECLARE_GLOBAL_DATA_PTR; 34 35 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \ 36 defined (CONFIG_CMDLINE_TAG) || \ 37 defined (CONFIG_INITRD_TAG) || \ 38 defined (CONFIG_SERIAL_TAG) || \ 39 defined (CONFIG_REVISION_TAG) 40 static void setup_start_tag (bd_t *bd); 41 42 # ifdef CONFIG_SETUP_MEMORY_TAGS 43 static void setup_memory_tags (bd_t *bd); 44 # endif 45 static void setup_commandline_tag (bd_t *bd, char *commandline); 46 47 # ifdef CONFIG_INITRD_TAG 48 static void setup_initrd_tag (bd_t *bd, ulong initrd_start, 49 ulong initrd_end); 50 # endif 51 static void setup_end_tag (bd_t *bd); 52 53 static struct tag *params; 54 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 55 56 static ulong get_sp(void); 57 #if defined(CONFIG_OF_LIBFDT) 58 static int bootm_linux_fdt(int machid, bootm_headers_t *images); 59 #endif 60 61 void arch_lmb_reserve(struct lmb *lmb) 62 { 63 ulong sp; 64 65 /* 66 * Booting a (Linux) kernel image 67 * 68 * Allocate space for command line and board info - the 69 * address should be as high as possible within the reach of 70 * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused 71 * memory, which means far enough below the current stack 72 * pointer. 73 */ 74 sp = get_sp(); 75 debug("## Current stack ends at 0x%08lx ", sp); 76 77 /* adjust sp by 1K to be safe */ 78 sp -= 1024; 79 lmb_reserve(lmb, sp, 80 gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); 81 } 82 83 static void announce_and_cleanup(void) 84 { 85 printf("\nStarting kernel ...\n\n"); 86 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 87 #ifdef CONFIG_BOOTSTAGE_REPORT 88 bootstage_report(); 89 #endif 90 91 #ifdef CONFIG_USB_DEVICE 92 { 93 extern void udc_disconnect(void); 94 udc_disconnect(); 95 } 96 #endif 97 cleanup_before_linux(); 98 } 99 100 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 101 { 102 bd_t *bd = gd->bd; 103 char *s; 104 int machid = bd->bi_arch_number; 105 void (*kernel_entry)(int zero, int arch, uint params); 106 107 #ifdef CONFIG_CMDLINE_TAG 108 char *commandline = getenv ("bootargs"); 109 #endif 110 111 if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) 112 return 1; 113 114 s = getenv ("machid"); 115 if (s) { 116 machid = simple_strtoul (s, NULL, 16); 117 printf ("Using machid 0x%x from environment\n", machid); 118 } 119 120 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 121 122 #ifdef CONFIG_OF_LIBFDT 123 if (images->ft_len) 124 return bootm_linux_fdt(machid, images); 125 #endif 126 127 kernel_entry = (void (*)(int, int, uint))images->ep; 128 129 debug ("## Transferring control to Linux (at address %08lx) ...\n", 130 (ulong) kernel_entry); 131 132 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \ 133 defined (CONFIG_CMDLINE_TAG) || \ 134 defined (CONFIG_INITRD_TAG) || \ 135 defined (CONFIG_SERIAL_TAG) || \ 136 defined (CONFIG_REVISION_TAG) 137 setup_start_tag (bd); 138 #ifdef CONFIG_SERIAL_TAG 139 setup_serial_tag (¶ms); 140 #endif 141 #ifdef CONFIG_REVISION_TAG 142 setup_revision_tag (¶ms); 143 #endif 144 #ifdef CONFIG_SETUP_MEMORY_TAGS 145 setup_memory_tags (bd); 146 #endif 147 #ifdef CONFIG_CMDLINE_TAG 148 setup_commandline_tag (bd, commandline); 149 #endif 150 #ifdef CONFIG_INITRD_TAG 151 if (images->rd_start && images->rd_end) 152 setup_initrd_tag (bd, images->rd_start, images->rd_end); 153 #endif 154 setup_end_tag(bd); 155 #endif 156 157 announce_and_cleanup(); 158 159 kernel_entry(0, machid, bd->bi_boot_params); 160 /* does not return */ 161 162 return 1; 163 } 164 165 #if defined(CONFIG_OF_LIBFDT) 166 static int fixup_memory_node(void *blob) 167 { 168 bd_t *bd = gd->bd; 169 int bank; 170 u64 start[CONFIG_NR_DRAM_BANKS]; 171 u64 size[CONFIG_NR_DRAM_BANKS]; 172 173 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { 174 start[bank] = bd->bi_dram[bank].start; 175 size[bank] = bd->bi_dram[bank].size; 176 } 177 178 return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); 179 } 180 181 static int bootm_linux_fdt(int machid, bootm_headers_t *images) 182 { 183 ulong rd_len; 184 void (*kernel_entry)(int zero, int dt_machid, void *dtblob); 185 ulong of_size = images->ft_len; 186 char **of_flat_tree = &images->ft_addr; 187 ulong *initrd_start = &images->initrd_start; 188 ulong *initrd_end = &images->initrd_end; 189 struct lmb *lmb = &images->lmb; 190 int ret; 191 192 kernel_entry = (void (*)(int, int, void *))images->ep; 193 194 boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree); 195 196 rd_len = images->rd_end - images->rd_start; 197 ret = boot_ramdisk_high(lmb, images->rd_start, rd_len, 198 initrd_start, initrd_end); 199 if (ret) 200 return ret; 201 202 ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size); 203 if (ret) 204 return ret; 205 206 debug("## Transferring control to Linux (at address %08lx) ...\n", 207 (ulong) kernel_entry); 208 209 fdt_chosen(*of_flat_tree, 1); 210 211 fixup_memory_node(*of_flat_tree); 212 213 fdt_fixup_ethernet(*of_flat_tree); 214 215 fdt_initrd(*of_flat_tree, *initrd_start, *initrd_end, 1); 216 217 announce_and_cleanup(); 218 219 kernel_entry(0, machid, *of_flat_tree); 220 /* does not return */ 221 222 return 1; 223 } 224 #endif 225 226 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \ 227 defined (CONFIG_CMDLINE_TAG) || \ 228 defined (CONFIG_INITRD_TAG) || \ 229 defined (CONFIG_SERIAL_TAG) || \ 230 defined (CONFIG_REVISION_TAG) 231 static void setup_start_tag (bd_t *bd) 232 { 233 params = (struct tag *) bd->bi_boot_params; 234 235 params->hdr.tag = ATAG_CORE; 236 params->hdr.size = tag_size (tag_core); 237 238 params->u.core.flags = 0; 239 params->u.core.pagesize = 0; 240 params->u.core.rootdev = 0; 241 242 params = tag_next (params); 243 } 244 245 246 #ifdef CONFIG_SETUP_MEMORY_TAGS 247 static void setup_memory_tags (bd_t *bd) 248 { 249 int i; 250 251 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 252 params->hdr.tag = ATAG_MEM; 253 params->hdr.size = tag_size (tag_mem32); 254 255 params->u.mem.start = bd->bi_dram[i].start; 256 params->u.mem.size = bd->bi_dram[i].size; 257 258 params = tag_next (params); 259 } 260 } 261 #endif /* CONFIG_SETUP_MEMORY_TAGS */ 262 263 264 static void setup_commandline_tag (bd_t *bd, char *commandline) 265 { 266 char *p; 267 268 if (!commandline) 269 return; 270 271 /* eat leading white space */ 272 for (p = commandline; *p == ' '; p++); 273 274 /* skip non-existent command lines so the kernel will still 275 * use its default command line. 276 */ 277 if (*p == '\0') 278 return; 279 280 params->hdr.tag = ATAG_CMDLINE; 281 params->hdr.size = 282 (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2; 283 284 strcpy (params->u.cmdline.cmdline, p); 285 286 params = tag_next (params); 287 } 288 289 290 #ifdef CONFIG_INITRD_TAG 291 static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end) 292 { 293 /* an ATAG_INITRD node tells the kernel where the compressed 294 * ramdisk can be found. ATAG_RDIMG is a better name, actually. 295 */ 296 params->hdr.tag = ATAG_INITRD2; 297 params->hdr.size = tag_size (tag_initrd); 298 299 params->u.initrd.start = initrd_start; 300 params->u.initrd.size = initrd_end - initrd_start; 301 302 params = tag_next (params); 303 } 304 #endif /* CONFIG_INITRD_TAG */ 305 306 #ifdef CONFIG_SERIAL_TAG 307 void setup_serial_tag (struct tag **tmp) 308 { 309 struct tag *params = *tmp; 310 struct tag_serialnr serialnr; 311 void get_board_serial(struct tag_serialnr *serialnr); 312 313 get_board_serial(&serialnr); 314 params->hdr.tag = ATAG_SERIAL; 315 params->hdr.size = tag_size (tag_serialnr); 316 params->u.serialnr.low = serialnr.low; 317 params->u.serialnr.high= serialnr.high; 318 params = tag_next (params); 319 *tmp = params; 320 } 321 #endif 322 323 #ifdef CONFIG_REVISION_TAG 324 void setup_revision_tag(struct tag **in_params) 325 { 326 u32 rev = 0; 327 u32 get_board_rev(void); 328 329 rev = get_board_rev(); 330 params->hdr.tag = ATAG_REVISION; 331 params->hdr.size = tag_size (tag_revision); 332 params->u.revision.rev = rev; 333 params = tag_next (params); 334 } 335 #endif /* CONFIG_REVISION_TAG */ 336 337 static void setup_end_tag (bd_t *bd) 338 { 339 params->hdr.tag = ATAG_NONE; 340 params->hdr.size = 0; 341 } 342 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 343 344 static ulong get_sp(void) 345 { 346 ulong ret; 347 348 asm("mov %0, sp" : "=r"(ret) : ); 349 return ret; 350 } 351