]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
fa61ef6b KP |
2 | /* |
3 | * Copyright (C) 2016 Marvell International Ltd. | |
fa61ef6b KP |
4 | * https://spdx.org/licenses |
5 | */ | |
6 | ||
7 | #include <config.h> | |
8 | #include <common.h> | |
9 | #include <command.h> | |
7b51b576 | 10 | #include <env.h> |
8e8ccfe1 | 11 | #include <image.h> |
90526e9f | 12 | #include <net.h> |
fa61ef6b KP |
13 | #include <vsprintf.h> |
14 | #include <errno.h> | |
15 | #include <dm.h> | |
16 | ||
17 | #include <spi_flash.h> | |
18 | #include <spi.h> | |
19 | #include <nand.h> | |
20 | #include <usb.h> | |
21 | #include <fs.h> | |
22 | #include <mmc.h> | |
e559ef1a KP |
23 | #ifdef CONFIG_BLK |
24 | #include <blk.h> | |
25 | #endif | |
fa61ef6b KP |
26 | #include <u-boot/sha1.h> |
27 | #include <u-boot/sha256.h> | |
93c1358b | 28 | #include <u-boot/sha512.h> |
fa61ef6b | 29 | |
fa61ef6b KP |
30 | #if defined(CONFIG_ARMADA_8K) |
31 | #define MAIN_HDR_MAGIC 0xB105B002 | |
32 | ||
33 | struct mvebu_image_header { | |
34 | u32 magic; /* 0-3 */ | |
35 | u32 prolog_size; /* 4-7 */ | |
36 | u32 prolog_checksum; /* 8-11 */ | |
37 | u32 boot_image_size; /* 12-15 */ | |
38 | u32 boot_image_checksum; /* 16-19 */ | |
39 | u32 rsrvd0; /* 20-23 */ | |
40 | u32 load_addr; /* 24-27 */ | |
41 | u32 exec_addr; /* 28-31 */ | |
42 | u8 uart_cfg; /* 32 */ | |
43 | u8 baudrate; /* 33 */ | |
44 | u8 ext_count; /* 34 */ | |
45 | u8 aux_flags; /* 35 */ | |
46 | u32 io_arg_0; /* 36-39 */ | |
47 | u32 io_arg_1; /* 40-43 */ | |
48 | u32 io_arg_2; /* 43-47 */ | |
49 | u32 io_arg_3; /* 48-51 */ | |
50 | u32 rsrvd1; /* 52-55 */ | |
51 | u32 rsrvd2; /* 56-59 */ | |
52 | u32 rsrvd3; /* 60-63 */ | |
53 | }; | |
54 | #elif defined(CONFIG_ARMADA_3700) /* A3700 */ | |
55 | #define HASH_SUM_LEN 16 | |
56 | #define IMAGE_VERSION_3_6_0 0x030600 | |
57 | #define IMAGE_VERSION_3_5_0 0x030500 | |
58 | ||
5d2f7d30 T |
59 | struct tim_boot_flash_sign { |
60 | unsigned int id; | |
61 | const char *name; | |
62 | }; | |
63 | ||
64 | struct tim_boot_flash_sign tim_boot_flash_signs[] = { | |
65 | { 0x454d4d08, "mmc" }, | |
66 | { 0x454d4d0b, "mmc" }, | |
67 | { 0x5350490a, "spi" }, | |
68 | { 0x5350491a, "nand" }, | |
69 | { 0x55415223, "uart" }, | |
70 | { 0x53415432, "sata" }, | |
71 | {}, | |
72 | }; | |
73 | ||
fa61ef6b KP |
74 | struct common_tim_data { |
75 | u32 version; | |
76 | u32 identifier; | |
77 | u32 trusted; | |
78 | u32 issue_date; | |
79 | u32 oem_unique_id; | |
80 | u32 reserved[5]; /* Reserve 20 bytes */ | |
81 | u32 boot_flash_sign; | |
82 | u32 num_images; | |
83 | u32 num_keys; | |
84 | u32 size_of_reserved; | |
85 | }; | |
86 | ||
87 | struct mvebu_image_info { | |
88 | u32 image_id; | |
89 | u32 next_image_id; | |
90 | u32 flash_entry_addr; | |
91 | u32 load_addr; | |
92 | u32 image_size; | |
93 | u32 image_size_to_hash; | |
94 | u32 hash_algorithm_id; | |
95 | u32 hash[HASH_SUM_LEN]; /* Reserve 512 bits for the hash */ | |
96 | u32 partition_number; | |
97 | u32 enc_algorithm_id; | |
98 | u32 encrypt_start_offset; | |
99 | u32 encrypt_size; | |
100 | }; | |
5d2f7d30 | 101 | #elif defined(CONFIG_ARMADA_32BIT) |
8ec6db78 | 102 | |
7af368f4 | 103 | /* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */ |
8ec6db78 JJ |
104 | struct a38x_main_hdr_v1 { |
105 | u8 blockid; /* 0x0 */ | |
106 | u8 flags; /* 0x1 */ | |
33cdd9ee | 107 | u16 nandpagesize; /* 0x2-0x3 */ |
8ec6db78 JJ |
108 | u32 blocksize; /* 0x4-0x7 */ |
109 | u8 version; /* 0x8 */ | |
110 | u8 headersz_msb; /* 0x9 */ | |
111 | u16 headersz_lsb; /* 0xA-0xB */ | |
112 | u32 srcaddr; /* 0xC-0xF */ | |
113 | u32 destaddr; /* 0x10-0x13 */ | |
114 | u32 execaddr; /* 0x14-0x17 */ | |
115 | u8 options; /* 0x18 */ | |
116 | u8 nandblocksize; /* 0x19 */ | |
117 | u8 nandbadblklocation; /* 0x1A */ | |
118 | u8 reserved4; /* 0x1B */ | |
119 | u16 reserved5; /* 0x1C-0x1D */ | |
120 | u8 ext; /* 0x1E */ | |
121 | u8 checksum; /* 0x1F */ | |
122 | }; | |
658854a6 JJ |
123 | |
124 | struct a38x_boot_mode { | |
125 | unsigned int id; | |
126 | const char *name; | |
127 | }; | |
128 | ||
129 | /* The blockid header field values used to indicate boot device of image */ | |
130 | struct a38x_boot_mode a38x_boot_modes[] = { | |
131 | { 0x4D, "i2c" }, | |
132 | { 0x5A, "spi" }, | |
133 | { 0x69, "uart" }, | |
134 | { 0x78, "sata" }, | |
135 | { 0x8B, "nand" }, | |
136 | { 0x9C, "pex" }, | |
137 | { 0xAE, "mmc" }, | |
138 | {}, | |
139 | }; | |
fa61ef6b | 140 | |
5d2f7d30 T |
141 | #endif |
142 | ||
fa61ef6b KP |
143 | struct bubt_dev { |
144 | char name[8]; | |
145 | size_t (*read)(const char *file_name); | |
146 | int (*write)(size_t image_size); | |
147 | int (*active)(void); | |
148 | }; | |
149 | ||
150 | static ulong get_load_addr(void) | |
151 | { | |
152 | const char *addr_str; | |
153 | unsigned long addr; | |
154 | ||
00caae6d | 155 | addr_str = env_get("loadaddr"); |
fa61ef6b | 156 | if (addr_str) |
7e5f460e | 157 | addr = hextoul(addr_str, NULL); |
fa61ef6b KP |
158 | else |
159 | addr = CONFIG_SYS_LOAD_ADDR; | |
160 | ||
161 | return addr; | |
162 | } | |
163 | ||
164 | /******************************************************************** | |
165 | * eMMC services | |
166 | ********************************************************************/ | |
d6400c3f | 167 | #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE) |
fa61ef6b KP |
168 | static int mmc_burn_image(size_t image_size) |
169 | { | |
170 | struct mmc *mmc; | |
171 | lbaint_t start_lba; | |
172 | lbaint_t blk_count; | |
173 | ulong blk_written; | |
174 | int err; | |
175 | const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV; | |
e559ef1a KP |
176 | #ifdef CONFIG_BLK |
177 | struct blk_desc *blk_desc; | |
178 | #endif | |
fa61ef6b KP |
179 | mmc = find_mmc_device(mmc_dev_num); |
180 | if (!mmc) { | |
181 | printf("No SD/MMC/eMMC card found\n"); | |
182 | return -ENOMEDIUM; | |
183 | } | |
184 | ||
185 | err = mmc_init(mmc); | |
186 | if (err) { | |
187 | printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC", | |
188 | mmc_dev_num); | |
189 | return err; | |
190 | } | |
191 | ||
fa61ef6b KP |
192 | /* SD reserves LBA-0 for MBR and boots from LBA-1, |
193 | * MMC/eMMC boots from LBA-0 | |
194 | */ | |
195 | start_lba = IS_SD(mmc) ? 1 : 0; | |
e559ef1a KP |
196 | #ifdef CONFIG_BLK |
197 | blk_count = image_size / mmc->write_bl_len; | |
198 | if (image_size % mmc->write_bl_len) | |
199 | blk_count += 1; | |
200 | ||
201 | blk_desc = mmc_get_blk_desc(mmc); | |
202 | if (!blk_desc) { | |
203 | printf("Error - failed to obtain block descriptor\n"); | |
204 | return -ENODEV; | |
205 | } | |
206 | blk_written = blk_dwrite(blk_desc, start_lba, blk_count, | |
207 | (void *)get_load_addr()); | |
208 | #else | |
fa61ef6b KP |
209 | blk_count = image_size / mmc->block_dev.blksz; |
210 | if (image_size % mmc->block_dev.blksz) | |
211 | blk_count += 1; | |
212 | ||
213 | blk_written = mmc->block_dev.block_write(mmc_dev_num, | |
e559ef1a KP |
214 | start_lba, blk_count, |
215 | (void *)get_load_addr()); | |
216 | #endif /* CONFIG_BLK */ | |
fa61ef6b KP |
217 | if (blk_written != blk_count) { |
218 | printf("Error - written %#lx blocks\n", blk_written); | |
219 | return -ENOSPC; | |
220 | } | |
221 | printf("Done!\n"); | |
222 | ||
fa61ef6b KP |
223 | return 0; |
224 | } | |
225 | ||
226 | static size_t mmc_read_file(const char *file_name) | |
227 | { | |
228 | loff_t act_read = 0; | |
229 | int rc; | |
230 | struct mmc *mmc; | |
231 | const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV; | |
232 | ||
233 | mmc = find_mmc_device(mmc_dev_num); | |
234 | if (!mmc) { | |
235 | printf("No SD/MMC/eMMC card found\n"); | |
236 | return 0; | |
237 | } | |
238 | ||
239 | if (mmc_init(mmc)) { | |
240 | printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC", | |
241 | mmc_dev_num); | |
242 | return 0; | |
243 | } | |
244 | ||
245 | /* Load from data partition (0) */ | |
246 | if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) { | |
247 | printf("Error: MMC 0 not found\n"); | |
248 | return 0; | |
249 | } | |
250 | ||
251 | /* Perfrom file read */ | |
252 | rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read); | |
253 | if (rc) | |
254 | return 0; | |
255 | ||
256 | return act_read; | |
257 | } | |
258 | ||
259 | static int is_mmc_active(void) | |
260 | { | |
261 | return 1; | |
262 | } | |
263 | #else /* CONFIG_DM_MMC */ | |
264 | static int mmc_burn_image(size_t image_size) | |
265 | { | |
266 | return -ENODEV; | |
267 | } | |
268 | ||
269 | static size_t mmc_read_file(const char *file_name) | |
270 | { | |
271 | return 0; | |
272 | } | |
273 | ||
274 | static int is_mmc_active(void) | |
275 | { | |
276 | return 0; | |
277 | } | |
278 | #endif /* CONFIG_DM_MMC */ | |
279 | ||
280 | /******************************************************************** | |
281 | * SPI services | |
282 | ********************************************************************/ | |
283 | #ifdef CONFIG_SPI_FLASH | |
284 | static int spi_burn_image(size_t image_size) | |
285 | { | |
286 | int ret; | |
287 | struct spi_flash *flash; | |
288 | u32 erase_bytes; | |
289 | ||
290 | /* Probe the SPI bus to get the flash device */ | |
7e6a6fd8 TR |
291 | flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, |
292 | CONFIG_SF_DEFAULT_CS, | |
fa61ef6b KP |
293 | CONFIG_SF_DEFAULT_SPEED, |
294 | CONFIG_SF_DEFAULT_MODE); | |
295 | if (!flash) { | |
296 | printf("Failed to probe SPI Flash\n"); | |
297 | return -ENOMEDIUM; | |
298 | } | |
299 | ||
fa61ef6b KP |
300 | erase_bytes = image_size + |
301 | (flash->erase_size - image_size % flash->erase_size); | |
302 | printf("Erasing %d bytes (%d blocks) at offset 0 ...", | |
303 | erase_bytes, erase_bytes / flash->erase_size); | |
304 | ret = spi_flash_erase(flash, 0, erase_bytes); | |
305 | if (ret) | |
306 | printf("Error!\n"); | |
307 | else | |
308 | printf("Done!\n"); | |
309 | ||
310 | printf("Writing %d bytes from 0x%lx to offset 0 ...", | |
311 | (int)image_size, get_load_addr()); | |
312 | ret = spi_flash_write(flash, 0, image_size, (void *)get_load_addr()); | |
313 | if (ret) | |
314 | printf("Error!\n"); | |
315 | else | |
316 | printf("Done!\n"); | |
317 | ||
fa61ef6b KP |
318 | return ret; |
319 | } | |
320 | ||
321 | static int is_spi_active(void) | |
322 | { | |
323 | return 1; | |
324 | } | |
325 | ||
326 | #else /* CONFIG_SPI_FLASH */ | |
327 | static int spi_burn_image(size_t image_size) | |
328 | { | |
329 | return -ENODEV; | |
330 | } | |
331 | ||
332 | static int is_spi_active(void) | |
333 | { | |
334 | return 0; | |
335 | } | |
336 | #endif /* CONFIG_SPI_FLASH */ | |
337 | ||
338 | /******************************************************************** | |
339 | * NAND services | |
340 | ********************************************************************/ | |
341 | #ifdef CONFIG_CMD_NAND | |
342 | static int nand_burn_image(size_t image_size) | |
343 | { | |
f2ca24d9 KP |
344 | int ret; |
345 | uint32_t block_size; | |
7021c7e6 | 346 | struct mtd_info *mtd; |
fa61ef6b | 347 | |
7021c7e6 GS |
348 | mtd = get_nand_dev_by_index(nand_curr_device); |
349 | if (!mtd) { | |
fa61ef6b KP |
350 | puts("\nno devices available\n"); |
351 | return -ENOMEDIUM; | |
352 | } | |
7021c7e6 | 353 | block_size = mtd->erasesize; |
fa61ef6b KP |
354 | |
355 | /* Align U-Boot size to currently used blocksize */ | |
356 | image_size = ((image_size + (block_size - 1)) & (~(block_size - 1))); | |
357 | ||
f41b85ee | 358 | /* Erase the U-Boot image space */ |
fa61ef6b | 359 | printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size); |
7021c7e6 | 360 | ret = nand_erase(mtd, 0, image_size); |
fa61ef6b KP |
361 | if (ret) { |
362 | printf("Error!\n"); | |
363 | goto error; | |
364 | } | |
365 | printf("Done!\n"); | |
366 | ||
367 | /* Write the image to flash */ | |
f2ca24d9 KP |
368 | printf("Writing %d bytes from 0x%lx to offset 0 ... ", |
369 | (int)image_size, get_load_addr()); | |
7021c7e6 | 370 | ret = nand_write(mtd, 0, &image_size, (void *)get_load_addr()); |
fa61ef6b KP |
371 | if (ret) |
372 | printf("Error!\n"); | |
373 | else | |
374 | printf("Done!\n"); | |
375 | ||
376 | error: | |
377 | return ret; | |
378 | } | |
379 | ||
380 | static int is_nand_active(void) | |
381 | { | |
382 | return 1; | |
383 | } | |
384 | ||
385 | #else /* CONFIG_CMD_NAND */ | |
386 | static int nand_burn_image(size_t image_size) | |
387 | { | |
388 | return -ENODEV; | |
389 | } | |
390 | ||
391 | static int is_nand_active(void) | |
392 | { | |
393 | return 0; | |
394 | } | |
395 | #endif /* CONFIG_CMD_NAND */ | |
396 | ||
397 | /******************************************************************** | |
398 | * USB services | |
399 | ********************************************************************/ | |
400 | #if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK) | |
401 | static size_t usb_read_file(const char *file_name) | |
402 | { | |
403 | loff_t act_read = 0; | |
404 | struct udevice *dev; | |
405 | int rc; | |
406 | ||
407 | usb_stop(); | |
408 | ||
409 | if (usb_init() < 0) { | |
410 | printf("Error: usb_init failed\n"); | |
411 | return 0; | |
412 | } | |
413 | ||
414 | /* Try to recognize storage devices immediately */ | |
e33a5c6b | 415 | blk_first_device(UCLASS_USB, &dev); |
fa61ef6b KP |
416 | if (!dev) { |
417 | printf("Error: USB storage device not found\n"); | |
418 | return 0; | |
419 | } | |
420 | ||
421 | /* Always load from usb 0 */ | |
422 | if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) { | |
423 | printf("Error: USB 0 not found\n"); | |
424 | return 0; | |
425 | } | |
426 | ||
427 | /* Perfrom file read */ | |
428 | rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read); | |
429 | if (rc) | |
430 | return 0; | |
431 | ||
432 | return act_read; | |
433 | } | |
434 | ||
435 | static int is_usb_active(void) | |
436 | { | |
437 | return 1; | |
438 | } | |
439 | ||
440 | #else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */ | |
441 | static size_t usb_read_file(const char *file_name) | |
442 | { | |
443 | return 0; | |
444 | } | |
445 | ||
446 | static int is_usb_active(void) | |
447 | { | |
448 | return 0; | |
449 | } | |
450 | #endif /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */ | |
451 | ||
452 | /******************************************************************** | |
453 | * Network services | |
454 | ********************************************************************/ | |
455 | #ifdef CONFIG_CMD_NET | |
456 | static size_t tftp_read_file(const char *file_name) | |
457 | { | |
4b9521f2 T |
458 | int ret; |
459 | ||
bb872dd9 SG |
460 | /* |
461 | * update global variable image_load_addr before tftp file from network | |
462 | */ | |
463 | image_load_addr = get_load_addr(); | |
4b9521f2 T |
464 | ret = net_loop(TFTPGET); |
465 | return ret > 0 ? ret : 0; | |
fa61ef6b KP |
466 | } |
467 | ||
468 | static int is_tftp_active(void) | |
469 | { | |
470 | return 1; | |
471 | } | |
472 | ||
473 | #else | |
474 | static size_t tftp_read_file(const char *file_name) | |
475 | { | |
476 | return 0; | |
477 | } | |
478 | ||
479 | static int is_tftp_active(void) | |
480 | { | |
481 | return 0; | |
482 | } | |
483 | #endif /* CONFIG_CMD_NET */ | |
484 | ||
485 | enum bubt_devices { | |
486 | BUBT_DEV_NET = 0, | |
487 | BUBT_DEV_USB, | |
488 | BUBT_DEV_MMC, | |
489 | BUBT_DEV_SPI, | |
490 | BUBT_DEV_NAND, | |
491 | ||
492 | BUBT_MAX_DEV | |
493 | }; | |
494 | ||
495 | struct bubt_dev bubt_devs[BUBT_MAX_DEV] = { | |
496 | {"tftp", tftp_read_file, NULL, is_tftp_active}, | |
497 | {"usb", usb_read_file, NULL, is_usb_active}, | |
498 | {"mmc", mmc_read_file, mmc_burn_image, is_mmc_active}, | |
499 | {"spi", NULL, spi_burn_image, is_spi_active}, | |
500 | {"nand", NULL, nand_burn_image, is_nand_active}, | |
501 | }; | |
502 | ||
503 | static int bubt_write_file(struct bubt_dev *dst, size_t image_size) | |
504 | { | |
505 | if (!dst->write) { | |
506 | printf("Error: Write not supported on device %s\n", dst->name); | |
507 | return -ENOTSUPP; | |
508 | } | |
509 | ||
510 | return dst->write(image_size); | |
511 | } | |
512 | ||
513 | #if defined(CONFIG_ARMADA_8K) | |
514 | u32 do_checksum32(u32 *start, int32_t len) | |
515 | { | |
516 | u32 sum = 0; | |
517 | u32 *startp = start; | |
518 | ||
519 | do { | |
520 | sum += *startp; | |
521 | startp++; | |
522 | len -= 4; | |
523 | } while (len > 0); | |
524 | ||
525 | return sum; | |
526 | } | |
527 | ||
528 | static int check_image_header(void) | |
529 | { | |
530 | struct mvebu_image_header *hdr = | |
531 | (struct mvebu_image_header *)get_load_addr(); | |
532 | u32 header_len = hdr->prolog_size; | |
533 | u32 checksum; | |
534 | u32 checksum_ref = hdr->prolog_checksum; | |
535 | ||
536 | /* | |
537 | * For now compare checksum, and magic. Later we can | |
538 | * verify more stuff on the header like interface type, etc | |
539 | */ | |
540 | if (hdr->magic != MAIN_HDR_MAGIC) { | |
541 | printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n", | |
542 | hdr->magic, MAIN_HDR_MAGIC); | |
543 | return -ENOEXEC; | |
544 | } | |
545 | ||
546 | /* The checksum value is discarded from checksum calculation */ | |
547 | hdr->prolog_checksum = 0; | |
548 | ||
549 | checksum = do_checksum32((u32 *)hdr, header_len); | |
550 | if (checksum != checksum_ref) { | |
551 | printf("Error: Bad Image checksum. 0x%x != 0x%x\n", | |
552 | checksum, checksum_ref); | |
553 | return -ENOEXEC; | |
554 | } | |
555 | ||
556 | /* Restore the checksum before writing */ | |
557 | hdr->prolog_checksum = checksum_ref; | |
558 | printf("Image checksum...OK!\n"); | |
559 | ||
560 | return 0; | |
561 | } | |
562 | #elif defined(CONFIG_ARMADA_3700) /* Armada 3700 */ | |
563 | static int check_image_header(void) | |
564 | { | |
565 | struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr(); | |
566 | int image_num; | |
567 | u8 hash_160_output[SHA1_SUM_LEN]; | |
568 | u8 hash_256_output[SHA256_SUM_LEN]; | |
93c1358b | 569 | u8 hash_512_output[SHA512_SUM_LEN]; |
fa61ef6b KP |
570 | sha1_context hash1_text; |
571 | sha256_context hash256_text; | |
93c1358b | 572 | sha512_context hash512_text; |
fa61ef6b KP |
573 | u8 *hash_output; |
574 | u32 hash_algorithm_id; | |
575 | u32 image_size_to_hash; | |
576 | u32 flash_entry_addr; | |
577 | u32 *hash_value; | |
578 | u32 internal_hash[HASH_SUM_LEN]; | |
579 | const u8 *buff; | |
580 | u32 num_of_image = hdr->num_images; | |
581 | u32 version = hdr->version; | |
582 | u32 trusted = hdr->trusted; | |
583 | ||
584 | /* bubt checksum validation only supports nontrusted images */ | |
585 | if (trusted == 1) { | |
586 | printf("bypass image validation, "); | |
587 | printf("only untrusted image is supported now\n"); | |
588 | return 0; | |
589 | } | |
590 | /* only supports image version 3.5 and 3.6 */ | |
591 | if (version != IMAGE_VERSION_3_5_0 && version != IMAGE_VERSION_3_6_0) { | |
592 | printf("Error: Unsupported Image version = 0x%08x\n", version); | |
593 | return -ENOEXEC; | |
594 | } | |
595 | /* validate images hash value */ | |
596 | for (image_num = 0; image_num < num_of_image; image_num++) { | |
597 | struct mvebu_image_info *info = | |
598 | (struct mvebu_image_info *)(get_load_addr() + | |
599 | sizeof(struct common_tim_data) + | |
600 | image_num * sizeof(struct mvebu_image_info)); | |
601 | hash_algorithm_id = info->hash_algorithm_id; | |
602 | image_size_to_hash = info->image_size_to_hash; | |
603 | flash_entry_addr = info->flash_entry_addr; | |
604 | hash_value = info->hash; | |
605 | buff = (const u8 *)(get_load_addr() + flash_entry_addr); | |
606 | ||
607 | if (image_num == 0) { | |
608 | /* | |
609 | * The first image includes hash values in its content. | |
610 | * For hash calculation, we need to save the original | |
611 | * hash values to a local variable that will be | |
612 | * copied back for comparsion and set all zeros to | |
613 | * the orignal hash values for calculating new value. | |
614 | * First image original format : | |
615 | * x...x (datum1) x...x(orig. hash values) x...x(datum2) | |
616 | * Replaced first image format : | |
617 | * x...x (datum1) 0...0(hash values) x...x(datum2) | |
618 | */ | |
619 | memcpy(internal_hash, hash_value, | |
620 | sizeof(internal_hash)); | |
621 | memset(hash_value, 0, sizeof(internal_hash)); | |
622 | } | |
623 | if (image_size_to_hash == 0) { | |
624 | printf("Warning: Image_%d hash checksum is disabled, ", | |
625 | image_num); | |
626 | printf("skip the image validation.\n"); | |
627 | continue; | |
628 | } | |
629 | switch (hash_algorithm_id) { | |
630 | case SHA1_SUM_LEN: | |
631 | sha1_starts(&hash1_text); | |
632 | sha1_update(&hash1_text, buff, image_size_to_hash); | |
633 | sha1_finish(&hash1_text, hash_160_output); | |
634 | hash_output = hash_160_output; | |
635 | break; | |
636 | case SHA256_SUM_LEN: | |
637 | sha256_starts(&hash256_text); | |
638 | sha256_update(&hash256_text, buff, image_size_to_hash); | |
639 | sha256_finish(&hash256_text, hash_256_output); | |
640 | hash_output = hash_256_output; | |
641 | break; | |
93c1358b T |
642 | case SHA512_SUM_LEN: |
643 | sha512_starts(&hash512_text); | |
644 | sha512_update(&hash512_text, buff, image_size_to_hash); | |
645 | sha512_finish(&hash512_text, hash_512_output); | |
646 | hash_output = hash_512_output; | |
647 | break; | |
fa61ef6b KP |
648 | default: |
649 | printf("Error: Unsupported hash_algorithm_id = %d\n", | |
650 | hash_algorithm_id); | |
651 | return -ENOEXEC; | |
652 | } | |
653 | if (image_num == 0) | |
654 | memcpy(hash_value, internal_hash, | |
655 | sizeof(internal_hash)); | |
656 | if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) { | |
657 | printf("Error: Image_%d checksum is not correct\n", | |
658 | image_num); | |
659 | return -ENOEXEC; | |
660 | } | |
661 | } | |
662 | printf("Image checksum...OK!\n"); | |
663 | ||
664 | return 0; | |
665 | } | |
5d2f7d30 | 666 | #elif defined(CONFIG_ARMADA_32BIT) |
8ec6db78 JJ |
667 | static size_t a38x_header_size(const struct a38x_main_hdr_v1 *h) |
668 | { | |
669 | if (h->version == 1) | |
670 | return (h->headersz_msb << 16) | le16_to_cpu(h->headersz_lsb); | |
671 | ||
672 | printf("Error: Invalid A38x image (header version 0x%x unknown)!\n", | |
673 | h->version); | |
674 | return 0; | |
675 | } | |
676 | ||
677 | static uint8_t image_checksum8(const void *start, size_t len) | |
678 | { | |
679 | u8 csum = 0; | |
680 | const u8 *p = start; | |
681 | ||
682 | while (len) { | |
683 | csum += *p; | |
684 | ++p; | |
685 | --len; | |
686 | } | |
687 | ||
688 | return csum; | |
689 | } | |
fa61ef6b | 690 | |
8ec6db78 JJ |
691 | static int check_image_header(void) |
692 | { | |
693 | u8 checksum; | |
694 | const struct a38x_main_hdr_v1 *hdr = | |
695 | (struct a38x_main_hdr_v1 *)get_load_addr(); | |
696 | const size_t image_size = a38x_header_size(hdr); | |
697 | ||
698 | if (!image_size) | |
699 | return -ENOEXEC; | |
700 | ||
701 | checksum = image_checksum8(hdr, image_size); | |
702 | checksum -= hdr->checksum; | |
703 | if (checksum != hdr->checksum) { | |
704 | printf("Error: Bad A38x image checksum. 0x%x != 0x%x\n", | |
705 | checksum, hdr->checksum); | |
706 | return -ENOEXEC; | |
707 | } | |
708 | ||
709 | printf("Image checksum...OK!\n"); | |
710 | return 0; | |
711 | } | |
fa61ef6b KP |
712 | #else /* Not ARMADA? */ |
713 | static int check_image_header(void) | |
714 | { | |
715 | printf("bubt cmd does not support this SoC device or family!\n"); | |
716 | return -ENOEXEC; | |
717 | } | |
718 | #endif | |
719 | ||
658854a6 JJ |
720 | static int bubt_check_boot_mode(const struct bubt_dev *dst) |
721 | { | |
5d2f7d30 T |
722 | #if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) |
723 | int mode; | |
724 | #if defined(CONFIG_ARMADA_3700) | |
725 | const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs; | |
726 | const struct common_tim_data *hdr = | |
727 | (struct common_tim_data *)get_load_addr(); | |
728 | u32 id = hdr->boot_flash_sign; | |
729 | #elif defined(CONFIG_ARMADA_32BIT) | |
730 | const struct a38x_boot_mode *boot_modes = a38x_boot_modes; | |
731 | const struct a38x_main_hdr_v1 *hdr = | |
732 | (struct a38x_main_hdr_v1 *)get_load_addr(); | |
733 | u32 id = hdr->blockid; | |
734 | #endif | |
658854a6 | 735 | |
5d2f7d30 T |
736 | for (mode = 0; boot_modes[mode].name; mode++) { |
737 | if (boot_modes[mode].id == id) | |
738 | break; | |
739 | } | |
f60a66ef | 740 | |
5d2f7d30 T |
741 | if (!boot_modes[mode].name) { |
742 | printf("Error: unknown boot device in image header: 0x%x\n", id); | |
658854a6 | 743 | return -ENOEXEC; |
658854a6 | 744 | } |
5d2f7d30 T |
745 | |
746 | if (strcmp(boot_modes[mode].name, dst->name) == 0) | |
747 | return 0; | |
748 | ||
749 | printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", | |
750 | boot_modes[mode].name, dst->name); | |
751 | return -ENOEXEC; | |
752 | #else | |
753 | return 0; | |
754 | #endif | |
658854a6 JJ |
755 | } |
756 | ||
757 | static int bubt_verify(const struct bubt_dev *dst) | |
fa61ef6b KP |
758 | { |
759 | int err; | |
760 | ||
761 | /* Check a correct image header exists */ | |
762 | err = check_image_header(); | |
763 | if (err) { | |
764 | printf("Error: Image header verification failed\n"); | |
765 | return err; | |
766 | } | |
767 | ||
658854a6 JJ |
768 | err = bubt_check_boot_mode(dst); |
769 | if (err) { | |
770 | printf("Error: Image boot mode verification failed\n"); | |
771 | return err; | |
772 | } | |
773 | ||
fa61ef6b KP |
774 | return 0; |
775 | } | |
776 | ||
777 | static int bubt_read_file(struct bubt_dev *src) | |
778 | { | |
779 | size_t image_size; | |
780 | ||
781 | if (!src->read) { | |
782 | printf("Error: Read not supported on device \"%s\"\n", | |
783 | src->name); | |
784 | return 0; | |
785 | } | |
786 | ||
787 | image_size = src->read(net_boot_file_name); | |
788 | if (image_size <= 0) { | |
789 | printf("Error: Failed to read file %s from %s\n", | |
790 | net_boot_file_name, src->name); | |
791 | return 0; | |
792 | } | |
793 | ||
794 | return image_size; | |
795 | } | |
796 | ||
797 | static int bubt_is_dev_active(struct bubt_dev *dev) | |
798 | { | |
799 | if (!dev->active) { | |
f41b85ee | 800 | printf("Device \"%s\" not supported by U-Boot image\n", |
fa61ef6b KP |
801 | dev->name); |
802 | return 0; | |
803 | } | |
804 | ||
805 | if (!dev->active()) { | |
806 | printf("Device \"%s\" is inactive\n", dev->name); | |
807 | return 0; | |
808 | } | |
809 | ||
810 | return 1; | |
811 | } | |
812 | ||
813 | struct bubt_dev *find_bubt_dev(char *dev_name) | |
814 | { | |
815 | int dev; | |
816 | ||
817 | for (dev = 0; dev < BUBT_MAX_DEV; dev++) { | |
818 | if (strcmp(bubt_devs[dev].name, dev_name) == 0) | |
819 | return &bubt_devs[dev]; | |
820 | } | |
821 | ||
822 | return 0; | |
823 | } | |
824 | ||
825 | #define DEFAULT_BUBT_SRC "tftp" | |
826 | ||
827 | #ifndef DEFAULT_BUBT_DST | |
828 | #ifdef CONFIG_MVEBU_SPI_BOOT | |
829 | #define DEFAULT_BUBT_DST "spi" | |
830 | #elif defined(CONFIG_MVEBU_NAND_BOOT) | |
831 | #define DEFAULT_BUBT_DST "nand" | |
832 | #elif defined(CONFIG_MVEBU_MMC_BOOT) | |
833 | #define DEFAULT_BUBT_DST "mmc" | |
9f27bcc3 | 834 | #else |
fa61ef6b KP |
835 | #define DEFAULT_BUBT_DST "error" |
836 | #endif | |
837 | #endif /* DEFAULT_BUBT_DST */ | |
838 | ||
09140113 | 839 | int do_bubt_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
fa61ef6b KP |
840 | { |
841 | struct bubt_dev *src, *dst; | |
842 | size_t image_size; | |
843 | char src_dev_name[8]; | |
844 | char dst_dev_name[8]; | |
845 | char *name; | |
846 | int err; | |
847 | ||
848 | if (argc < 2) | |
849 | copy_filename(net_boot_file_name, | |
850 | CONFIG_MVEBU_UBOOT_DFLT_NAME, | |
851 | sizeof(net_boot_file_name)); | |
852 | else | |
853 | copy_filename(net_boot_file_name, argv[1], | |
854 | sizeof(net_boot_file_name)); | |
855 | ||
856 | if (argc >= 3) { | |
857 | strncpy(dst_dev_name, argv[2], 8); | |
858 | } else { | |
859 | name = DEFAULT_BUBT_DST; | |
860 | strncpy(dst_dev_name, name, 8); | |
861 | } | |
862 | ||
863 | if (argc >= 4) | |
864 | strncpy(src_dev_name, argv[3], 8); | |
865 | else | |
866 | strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8); | |
867 | ||
868 | /* Figure out the destination device */ | |
869 | dst = find_bubt_dev(dst_dev_name); | |
870 | if (!dst) { | |
871 | printf("Error: Unknown destination \"%s\"\n", dst_dev_name); | |
09b0e20d | 872 | return 1; |
fa61ef6b KP |
873 | } |
874 | ||
875 | if (!bubt_is_dev_active(dst)) | |
09b0e20d | 876 | return 1; |
fa61ef6b KP |
877 | |
878 | /* Figure out the source device */ | |
879 | src = find_bubt_dev(src_dev_name); | |
880 | if (!src) { | |
881 | printf("Error: Unknown source \"%s\"\n", src_dev_name); | |
882 | return 1; | |
883 | } | |
884 | ||
885 | if (!bubt_is_dev_active(src)) | |
886 | return -ENODEV; | |
887 | ||
f41b85ee | 888 | printf("Burning U-Boot image \"%s\" from \"%s\" to \"%s\"\n", |
fa61ef6b KP |
889 | net_boot_file_name, src->name, dst->name); |
890 | ||
891 | image_size = bubt_read_file(src); | |
892 | if (!image_size) | |
09b0e20d | 893 | return 1; |
fa61ef6b | 894 | |
658854a6 | 895 | err = bubt_verify(dst); |
fa61ef6b | 896 | if (err) |
09b0e20d | 897 | return 1; |
fa61ef6b KP |
898 | |
899 | err = bubt_write_file(dst, image_size); | |
900 | if (err) | |
09b0e20d | 901 | return 1; |
fa61ef6b KP |
902 | |
903 | return 0; | |
904 | } | |
905 | ||
906 | U_BOOT_CMD( | |
907 | bubt, 4, 0, do_bubt_cmd, | |
908 | "Burn a u-boot image to flash", | |
909 | "[file-name] [destination [source]]\n" | |
32771530 T |
910 | "\t-file-name The image file name to burn. Default = " CONFIG_MVEBU_UBOOT_DFLT_NAME "\n" |
911 | "\t-destination Flash to burn to [spi, nand, mmc]. Default = " DEFAULT_BUBT_DST "\n" | |
912 | "\t-source The source to load image from [tftp, usb, mmc]. Default = " DEFAULT_BUBT_SRC "\n" | |
fa61ef6b KP |
913 | "Examples:\n" |
914 | "\tbubt - Burn flash-image.bin from tftp to active boot device\n" | |
915 | "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n" | |
916 | "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-image.bin from usb to MMC\n" | |
917 | ||
918 | ); |