Newer
Older
/*
* (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)
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <u-boot/zlib.h>
#include <asm/bootparam.h>
#include <asm/byteorder.h>
#include <asm/zimage.h>
#ifdef CONFIG_SYS_COREBOOT
#include <asm/arch/timestamp.h>
#endif
#define COMMAND_LINE_OFFSET 0x9000
/*
* Implement a weak default function for boards that optionally
* need to clean up the system before jumping to the kernel.
*/
__weak void board_final_cleanup(void)
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();
Marian Balakowicz
committed
#endif
#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
/* 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
if (images->legacy_hdr_valid) {
hdr = images->legacy_hdr_os;
if (image_check_type(hdr, IH_TYPE_MULTI)) {
/* if multi-part image, we need to get first subimage */
image_multi_getimg(hdr, 0, &os_data, &os_len);
data = (void *)os_data;
len = os_len;
} else {
/* otherwise get image data */
data = (void *)image_get_data(hdr);
len = image_get_data_size(hdr);
#if defined(CONFIG_FIT)
} else if (images->fit_uname_os && is_zimage) {
ret = fit_image_get_data(images->fit_hdr_os,
images->fit_noffset_os,
(const void **)&data, &len);
Marian Balakowicz
committed
if (ret) {
puts("Can't get image data/size!\n");
Marian Balakowicz
committed
goto error;
}
ulong load_address;
base_ptr = (char *)load_zimage(data, len, &load_address);
images->os.load = load_address;
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 {
printf("## Kernel loading failed (no setup) ...\n");
Marian Balakowicz
committed
goto error;
printf("Setup at %#08lx\n", images->ep);
ret = setup_zimage((void *)images->ep, cmd_line_dest,
0, images->rd_start,
images->rd_end - images->rd_start);
if (ret) {
printf("## Setting up boot parameters failed ...\n");
Marian Balakowicz
committed
error:
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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) {
/* TODO(boot 64-bit kernel) */
} 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.
* U-boot is setting them up that way for itself in
* arch/i386/cpu/cpu.c.
*/
__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)
);
}
/* We can't get to here */
return -EFAULT;
}
/* 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);
return boot_linux_kernel(images->ep, images->os.load, false);
}
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);
if (flag & BOOTM_STATE_OS_GO)
return boot_jump_linux(images);
return boot_jump_linux(images);
}