blob: 4c5c7f5aa796bc679cf2bb91f6f16f64de128098 [file] [log] [blame]
wdenk591dda52002-11-18 00:14:45 +00001/*
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 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
wdenk591dda52002-11-18 00:14:45 +00009 */
10
11#include <common.h>
12#include <command.h>
Simon Glassaa83f2b2014-10-19 21:11:20 -060013#include <fdt_support.h>
wdenk591dda52002-11-18 00:14:45 +000014#include <image.h>
Jean-Christophe PLAGNIOL-VILLARD6bb94492009-04-04 12:49:11 +020015#include <u-boot/zlib.h>
Gabe Black540c2622011-12-05 12:09:26 +000016#include <asm/bootparam.h>
wdenk591dda52002-11-18 00:14:45 +000017#include <asm/byteorder.h>
18#include <asm/zimage.h>
Simon Glassaa83f2b2014-10-19 21:11:20 -060019#ifdef CONFIG_SYS_COREBOOT
20#include <asm/arch/timestamp.h>
21#endif
wdenk591dda52002-11-18 00:14:45 +000022
Gabe Black540c2622011-12-05 12:09:26 +000023#define COMMAND_LINE_OFFSET 0x9000
24
Simon Glassaa83f2b2014-10-19 21:11:20 -060025/*
26 * Implement a weak default function for boards that optionally
27 * need to clean up the system before jumping to the kernel.
28 */
29__weak void board_final_cleanup(void)
wdenk591dda52002-11-18 00:14:45 +000030{
Simon Glassaa83f2b2014-10-19 21:11:20 -060031}
Graeme Russ2fe2a972008-09-07 07:08:42 +100032
Simon Glassaa83f2b2014-10-19 21:11:20 -060033void bootm_announce_and_cleanup(void)
34{
35 printf("\nStarting kernel ...\n\n");
36
37#ifdef CONFIG_SYS_COREBOOT
38 timestamp_add_now(TS_U_BOOT_START_KERNEL);
39#endif
40 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
41#ifdef CONFIG_BOOTSTAGE_REPORT
42 bootstage_report();
Marian Balakowiczdf8ff332008-03-12 10:33:00 +010043#endif
Simon Glassaa83f2b2014-10-19 21:11:20 -060044 board_final_cleanup();
45}
wdenk57b2d802003-06-27 21:31:46 +000046
Simon Glassaa83f2b2014-10-19 21:11:20 -060047#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
48int arch_fixup_memory_node(void *blob)
49{
50 bd_t *bd = gd->bd;
51 int bank;
52 u64 start[CONFIG_NR_DRAM_BANKS];
53 u64 size[CONFIG_NR_DRAM_BANKS];
Kumar Gala18178bc2008-10-21 17:25:45 -050054
Simon Glassaa83f2b2014-10-19 21:11:20 -060055 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
56 start[bank] = bd->bi_dram[bank].start;
57 size[bank] = bd->bi_dram[bank].size;
58 }
59
60 return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
61}
62#endif
63
64/* Subcommand: PREP */
65static int boot_prep_linux(bootm_headers_t *images)
66{
67 char *cmd_line_dest = NULL;
68 image_header_t *hdr;
69 int is_zimage = 0;
70 void *data = NULL;
71 size_t len;
72 int ret;
73
74#ifdef CONFIG_OF_LIBFDT
75 if (images->ft_len) {
76 debug("using: FDT\n");
77 if (image_setup_linux(images)) {
78 puts("FDT creation failed! hanging...");
79 hang();
80 }
81 }
82#endif
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010083 if (images->legacy_hdr_valid) {
84 hdr = images->legacy_hdr_os;
Graeme Russ883c6032011-11-08 02:33:15 +000085 if (image_check_type(hdr, IH_TYPE_MULTI)) {
Simon Glassaa83f2b2014-10-19 21:11:20 -060086 ulong os_data, os_len;
87
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010088 /* if multi-part image, we need to get first subimage */
Graeme Russ883c6032011-11-08 02:33:15 +000089 image_multi_getimg(hdr, 0, &os_data, &os_len);
Simon Glassaa83f2b2014-10-19 21:11:20 -060090 data = (void *)os_data;
91 len = os_len;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010092 } else {
93 /* otherwise get image data */
Simon Glassaa83f2b2014-10-19 21:11:20 -060094 data = (void *)image_get_data(hdr);
95 len = image_get_data_size(hdr);
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010096 }
Simon Glassaa83f2b2014-10-19 21:11:20 -060097 is_zimage = 1;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010098#if defined(CONFIG_FIT)
Simon Glassaa83f2b2014-10-19 21:11:20 -060099 } else if (images->fit_uname_os && is_zimage) {
Graeme Russ883c6032011-11-08 02:33:15 +0000100 ret = fit_image_get_data(images->fit_hdr_os,
Simon Glassaa83f2b2014-10-19 21:11:20 -0600101 images->fit_noffset_os,
102 (const void **)&data, &len);
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100103 if (ret) {
Graeme Russ883c6032011-11-08 02:33:15 +0000104 puts("Can't get image data/size!\n");
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100105 goto error;
106 }
Simon Glassaa83f2b2014-10-19 21:11:20 -0600107 is_zimage = 1;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100108#endif
Wolfgang Denk44cacdc2006-07-21 11:30:18 +0200109 }
110
Simon Glassaa83f2b2014-10-19 21:11:20 -0600111 if (is_zimage) {
112 void *load_address;
113 char *base_ptr;
wdenk591dda52002-11-18 00:14:45 +0000114
Simon Glassaa83f2b2014-10-19 21:11:20 -0600115 base_ptr = (char *)load_zimage(data, len, &load_address);
116 images->os.load = (ulong)load_address;
117 cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
118 images->ep = (ulong)base_ptr;
119 } else if (images->ep) {
120 cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
121 } else {
122 printf("## Kernel loading failed (no setup) ...\n");
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100123 goto error;
Gabe Black540c2622011-12-05 12:09:26 +0000124 }
wdenk57b2d802003-06-27 21:31:46 +0000125
Simon Glassaa83f2b2014-10-19 21:11:20 -0600126 printf("Setup at %#08lx\n", images->ep);
127 ret = setup_zimage((void *)images->ep, cmd_line_dest,
Gabe Black540c2622011-12-05 12:09:26 +0000128 0, images->rd_start,
Simon Glassaa83f2b2014-10-19 21:11:20 -0600129 images->rd_end - images->rd_start);
130
131 if (ret) {
Gabe Black540c2622011-12-05 12:09:26 +0000132 printf("## Setting up boot parameters failed ...\n");
Simon Glassaa83f2b2014-10-19 21:11:20 -0600133 return 1;
wdenk591dda52002-11-18 00:14:45 +0000134 }
wdenk57b2d802003-06-27 21:31:46 +0000135
Simon Glassaa83f2b2014-10-19 21:11:20 -0600136 return 0;
wdenk591dda52002-11-18 00:14:45 +0000137
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100138error:
Kumar Gala48626aa2008-08-15 08:24:45 -0500139 return 1;
wdenk57b2d802003-06-27 21:31:46 +0000140}
Simon Glassaa83f2b2014-10-19 21:11:20 -0600141
142/* Subcommand: GO */
143static int boot_jump_linux(bootm_headers_t *images)
144{
145 debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
146 images->ep, images->os.load);
147
148 boot_zimage((struct boot_params *)images->ep, (void *)images->os.load);
149 /* does not return */
150
151 return 1;
152}
153
154int do_bootm_linux(int flag, int argc, char * const argv[],
155 bootm_headers_t *images)
156{
157 /* No need for those on x86 */
158 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
159 return -1;
160
161 if (flag & BOOTM_STATE_OS_PREP)
162 return boot_prep_linux(images);
163
164 if (flag & BOOTM_STATE_OS_GO) {
165 boot_jump_linux(images);
166 return 0;
167 }
168
169 return boot_jump_linux(images);
170}