bootm.c 5.3 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7
/*
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Marius Groeger <mgroeger@sysgo.de>
 *
 * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
 *
8
 * SPDX-License-Identifier:	GPL-2.0+
W
wdenk 已提交
9 10 11 12
 */

#include <common.h>
#include <command.h>
13 14
#include <dm/device.h>
#include <dm/root.h>
15
#include <errno.h>
16
#include <fdt_support.h>
W
wdenk 已提交
17
#include <image.h>
18
#include <u-boot/zlib.h>
19
#include <asm/bootparam.h>
20
#include <asm/cpu.h>
W
wdenk 已提交
21 22
#include <asm/byteorder.h>
#include <asm/zimage.h>
23 24 25
#ifdef CONFIG_SYS_COREBOOT
#include <asm/arch/timestamp.h>
#endif
W
wdenk 已提交
26

27 28
DECLARE_GLOBAL_DATA_PTR;

29 30
#define COMMAND_LINE_OFFSET 0x9000

31 32 33 34 35
int arch_fixup_fdt(void *blob)
{
	return 0;
}

36 37 38 39
__weak void board_quiesce_devices(void)
{
}

40 41 42 43 44 45 46 47 48 49
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();
50
#endif
51 52 53 54 55 56 57

	/*
	 * Call remove function of all devices with a removal flag set.
	 * This may be useful for last-stage operations, like cancelling
	 * of DMA operation or releasing device internal buffers.
	 */
	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
58
}
W
wdenk 已提交
59

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#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
K
Kumar Gala 已提交
76

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/* 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
96 97
	if (images->legacy_hdr_valid) {
		hdr = images->legacy_hdr_os;
98
		if (image_check_type(hdr, IH_TYPE_MULTI)) {
99 100
			ulong os_data, os_len;

101
			/* if multi-part image, we need to get first subimage */
102
			image_multi_getimg(hdr, 0, &os_data, &os_len);
103 104
			data = (void *)os_data;
			len = os_len;
105 106
		} else {
			/* otherwise get image data */
107 108
			data = (void *)image_get_data(hdr);
			len = image_get_data_size(hdr);
109
		}
110
		is_zimage = 1;
111
#if defined(CONFIG_FIT)
112
	} else if (images->fit_uname_os) {
113
		ret = fit_image_get_data(images->fit_hdr_os,
114 115
				images->fit_noffset_os,
				(const void **)&data, &len);
116
		if (ret) {
117
			puts("Can't get image data/size!\n");
118 119
			goto error;
		}
120
		is_zimage = 1;
121
#endif
122 123
	}

124
	if (is_zimage) {
125
		ulong load_address;
126
		char *base_ptr;
W
wdenk 已提交
127

128
		base_ptr = (char *)load_zimage(data, len, &load_address);
129
		images->os.load = load_address;
130 131 132 133 134
		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 {
135
		printf("## Kernel loading failed (missing x86 kernel setup) ...\n");
136
		goto error;
137
	}
W
wdenk 已提交
138

139 140
	printf("Setup at %#08lx\n", images->ep);
	ret = setup_zimage((void *)images->ep, cmd_line_dest,
141
			0, images->rd_start,
142 143 144
			images->rd_end - images->rd_start);

	if (ret) {
145
		printf("## Setting up boot parameters failed ...\n");
146
		return 1;
W
wdenk 已提交
147
	}
W
wdenk 已提交
148

149
	return 0;
W
wdenk 已提交
150

151
error:
152
	return 1;
W
wdenk 已提交
153
}
154

155 156 157 158 159 160 161 162
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) {
163 164 165 166
		if (!cpu_has_64bit()) {
			puts("Cannot boot 64-bit kernel on 32-bit machine\n");
			return -EFAULT;
		}
167 168 169 170 171 172
		/* At present 64-bit U-Boot does not support booting a
		 * kernel.
		 * TODO(sjg@chromium.org): Support booting both 32-bit and
		 * 64-bit kernels from 64-bit U-Boot.
		 */
#if !CONFIG_IS_ENABLED(X86_64)
173
		return cpu_jump_to_64bit(setup_base, load_address);
174
#endif
175 176 177 178 179 180
	} 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.
B
Bin Meng 已提交
181
		* U-Boot is setting them up that way for itself in
182
		* arch/i386/cpu/cpu.c.
S
Simon Glass 已提交
183 184 185
		*
		* Note that we cannot currently boot a kernel while running as
		* an EFI application. Please use the payload option for that.
186
		*/
S
Simon Glass 已提交
187
#ifndef CONFIG_EFI_APP
188 189 190 191 192 193 194 195
		__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)
		);
S
Simon Glass 已提交
196
#endif
197 198 199 200 201 202
	}

	/* We can't get to here */
	return -EFAULT;
}

203 204 205 206 207 208
/* 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);

209 210
	return boot_linux_kernel(images->ep, images->os.load,
				 images->os.arch == IH_ARCH_X86_64);
211 212 213 214 215 216 217 218 219 220 221 222
}

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);

223 224
	if (flag & BOOTM_STATE_OS_GO)
		return boot_jump_linux(images);
225 226 227

	return boot_jump_linux(images);
}