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,
81 uint32_t secure_version;
83 uint32_t metadata_len;
95 uint8_t public_key_modulus[512];
96 uint8_t public_key_exponent[4];
100 uint8_t bist_gpio_pin_cfg;
101 uint8_t bist_gpio_level_cfg;
103 uint32_t xml_version;
104 uint32_t relocatable_img_len;
122 enum mrpc_bg_status *bgstatus)
124 uint32_t cmd = MRPC_FWDNLD;
125 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
137 &result,
sizeof(result));
143 *status = result.dlstatus;
145 if (bgstatus != NULL)
146 *bgstatus = result.bgstatus;
151static int switchtec_fw_wait(
struct switchtec_dev *dev,
154 enum mrpc_bg_status bgstatus;
165 if (bgstatus == MRPC_BG_STAT_OFFSET)
166 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
168 if (bgstatus == MRPC_BG_STAT_ERROR) {
169 if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
170 *status != SWITCHTEC_DLSTAT_COMPLETES &&
171 *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
172 *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
175 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
178 }
while (bgstatus == MRPC_BG_STAT_INPROGRESS);
194 int toggle_bl2,
int toggle_key,
195 int toggle_fw,
int toggle_cfg)
208 cmd.subcmd = MRPC_FW_TX_TOGGLE;
210 cmd_id = MRPC_FWDNLD;
211 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
214 cmd.toggle_bl2 = !!toggle_bl2;
215 cmd.toggle_key = !!toggle_key;
216 cmd.toggle_fw = !!toggle_fw;
217 cmd.toggle_cfg = !!toggle_cfg;
223static enum switchtec_fw_part_type_gen4
224switchtec_fw_type_gen4(
enum switchtec_fw_type type)
227 case SWITCHTEC_FW_TYPE_MAP:
228 return SWITCHTEC_FW_IMG_TYPE_MAP_GEN4;
229 case SWITCHTEC_FW_TYPE_IMG:
230 return SWITCHTEC_FW_IMG_TYPE_IMG_GEN4;
231 case SWITCHTEC_FW_TYPE_CFG:
232 return SWITCHTEC_FW_IMG_TYPE_CFG_GEN4;
233 case SWITCHTEC_FW_TYPE_NVLOG:
234 return SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4;
235 case SWITCHTEC_FW_TYPE_SEEPROM:
236 return SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4;
237 case SWITCHTEC_FW_TYPE_KEY:
238 return SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4;
239 case SWITCHTEC_FW_TYPE_BL2:
240 return SWITCHTEC_FW_IMG_TYPE_BL2_GEN4;
242 return SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN4;
256 enum switchtec_fw_redundancy redund,
257 enum switchtec_fw_type type)
261 struct set_fw_redundancy{
267 .sub_cmd = MRPC_FWDNLD_SET_REDUNDANCY,
268 .part_type = switchtec_fw_type_gen4(type),
277 ret =
switchtec_cmd(dev, MRPC_FWDNLD, &cmd,
sizeof(cmd), NULL, 0);
285 uint8_t dont_activate;
291 uint8_t data[MRPC_MAX_DATA_LEN -
sizeof(
struct cmd_fwdl_hdr)];
306 int dont_activate,
int force,
307 void (*progress_callback)(
int cur,
int tot))
310 enum mrpc_bg_status bgstatus;
311 ssize_t image_size, offset = 0;
314 uint32_t cmd_id = MRPC_FWDNLD;
319 image_size = lseek(img_fd, 0, SEEK_END);
322 lseek(img_fd, 0, SEEK_SET);
326 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
331 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
337 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
339 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
341 cmd.hdr.dont_activate = !!dont_activate;
342 cmd.hdr.img_length = htole32(image_size);
344 while (offset < image_size) {
345 ssize_t blklen = read(img_fd, &cmd.data,
348 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
357 cmd.hdr.offset = htole32(offset);
358 cmd.hdr.blk_length = htole32(blklen);
366 ret = switchtec_fw_wait(dev, &status);
370 offset += le32toh(cmd.hdr.blk_length);
372 if (progress_callback)
373 progress_callback(offset, image_size);
377 if (status == SWITCHTEC_DLSTAT_COMPLETES)
380 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
383 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
387 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
399 uint8_t major = (version >> 24) & 0xff;
403 case 2:
return SWITCHTEC_GEN3;
406 case 5:
return SWITCHTEC_GEN4;
409 case 8:
return SWITCHTEC_GEN5;
410 default:
return SWITCHTEC_GEN_UNKNOWN;
426 int dont_activate,
int force,
427 void (*progress_callback)(
int cur,
int tot))
430 enum mrpc_bg_status bgstatus;
431 ssize_t image_size, offset = 0;
434 uint32_t cmd_id = MRPC_FWDNLD;
439 ret = fseek(fimg, 0, SEEK_END);
442 image_size = ftell(fimg);
445 ret = fseek(fimg, 0, SEEK_SET);
451 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
456 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
462 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
464 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
466 cmd.hdr.dont_activate = !!dont_activate;
467 cmd.hdr.img_length = htole32(image_size);
469 while (offset < image_size) {
470 ssize_t blklen = fread(&cmd.data, 1,
sizeof(cmd.data), fimg);
479 cmd.hdr.offset = htole32(offset);
480 cmd.hdr.blk_length = htole32(blklen);
488 ret = switchtec_fw_wait(dev, &status);
492 offset += le32toh(cmd.hdr.blk_length);
494 if (progress_callback)
495 progress_callback(offset, image_size);
498 if (status == SWITCHTEC_DLSTAT_COMPLETES)
501 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
504 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
508 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
531 case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
532 msg =
"Header incorrect";
break;
533 case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
534 msg =
"Offset incorrect";
break;
535 case SWITCHTEC_DLSTAT_CRC_INCORRECT:
536 msg =
"CRC incorrect";
break;
537 case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
538 msg =
"Length incorrect";
break;
539 case SWITCHTEC_DLSTAT_HARDWARE_ERR:
540 msg =
"Hardware Error";
break;
541 case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
542 msg =
"Package length less than 32 bytes";
break;
543 case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
544 msg =
"Signature memory allocation failed";
break;
545 case SWITCHTEC_DLSTAT_SEEPROM:
546 msg =
"SEEPROM download failed";
break;
547 case SWITCHTEC_DLSTAT_READONLY_PARTITION:
548 msg =
"Programming a read-only partition";
break;
549 case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
550 msg =
"Download Timeout";
break;
551 case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
552 msg =
"SEEPROM or related TWI bus isn't enabled";
break;
553 case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
554 msg =
"Programming a running partition";
break;
555 case SWITCHTEC_DLSTAT_NOT_ALLOWED:
556 msg =
"Programming not allowed over this interface";
break;
557 case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
558 msg =
"Activation failed due to XML version mismatch";
break;
559 case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
560 msg =
"Activation failed due to unknown error";
break;
561 case SWITCHTEC_DLSTAT_ERROR_OFFSET:
562 msg =
"Data offset error during programming";
break;
563 case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
564 msg =
"Failed to program to flash";
break;
566 case SWITCHTEC_DLSTAT_NO_FILE:
567 msg =
"No Image Transferred";
break;
569 fprintf(stderr,
"%s: Unknown Error (0x%x)\n", s, ret);
573 fprintf(stderr,
"%s: %s\n", s, msg);
576static enum switchtec_fw_type
579 switch ((
unsigned long)info->
part_id) {
580 case SWITCHTEC_FW_PART_ID_G3_BOOT:
return SWITCHTEC_FW_TYPE_BOOT;
581 case SWITCHTEC_FW_PART_ID_G3_MAP0:
return SWITCHTEC_FW_TYPE_MAP;
582 case SWITCHTEC_FW_PART_ID_G3_MAP1:
return SWITCHTEC_FW_TYPE_MAP;
583 case SWITCHTEC_FW_PART_ID_G3_IMG0:
return SWITCHTEC_FW_TYPE_IMG;
584 case SWITCHTEC_FW_PART_ID_G3_IMG1:
return SWITCHTEC_FW_TYPE_IMG;
585 case SWITCHTEC_FW_PART_ID_G3_DAT0:
return SWITCHTEC_FW_TYPE_CFG;
586 case SWITCHTEC_FW_PART_ID_G3_DAT1:
return SWITCHTEC_FW_TYPE_CFG;
587 case SWITCHTEC_FW_PART_ID_G3_NVLOG:
return SWITCHTEC_FW_TYPE_NVLOG;
588 case SWITCHTEC_FW_PART_ID_G3_SEEPROM:
return SWITCHTEC_FW_TYPE_SEEPROM;
591 case 0xa8000000:
return SWITCHTEC_FW_TYPE_BOOT;
592 case 0xa8020000:
return SWITCHTEC_FW_TYPE_MAP;
593 case 0xa8060000:
return SWITCHTEC_FW_TYPE_IMG;
594 case 0xa8210000:
return SWITCHTEC_FW_TYPE_CFG;
596 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
600static enum switchtec_fw_type
604 case SWITCHTEC_FW_PART_ID_G4_MAP0:
return SWITCHTEC_FW_TYPE_MAP;
605 case SWITCHTEC_FW_PART_ID_G4_MAP1:
return SWITCHTEC_FW_TYPE_MAP;
606 case SWITCHTEC_FW_PART_ID_G4_KEY0:
return SWITCHTEC_FW_TYPE_KEY;
607 case SWITCHTEC_FW_PART_ID_G4_KEY1:
return SWITCHTEC_FW_TYPE_KEY;
608 case SWITCHTEC_FW_PART_ID_G4_BL20:
return SWITCHTEC_FW_TYPE_BL2;
609 case SWITCHTEC_FW_PART_ID_G4_BL21:
return SWITCHTEC_FW_TYPE_BL2;
610 case SWITCHTEC_FW_PART_ID_G4_CFG0:
return SWITCHTEC_FW_TYPE_CFG;
611 case SWITCHTEC_FW_PART_ID_G4_CFG1:
return SWITCHTEC_FW_TYPE_CFG;
612 case SWITCHTEC_FW_PART_ID_G4_IMG0:
return SWITCHTEC_FW_TYPE_IMG;
613 case SWITCHTEC_FW_PART_ID_G4_IMG1:
return SWITCHTEC_FW_TYPE_IMG;
614 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
return SWITCHTEC_FW_TYPE_NVLOG;
615 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
return SWITCHTEC_FW_TYPE_SEEPROM;
616 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
620static enum switchtec_fw_type
624 case SWITCHTEC_GEN3:
return switchtec_fw_id_to_type_gen3(info);
626 case SWITCHTEC_GEN5:
return switchtec_fw_id_to_type_gen4(info);
627 default:
return SWITCHTEC_FW_TYPE_UNKNOWN;
631static int switchtec_fw_file_info_gen3(
int fd,
637 ret = read(fd, &hdr,
sizeof(hdr));
638 lseek(fd, 0, SEEK_SET);
640 if (ret !=
sizeof(hdr))
643 if (strcmp(hdr.magic,
"PMC") != 0)
649 info->
gen = SWITCHTEC_GEN3;
651 info->
image_crc = le32toh(hdr.image_crc);
652 version_to_string(hdr.version, info->
version,
sizeof(info->
version));
653 info->
image_len = le32toh(hdr.image_len);
655 info->
type = switchtec_fw_id_to_type(info);
657 info->secure_version = 0;
658 info->signed_image = 0;
667static int switchtec_fw_file_info_gen4(
int fd,
672 uint8_t exp_zero[4] = {};
675 ret = read(fd, &hdr,
sizeof(hdr));
676 lseek(fd, 0, SEEK_SET);
678 if (ret !=
sizeof(hdr))
681 if (strncmp(hdr.magic,
"MSCC",
sizeof(hdr.magic)))
684 if (strncmp(hdr.sub_magic,
"_MD ",
sizeof(hdr.sub_magic)))
690 switch (le32toh(hdr.type)) {
691 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
692 info->
part_id = SWITCHTEC_FW_PART_ID_G4_MAP0;
694 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
695 info->
part_id = SWITCHTEC_FW_PART_ID_G4_KEY0;
697 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
698 info->
part_id = SWITCHTEC_FW_PART_ID_G4_BL20;
700 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
701 info->
part_id = SWITCHTEC_FW_PART_ID_G4_CFG0;
703 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
704 info->
part_id = SWITCHTEC_FW_PART_ID_G4_IMG0;
706 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
707 info->
part_id = SWITCHTEC_FW_PART_ID_G4_NVLOG;
709 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
710 info->
part_id = SWITCHTEC_FW_PART_ID_G4_SEEPROM;
716 info->
image_crc = le32toh(hdr.image_crc);
717 version = le32toh(hdr.version);
719 info->
image_len = le32toh(hdr.image_len);
722 info->
type = switchtec_fw_id_to_type(info);
724 info->secure_version = le32toh(hdr.secure_version);
725 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
745 ret = read(fd, &magic,
sizeof(magic));
746 lseek(fd, 0, SEEK_SET);
748 if (ret !=
sizeof(magic)) {
753 if (!strncmp(magic,
"PMC",
sizeof(magic))) {
754 return switchtec_fw_file_info_gen3(fd, info);
755 }
else if (!strncmp(magic,
"MSCC",
sizeof(magic))) {
756 return switchtec_fw_file_info_gen4(fd, info);
787 if (!info.signed_image)
792 sn_info.ver_bl2 = 0xffffffff;
793 sn_info.ver_main = 0xffffffff;
794 sn_info.ver_km = 0xffffffff;
798 case SWITCHTEC_FW_TYPE_BL2:
799 if (info.secure_version > sn_info.ver_bl2)
803 case SWITCHTEC_FW_TYPE_IMG:
804 if (info.secure_version > sn_info.ver_main)
808 case SWITCHTEC_FW_TYPE_KEY:
809 if (info.secure_version > sn_info.ver_km)
827 switch (info->
type) {
828 case SWITCHTEC_FW_TYPE_BOOT:
return "BOOT";
829 case SWITCHTEC_FW_TYPE_MAP:
return "MAP";
830 case SWITCHTEC_FW_TYPE_IMG:
return "IMG";
831 case SWITCHTEC_FW_TYPE_CFG:
return "CFG";
832 case SWITCHTEC_FW_TYPE_KEY:
return "KEY";
833 case SWITCHTEC_FW_TYPE_BL2:
return "BL2";
834 case SWITCHTEC_FW_TYPE_NVLOG:
return "NVLOG";
835 case SWITCHTEC_FW_TYPE_SEEPROM:
return "SEEPROM";
836 default:
return "UNKNOWN";
840static int switchtec_fw_map_get_active(
struct switchtec_dev *dev,
843 uint32_t map0_update_index;
844 uint32_t map1_update_index;
848 sizeof(uint32_t), &map0_update_index);
853 sizeof(uint32_t), &map1_update_index);
858 if (map0_update_index > map1_update_index) {
859 if (info->
part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
862 if (info->
part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
869static int switchtec_fw_info_metadata_gen3(
struct switchtec_dev *dev,
876 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
879 metadata = malloc(
sizeof(*metadata));
889 if (strncmp(metadata->magic,
"PMC",
sizeof(metadata->magic)))
892 version_to_string(metadata->version, inf->
version,
897 inf->metadata = metadata;
906static int switchtec_fw_part_info_gen3(
struct switchtec_dev *dev,
914 case SWITCHTEC_FW_PART_ID_G3_BOOT:
915 inf->
part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
916 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
919 case SWITCHTEC_FW_PART_ID_G3_MAP0:
920 inf->
part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
921 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
922 ret = switchtec_fw_map_get_active(dev, inf);
924 case SWITCHTEC_FW_PART_ID_G3_MAP1:
925 inf->
part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
926 inf->
part_len = SWITCHTEC_FLASH_PART_LEN;
927 ret = switchtec_fw_map_get_active(dev, inf);
931 inf->read_only =
false;
939 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
942 return switchtec_fw_info_metadata_gen3(dev, inf);
945static int switchtec_fw_info_metadata_gen4(
struct switchtec_dev *dev,
953 .subcmd = MRPC_PART_INFO_GET_METADATA,
958 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
960 if (inf->
part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
961 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
963 metadata = malloc(
sizeof(*metadata));
967 ret =
switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
sizeof(subcmd),
968 metadata,
sizeof(*metadata));
972 if (strncmp(metadata->magic,
"MSCC",
sizeof(metadata->magic)))
975 if (strncmp(metadata->sub_magic,
"_MD ",
sizeof(metadata->sub_magic)))
978 version_to_string(le32toh(metadata->version), inf->
version,
981 inf->
image_crc = le32toh(metadata->image_crc);
982 inf->
image_len = le32toh(metadata->image_len);
983 inf->metadata = metadata;
993 uint32_t firmware_version;
998 uint8_t running_bl2_flag;
999 uint8_t running_cfg_flag;
1000 uint8_t running_img_flag;
1001 uint8_t running_key_flag;
1002 uint8_t redundancy_key_flag;
1003 uint8_t redundancy_bl2_flag;
1004 uint8_t redundancy_cfg_flag;
1005 uint8_t redundancy_img_flag;
1010 uint16_t image_version;
1013 uint32_t part_start;
1015 uint32_t part_offset;
1016 uint32_t part_size_dw;
1020 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1021 img0, img1, nvlog, vendor[8];
1024static int switchtec_fw_part_info_gen4(
struct switchtec_dev *dev,
1028 struct switchtec_flash_part_info_gen4 *part_info;
1032 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1033 part_info = &all->map0;
1035 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1036 part_info = &all->map1;
1038 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1039 part_info = &all->keyman0;
1040 inf->redundant = all->redundancy_key_flag;
1042 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1043 part_info = &all->keyman1;
1044 inf->redundant = all->redundancy_key_flag;
1046 case SWITCHTEC_FW_PART_ID_G4_BL20:
1047 part_info = &all->bl20;
1048 inf->redundant = all->redundancy_bl2_flag;
1050 case SWITCHTEC_FW_PART_ID_G4_BL21:
1051 part_info = &all->bl21;
1052 inf->redundant = all->redundancy_bl2_flag;
1054 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1055 part_info = &all->img0;
1056 inf->redundant = all->redundancy_img_flag;
1058 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1059 part_info = &all->img1;
1060 inf->redundant = all->redundancy_img_flag;
1062 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1063 part_info = &all->cfg0;
1064 inf->redundant = all->redundancy_cfg_flag;
1066 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1067 part_info = &all->cfg1;
1068 inf->redundant = all->redundancy_cfg_flag;
1070 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1071 part_info = &all->nvlog;
1073 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1081 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1083 inf->running =
true;
1093 inf->
part_addr = le32toh(part_info->part_start);
1094 inf->
part_len = le32toh(part_info->part_size_dw) * 4;
1095 inf->active = part_info->active;
1096 inf->running = part_info->is_using;
1097 inf->read_only = part_info->read_only;
1098 inf->valid = part_info->valid;
1102 return switchtec_fw_info_metadata_gen4(dev, inf);
1119 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1122 if (info == NULL || nr_info == 0)
1125 if (dev->gen > SWITCHTEC_GEN3) {
1127 sizeof(subcmd), &all_info,
1131 all_info.firmware_version = le32toh(all_info.firmware_version);
1132 all_info.flash_size = le32toh(all_info.flash_size);
1133 all_info.device_id = le16toh(all_info.device_id);
1136 for (i = 0; i < nr_info; i++) {
1140 inf->
gen = dev->gen;
1141 inf->
type = switchtec_fw_id_to_type(inf);
1142 inf->active =
false;
1143 inf->running =
false;
1146 switch (info->
gen) {
1147 case SWITCHTEC_GEN3:
1148 ret = switchtec_fw_part_info_gen3(dev, inf);
1150 case SWITCHTEC_GEN4:
1151 case SWITCHTEC_GEN5:
1152 ret = switchtec_fw_part_info_gen4(dev, inf, &all_info);
1165 inf->metadata = NULL;
1172static long multicfg_subcmd(
struct switchtec_dev *dev, uint32_t subcmd,
1178 subcmd |= index << 8;
1179 subcmd = htole32(subcmd);
1181 ret =
switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd,
sizeof(subcmd),
1182 &result,
sizeof(result));
1189static int get_multicfg(
struct switchtec_dev *dev,
1196 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1205 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1212 for (i = 0; i < *nr_mult; i++) {
1213 info[i].
part_addr = multicfg_subcmd(dev,
1214 MRPC_MULTI_CFG_START_ADDR,
1216 info[i].
part_len = multicfg_subcmd(dev,
1217 MRPC_MULTI_CFG_LENGTH, i);
1223 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1228 info[ret].active = 1;
1233static const enum switchtec_fw_image_part_id_gen3
1234switchtec_fw_partitions_gen3[] = {
1235 SWITCHTEC_FW_PART_ID_G3_BOOT,
1236 SWITCHTEC_FW_PART_ID_G3_MAP0,
1237 SWITCHTEC_FW_PART_ID_G3_MAP1,
1238 SWITCHTEC_FW_PART_ID_G3_IMG0,
1239 SWITCHTEC_FW_PART_ID_G3_DAT0,
1240 SWITCHTEC_FW_PART_ID_G3_DAT1,
1241 SWITCHTEC_FW_PART_ID_G3_NVLOG,
1242 SWITCHTEC_FW_PART_ID_G3_IMG1,
1245static const enum switchtec_fw_image_part_id_gen4
1246switchtec_fw_partitions_gen4[] = {
1247 SWITCHTEC_FW_PART_ID_G4_MAP0,
1248 SWITCHTEC_FW_PART_ID_G4_MAP1,
1249 SWITCHTEC_FW_PART_ID_G4_KEY0,
1250 SWITCHTEC_FW_PART_ID_G4_KEY1,
1251 SWITCHTEC_FW_PART_ID_G4_BL20,
1252 SWITCHTEC_FW_PART_ID_G4_BL21,
1253 SWITCHTEC_FW_PART_ID_G4_CFG0,
1254 SWITCHTEC_FW_PART_ID_G4_CFG1,
1255 SWITCHTEC_FW_PART_ID_G4_IMG0,
1256 SWITCHTEC_FW_PART_ID_G4_IMG1,
1257 SWITCHTEC_FW_PART_ID_G4_NVLOG,
1258 SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1261static struct switchtec_fw_part_type *
1265 switch (info->
type) {
1266 case SWITCHTEC_FW_TYPE_BOOT:
return &summary->boot;
1267 case SWITCHTEC_FW_TYPE_MAP:
return &summary->map;
1268 case SWITCHTEC_FW_TYPE_IMG:
return &summary->img;
1269 case SWITCHTEC_FW_TYPE_CFG:
return &summary->cfg;
1270 case SWITCHTEC_FW_TYPE_NVLOG:
return &summary->nvlog;
1271 case SWITCHTEC_FW_TYPE_SEEPROM:
return &summary->seeprom;
1272 case SWITCHTEC_FW_TYPE_KEY:
return &summary->key;
1273 case SWITCHTEC_FW_TYPE_BL2:
return &summary->bl2;
1274 default:
return NULL;
1291 struct switchtec_fw_part_type *type;
1292 int nr_info, nr_mcfg = 16;
1297 case SWITCHTEC_GEN3:
1298 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1300 case SWITCHTEC_GEN4:
1301 case SWITCHTEC_GEN5:
1302 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1309 st_sz =
sizeof(*summary) +
sizeof(*summary->all) * (nr_info + nr_mcfg);
1311 summary = malloc(st_sz);
1315 memset(summary, 0, st_sz);
1316 summary->nr_info = nr_info;
1319 case SWITCHTEC_GEN3:
1320 for (i = 0; i < nr_info; i++)
1322 switchtec_fw_partitions_gen3[i];
1324 case SWITCHTEC_GEN4:
1325 case SWITCHTEC_GEN5:
1326 for (i = 0; i < nr_info; i++)
1328 switchtec_fw_partitions_gen4[i];
1336 if (ret != nr_info) {
1341 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1347 for (i = 0; i < nr_info; i++) {
1348 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1353 if (summary->all[i].active)
1354 type->active = &summary->all[i];
1356 type->inactive = &summary->all[i];
1359 infp = &summary->mult_cfg;
1360 for (; i < nr_info + nr_mcfg; i++) {
1361 *infp = &summary->all[i];
1362 infp = &summary->all[i].next;
1376 for (i = 0; i < summary->nr_info; i++)
1377 free(summary->all[i].metadata);
1391 size_t len,
void *buf)
1398 unsigned char *cbuf = buf;
1402 size_t chunk_len = len;
1403 if (chunk_len > MRPC_MAX_DATA_LEN-8)
1404 chunk_len = MRPC_MAX_DATA_LEN-8;
1406 cmd.addr = htole32(addr);
1407 cmd.length = htole32(chunk_len);
1435 unsigned long addr,
size_t len,
1436 void (*progress_callback)(
int cur,
int tot))
1439 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1441 size_t total_len = len;
1446 size_t chunk_len = len;
1447 if (chunk_len >
sizeof(buf))
1448 chunk_len =
sizeof(buf);
1455 while (total_wrote < ret) {
1456 wrote = write(fd, &buf[total_wrote],
1460 total_wrote += wrote;
1467 if (progress_callback)
1468 progress_callback(read, total_len);
1485 void (*progress_callback)(
int cur,
int tot))
1492static int switchtec_fw_img_write_hdr_gen3(
int fd,
1498 memcpy(hdr.magic, ftr->magic,
sizeof(hdr.magic));
1499 hdr.image_len = ftr->image_len;
1501 hdr.load_addr = ftr->load_addr;
1502 hdr.version = ftr->version;
1503 hdr.header_crc = ftr->header_crc;
1504 hdr.image_crc = ftr->image_crc;
1506 if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1507 hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1508 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1509 hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1510 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1511 hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1513 return write(fd, &hdr,
sizeof(hdr));
1516static int switchtec_fw_img_write_hdr_gen4(
int fd,
1522 ret = write(fd, hdr,
sizeof(*hdr));
1544 switch (info->
gen) {
1545 case SWITCHTEC_GEN3:
return switchtec_fw_img_write_hdr_gen3(fd, info);
1546 case SWITCHTEC_GEN4:
1547 case SWITCHTEC_GEN5:
return switchtec_fw_img_write_hdr_gen4(fd, info);
1570 .subcmd = MRPC_FWDNLD_BOOT_RO,
1576 uint8_t reserved[3];
1586 ret =
switchtec_cmd(dev, MRPC_FWDNLD, &subcmd,
sizeof(subcmd),
1587 &result,
sizeof(result));
1589 if (ret == ERR_SUBCMD_INVALID) {
1597 return result.status;
1610 .subcmd = MRPC_FWDNLD_BOOT_RO,
1620 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_setup_redundancy(struct switchtec_dev *dev, enum switchtec_fw_redundancy redund, enum switchtec_fw_type type)
Set or clear the redundancy flag of a partition type.
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.
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.
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.