]>
Commit | Line | Data |
---|---|---|
41506ff5 SG |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Image code used by boards (and not host tools) | |
4 | * | |
5 | * (C) Copyright 2008 Semihalf | |
6 | * | |
7 | * (C) Copyright 2000-2006 | |
8 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <bootstage.h> | |
13 | #include <cpu_func.h> | |
14 | #include <env.h> | |
15 | #include <fpga.h> | |
16 | #include <image.h> | |
17 | #include <mapmem.h> | |
18 | #include <watchdog.h> | |
19 | #include <asm/cache.h> | |
20 | #include <asm/global_data.h> | |
21 | ||
22 | #ifndef CONFIG_SYS_BARGSIZE | |
23 | #define CONFIG_SYS_BARGSIZE 512 | |
24 | #endif | |
25 | ||
26 | DECLARE_GLOBAL_DATA_PTR; | |
27 | ||
28 | #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) | |
29 | /** | |
30 | * image_get_ramdisk - get and verify ramdisk image | |
31 | * @rd_addr: ramdisk image start address | |
32 | * @arch: expected ramdisk architecture | |
33 | * @verify: checksum verification flag | |
34 | * | |
35 | * image_get_ramdisk() returns a pointer to the verified ramdisk image | |
36 | * header. Routine receives image start address and expected architecture | |
37 | * flag. Verification done covers data and header integrity and os/type/arch | |
38 | * fields checking. | |
39 | * | |
40 | * returns: | |
41 | * pointer to a ramdisk image header, if image was found and valid | |
42 | * otherwise, return NULL | |
43 | */ | |
44 | static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, | |
45 | int verify) | |
46 | { | |
47 | const image_header_t *rd_hdr = (const image_header_t *)rd_addr; | |
48 | ||
49 | if (!image_check_magic(rd_hdr)) { | |
50 | puts("Bad Magic Number\n"); | |
51 | bootstage_error(BOOTSTAGE_ID_RD_MAGIC); | |
52 | return NULL; | |
53 | } | |
54 | ||
55 | if (!image_check_hcrc(rd_hdr)) { | |
56 | puts("Bad Header Checksum\n"); | |
57 | bootstage_error(BOOTSTAGE_ID_RD_HDR_CHECKSUM); | |
58 | return NULL; | |
59 | } | |
60 | ||
61 | bootstage_mark(BOOTSTAGE_ID_RD_MAGIC); | |
62 | image_print_contents(rd_hdr); | |
63 | ||
64 | if (verify) { | |
65 | puts(" Verifying Checksum ... "); | |
66 | if (!image_check_dcrc(rd_hdr)) { | |
67 | puts("Bad Data CRC\n"); | |
68 | bootstage_error(BOOTSTAGE_ID_RD_CHECKSUM); | |
69 | return NULL; | |
70 | } | |
71 | puts("OK\n"); | |
72 | } | |
73 | ||
74 | bootstage_mark(BOOTSTAGE_ID_RD_HDR_CHECKSUM); | |
75 | ||
76 | if (!image_check_os(rd_hdr, IH_OS_LINUX) || | |
77 | !image_check_arch(rd_hdr, arch) || | |
78 | !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) { | |
79 | printf("No Linux %s Ramdisk Image\n", | |
80 | genimg_get_arch_name(arch)); | |
81 | bootstage_error(BOOTSTAGE_ID_RAMDISK); | |
82 | return NULL; | |
83 | } | |
84 | ||
85 | return rd_hdr; | |
86 | } | |
87 | #endif | |
88 | ||
89 | /*****************************************************************************/ | |
90 | /* Shared dual-format routines */ | |
91 | /*****************************************************************************/ | |
92 | ulong image_load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ | |
93 | ulong image_save_addr; /* Default Save Address */ | |
94 | ulong image_save_size; /* Default Save Size (in bytes) */ | |
95 | ||
96 | static int on_loadaddr(const char *name, const char *value, enum env_op op, | |
97 | int flags) | |
98 | { | |
99 | switch (op) { | |
100 | case env_op_create: | |
101 | case env_op_overwrite: | |
102 | image_load_addr = hextoul(value, NULL); | |
103 | break; | |
104 | default: | |
105 | break; | |
106 | } | |
107 | ||
108 | return 0; | |
109 | } | |
110 | U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr); | |
111 | ||
112 | ulong env_get_bootm_low(void) | |
113 | { | |
114 | char *s = env_get("bootm_low"); | |
115 | if (s) { | |
116 | ulong tmp = hextoul(s, NULL); | |
117 | return tmp; | |
118 | } | |
119 | ||
120 | #if defined(CONFIG_SYS_SDRAM_BASE) | |
121 | return CONFIG_SYS_SDRAM_BASE; | |
122 | #elif defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE) || defined(CONFIG_RISCV) | |
123 | return gd->bd->bi_dram[0].start; | |
124 | #else | |
125 | return 0; | |
126 | #endif | |
127 | } | |
128 | ||
129 | phys_size_t env_get_bootm_size(void) | |
130 | { | |
131 | phys_size_t tmp, size; | |
132 | phys_addr_t start; | |
133 | char *s = env_get("bootm_size"); | |
134 | if (s) { | |
135 | tmp = (phys_size_t)simple_strtoull(s, NULL, 16); | |
136 | return tmp; | |
137 | } | |
138 | ||
139 | start = gd->ram_base; | |
140 | size = gd->ram_size; | |
141 | ||
142 | if (start + size > gd->ram_top) | |
143 | size = gd->ram_top - start; | |
144 | ||
145 | s = env_get("bootm_low"); | |
146 | if (s) | |
147 | tmp = (phys_size_t)simple_strtoull(s, NULL, 16); | |
148 | else | |
149 | tmp = start; | |
150 | ||
151 | return size - (tmp - start); | |
152 | } | |
153 | ||
154 | phys_size_t env_get_bootm_mapsize(void) | |
155 | { | |
156 | phys_size_t tmp; | |
157 | char *s = env_get("bootm_mapsize"); | |
158 | if (s) { | |
159 | tmp = (phys_size_t)simple_strtoull(s, NULL, 16); | |
160 | return tmp; | |
161 | } | |
162 | ||
163 | #if defined(CONFIG_SYS_BOOTMAPSZ) | |
164 | return CONFIG_SYS_BOOTMAPSZ; | |
165 | #else | |
166 | return env_get_bootm_size(); | |
167 | #endif | |
168 | } | |
169 | ||
170 | void memmove_wd(void *to, void *from, size_t len, ulong chunksz) | |
171 | { | |
172 | if (to == from) | |
173 | return; | |
174 | ||
175 | #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) | |
176 | if (to > from) { | |
177 | from += len; | |
178 | to += len; | |
179 | } | |
180 | while (len > 0) { | |
181 | size_t tail = (len > chunksz) ? chunksz : len; | |
182 | WATCHDOG_RESET(); | |
183 | if (to > from) { | |
184 | to -= tail; | |
185 | from -= tail; | |
186 | } | |
187 | memmove(to, from, tail); | |
188 | if (to < from) { | |
189 | to += tail; | |
190 | from += tail; | |
191 | } | |
192 | len -= tail; | |
193 | } | |
194 | #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ | |
195 | memmove(to, from, len); | |
196 | #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ | |
197 | } | |
198 | ||
199 | /** | |
200 | * genimg_get_kernel_addr_fit - get the real kernel address and return 2 | |
201 | * FIT strings | |
202 | * @img_addr: a string might contain real image address | |
203 | * @fit_uname_config: double pointer to a char, will hold pointer to a | |
204 | * configuration unit name | |
205 | * @fit_uname_kernel: double pointer to a char, will hold pointer to a subimage | |
206 | * name | |
207 | * | |
208 | * genimg_get_kernel_addr_fit get the real kernel start address from a string | |
209 | * which is normally the first argv of bootm/bootz | |
210 | * | |
211 | * returns: | |
212 | * kernel start address | |
213 | */ | |
214 | ulong genimg_get_kernel_addr_fit(char * const img_addr, | |
215 | const char **fit_uname_config, | |
216 | const char **fit_uname_kernel) | |
217 | { | |
218 | ulong kernel_addr; | |
219 | ||
220 | /* find out kernel image address */ | |
221 | if (!img_addr) { | |
222 | kernel_addr = image_load_addr; | |
223 | debug("* kernel: default image load address = 0x%08lx\n", | |
224 | image_load_addr); | |
225 | #if CONFIG_IS_ENABLED(FIT) | |
226 | } else if (fit_parse_conf(img_addr, image_load_addr, &kernel_addr, | |
227 | fit_uname_config)) { | |
228 | debug("* kernel: config '%s' from image at 0x%08lx\n", | |
229 | *fit_uname_config, kernel_addr); | |
230 | } else if (fit_parse_subimage(img_addr, image_load_addr, &kernel_addr, | |
231 | fit_uname_kernel)) { | |
232 | debug("* kernel: subimage '%s' from image at 0x%08lx\n", | |
233 | *fit_uname_kernel, kernel_addr); | |
234 | #endif | |
235 | } else { | |
236 | kernel_addr = hextoul(img_addr, NULL); | |
237 | debug("* kernel: cmdline image address = 0x%08lx\n", | |
238 | kernel_addr); | |
239 | } | |
240 | ||
241 | return kernel_addr; | |
242 | } | |
243 | ||
244 | /** | |
245 | * genimg_get_kernel_addr() is the simple version of | |
246 | * genimg_get_kernel_addr_fit(). It ignores those return FIT strings | |
247 | */ | |
248 | ulong genimg_get_kernel_addr(char * const img_addr) | |
249 | { | |
250 | const char *fit_uname_config = NULL; | |
251 | const char *fit_uname_kernel = NULL; | |
252 | ||
253 | return genimg_get_kernel_addr_fit(img_addr, &fit_uname_config, | |
254 | &fit_uname_kernel); | |
255 | } | |
256 | ||
257 | /** | |
258 | * genimg_get_format - get image format type | |
259 | * @img_addr: image start address | |
260 | * | |
261 | * genimg_get_format() checks whether provided address points to a valid | |
262 | * legacy or FIT image. | |
263 | * | |
264 | * New uImage format and FDT blob are based on a libfdt. FDT blob | |
265 | * may be passed directly or embedded in a FIT image. In both situations | |
266 | * genimg_get_format() must be able to dectect libfdt header. | |
267 | * | |
268 | * returns: | |
269 | * image format type or IMAGE_FORMAT_INVALID if no image is present | |
270 | */ | |
271 | int genimg_get_format(const void *img_addr) | |
272 | { | |
273 | #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) | |
274 | const image_header_t *hdr; | |
275 | ||
276 | hdr = (const image_header_t *)img_addr; | |
277 | if (image_check_magic(hdr)) | |
278 | return IMAGE_FORMAT_LEGACY; | |
279 | #endif | |
280 | #if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT | |
281 | if (fdt_check_header(img_addr) == 0) | |
282 | return IMAGE_FORMAT_FIT; | |
283 | #endif | |
284 | #ifdef CONFIG_ANDROID_BOOT_IMAGE | |
285 | if (android_image_check_header(img_addr) == 0) | |
286 | return IMAGE_FORMAT_ANDROID; | |
287 | #endif | |
288 | ||
289 | return IMAGE_FORMAT_INVALID; | |
290 | } | |
291 | ||
292 | /** | |
293 | * fit_has_config - check if there is a valid FIT configuration | |
294 | * @images: pointer to the bootm command headers structure | |
295 | * | |
296 | * fit_has_config() checks if there is a FIT configuration in use | |
297 | * (if FTI support is present). | |
298 | * | |
299 | * returns: | |
300 | * 0, no FIT support or no configuration found | |
301 | * 1, configuration found | |
302 | */ | |
303 | int genimg_has_config(bootm_headers_t *images) | |
304 | { | |
305 | #if IMAGE_ENABLE_FIT | |
306 | if (images->fit_uname_cfg) | |
307 | return 1; | |
308 | #endif | |
309 | return 0; | |
310 | } | |
311 | ||
312 | /** | |
313 | * boot_get_ramdisk - main ramdisk handling routine | |
314 | * @argc: command argument count | |
315 | * @argv: command argument list | |
316 | * @images: pointer to the bootm images structure | |
317 | * @arch: expected ramdisk architecture | |
318 | * @rd_start: pointer to a ulong variable, will hold ramdisk start address | |
319 | * @rd_end: pointer to a ulong variable, will hold ramdisk end | |
320 | * | |
321 | * boot_get_ramdisk() is responsible for finding a valid ramdisk image. | |
322 | * Curently supported are the following ramdisk sources: | |
323 | * - multicomponent kernel/ramdisk image, | |
324 | * - commandline provided address of decicated ramdisk image. | |
325 | * | |
326 | * returns: | |
327 | * 0, if ramdisk image was found and valid, or skiped | |
328 | * rd_start and rd_end are set to ramdisk start/end addresses if | |
329 | * ramdisk image is found and valid | |
330 | * | |
331 | * 1, if ramdisk image is found but corrupted, or invalid | |
332 | * rd_start and rd_end are set to 0 if no ramdisk exists | |
333 | */ | |
334 | int boot_get_ramdisk(int argc, char *const argv[], bootm_headers_t *images, | |
335 | uint8_t arch, ulong *rd_start, ulong *rd_end) | |
336 | { | |
337 | ulong rd_addr, rd_load; | |
338 | ulong rd_data, rd_len; | |
339 | #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) | |
340 | const image_header_t *rd_hdr; | |
341 | #endif | |
342 | void *buf; | |
343 | #ifdef CONFIG_SUPPORT_RAW_INITRD | |
344 | char *end; | |
345 | #endif | |
346 | #if IMAGE_ENABLE_FIT | |
347 | const char *fit_uname_config = images->fit_uname_cfg; | |
348 | const char *fit_uname_ramdisk = NULL; | |
349 | ulong default_addr; | |
350 | int rd_noffset; | |
351 | #endif | |
352 | const char *select = NULL; | |
353 | ||
354 | *rd_start = 0; | |
355 | *rd_end = 0; | |
356 | ||
357 | #ifdef CONFIG_ANDROID_BOOT_IMAGE | |
358 | /* | |
359 | * Look for an Android boot image. | |
360 | */ | |
361 | buf = map_sysmem(images->os.start, 0); | |
362 | if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) | |
363 | select = (argc == 0) ? env_get("loadaddr") : argv[0]; | |
364 | #endif | |
365 | ||
366 | if (argc >= 2) | |
367 | select = argv[1]; | |
368 | ||
369 | /* | |
370 | * Look for a '-' which indicates to ignore the | |
371 | * ramdisk argument | |
372 | */ | |
373 | if (select && strcmp(select, "-") == 0) { | |
374 | debug("## Skipping init Ramdisk\n"); | |
375 | rd_len = rd_data = 0; | |
376 | } else if (select || genimg_has_config(images)) { | |
377 | #if IMAGE_ENABLE_FIT | |
378 | if (select) { | |
379 | /* | |
380 | * If the init ramdisk comes from the FIT image and | |
381 | * the FIT image address is omitted in the command | |
382 | * line argument, try to use os FIT image address or | |
383 | * default load address. | |
384 | */ | |
385 | if (images->fit_uname_os) | |
386 | default_addr = (ulong)images->fit_hdr_os; | |
387 | else | |
388 | default_addr = image_load_addr; | |
389 | ||
390 | if (fit_parse_conf(select, default_addr, | |
391 | &rd_addr, &fit_uname_config)) { | |
392 | debug("* ramdisk: config '%s' from image at " | |
393 | "0x%08lx\n", | |
394 | fit_uname_config, rd_addr); | |
395 | } else if (fit_parse_subimage(select, default_addr, | |
396 | &rd_addr, &fit_uname_ramdisk)) { | |
397 | debug("* ramdisk: subimage '%s' from image at " | |
398 | "0x%08lx\n", | |
399 | fit_uname_ramdisk, rd_addr); | |
400 | } else | |
401 | #endif | |
402 | { | |
403 | rd_addr = hextoul(select, NULL); | |
404 | debug("* ramdisk: cmdline image address = " | |
405 | "0x%08lx\n", | |
406 | rd_addr); | |
407 | } | |
408 | #if IMAGE_ENABLE_FIT | |
409 | } else { | |
410 | /* use FIT configuration provided in first bootm | |
411 | * command argument. If the property is not defined, | |
412 | * quit silently. | |
413 | */ | |
414 | rd_addr = map_to_sysmem(images->fit_hdr_os); | |
415 | rd_noffset = fit_get_node_from_config(images, | |
416 | FIT_RAMDISK_PROP, rd_addr); | |
417 | if (rd_noffset == -ENOENT) | |
418 | return 0; | |
419 | else if (rd_noffset < 0) | |
420 | return 1; | |
421 | } | |
422 | #endif | |
423 | ||
424 | /* | |
425 | * Check if there is an initrd image at the | |
426 | * address provided in the second bootm argument | |
427 | * check image type, for FIT images get FIT node. | |
428 | */ | |
429 | buf = map_sysmem(rd_addr, 0); | |
430 | switch (genimg_get_format(buf)) { | |
431 | #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) | |
432 | case IMAGE_FORMAT_LEGACY: | |
433 | printf("## Loading init Ramdisk from Legacy " | |
434 | "Image at %08lx ...\n", rd_addr); | |
435 | ||
436 | bootstage_mark(BOOTSTAGE_ID_CHECK_RAMDISK); | |
437 | rd_hdr = image_get_ramdisk(rd_addr, arch, | |
438 | images->verify); | |
439 | ||
440 | if (rd_hdr == NULL) | |
441 | return 1; | |
442 | ||
443 | rd_data = image_get_data(rd_hdr); | |
444 | rd_len = image_get_data_size(rd_hdr); | |
445 | rd_load = image_get_load(rd_hdr); | |
446 | break; | |
447 | #endif | |
448 | #if IMAGE_ENABLE_FIT | |
449 | case IMAGE_FORMAT_FIT: | |
450 | rd_noffset = fit_image_load(images, | |
451 | rd_addr, &fit_uname_ramdisk, | |
452 | &fit_uname_config, arch, | |
453 | IH_TYPE_RAMDISK, | |
454 | BOOTSTAGE_ID_FIT_RD_START, | |
455 | FIT_LOAD_OPTIONAL_NON_ZERO, | |
456 | &rd_data, &rd_len); | |
457 | if (rd_noffset < 0) | |
458 | return 1; | |
459 | ||
460 | images->fit_hdr_rd = map_sysmem(rd_addr, 0); | |
461 | images->fit_uname_rd = fit_uname_ramdisk; | |
462 | images->fit_noffset_rd = rd_noffset; | |
463 | break; | |
464 | #endif | |
465 | #ifdef CONFIG_ANDROID_BOOT_IMAGE | |
466 | case IMAGE_FORMAT_ANDROID: | |
467 | android_image_get_ramdisk((void *)images->os.start, | |
468 | &rd_data, &rd_len); | |
469 | break; | |
470 | #endif | |
471 | default: | |
472 | #ifdef CONFIG_SUPPORT_RAW_INITRD | |
473 | end = NULL; | |
474 | if (select) | |
475 | end = strchr(select, ':'); | |
476 | if (end) { | |
477 | rd_len = hextoul(++end, NULL); | |
478 | rd_data = rd_addr; | |
479 | } else | |
480 | #endif | |
481 | { | |
482 | puts("Wrong Ramdisk Image Format\n"); | |
483 | rd_data = rd_len = rd_load = 0; | |
484 | return 1; | |
485 | } | |
486 | } | |
487 | } else if (images->legacy_hdr_valid && | |
488 | image_check_type(&images->legacy_hdr_os_copy, | |
489 | IH_TYPE_MULTI)) { | |
490 | ||
491 | /* | |
492 | * Now check if we have a legacy mult-component image, | |
493 | * get second entry data start address and len. | |
494 | */ | |
495 | bootstage_mark(BOOTSTAGE_ID_RAMDISK); | |
496 | printf("## Loading init Ramdisk from multi component " | |
497 | "Legacy Image at %08lx ...\n", | |
498 | (ulong)images->legacy_hdr_os); | |
499 | ||
500 | image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len); | |
501 | } else { | |
502 | /* | |
503 | * no initrd image | |
504 | */ | |
505 | bootstage_mark(BOOTSTAGE_ID_NO_RAMDISK); | |
506 | rd_len = rd_data = 0; | |
507 | } | |
508 | ||
509 | if (!rd_data) { | |
510 | debug("## No init Ramdisk\n"); | |
511 | } else { | |
512 | *rd_start = rd_data; | |
513 | *rd_end = rd_data + rd_len; | |
514 | } | |
515 | debug(" ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n", | |
516 | *rd_start, *rd_end); | |
517 | ||
518 | return 0; | |
519 | } | |
520 | ||
521 | #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH | |
522 | /** | |
523 | * boot_ramdisk_high - relocate init ramdisk | |
524 | * @lmb: pointer to lmb handle, will be used for memory mgmt | |
525 | * @rd_data: ramdisk data start address | |
526 | * @rd_len: ramdisk data length | |
527 | * @initrd_start: pointer to a ulong variable, will hold final init ramdisk | |
528 | * start address (after possible relocation) | |
529 | * @initrd_end: pointer to a ulong variable, will hold final init ramdisk | |
530 | * end address (after possible relocation) | |
531 | * | |
532 | * boot_ramdisk_high() takes a relocation hint from "initrd_high" environment | |
533 | * variable and if requested ramdisk data is moved to a specified location. | |
534 | * | |
535 | * Initrd_start and initrd_end are set to final (after relocation) ramdisk | |
536 | * start/end addresses if ramdisk image start and len were provided, | |
537 | * otherwise set initrd_start and initrd_end set to zeros. | |
538 | * | |
539 | * returns: | |
540 | * 0 - success | |
541 | * -1 - failure | |
542 | */ | |
543 | int boot_ramdisk_high(struct lmb *lmb, ulong rd_data, ulong rd_len, | |
544 | ulong *initrd_start, ulong *initrd_end) | |
545 | { | |
546 | char *s; | |
547 | ulong initrd_high; | |
548 | int initrd_copy_to_ram = 1; | |
549 | ||
550 | s = env_get("initrd_high"); | |
551 | if (s) { | |
552 | /* a value of "no" or a similar string will act like 0, | |
553 | * turning the "load high" feature off. This is intentional. | |
554 | */ | |
555 | initrd_high = hextoul(s, NULL); | |
556 | if (initrd_high == ~0) | |
557 | initrd_copy_to_ram = 0; | |
558 | } else { | |
559 | initrd_high = env_get_bootm_mapsize() + env_get_bootm_low(); | |
560 | } | |
561 | ||
562 | ||
563 | debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n", | |
564 | initrd_high, initrd_copy_to_ram); | |
565 | ||
566 | if (rd_data) { | |
567 | if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */ | |
568 | debug(" in-place initrd\n"); | |
569 | *initrd_start = rd_data; | |
570 | *initrd_end = rd_data + rd_len; | |
571 | lmb_reserve(lmb, rd_data, rd_len); | |
572 | } else { | |
573 | if (initrd_high) | |
574 | *initrd_start = (ulong)lmb_alloc_base(lmb, | |
575 | rd_len, 0x1000, initrd_high); | |
576 | else | |
577 | *initrd_start = (ulong)lmb_alloc(lmb, rd_len, | |
578 | 0x1000); | |
579 | ||
580 | if (*initrd_start == 0) { | |
581 | puts("ramdisk - allocation error\n"); | |
582 | goto error; | |
583 | } | |
584 | bootstage_mark(BOOTSTAGE_ID_COPY_RAMDISK); | |
585 | ||
586 | *initrd_end = *initrd_start + rd_len; | |
587 | printf(" Loading Ramdisk to %08lx, end %08lx ... ", | |
588 | *initrd_start, *initrd_end); | |
589 | ||
590 | memmove_wd((void *)*initrd_start, | |
591 | (void *)rd_data, rd_len, CHUNKSZ); | |
592 | ||
593 | #ifdef CONFIG_MP | |
594 | /* | |
595 | * Ensure the image is flushed to memory to handle | |
596 | * AMP boot scenarios in which we might not be | |
597 | * HW cache coherent | |
598 | */ | |
599 | flush_cache((unsigned long)*initrd_start, | |
600 | ALIGN(rd_len, ARCH_DMA_MINALIGN)); | |
601 | #endif | |
602 | puts("OK\n"); | |
603 | } | |
604 | } else { | |
605 | *initrd_start = 0; | |
606 | *initrd_end = 0; | |
607 | } | |
608 | debug(" ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n", | |
609 | *initrd_start, *initrd_end); | |
610 | ||
611 | return 0; | |
612 | ||
613 | error: | |
614 | return -1; | |
615 | } | |
616 | #endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */ | |
617 | ||
618 | int boot_get_setup(bootm_headers_t *images, uint8_t arch, | |
619 | ulong *setup_start, ulong *setup_len) | |
620 | { | |
621 | #if IMAGE_ENABLE_FIT | |
622 | return boot_get_setup_fit(images, arch, setup_start, setup_len); | |
623 | #else | |
624 | return -ENOENT; | |
625 | #endif | |
626 | } | |
627 | ||
628 | #if IMAGE_ENABLE_FIT | |
629 | #if defined(CONFIG_FPGA) | |
630 | int boot_get_fpga(int argc, char *const argv[], bootm_headers_t *images, | |
631 | uint8_t arch, const ulong *ld_start, ulong * const ld_len) | |
632 | { | |
633 | ulong tmp_img_addr, img_data, img_len; | |
634 | void *buf; | |
635 | int conf_noffset; | |
636 | int fit_img_result; | |
637 | const char *uname, *name; | |
638 | int err; | |
639 | int devnum = 0; /* TODO support multi fpga platforms */ | |
640 | ||
641 | /* Check to see if the images struct has a FIT configuration */ | |
642 | if (!genimg_has_config(images)) { | |
643 | debug("## FIT configuration was not specified\n"); | |
644 | return 0; | |
645 | } | |
646 | ||
647 | /* | |
648 | * Obtain the os FIT header from the images struct | |
649 | */ | |
650 | tmp_img_addr = map_to_sysmem(images->fit_hdr_os); | |
651 | buf = map_sysmem(tmp_img_addr, 0); | |
652 | /* | |
653 | * Check image type. For FIT images get FIT node | |
654 | * and attempt to locate a generic binary. | |
655 | */ | |
656 | switch (genimg_get_format(buf)) { | |
657 | case IMAGE_FORMAT_FIT: | |
658 | conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg); | |
659 | ||
660 | uname = fdt_stringlist_get(buf, conf_noffset, FIT_FPGA_PROP, 0, | |
661 | NULL); | |
662 | if (!uname) { | |
663 | debug("## FPGA image is not specified\n"); | |
664 | return 0; | |
665 | } | |
666 | fit_img_result = fit_image_load(images, | |
667 | tmp_img_addr, | |
668 | (const char **)&uname, | |
669 | &(images->fit_uname_cfg), | |
670 | arch, | |
671 | IH_TYPE_FPGA, | |
672 | BOOTSTAGE_ID_FPGA_INIT, | |
673 | FIT_LOAD_OPTIONAL_NON_ZERO, | |
674 | &img_data, &img_len); | |
675 | ||
676 | debug("FPGA image (%s) loaded to 0x%lx/size 0x%lx\n", | |
677 | uname, img_data, img_len); | |
678 | ||
679 | if (fit_img_result < 0) { | |
680 | /* Something went wrong! */ | |
681 | return fit_img_result; | |
682 | } | |
683 | ||
684 | if (!fpga_is_partial_data(devnum, img_len)) { | |
685 | name = "full"; | |
686 | err = fpga_loadbitstream(devnum, (char *)img_data, | |
687 | img_len, BIT_FULL); | |
688 | if (err) | |
689 | err = fpga_load(devnum, (const void *)img_data, | |
690 | img_len, BIT_FULL); | |
691 | } else { | |
692 | name = "partial"; | |
693 | err = fpga_loadbitstream(devnum, (char *)img_data, | |
694 | img_len, BIT_PARTIAL); | |
695 | if (err) | |
696 | err = fpga_load(devnum, (const void *)img_data, | |
697 | img_len, BIT_PARTIAL); | |
698 | } | |
699 | ||
700 | if (err) | |
701 | return err; | |
702 | ||
703 | printf(" Programming %s bitstream... OK\n", name); | |
704 | break; | |
705 | default: | |
706 | printf("The given image format is not supported (corrupt?)\n"); | |
707 | return 1; | |
708 | } | |
709 | ||
710 | return 0; | |
711 | } | |
712 | #endif | |
713 | ||
714 | static void fit_loadable_process(uint8_t img_type, | |
715 | ulong img_data, | |
716 | ulong img_len) | |
717 | { | |
718 | int i; | |
719 | const unsigned int count = | |
720 | ll_entry_count(struct fit_loadable_tbl, fit_loadable); | |
721 | struct fit_loadable_tbl *fit_loadable_handler = | |
722 | ll_entry_start(struct fit_loadable_tbl, fit_loadable); | |
723 | /* For each loadable handler */ | |
724 | for (i = 0; i < count; i++, fit_loadable_handler++) | |
725 | /* matching this type */ | |
726 | if (fit_loadable_handler->type == img_type) | |
727 | /* call that handler with this image data */ | |
728 | fit_loadable_handler->handler(img_data, img_len); | |
729 | } | |
730 | ||
731 | int boot_get_loadable(int argc, char *const argv[], bootm_headers_t *images, | |
732 | uint8_t arch, const ulong *ld_start, ulong * const ld_len) | |
733 | { | |
734 | /* | |
735 | * These variables are used to hold the current image location | |
736 | * in system memory. | |
737 | */ | |
738 | ulong tmp_img_addr; | |
739 | /* | |
740 | * These two variables are requirements for fit_image_load, but | |
741 | * their values are not used | |
742 | */ | |
743 | ulong img_data, img_len; | |
744 | void *buf; | |
745 | int loadables_index; | |
746 | int conf_noffset; | |
747 | int fit_img_result; | |
748 | const char *uname; | |
749 | uint8_t img_type; | |
750 | ||
751 | /* Check to see if the images struct has a FIT configuration */ | |
752 | if (!genimg_has_config(images)) { | |
753 | debug("## FIT configuration was not specified\n"); | |
754 | return 0; | |
755 | } | |
756 | ||
757 | /* | |
758 | * Obtain the os FIT header from the images struct | |
759 | */ | |
760 | tmp_img_addr = map_to_sysmem(images->fit_hdr_os); | |
761 | buf = map_sysmem(tmp_img_addr, 0); | |
762 | /* | |
763 | * Check image type. For FIT images get FIT node | |
764 | * and attempt to locate a generic binary. | |
765 | */ | |
766 | switch (genimg_get_format(buf)) { | |
767 | case IMAGE_FORMAT_FIT: | |
768 | conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg); | |
769 | ||
770 | for (loadables_index = 0; | |
771 | uname = fdt_stringlist_get(buf, conf_noffset, | |
772 | FIT_LOADABLE_PROP, loadables_index, | |
773 | NULL), uname; | |
774 | loadables_index++) | |
775 | { | |
776 | fit_img_result = fit_image_load(images, | |
777 | tmp_img_addr, | |
778 | &uname, | |
779 | &(images->fit_uname_cfg), arch, | |
780 | IH_TYPE_LOADABLE, | |
781 | BOOTSTAGE_ID_FIT_LOADABLE_START, | |
782 | FIT_LOAD_OPTIONAL_NON_ZERO, | |
783 | &img_data, &img_len); | |
784 | if (fit_img_result < 0) { | |
785 | /* Something went wrong! */ | |
786 | return fit_img_result; | |
787 | } | |
788 | ||
789 | fit_img_result = fit_image_get_node(buf, uname); | |
790 | if (fit_img_result < 0) { | |
791 | /* Something went wrong! */ | |
792 | return fit_img_result; | |
793 | } | |
794 | fit_img_result = fit_image_get_type(buf, | |
795 | fit_img_result, | |
796 | &img_type); | |
797 | if (fit_img_result < 0) { | |
798 | /* Something went wrong! */ | |
799 | return fit_img_result; | |
800 | } | |
801 | ||
802 | fit_loadable_process(img_type, img_data, img_len); | |
803 | } | |
804 | break; | |
805 | default: | |
806 | printf("The given image format is not supported (corrupt?)\n"); | |
807 | return 1; | |
808 | } | |
809 | ||
810 | return 0; | |
811 | } | |
812 | #endif | |
813 | ||
814 | #ifdef CONFIG_SYS_BOOT_GET_CMDLINE | |
815 | /** | |
816 | * boot_get_cmdline - allocate and initialize kernel cmdline | |
817 | * @lmb: pointer to lmb handle, will be used for memory mgmt | |
818 | * @cmd_start: pointer to a ulong variable, will hold cmdline start | |
819 | * @cmd_end: pointer to a ulong variable, will hold cmdline end | |
820 | * | |
821 | * boot_get_cmdline() allocates space for kernel command line below | |
822 | * BOOTMAPSZ + env_get_bootm_low() address. If "bootargs" U-Boot environment | |
823 | * variable is present its contents is copied to allocated kernel | |
824 | * command line. | |
825 | * | |
826 | * returns: | |
827 | * 0 - success | |
828 | * -1 - failure | |
829 | */ | |
830 | int boot_get_cmdline(struct lmb *lmb, ulong *cmd_start, ulong *cmd_end) | |
831 | { | |
832 | char *cmdline; | |
833 | char *s; | |
834 | ||
835 | cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf, | |
836 | env_get_bootm_mapsize() + env_get_bootm_low()); | |
837 | ||
838 | if (cmdline == NULL) | |
839 | return -1; | |
840 | ||
841 | s = env_get("bootargs"); | |
842 | if (!s) | |
843 | s = ""; | |
844 | ||
845 | strcpy(cmdline, s); | |
846 | ||
847 | *cmd_start = (ulong) & cmdline[0]; | |
848 | *cmd_end = *cmd_start + strlen(cmdline); | |
849 | ||
850 | debug("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end); | |
851 | ||
852 | return 0; | |
853 | } | |
854 | #endif /* CONFIG_SYS_BOOT_GET_CMDLINE */ | |
855 | ||
856 | #ifdef CONFIG_SYS_BOOT_GET_KBD | |
857 | /** | |
858 | * boot_get_kbd - allocate and initialize kernel copy of board info | |
859 | * @lmb: pointer to lmb handle, will be used for memory mgmt | |
860 | * @kbd: double pointer to board info data | |
861 | * | |
862 | * boot_get_kbd() allocates space for kernel copy of board info data below | |
863 | * BOOTMAPSZ + env_get_bootm_low() address and kernel board info is initialized | |
864 | * with the current u-boot board info data. | |
865 | * | |
866 | * returns: | |
867 | * 0 - success | |
868 | * -1 - failure | |
869 | */ | |
870 | int boot_get_kbd(struct lmb *lmb, struct bd_info **kbd) | |
871 | { | |
872 | *kbd = (struct bd_info *)(ulong)lmb_alloc_base(lmb, | |
873 | sizeof(struct bd_info), | |
874 | 0xf, | |
875 | env_get_bootm_mapsize() + env_get_bootm_low()); | |
876 | if (*kbd == NULL) | |
877 | return -1; | |
878 | ||
879 | **kbd = *(gd->bd); | |
880 | ||
881 | debug("## kernel board info at 0x%08lx\n", (ulong)*kbd); | |
882 | ||
883 | #if defined(DEBUG) && defined(CONFIG_CMD_BDI) | |
884 | do_bdinfo(NULL, 0, 0, NULL); | |
885 | #endif | |
886 | ||
887 | return 0; | |
888 | } | |
889 | #endif /* CONFIG_SYS_BOOT_GET_KBD */ | |
890 | ||
891 | #ifdef CONFIG_LMB | |
892 | int image_setup_linux(bootm_headers_t *images) | |
893 | { | |
894 | ulong of_size = images->ft_len; | |
895 | char **of_flat_tree = &images->ft_addr; | |
896 | struct lmb *lmb = &images->lmb; | |
897 | int ret; | |
898 | ||
899 | if (IMAGE_ENABLE_OF_LIBFDT) | |
900 | boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree); | |
901 | ||
902 | if (IMAGE_BOOT_GET_CMDLINE) { | |
903 | ret = boot_get_cmdline(lmb, &images->cmdline_start, | |
904 | &images->cmdline_end); | |
905 | if (ret) { | |
906 | puts("ERROR with allocation of cmdline\n"); | |
907 | return ret; | |
908 | } | |
909 | } | |
910 | ||
911 | if (IMAGE_ENABLE_OF_LIBFDT) { | |
912 | ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size); | |
913 | if (ret) | |
914 | return ret; | |
915 | } | |
916 | ||
917 | if (IMAGE_ENABLE_OF_LIBFDT && of_size) { | |
918 | ret = image_setup_libfdt(images, *of_flat_tree, of_size, lmb); | |
919 | if (ret) | |
920 | return ret; | |
921 | } | |
922 | ||
923 | return 0; | |
924 | } | |
925 | #endif /* CONFIG_LMB */ |