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