30#define SWITCHTEC_LIB_CORE
32#include "switchtec_priv.h"
34#include "switchtec/errors.h"
35#include "switchtec/endian.h"
36#include "switchtec/utils.h"
37#include "switchtec/mfg.h"
66enum switchtec_fw_part_type_gen4 {
67 SWITCHTEC_FW_IMG_TYPE_MAP_GEN4 = 0x0,
68 SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4 = 0x1,
69 SWITCHTEC_FW_IMG_TYPE_BL2_GEN4 = 0x2,
70 SWITCHTEC_FW_IMG_TYPE_CFG_GEN4 = 0x3,
71 SWITCHTEC_FW_IMG_TYPE_IMG_GEN4 = 0x4,
72 SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4 = 0x5,
73 SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4 = 0xFE,
74 SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN4,
77enum switchtec_fw_part_type_gen5 {
78 SWITCHTEC_FW_IMG_TYPE_MAP_GEN5 = 0x0,
79 SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5 = 0x1,
80 SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5 = 0x2,
81 SWITCHTEC_FW_IMG_TYPE_BL2_GEN5 = 0x3,
82 SWITCHTEC_FW_IMG_TYPE_CFG_GEN5 = 0x4,
83 SWITCHTEC_FW_IMG_TYPE_IMG_GEN5 = 0x5,
84 SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5 = 0x6,
85 SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5 = 0xFE,
86 SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN5,
93 uint32_t secure_version;
95 uint32_t metadata_len;
108 uint8_t public_key_modulus[512];
109 uint8_t public_key_exponent[4];
113 uint8_t bist_gpio_pin_cfg;
114 uint8_t bist_gpio_level_cfg;
116 uint32_t xml_version;
117 uint32_t relocatable_img_len;
125 uint32_t hdr_version;
126 uint32_t secure_version;
128 uint32_t metadata_len;
141 uint8_t public_key_modulus[512];
142 uint8_t public_key_exponent[4];
146 uint8_t bist_gpio_pin_cfg;
147 uint8_t bist_gpio_level_cfg;
148 uint8_t rollback_enable;
150 uint32_t xml_version;
151 uint32_t relocatable_img_len;
167static uint32_t get_fw_tx_id(
struct switchtec_dev *dev)
170 return MRPC_FW_TX_GEN5;
177 enum mrpc_bg_status *bgstatus)
179 uint32_t cmd = MRPC_FWDNLD;
180 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
189 cmd = get_fw_tx_id(dev);
192 &result,
sizeof(result));
198 *status = result.dlstatus;
200 if (bgstatus != NULL)
201 *bgstatus = result.bgstatus;
206static int switchtec_fw_wait(
struct switchtec_dev *dev,
209 enum mrpc_bg_status bgstatus;
220 if (bgstatus == MRPC_BG_STAT_OFFSET)
221 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
223 if (bgstatus == MRPC_BG_STAT_ERROR) {
224 if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
225 *status != SWITCHTEC_DLSTAT_COMPLETES &&
226 *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
227 *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
230 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
233 }
while (bgstatus == MRPC_BG_STAT_INPROGRESS);
249 int toggle_bl2,
int toggle_key,
250 int toggle_fw,
int toggle_cfg)
262 cmd_id = get_fw_tx_id(dev);
263 cmd.subcmd = MRPC_FW_TX_TOGGLE;
265 cmd_id = MRPC_FWDNLD;
266 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
269 cmd.toggle_bl2 = !!toggle_bl2;
270 cmd.toggle_key = !!toggle_key;
271 cmd.toggle_fw = !!toggle_fw;
272 cmd.toggle_cfg = !!toggle_cfg;
281 uint8_t dont_activate;
287 uint8_t data[MRPC_MAX_DATA_LEN -
sizeof(
struct cmd_fwdl_hdr)];
302 int dont_activate,
int force,
303 void (*progress_callback)(
int cur,
int tot))
306 enum mrpc_bg_status bgstatus;
307 ssize_t image_size, offset = 0;
310 uint32_t cmd_id = MRPC_FWDNLD;
313 cmd_id = get_fw_tx_id(dev);
315 image_size = lseek(img_fd, 0, SEEK_END);
318 lseek(img_fd, 0, SEEK_SET);
322 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
327 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
333 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
335 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
337 cmd.hdr.dont_activate = !!dont_activate;
338 cmd.hdr.img_length = htole32(image_size);
340 while (offset < image_size) {
341 ssize_t blklen = read(img_fd, &cmd.data,
344 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
353 cmd.hdr.offset = htole32(offset);
354 cmd.hdr.blk_length = htole32(blklen);
362 ret = switchtec_fw_wait(dev, &status);
366 offset += le32toh(cmd.hdr.blk_length);
368 if (progress_callback)
369 progress_callback(offset, image_size);
373 if (status == SWITCHTEC_DLSTAT_COMPLETES)
376 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
379 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
383 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
395 uint8_t major = (version >> 24) & 0xff;
399 case 2:
return SWITCHTEC_GEN3;
402 case 5:
return SWITCHTEC_GEN4;
405 case 8:
return SWITCHTEC_GEN5;
406 default:
return SWITCHTEC_GEN_UNKNOWN;
422 int dont_activate,
int force,
423 void (*progress_callback)(
int cur,
int tot))
426 enum mrpc_bg_status bgstatus;
427 ssize_t image_size, offset = 0;
430 uint32_t cmd_id = MRPC_FWDNLD;
433 cmd_id = get_fw_tx_id(dev);
435 ret = fseek(fimg, 0, SEEK_END);
438 image_size = ftell(fimg);
441 ret = fseek(fimg, 0, SEEK_SET);
447 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
452 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
458 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
460 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
462 cmd.hdr.dont_activate = !!dont_activate;
463 cmd.hdr.img_length = htole32(image_size);
465 while (offset < image_size) {
466 ssize_t blklen = fread(&cmd.data, 1,
sizeof(cmd.data), fimg);
475 cmd.hdr.offset = htole32(offset);
476 cmd.hdr.blk_length = htole32(blklen);
484 ret = switchtec_fw_wait(dev, &status);
488 offset += le32toh(cmd.hdr.blk_length);
490 if (progress_callback)
491 progress_callback(offset, image_size);
494 if (status == SWITCHTEC_DLSTAT_COMPLETES)
497 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
500 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
504 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
527 case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
528 msg =
"Header incorrect";
break;
529 case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
530 msg =
"Offset incorrect";
break;
531 case SWITCHTEC_DLSTAT_CRC_INCORRECT:
532 msg =
"CRC incorrect";
break;
533 case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
534 msg =
"Length incorrect";
break;
535 case SWITCHTEC_DLSTAT_HARDWARE_ERR:
536 msg =
"Hardware Error";
break;
537 case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
538 msg =
"Package length less than 32 bytes";
break;
539 case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
540 msg =
"Signature memory allocation failed";
break;
541 case SWITCHTEC_DLSTAT_SEEPROM:
542 msg =
"SEEPROM download failed";
break;
543 case SWITCHTEC_DLSTAT_READONLY_PARTITION:
544 msg =
"Programming a read-only partition";
break;
545 case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
546 msg =
"Download Timeout";
break;
547 case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
548 msg =
"SEEPROM or related TWI bus isn't enabled";
break;
549 case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
550 msg =
"Programming a running partition";
break;
551 case SWITCHTEC_DLSTAT_NOT_ALLOWED:
552 msg =
"Programming not allowed over this interface";
break;
553 case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
554 msg =
"Activation failed due to XML version mismatch";
break;
555 case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
556 msg =
"Activation failed due to unknown error";
break;
557 case SWITCHTEC_DLSTAT_ERROR_OFFSET:
558 msg =
"Data offset error during programming";
break;
559 case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
560 msg =
"Failed to program to flash";
break;
562 case SWITCHTEC_DLSTAT_NO_FILE:
563 msg =
"No Image Transferred";
break;
565 fprintf(stderr,
"%s: Unknown Error (0x%x)\n", s, ret);
569 fprintf(stderr,
"%s: %s\n", s, msg);
572static enum switchtec_fw_type
575 switch ((
unsigned long)info->
part_id) {
576 case SWITCHTEC_FW_PART_ID_G3_BOOT:
return SWITCHTEC_FW_TYPE_BOOT;
577 case SWITCHTEC_FW_PART_ID_G3_MAP0:
return SWITCHTEC_FW_TYPE_MAP;
578 case SWITCHTEC_FW_PART_ID_G3_MAP1:
return SWITCHTEC_FW_TYPE_MAP;
579 case SWITCHTEC_FW_PART_ID_G3_IMG0:
return SWITCHTEC_FW_TYPE_IMG;
580 case SWITCHTEC_FW_PART_ID_G3_IMG1:
return SWITCHTEC_FW_TYPE_IMG;
581 case SWITCHTEC_FW_PART_ID_G3_DAT0:
return SWITCHTEC_FW_TYPE_CFG;
582 case SWITCHTEC_FW_PART_ID_G3_DAT1:
return SWITCHTEC_FW_TYPE_CFG;
583 case SWITCHTEC_FW_PART_ID_G3_NVLOG:
return SWITCHTEC_FW_TYPE_NVLOG;
584 case SWITCHTEC_FW_PART_ID_G3_SEEPROM:
return SWITCHTEC_FW_TYPE_SEEPROM;
587 case 0xa8000000:
return SWITCHTEC_FW_TYPE_BOOT;
588 case 0xa8020000:
return SWITCHTEC_FW_TYPE_MAP;
589 case 0xa8060000:
return SWITCHTEC_FW_TYPE_IMG;
590 case 0xa8210000:
return SWITCHTEC_FW_TYPE_CFG;
592 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
596static enum switchtec_fw_type
600 case SWITCHTEC_FW_PART_ID_G4_MAP0:
return SWITCHTEC_FW_TYPE_MAP;
601 case SWITCHTEC_FW_PART_ID_G4_MAP1:
return SWITCHTEC_FW_TYPE_MAP;
602 case SWITCHTEC_FW_PART_ID_G4_KEY0:
return SWITCHTEC_FW_TYPE_KEY;
603 case SWITCHTEC_FW_PART_ID_G4_KEY1:
return SWITCHTEC_FW_TYPE_KEY;
604 case SWITCHTEC_FW_PART_ID_G4_BL20:
return SWITCHTEC_FW_TYPE_BL2;
605 case SWITCHTEC_FW_PART_ID_G4_BL21:
return SWITCHTEC_FW_TYPE_BL2;
606 case SWITCHTEC_FW_PART_ID_G4_CFG0:
return SWITCHTEC_FW_TYPE_CFG;
607 case SWITCHTEC_FW_PART_ID_G4_CFG1:
return SWITCHTEC_FW_TYPE_CFG;
608 case SWITCHTEC_FW_PART_ID_G4_IMG0:
return SWITCHTEC_FW_TYPE_IMG;
609 case SWITCHTEC_FW_PART_ID_G4_IMG1:
return SWITCHTEC_FW_TYPE_IMG;
610 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
return SWITCHTEC_FW_TYPE_NVLOG;
611 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
return SWITCHTEC_FW_TYPE_SEEPROM;
612 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
616static enum switchtec_fw_type
620 case SWITCHTEC_FW_PART_ID_G5_MAP0:
return SWITCHTEC_FW_TYPE_MAP;
621 case SWITCHTEC_FW_PART_ID_G5_MAP1:
return SWITCHTEC_FW_TYPE_MAP;
622 case SWITCHTEC_FW_PART_ID_G5_KEY0:
return SWITCHTEC_FW_TYPE_KEY;
623 case SWITCHTEC_FW_PART_ID_G5_KEY1:
return SWITCHTEC_FW_TYPE_KEY;
624 case SWITCHTEC_FW_PART_ID_G5_RIOT0:
return SWITCHTEC_FW_TYPE_RIOT;
625 case SWITCHTEC_FW_PART_ID_G5_RIOT1:
return SWITCHTEC_FW_TYPE_RIOT;
626 case SWITCHTEC_FW_PART_ID_G5_BL20:
return SWITCHTEC_FW_TYPE_BL2;
627 case SWITCHTEC_FW_PART_ID_G5_BL21:
return SWITCHTEC_FW_TYPE_BL2;
628 case SWITCHTEC_FW_PART_ID_G5_CFG0:
return SWITCHTEC_FW_TYPE_CFG;
629 case SWITCHTEC_FW_PART_ID_G5_CFG1:
return SWITCHTEC_FW_TYPE_CFG;
630 case SWITCHTEC_FW_PART_ID_G5_IMG0:
return SWITCHTEC_FW_TYPE_IMG;
631 case SWITCHTEC_FW_PART_ID_G5_IMG1:
return SWITCHTEC_FW_TYPE_IMG;
632 case SWITCHTEC_FW_PART_ID_G5_NVLOG:
return SWITCHTEC_FW_TYPE_NVLOG;
633 case SWITCHTEC_FW_PART_ID_G5_SEEPROM:
return SWITCHTEC_FW_TYPE_SEEPROM;
634 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
638static enum switchtec_fw_type
642 case SWITCHTEC_GEN3:
return switchtec_fw_id_to_type_gen3(info);
643 case SWITCHTEC_GEN4:
return switchtec_fw_id_to_type_gen4(info);
644 case SWITCHTEC_GEN5:
return switchtec_fw_id_to_type_gen5(info);
645 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
649static int switchtec_fw_file_info_gen3(
int fd,
655 ret = read(fd, &hdr,
sizeof(hdr));
656 lseek(fd, 0, SEEK_SET);
658 if (ret !=
sizeof(hdr))
661 if (strcmp(hdr.magic,
"PMC") != 0)
667 info->
gen = SWITCHTEC_GEN3;
669 info->
image_crc = le32toh(hdr.image_crc);
670 version_to_string(hdr.version, info->
version,
sizeof(info->
version));
671 info->
image_len = le32toh(hdr.image_len);
673 info->
type = switchtec_fw_id_to_type(info);
675 info->secure_version = 0;
676 info->signed_image = 0;
685static enum switchtec_fw_image_part_id_gen4 hdr_type2_id_gen4(uint32_t type)
688 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
689 return SWITCHTEC_FW_PART_ID_G4_MAP0;
691 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
692 return SWITCHTEC_FW_PART_ID_G4_KEY0;
694 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
695 return SWITCHTEC_FW_PART_ID_G4_BL20;
697 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
698 return SWITCHTEC_FW_PART_ID_G4_CFG0;
700 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
701 return SWITCHTEC_FW_PART_ID_G4_IMG0;
703 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
704 return SWITCHTEC_FW_PART_ID_G4_NVLOG;
706 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
707 return SWITCHTEC_FW_PART_ID_G4_SEEPROM;
714static enum switchtec_fw_image_part_id_gen5 hdr_type2_id_gen5(uint32_t type)
717 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN5:
718 return SWITCHTEC_FW_PART_ID_G5_MAP0;
720 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5:
721 return SWITCHTEC_FW_PART_ID_G5_KEY0;
723 case SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5:
724 return SWITCHTEC_FW_PART_ID_G5_RIOT0;
726 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN5:
727 return SWITCHTEC_FW_PART_ID_G5_BL20;
729 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN5:
730 return SWITCHTEC_FW_PART_ID_G5_CFG0;
732 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN5:
733 return SWITCHTEC_FW_PART_ID_G5_IMG0;
735 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5:
736 return SWITCHTEC_FW_PART_ID_G5_NVLOG;
738 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5:
739 return SWITCHTEC_FW_PART_ID_G5_SEEPROM;
746static int switchtec_fw_file_info_gen45(
int fd,
751 uint8_t exp_zero[4] = {};
755 ret = read(fd, &hdr,
sizeof(hdr));
756 lseek(fd, 0, SEEK_SET);
758 if (ret !=
sizeof(hdr))
761 if (strncmp(hdr.magic,
"MSCC",
sizeof(hdr.magic)))
764 if (strncmp(hdr.sub_magic,
"_MD ",
sizeof(hdr.sub_magic)))
772 part_id = hdr_type2_id_gen5(le32toh(hdr.type));
774 part_id = hdr_type2_id_gen4(le32toh(hdr.type));
781 info->
image_crc = le32toh(hdr.image_crc);
782 version = le32toh(hdr.version);
784 info->
image_len = le32toh(hdr.image_len);
787 info->
type = switchtec_fw_id_to_type(info);
789 info->secure_version = le32toh(hdr.secure_version);
790 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
810 ret = read(fd, &magic,
sizeof(magic));
811 lseek(fd, 0, SEEK_SET);
813 if (ret !=
sizeof(magic)) {
818 if (!strncmp(magic,
"PMC",
sizeof(magic))) {
819 return switchtec_fw_file_info_gen3(fd, info);
820 }
else if (!strncmp(magic,
"MSCC",
sizeof(magic))) {
821 return switchtec_fw_file_info_gen45(fd, info);
852 if (!info.signed_image)
857 sn_info.ver_bl2 = 0xffffffff;
858 sn_info.ver_main = 0xffffffff;
859 sn_info.ver_km = 0xffffffff;
863 case SWITCHTEC_FW_TYPE_BL2:
864 if (info.secure_version > sn_info.ver_bl2)
868 case SWITCHTEC_FW_TYPE_IMG:
869 if (info.secure_version > sn_info.ver_main)
873 case SWITCHTEC_FW_TYPE_KEY:
874 if (info.secure_version > sn_info.ver_km)
892 switch (info->
type) {
893 case SWITCHTEC_FW_TYPE_BOOT:
return "BOOT";
894 case SWITCHTEC_FW_TYPE_MAP:
return "MAP";
895 case SWITCHTEC_FW_TYPE_IMG:
return "IMG";
896 case SWITCHTEC_FW_TYPE_CFG:
return "CFG";
897 case SWITCHTEC_FW_TYPE_KEY:
return "KEY";
898 case SWITCHTEC_FW_TYPE_RIOT:
return "RIOT";
899 case SWITCHTEC_FW_TYPE_BL2:
return "BL2";
900 case SWITCHTEC_FW_TYPE_NVLOG:
return "NVLOG";
901 case SWITCHTEC_FW_TYPE_SEEPROM:
return "SEEPROM";
902 default:
return "UNKNOWN";
906static int switchtec_fw_map_get_active(
struct switchtec_dev *dev,
909 uint32_t map0_update_index;
910 uint32_t map1_update_index;
914 sizeof(uint32_t), &map0_update_index);
919 sizeof(uint32_t), &map1_update_index);
924 if (map0_update_index > map1_update_index) {
925 if (info->
part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
928 if (info->
part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
935static int switchtec_fw_info_metadata_gen3(
struct switchtec_dev *dev,
942 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
945 metadata = malloc(
sizeof(*metadata));
955 if (strncmp(metadata->magic,
"PMC",
sizeof(metadata->magic)))
958 version_to_string(metadata->version, inf->
version,
963 inf->metadata = metadata;
972static int switchtec_fw_part_info_gen3(
struct switchtec_dev *dev,
980 case SWITCHTEC_FW_PART_ID_G3_BOOT:
981 inf->
part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
982 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
985 case SWITCHTEC_FW_PART_ID_G3_MAP0:
986 inf->
part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
987 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
988 ret = switchtec_fw_map_get_active(dev, inf);
990 case SWITCHTEC_FW_PART_ID_G3_MAP1:
991 inf->
part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
992 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
993 ret = switchtec_fw_map_get_active(dev, inf);
997 inf->read_only =
false;
1005 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1008 return switchtec_fw_info_metadata_gen3(dev, inf);
1011static int switchtec_fw_info_metadata_gen4(
struct switchtec_dev *dev,
1019 .subcmd = MRPC_PART_INFO_GET_METADATA,
1024 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
1026 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
1027 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1029 metadata = malloc(
sizeof(*metadata));
1033 ret =
switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
sizeof(subcmd),
1034 metadata,
sizeof(*metadata));
1038 if (strncmp(metadata->magic,
"MSCC",
sizeof(metadata->magic)))
1041 if (strncmp(metadata->sub_magic,
"_MD ",
sizeof(metadata->sub_magic)))
1044 version_to_string(le32toh(metadata->version), inf->
version,
1047 inf->
image_crc = le32toh(metadata->image_crc);
1048 inf->
image_len = le32toh(metadata->image_len);
1049 inf->metadata = metadata;
1058static int switchtec_fw_info_metadata_gen5(
struct switchtec_dev *dev,
1066 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN5,
1071 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G5_NVLOG)
1073 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G5_SEEPROM)
1074 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1076 metadata = malloc(
sizeof(*metadata));
1080 ret =
switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
sizeof(subcmd),
1081 metadata,
sizeof(*metadata));
1085 if (strncmp(metadata->magic,
"MSCC",
sizeof(metadata->magic)))
1088 if (strncmp(metadata->sub_magic,
"_MD ",
sizeof(metadata->sub_magic)))
1091 version_to_string(le32toh(metadata->version), inf->
version,
1094 inf->
image_crc = le32toh(metadata->image_crc);
1095 inf->
image_len = le32toh(metadata->image_len);
1096 inf->metadata = metadata;
1106 uint32_t firmware_version;
1107 uint32_t flash_size;
1111 uint8_t running_bl2_flag;
1112 uint8_t running_cfg_flag;
1113 uint8_t running_img_flag;
1114 uint8_t running_key_flag;
1119 uint16_t image_version;
1122 uint32_t part_start;
1124 uint32_t part_offset;
1125 uint32_t part_size_dw;
1129 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1130 img0, img1, nvlog, vendor[8];
1134 uint32_t firmware_version;
1135 uint32_t flash_size;
1139 uint8_t running_riot_flag;
1140 uint8_t running_bl2_flag;
1141 uint8_t running_cfg_flag;
1142 uint8_t running_img_flag;
1143 uint8_t running_key_flag;
1145 uint8_t key_redundant_flag;
1146 uint8_t riot_redundant_flag;
1147 uint8_t bl2_redundant_flag;
1148 uint8_t cfg_redundant_flag;
1149 uint8_t img_redundant_flag;
1152 struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1,
1153 riot0, riot1, bl20, bl21,
1154 cfg0, cfg1, img0, img1, nvlog,
1158static int switchtec_fw_part_info_gen4(
struct switchtec_dev *dev,
1162 struct switchtec_flash_part_info_gen4 *part_info;
1166 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1167 part_info = &all->map0;
1169 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1170 part_info = &all->map1;
1172 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1173 part_info = &all->keyman0;
1175 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1176 part_info = &all->keyman1;
1178 case SWITCHTEC_FW_PART_ID_G4_BL20:
1179 part_info = &all->bl20;
1181 case SWITCHTEC_FW_PART_ID_G4_BL21:
1182 part_info = &all->bl21;
1184 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1185 part_info = &all->img0;
1187 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1188 part_info = &all->img1;
1190 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1191 part_info = &all->cfg0;
1193 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1194 part_info = &all->cfg1;
1196 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1197 part_info = &all->nvlog;
1199 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1207 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1209 inf->running =
true;
1219 inf->
part_addr = le32toh(part_info->part_start);
1220 inf->
part_len = le32toh(part_info->part_size_dw) * 4;
1221 inf->active = part_info->active;
1222 inf->running = part_info->is_using;
1223 inf->read_only = part_info->read_only;
1224 inf->valid = part_info->valid;
1228 return switchtec_fw_info_metadata_gen4(dev, inf);
1231static int switchtec_fw_part_info_gen5(
struct switchtec_dev *dev,
1235 struct switchtec_flash_part_info_gen4 *part_info;
1239 case SWITCHTEC_FW_PART_ID_G5_MAP0:
1240 part_info = &all->map0;
1242 case SWITCHTEC_FW_PART_ID_G5_MAP1:
1243 part_info = &all->map1;
1245 case SWITCHTEC_FW_PART_ID_G5_RIOT0:
1246 part_info = &all->riot0;
1248 case SWITCHTEC_FW_PART_ID_G5_RIOT1:
1249 part_info = &all->riot1;
1251 case SWITCHTEC_FW_PART_ID_G5_KEY0:
1252 part_info = &all->keyman0;
1254 case SWITCHTEC_FW_PART_ID_G5_KEY1:
1255 part_info = &all->keyman1;
1257 case SWITCHTEC_FW_PART_ID_G5_BL20:
1258 part_info = &all->bl20;
1260 case SWITCHTEC_FW_PART_ID_G5_BL21:
1261 part_info = &all->bl21;
1263 case SWITCHTEC_FW_PART_ID_G5_IMG0:
1264 part_info = &all->img0;
1266 case SWITCHTEC_FW_PART_ID_G5_IMG1:
1267 part_info = &all->img1;
1269 case SWITCHTEC_FW_PART_ID_G5_CFG0:
1270 part_info = &all->cfg0;
1272 case SWITCHTEC_FW_PART_ID_G5_CFG1:
1273 part_info = &all->cfg1;
1275 case SWITCHTEC_FW_PART_ID_G5_NVLOG:
1276 part_info = &all->nvlog;
1278 case SWITCHTEC_FW_PART_ID_G5_SEEPROM:
1283 ret = switchtec_fw_info_metadata_gen5(dev, inf);
1285 inf->running =
true;
1295 inf->
part_addr = le32toh(part_info->part_start);
1296 inf->
part_len = le32toh(part_info->part_size_dw) * 4;
1297 inf->active = part_info->active;
1298 inf->running = part_info->is_using;
1299 inf->read_only = part_info->read_only;
1300 inf->valid = part_info->valid;
1304 return switchtec_fw_info_metadata_gen5(dev, inf);
1321 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1325 if (info == NULL || nr_info == 0)
1328 if (dev->gen == SWITCHTEC_GEN4) {
1330 sizeof(subcmd), &all_info_gen4,
1331 sizeof(all_info_gen4));
1334 all_info_gen4.firmware_version =
1335 le32toh(all_info_gen4.firmware_version);
1336 all_info_gen4.flash_size = le32toh(all_info_gen4.flash_size);
1337 all_info_gen4.device_id = le16toh(all_info_gen4.device_id);
1338 }
else if (dev->gen == SWITCHTEC_GEN5) {
1339 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1341 sizeof(subcmd), &all_info_gen5,
1342 sizeof(all_info_gen5));
1345 all_info_gen5.firmware_version =
1346 le32toh(all_info_gen5.firmware_version);
1347 all_info_gen5.flash_size = le32toh(all_info_gen5.flash_size);
1348 all_info_gen5.device_id = le16toh(all_info_gen5.device_id);
1351 for (i = 0; i < nr_info; i++) {
1355 inf->
gen = dev->gen;
1356 inf->
type = switchtec_fw_id_to_type(inf);
1357 inf->active =
false;
1358 inf->running =
false;
1361 switch (info->
gen) {
1362 case SWITCHTEC_GEN3:
1363 ret = switchtec_fw_part_info_gen3(dev, inf);
1365 case SWITCHTEC_GEN4:
1366 ret = switchtec_fw_part_info_gen4(dev, inf,
1369 case SWITCHTEC_GEN5:
1370 ret = switchtec_fw_part_info_gen5(dev, inf,
1384 inf->metadata = NULL;
1391int switchtec_get_device_id_bl2(
struct switchtec_dev *dev,
1392 unsigned short *device_id)
1395 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1399 if (dev->gen != SWITCHTEC_GEN_UNKNOWN)
1403 sizeof(subcmd), &all_info,
1406 *device_id = le16toh(all_info.device_id);
1407 }
else if (ret == ERR_SUBCMD_INVALID) {
1408 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1410 sizeof(subcmd), &all_info_gen5,
1411 sizeof(all_info_gen5));
1413 *device_id = le16toh(all_info_gen5.device_id);
1419static long multicfg_subcmd(
struct switchtec_dev *dev, uint32_t subcmd,
1425 subcmd |= index << 8;
1426 subcmd = htole32(subcmd);
1428 ret =
switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd,
sizeof(subcmd),
1429 &result,
sizeof(result));
1436static int get_multicfg(
struct switchtec_dev *dev,
1443 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1452 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1459 for (i = 0; i < *nr_mult; i++) {
1460 info[i].
part_addr = multicfg_subcmd(dev,
1461 MRPC_MULTI_CFG_START_ADDR,
1463 info[i].
part_len = multicfg_subcmd(dev,
1464 MRPC_MULTI_CFG_LENGTH, i);
1465 strcpy(info[i].version,
"");
1470 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1475 info[ret].active = 1;
1480static const enum switchtec_fw_image_part_id_gen3
1481switchtec_fw_partitions_gen3[] = {
1482 SWITCHTEC_FW_PART_ID_G3_BOOT,
1483 SWITCHTEC_FW_PART_ID_G3_MAP0,
1484 SWITCHTEC_FW_PART_ID_G3_MAP1,
1485 SWITCHTEC_FW_PART_ID_G3_IMG0,
1486 SWITCHTEC_FW_PART_ID_G3_DAT0,
1487 SWITCHTEC_FW_PART_ID_G3_DAT1,
1488 SWITCHTEC_FW_PART_ID_G3_NVLOG,
1489 SWITCHTEC_FW_PART_ID_G3_IMG1,
1492static const enum switchtec_fw_image_part_id_gen4
1493switchtec_fw_partitions_gen4[] = {
1494 SWITCHTEC_FW_PART_ID_G4_MAP0,
1495 SWITCHTEC_FW_PART_ID_G4_MAP1,
1496 SWITCHTEC_FW_PART_ID_G4_KEY0,
1497 SWITCHTEC_FW_PART_ID_G4_KEY1,
1498 SWITCHTEC_FW_PART_ID_G4_BL20,
1499 SWITCHTEC_FW_PART_ID_G4_BL21,
1500 SWITCHTEC_FW_PART_ID_G4_CFG0,
1501 SWITCHTEC_FW_PART_ID_G4_CFG1,
1502 SWITCHTEC_FW_PART_ID_G4_IMG0,
1503 SWITCHTEC_FW_PART_ID_G4_IMG1,
1504 SWITCHTEC_FW_PART_ID_G4_NVLOG,
1505 SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1508static const enum switchtec_fw_image_part_id_gen5
1509switchtec_fw_partitions_gen5[] = {
1510 SWITCHTEC_FW_PART_ID_G5_MAP0,
1511 SWITCHTEC_FW_PART_ID_G5_MAP1,
1512 SWITCHTEC_FW_PART_ID_G5_KEY0,
1513 SWITCHTEC_FW_PART_ID_G5_KEY1,
1514 SWITCHTEC_FW_PART_ID_G5_RIOT0,
1515 SWITCHTEC_FW_PART_ID_G5_RIOT1,
1516 SWITCHTEC_FW_PART_ID_G5_BL20,
1517 SWITCHTEC_FW_PART_ID_G5_BL21,
1518 SWITCHTEC_FW_PART_ID_G5_CFG0,
1519 SWITCHTEC_FW_PART_ID_G5_CFG1,
1520 SWITCHTEC_FW_PART_ID_G5_IMG0,
1521 SWITCHTEC_FW_PART_ID_G5_IMG1,
1522 SWITCHTEC_FW_PART_ID_G5_NVLOG,
1523 SWITCHTEC_FW_PART_ID_G5_SEEPROM,
1526static struct switchtec_fw_part_type *
1530 switch (info->
type) {
1531 case SWITCHTEC_FW_TYPE_BOOT:
return &summary->boot;
1532 case SWITCHTEC_FW_TYPE_MAP:
return &summary->map;
1533 case SWITCHTEC_FW_TYPE_IMG:
return &summary->img;
1534 case SWITCHTEC_FW_TYPE_CFG:
return &summary->cfg;
1535 case SWITCHTEC_FW_TYPE_NVLOG:
return &summary->nvlog;
1536 case SWITCHTEC_FW_TYPE_SEEPROM:
return &summary->seeprom;
1537 case SWITCHTEC_FW_TYPE_KEY:
return &summary->key;
1538 case SWITCHTEC_FW_TYPE_BL2:
return &summary->bl2;
1539 case SWITCHTEC_FW_TYPE_RIOT:
return &summary->riot;
1540 default:
return NULL;
1557 struct switchtec_fw_part_type *type;
1558 int nr_info, nr_mcfg = 16;
1563 case SWITCHTEC_GEN3:
1564 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1566 case SWITCHTEC_GEN4:
1567 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1569 case SWITCHTEC_GEN5:
1570 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen5);
1577 st_sz =
sizeof(*summary) +
sizeof(*summary->all) * (nr_info + nr_mcfg);
1579 summary = malloc(st_sz);
1583 memset(summary, 0, st_sz);
1584 summary->nr_info = nr_info;
1587 case SWITCHTEC_GEN3:
1588 for (i = 0; i < nr_info; i++)
1590 switchtec_fw_partitions_gen3[i];
1592 case SWITCHTEC_GEN4:
1593 for (i = 0; i < nr_info; i++)
1595 switchtec_fw_partitions_gen4[i];
1597 case SWITCHTEC_GEN5:
1598 for (i = 0; i < nr_info; i++)
1600 switchtec_fw_partitions_gen5[i];
1608 if (ret != nr_info) {
1613 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1619 for (i = 0; i < nr_info; i++) {
1620 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1625 if (summary->all[i].active)
1626 type->active = &summary->all[i];
1628 type->inactive = &summary->all[i];
1631 infp = &summary->mult_cfg;
1632 for (; i < nr_info + nr_mcfg; i++) {
1633 *infp = &summary->all[i];
1634 infp = &summary->all[i].next;
1648 for (i = 0; i < summary->nr_info; i++)
1649 free(summary->all[i].metadata);
1663 size_t len,
void *buf)
1670 unsigned char *cbuf = buf;
1674 size_t chunk_len = len;
1675 if (chunk_len > MRPC_MAX_DATA_LEN-8)
1676 chunk_len = MRPC_MAX_DATA_LEN-8;
1678 cmd.addr = htole32(addr);
1679 cmd.length = htole32(chunk_len);
1707 unsigned long addr,
size_t len,
1708 void (*progress_callback)(
int cur,
int tot))
1711 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1713 size_t total_len = len;
1718 size_t chunk_len = len;
1719 if (chunk_len >
sizeof(buf))
1720 chunk_len =
sizeof(buf);
1727 while (total_wrote < ret) {
1728 wrote = write(fd, &buf[total_wrote],
1732 total_wrote += wrote;
1739 if (progress_callback)
1740 progress_callback(read, total_len);
1757 void (*progress_callback)(
int cur,
int tot))
1764static int switchtec_fw_img_write_hdr_gen3(
int fd,
1770 memcpy(hdr.magic, ftr->magic,
sizeof(hdr.magic));
1771 hdr.image_len = ftr->image_len;
1773 hdr.load_addr = ftr->load_addr;
1774 hdr.version = ftr->version;
1775 hdr.header_crc = ftr->header_crc;
1776 hdr.image_crc = ftr->image_crc;
1778 if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1779 hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1780 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1781 hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1782 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1783 hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1785 return write(fd, &hdr,
sizeof(hdr));
1788static int switchtec_fw_img_write_hdr_gen4(
int fd,
1794 ret = write(fd, hdr,
sizeof(*hdr));
1816 switch (info->
gen) {
1817 case SWITCHTEC_GEN3:
return switchtec_fw_img_write_hdr_gen3(fd, info);
1818 case SWITCHTEC_GEN4:
1819 case SWITCHTEC_GEN5:
return switchtec_fw_img_write_hdr_gen4(fd, info);
1842 .subcmd = MRPC_FWDNLD_BOOT_RO,
1848 uint8_t reserved[3];
1858 ret =
switchtec_cmd(dev, MRPC_FWDNLD, &subcmd,
sizeof(subcmd),
1859 &result,
sizeof(result));
1861 if (ret == ERR_SUBCMD_INVALID) {
1869 return result.status;
1882 .subcmd = MRPC_FWDNLD_BOOT_RO,
1892 return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd,
sizeof(subcmd),
int switchtec_cmd(struct switchtec_dev *dev, uint32_t cmd, const void *payload, size_t payload_len, void *resp, size_t resp_len)
Execute an MRPC command.
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
int switchtec_fw_img_write_hdr(int fd, struct switchtec_fw_image_info *info)
Write the header for a Switchtec firmware image file.
int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr, size_t len, void *buf)
Read a Switchtec device's flash data.
int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd, struct switchtec_fw_image_info *info, void(*progress_callback)(int cur, int tot))
Read a Switchtec device's flash image body into a file.
int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev, int img_fd)
Check if the secure version of an image file is newer than that of the image on device.
int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev, int toggle_bl2, int toggle_key, int toggle_fw, int toggle_cfg)
Toggle the active firmware partition for the main or configuration images.
int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd, unsigned long addr, size_t len, void(*progress_callback)(int cur, int tot))
Read a Switchtec device's flash data into a file.
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd, int dont_activate, int force, void(*progress_callback)(int cur, int tot))
Write a firmware file to the switchtec device.
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info, struct switchtec_fw_image_info *info)
Return firmware information structures for a number of firmware partitions.
int switchtec_fw_set_boot_ro(struct switchtec_dev *dev, enum switchtec_fw_ro ro)
Set or clear a boot partition's read-only flag.
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
const char * switchtec_fw_image_type(const struct switchtec_fw_image_info *info)
Return a string describing the type of a firmware image.
int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg, int dont_activate, int force, void(*progress_callback)(int cur, int tot))
Write a firmware file to the switchtec device.
struct switchtec_fw_part_summary * switchtec_fw_part_summary(struct switchtec_dev *dev)
Return firmware summary information structure for the flash partitfons in the device.
int switchtec_flash_part(struct switchtec_dev *dev, struct switchtec_fw_image_info *info, enum switchtec_fw_image_part_id_gen3 part)
Retrieve information about a flash partition.
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Information about a firmware image or partition.
enum switchtec_gen gen
Image generation.
size_t part_body_offset
Partition image body offset.
unsigned long image_crc
CRC checksum of the image.
char version[32]
Firmware/Config version.
size_t image_len
Length of the image.
unsigned long part_id
Image partition ID.
size_t part_addr
Address of the partition.
size_t part_len
Length of the partition.
enum switchtec_fw_type type
Image partition type.
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
switchtec_gen
The PCIe generations.
switchtec_boot_phase
Device boot phase.
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
switchtec_fw_dlstatus
Firmware update status.
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.