]>
Commit | Line | Data |
---|---|---|
2262cfee WD |
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 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
2262cfee WD |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <command.h> | |
76539383 | 13 | #include <errno.h> |
0d0ba59c | 14 | #include <fdt_support.h> |
2262cfee | 15 | #include <image.h> |
a31e091a | 16 | #include <u-boot/zlib.h> |
69370d14 | 17 | #include <asm/bootparam.h> |
61643ae6 | 18 | #include <asm/cpu.h> |
2262cfee WD |
19 | #include <asm/byteorder.h> |
20 | #include <asm/zimage.h> | |
0d0ba59c SG |
21 | #ifdef CONFIG_SYS_COREBOOT |
22 | #include <asm/arch/timestamp.h> | |
23 | #endif | |
2262cfee | 24 | |
69370d14 GB |
25 | #define COMMAND_LINE_OFFSET 0x9000 |
26 | ||
0d0ba59c SG |
27 | /* |
28 | * Implement a weak default function for boards that optionally | |
29 | * need to clean up the system before jumping to the kernel. | |
30 | */ | |
31 | __weak void board_final_cleanup(void) | |
2262cfee | 32 | { |
0d0ba59c | 33 | } |
3ef96ded | 34 | |
0d0ba59c SG |
35 | void bootm_announce_and_cleanup(void) |
36 | { | |
37 | printf("\nStarting kernel ...\n\n"); | |
38 | ||
39 | #ifdef CONFIG_SYS_COREBOOT | |
40 | timestamp_add_now(TS_U_BOOT_START_KERNEL); | |
41 | #endif | |
42 | bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); | |
43 | #ifdef CONFIG_BOOTSTAGE_REPORT | |
44 | bootstage_report(); | |
cd7c596e | 45 | #endif |
0d0ba59c SG |
46 | board_final_cleanup(); |
47 | } | |
8bde7f77 | 48 | |
0d0ba59c SG |
49 | #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) |
50 | int arch_fixup_memory_node(void *blob) | |
51 | { | |
52 | bd_t *bd = gd->bd; | |
53 | int bank; | |
54 | u64 start[CONFIG_NR_DRAM_BANKS]; | |
55 | u64 size[CONFIG_NR_DRAM_BANKS]; | |
56 | ||
57 | for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { | |
58 | start[bank] = bd->bi_dram[bank].start; | |
59 | size[bank] = bd->bi_dram[bank].size; | |
60 | } | |
61 | ||
62 | return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS); | |
63 | } | |
64 | #endif | |
49c3a861 | 65 | |
0d0ba59c SG |
66 | /* Subcommand: PREP */ |
67 | static int boot_prep_linux(bootm_headers_t *images) | |
68 | { | |
69 | char *cmd_line_dest = NULL; | |
70 | image_header_t *hdr; | |
71 | int is_zimage = 0; | |
72 | void *data = NULL; | |
73 | size_t len; | |
74 | int ret; | |
75 | ||
76 | #ifdef CONFIG_OF_LIBFDT | |
77 | if (images->ft_len) { | |
78 | debug("using: FDT\n"); | |
79 | if (image_setup_linux(images)) { | |
80 | puts("FDT creation failed! hanging..."); | |
81 | hang(); | |
82 | } | |
83 | } | |
84 | #endif | |
d5934ad7 MB |
85 | if (images->legacy_hdr_valid) { |
86 | hdr = images->legacy_hdr_os; | |
83088afb | 87 | if (image_check_type(hdr, IH_TYPE_MULTI)) { |
0d0ba59c SG |
88 | ulong os_data, os_len; |
89 | ||
d5934ad7 | 90 | /* if multi-part image, we need to get first subimage */ |
83088afb | 91 | image_multi_getimg(hdr, 0, &os_data, &os_len); |
0d0ba59c SG |
92 | data = (void *)os_data; |
93 | len = os_len; | |
d5934ad7 MB |
94 | } else { |
95 | /* otherwise get image data */ | |
0d0ba59c SG |
96 | data = (void *)image_get_data(hdr); |
97 | len = image_get_data_size(hdr); | |
d5934ad7 | 98 | } |
0d0ba59c | 99 | is_zimage = 1; |
d5934ad7 | 100 | #if defined(CONFIG_FIT) |
0d0ba59c | 101 | } else if (images->fit_uname_os && is_zimage) { |
83088afb | 102 | ret = fit_image_get_data(images->fit_hdr_os, |
0d0ba59c SG |
103 | images->fit_noffset_os, |
104 | (const void **)&data, &len); | |
cd7c596e | 105 | if (ret) { |
83088afb | 106 | puts("Can't get image data/size!\n"); |
cd7c596e MB |
107 | goto error; |
108 | } | |
0d0ba59c | 109 | is_zimage = 1; |
d5934ad7 | 110 | #endif |
e644670b WD |
111 | } |
112 | ||
0d0ba59c | 113 | if (is_zimage) { |
76539383 | 114 | ulong load_address; |
0d0ba59c | 115 | char *base_ptr; |
2262cfee | 116 | |
0d0ba59c | 117 | base_ptr = (char *)load_zimage(data, len, &load_address); |
76539383 | 118 | images->os.load = load_address; |
0d0ba59c SG |
119 | cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET; |
120 | images->ep = (ulong)base_ptr; | |
121 | } else if (images->ep) { | |
122 | cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET; | |
123 | } else { | |
124 | printf("## Kernel loading failed (no setup) ...\n"); | |
cd7c596e | 125 | goto error; |
69370d14 | 126 | } |
8bde7f77 | 127 | |
0d0ba59c SG |
128 | printf("Setup at %#08lx\n", images->ep); |
129 | ret = setup_zimage((void *)images->ep, cmd_line_dest, | |
69370d14 | 130 | 0, images->rd_start, |
0d0ba59c SG |
131 | images->rd_end - images->rd_start); |
132 | ||
133 | if (ret) { | |
69370d14 | 134 | printf("## Setting up boot parameters failed ...\n"); |
0d0ba59c | 135 | return 1; |
2262cfee | 136 | } |
8bde7f77 | 137 | |
0d0ba59c | 138 | return 0; |
2262cfee | 139 | |
cd7c596e | 140 | error: |
40d7e99d | 141 | return 1; |
8bde7f77 | 142 | } |
0d0ba59c | 143 | |
76539383 SG |
144 | int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) |
145 | { | |
146 | bootm_announce_and_cleanup(); | |
147 | ||
148 | #ifdef CONFIG_SYS_COREBOOT | |
149 | timestamp_add_now(TS_U_BOOT_START_KERNEL); | |
150 | #endif | |
151 | if (image_64bit) { | |
61643ae6 SG |
152 | if (!cpu_has_64bit()) { |
153 | puts("Cannot boot 64-bit kernel on 32-bit machine\n"); | |
154 | return -EFAULT; | |
155 | } | |
156 | return cpu_jump_to_64bit(setup_base, load_address); | |
76539383 SG |
157 | } else { |
158 | /* | |
159 | * Set %ebx, %ebp, and %edi to 0, %esi to point to the | |
160 | * boot_params structure, and then jump to the kernel. We | |
161 | * assume that %cs is 0x10, 4GB flat, and read/execute, and | |
162 | * the data segments are 0x18, 4GB flat, and read/write. | |
163 | * U-boot is setting them up that way for itself in | |
164 | * arch/i386/cpu/cpu.c. | |
165 | */ | |
166 | __asm__ __volatile__ ( | |
167 | "movl $0, %%ebp\n" | |
168 | "cli\n" | |
169 | "jmp *%[kernel_entry]\n" | |
170 | :: [kernel_entry]"a"(load_address), | |
171 | [boot_params] "S"(setup_base), | |
172 | "b"(0), "D"(0) | |
173 | ); | |
174 | } | |
175 | ||
176 | /* We can't get to here */ | |
177 | return -EFAULT; | |
178 | } | |
179 | ||
0d0ba59c SG |
180 | /* Subcommand: GO */ |
181 | static int boot_jump_linux(bootm_headers_t *images) | |
182 | { | |
183 | debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n", | |
184 | images->ep, images->os.load); | |
185 | ||
61643ae6 SG |
186 | return boot_linux_kernel(images->ep, images->os.load, |
187 | images->os.arch == IH_ARCH_X86_64); | |
0d0ba59c SG |
188 | } |
189 | ||
190 | int do_bootm_linux(int flag, int argc, char * const argv[], | |
191 | bootm_headers_t *images) | |
192 | { | |
193 | /* No need for those on x86 */ | |
194 | if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) | |
195 | return -1; | |
196 | ||
197 | if (flag & BOOTM_STATE_OS_PREP) | |
198 | return boot_prep_linux(images); | |
199 | ||
76539383 SG |
200 | if (flag & BOOTM_STATE_OS_GO) |
201 | return boot_jump_linux(images); | |
0d0ba59c SG |
202 | |
203 | return boot_jump_linux(images); | |
204 | } |