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