Switchtec Userspace PROJECT_NUMBER = 4.4
Loading...
Searching...
No Matches
fw.c
Go to the documentation of this file.
1/*
2 * Microsemi Switchtec(tm) PCIe Management Library
3 * Copyright (c) 2017, Microsemi Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
29
30#define SWITCHTEC_LIB_CORE
31
32#include "switchtec_priv.h"
33#include "switchtec/switchtec.h"
34#include "switchtec/errors.h"
35#include "switchtec/endian.h"
36#include "switchtec/utils.h"
37#include "switchtec/mfg.h"
38
39#include <unistd.h>
40
41#include <errno.h>
42#include <stdio.h>
43#include <string.h>
44
55
57 char magic[4];
58 uint32_t image_len;
59 uint32_t load_addr;
60 uint32_t version;
61 uint32_t rsvd;
62 uint32_t header_crc;
63 uint32_t image_crc;
64};
65
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,
75};
76
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,
87};
88
90 char magic[4];
91 char sub_magic[4];
92 uint32_t hdr_version;
93 uint32_t secure_version;
94 uint32_t header_len;
95 uint32_t metadata_len;
96 uint32_t image_len;
97 uint32_t type;
98 uint8_t fw_id;
99 uint8_t rsvd[3];
100 uint32_t version;
101 uint32_t sequence;
102 uint32_t reserved1;
103 uint8_t date_str[8];
104 uint8_t time_str[8];
105 uint8_t img_str[16];
106 uint8_t rsvd1[4];
107 uint32_t image_crc;
108 uint8_t public_key_modulus[512];
109 uint8_t public_key_exponent[4];
110 uint8_t uart_port;
111 uint8_t uart_rate;
112 uint8_t bist_enable;
113 uint8_t bist_gpio_pin_cfg;
114 uint8_t bist_gpio_level_cfg;
115 uint8_t rsvd2[3];
116 uint32_t xml_version;
117 uint32_t relocatable_img_len;
118 uint32_t link_addr;
119 uint32_t header_crc;
120};
121
123 char magic[4];
124 char sub_magic[4];
125 uint32_t hdr_version;
126 uint32_t secure_version;
127 uint32_t header_len;
128 uint32_t metadata_len;
129 uint32_t image_len;
130 uint32_t type;
131 uint8_t fw_id;
132 uint8_t rsvd[3];
133 uint32_t version;
134 uint32_t sequence;
135 uint32_t reserved1;
136 uint8_t date_str[8];
137 uint8_t time_str[8];
138 uint8_t img_str[16];
139 uint8_t rsvd1[4];
140 uint32_t image_crc;
141 uint8_t public_key_modulus[512];
142 uint8_t public_key_exponent[4];
143 uint8_t uart_port;
144 uint8_t uart_rate;
145 uint8_t bist_enable;
146 uint8_t bist_gpio_pin_cfg;
147 uint8_t bist_gpio_level_cfg;
148 uint8_t rollback_enable;
149 uint8_t rsvd2[2];
150 uint32_t xml_version;
151 uint32_t relocatable_img_len;
152 uint32_t link_addr;
153 uint32_t header_crc;
154};
155
157 char magic[4];
158 char sub_magic[4];
159 uint32_t hdr_version;
160 uint32_t secure_version;
161 uint32_t header_len;
162 uint32_t metadata_len;
163 uint32_t image_len;
164 uint32_t type;
165 uint8_t fw_id;
166 uint8_t rsvd[3];
167 uint32_t version;
168 uint32_t sequence;
169 uint32_t reserved1;
170 uint8_t date_str[8];
171 uint8_t time_str[8];
172 uint8_t img_str[16];
173 uint8_t rsvd1[4];
174 uint32_t image_crc;
175 uint8_t public_key_modulus[512];
176 uint8_t public_key_exponent[4];
177 uint8_t uart_port;
178 uint8_t uart_rate;
179 uint8_t bist_enable;
180 uint8_t bist_gpio_pin_cfg;
181 uint8_t bist_gpio_level_cfg;
182 uint8_t rollback_enable;
183 uint8_t rsvd2[2];
184 uint32_t xml_version;
185 uint32_t relocatable_img_len;
186 uint32_t link_addr;
187 uint32_t header_crc;
188};
189
191 char magic[4];
192 uint32_t image_len;
193 uint32_t type;
194 uint32_t load_addr;
195 uint32_t version;
196 uint32_t rsvd[9];
197 uint32_t header_crc;
198 uint32_t image_crc;
199};
200
201typedef enum {
202 MRPC_FW_IMG_GET_CMD_START = 0,
203 MRPC_FW_IMG_GET_CMD_NEXT = 1,
204
205 MRPC_FW_IMG_GET_CMD_MAX
206} mrpc_fw_img_get_cmd_e;
207
208struct cmd_fwget {
209 uint8_t subcmd;
210 uint8_t fw_type;
211 uint8_t fw_slot;
212 uint8_t f_from_start;
213};
214
215static uint32_t get_fw_tx_id(struct switchtec_dev *dev)
216{
217 if (switchtec_is_gen6(dev))
218 return MRPC_FW_TX_GEN6;
219 if (switchtec_is_gen5(dev))
220 return MRPC_FW_TX_GEN5;
221
222 return MRPC_FW_TX;
223}
224
225static int switchtec_fw_dlstatus(struct switchtec_dev *dev,
226 enum switchtec_fw_dlstatus *status,
227 enum mrpc_bg_status *bgstatus)
228{
229 uint32_t cmd = MRPC_FWDNLD;
230 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
231 struct {
232 uint8_t dlstatus;
233 uint8_t bgstatus;
234 uint16_t reserved;
235 } result;
236 int ret;
237
238 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
239 cmd = get_fw_tx_id(dev);
240
241 ret = switchtec_cmd(dev, cmd, &subcmd, sizeof(subcmd),
242 &result, sizeof(result));
243
244 if (ret)
245 return ret;
246
247 if (status != NULL)
248 *status = result.dlstatus;
249
250 if (bgstatus != NULL)
251 *bgstatus = result.bgstatus;
252
253 return 0;
254}
255
256static int switchtec_fw_wait(struct switchtec_dev *dev,
257 enum switchtec_fw_dlstatus *status)
258{
259 enum mrpc_bg_status bgstatus;
260 int ret;
261
262 do {
263 // Delay slightly to avoid interrupting the firmware too much
264 usleep(5000);
265
266 ret = switchtec_fw_dlstatus(dev, status, &bgstatus);
267 if (ret < 0)
268 return ret;
269
270 if (bgstatus == MRPC_BG_STAT_OFFSET)
271 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
272
273 if (bgstatus == MRPC_BG_STAT_ERROR) {
274 if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
275 *status != SWITCHTEC_DLSTAT_COMPLETES &&
276 *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
277 *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
278 return *status;
279 else
280 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
281 }
282
283 } while (bgstatus == MRPC_BG_STAT_INPROGRESS);
284
285 return 0;
286}
287
288static int set_redundant(struct switchtec_dev *dev, int type, int set)
289{
290 int ret;
291 char *part_types[] = {
292 "KEYMAN",
293 "RIOT",
294 "BL2",
295 "CFG",
296 "MAIN-FW"
297 };
298
299 struct {
300 uint8_t subcmd;
301 uint8_t part_type;
302 uint8_t redundant_val;
303 uint8_t reserved;
304 } cmd;
305
306 cmd.subcmd = MRPC_FWDNLD_SET_RDNDNT;
307 cmd.redundant_val = set;
308 if (switchtec_is_gen6(dev) && type != 1)
309 cmd.part_type = type - 1;
310 else
311 cmd.part_type = type;
312
313 printf("%s redundant flag \t(%s)\n", set ? "Checking" : "Un-checking",
314 part_types[type-1]);
315 ret = switchtec_cmd(dev, MRPC_FWDNLD, &cmd, sizeof(cmd), NULL, 0);
316 if (ret) {
317 fprintf(stderr, "Error: setting redudant flag \t(%s)\n",
318 part_types[type-1]);
319 return 1;
320 }
321 else {
322 printf("Success: set redundant flag \t(%s)\n",
323 part_types[type-1]);
324 }
325 return 0;
326}
327
334int switchtec_fw_set_redundant_flag (struct switchtec_dev *dev, int keyman,
335 int riot, int bl2, int cfg, int fw,
336 int set)
337{
338 int ret = 0;
339 if (keyman)
340 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_KEYMAN, set);
341 if (riot)
342 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_RC, set);
343 if (bl2)
344 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_BL2, set);
345 if (cfg)
346 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_CFG, set);
347 if (fw)
348 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_FW, set);
349
350 return ret;
351}
352
367int switchtec_fw_img_get(struct switchtec_dev *dev, int fd,
368 enum switchtec_fw_type_gen6 fw_type, int fw_slot,
369 void (*progress_callback)(int cur, int tot))
370{
371 struct cmd_fwget cmd = {0};
372
373 struct fw_img_get_resp_t {
374 uint8_t status;
375 uint8_t fw_type;
376 uint8_t fw_slot;
377 uint8_t reserved;
378 uint32_t total_len;
379 uint32_t offset;
380 uint32_t chunk_len;
381 uint32_t *data;
382 };
383
384 uint8_t resp[MRPC_MAX_DATA_LEN] ={};
385 struct fw_img_get_resp_t *fw_img_get_resp = (struct fw_img_get_resp_t *)resp;
386 int ret;
387
388 /* erase existing file */
389 if (ftruncate(fd, 0) == -1) {
390 perror("ftruncate");
391 return 1;
392 }
393
394 cmd.subcmd = 0;
395 cmd.fw_type = fw_type;
396 cmd.fw_slot = fw_slot;
397 cmd.f_from_start = MRPC_FW_IMG_GET_CMD_START;
398
399 ret = switchtec_cmd(dev, MRPC_FW_IMG_GET, &cmd, sizeof(cmd),
400 resp, sizeof(resp));
401
402 if (ret) {
403 printf("Error during FW image get\n");
404 return ret;
405 }
406
407 size_t written = write(fd, (void*)(&fw_img_get_resp->data), fw_img_get_resp->chunk_len);
408 if (written != fw_img_get_resp->chunk_len) {
409 perror("Error writing to file");
410 return 1;
411 }
412
413 if (progress_callback)
414 progress_callback(fw_img_get_resp->offset, fw_img_get_resp->total_len);
415
416 do {
417 cmd.subcmd = 0;
418 cmd.fw_type = fw_type;
419 cmd.fw_slot = fw_slot;
420 cmd.f_from_start = MRPC_FW_IMG_GET_CMD_NEXT;
421
422 ret = switchtec_cmd(dev, MRPC_FW_IMG_GET, &cmd, sizeof(cmd),
423 resp, sizeof(resp));
424
425 if (ret) {
426 printf("Error during FW image get\n");
427 return ret;
428 }
429
430 size_t written = write(fd, (void *)(&fw_img_get_resp->data), fw_img_get_resp->chunk_len);
431 if (written != fw_img_get_resp->chunk_len) {
432 perror("Error writing to file");
433 return 1;
434 }
435
436 if (progress_callback)
437 progress_callback(fw_img_get_resp->offset, fw_img_get_resp->total_len);
438
439 } while ((fw_img_get_resp->offset + fw_img_get_resp->chunk_len) < fw_img_get_resp->total_len);
440
441 return 0;
442}
443
454int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev,
455 int toggle_bl2, int toggle_key,
456 int toggle_fw, int toggle_cfg,
457 int toggle_riotcore)
458{
459 uint32_t cmd_id;
460 size_t cmd_size;
461 int ret;
462 struct {
463 uint8_t subcmd;
464 uint8_t toggle_fw;
465 uint8_t toggle_cfg;
466 uint8_t toggle_bl2;
467 uint8_t toggle_key;
468 uint8_t toggle_riotcore;
469 uint16_t reserved;
470 } cmd;
471
472 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) {
473 cmd_size = sizeof(cmd);
474 cmd_id = get_fw_tx_id(dev);
475 cmd.subcmd = MRPC_FW_TX_TOGGLE;
476 cmd.toggle_bl2 = !!toggle_bl2;
477 ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0);
478 if (ret)
479 return ret;
480 cmd.toggle_bl2 = 0;
481 cmd.toggle_fw = !!toggle_fw;
482 ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0);
483 if (ret)
484 return ret;
485 cmd.toggle_fw = 0;
486 cmd.toggle_cfg = !!toggle_cfg;
487 ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0);
488 if (ret)
489 return ret;
490
491 return 0;
492 }
493
494 cmd_id = MRPC_FWDNLD;
495 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
496 cmd.toggle_bl2 = !!toggle_bl2;
497 cmd.toggle_key = !!toggle_key;
498 cmd.toggle_fw = !!toggle_fw;
499 cmd.toggle_cfg = !!toggle_cfg;
500 if (switchtec_is_gen5(dev))
501 cmd.toggle_riotcore = !!toggle_riotcore;
502 cmd_size = sizeof(cmd);
503
504 return switchtec_cmd(dev, cmd_id, &cmd, cmd_size,
505 NULL, 0);
506}
507
508struct cmd_fwdl {
510 uint8_t subcmd;
511 uint8_t dont_activate;
512 uint8_t reserved[2];
513 uint32_t offset;
514 uint32_t img_length;
515 uint32_t blk_length;
516 } hdr;
517 uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
518};
519
531int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
532 int dont_activate, int force,
533 void (*progress_callback)(int cur, int tot))
534{
535 enum switchtec_fw_dlstatus status;
536 enum mrpc_bg_status bgstatus;
537 ssize_t image_size, offset = 0;
538 int ret;
539 struct cmd_fwdl cmd = {};
540 uint32_t cmd_id = MRPC_FWDNLD;
541
542 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
543 cmd_id = get_fw_tx_id(dev);
544
545 image_size = lseek(img_fd, 0, SEEK_END);
546 if (image_size < 0)
547 return -errno;
548 lseek(img_fd, 0, SEEK_SET);
549
550 switchtec_fw_dlstatus(dev, &status, &bgstatus);
551
552 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
553 errno = EBUSY;
554 return -EBUSY;
555 }
556
557 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
558 errno = EBUSY;
559 return -EBUSY;
560 }
561
562 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
563 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
564 else
565 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
566
567 cmd.hdr.dont_activate = !!dont_activate;
568 cmd.hdr.img_length = htole32(image_size);
569
570 while (offset < image_size) {
571 ssize_t blklen = read(img_fd, &cmd.data,
572 sizeof(cmd.data));
573
574 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
575 continue;
576
577 if (blklen < 0)
578 return -errno;
579
580 if (blklen == 0)
581 break;
582
583 cmd.hdr.offset = htole32(offset);
584 cmd.hdr.blk_length = htole32(blklen);
585
586 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
587 NULL, 0);
588
589 if (ret)
590 return ret;
591
592 ret = switchtec_fw_wait(dev, &status);
593 if (ret != 0)
594 return ret;
595
596 offset += le32toh(cmd.hdr.blk_length);
597
598 if (progress_callback)
599 progress_callback(offset, image_size);
600
601 }
602
603 if (status == SWITCHTEC_DLSTAT_COMPLETES)
604 return 0;
605
606 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
607 return 0;
608
609 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
610 return 0;
611
612 if (status == 0)
613 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
614
615 return status;
616}
617
624{
625 uint8_t major = (version >> 24) & 0xff;
626
627 switch (major) {
628 case 1:
629 case 2: return SWITCHTEC_GEN3;
630 case 3:
631 case 4:
632 case 5: return SWITCHTEC_GEN4;
633 case 6:
634 case 7:
635 case 8: return SWITCHTEC_GEN5;
636 case 9:
637 case 10:
638 case 11: return SWITCHTEC_GEN6;
639 default: return SWITCHTEC_GEN_UNKNOWN;
640 }
641}
642
654int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
655 int dont_activate, int force,
656 void (*progress_callback)(int cur, int tot))
657{
658 enum switchtec_fw_dlstatus status;
659 enum mrpc_bg_status bgstatus;
660 ssize_t image_size, offset = 0;
661 int ret;
662 struct cmd_fwdl cmd = {};
663 uint32_t cmd_id = MRPC_FWDNLD;
664
665 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
666 cmd_id = get_fw_tx_id(dev);
667
668 ret = fseek(fimg, 0, SEEK_END);
669 if (ret)
670 return -errno;
671 image_size = ftell(fimg);
672 if (image_size < 0)
673 return -errno;
674 ret = fseek(fimg, 0, SEEK_SET);
675 if (ret)
676 return -errno;
677
678 switchtec_fw_dlstatus(dev, &status, &bgstatus);
679
680 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
681 errno = EBUSY;
682 return -EBUSY;
683 }
684
685 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
686 errno = EBUSY;
687 return -EBUSY;
688 }
689
690 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
691 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
692 else
693 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
694
695 cmd.hdr.dont_activate = !!dont_activate;
696 cmd.hdr.img_length = htole32(image_size);
697
698 while (offset < image_size) {
699 ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
700
701 if (blklen == 0) {
702 ret = ferror(fimg);
703 if (ret)
704 return ret;
705 break;
706 }
707
708 cmd.hdr.offset = htole32(offset);
709 cmd.hdr.blk_length = htole32(blklen);
710
711 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
712 NULL, 0);
713
714 if (ret)
715 return ret;
716
717 ret = switchtec_fw_wait(dev, &status);
718 if (ret != 0)
719 return ret;
720
721 offset += le32toh(cmd.hdr.blk_length);
722
723 if (progress_callback)
724 progress_callback(offset, image_size);
725 }
726
727 if (status == SWITCHTEC_DLSTAT_COMPLETES)
728 return 0;
729
730 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
731 return 0;
732
733 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
734 return 0;
735
736 if (status == 0)
737 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
738
739 return status;
740}
741
750void switchtec_fw_perror(const char *s, int ret)
751{
752 const char *msg;
753
754 if (ret <= 0) {
755 perror(s);
756 return;
757 }
758
759 switch (ret) {
760 case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
761 msg = "Header incorrect"; break;
762 case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
763 msg = "Offset incorrect"; break;
764 case SWITCHTEC_DLSTAT_CRC_INCORRECT:
765 msg = "CRC incorrect"; break;
766 case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
767 msg = "Length incorrect"; break;
768 case SWITCHTEC_DLSTAT_HARDWARE_ERR:
769 msg = "Hardware Error"; break;
770 case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
771 msg = "Package length less than 32 bytes"; break;
772 case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
773 msg = "Signature memory allocation failed"; break;
774 case SWITCHTEC_DLSTAT_SEEPROM:
775 msg = "SEEPROM download failed"; break;
776 case SWITCHTEC_DLSTAT_READONLY_PARTITION:
777 msg = "Programming a read-only partition"; break;
778 case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
779 msg = "Download Timeout"; break;
780 case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
781 msg = "SEEPROM or related TWI bus isn't enabled"; break;
782 case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
783 msg = "Programming a running partition"; break;
784 case SWITCHTEC_DLSTAT_NOT_ALLOWED:
785 msg = "Programming not allowed over this interface"; break;
786 case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
787 msg = "Activation failed due to XML version mismatch"; break;
788 case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
789 msg = "Activation failed due to unknown error"; break;
790 case SWITCHTEC_DLSTAT_ERROR_OFFSET:
791 msg = "Data offset error during programming"; break;
792 case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
793 msg = "Failed to program to flash"; break;
794
795 case SWITCHTEC_DLSTAT_NO_FILE:
796 msg = "No Image Transferred"; break;
797 default:
798 fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
799 return;
800 }
801
802 fprintf(stderr, "%s: %s\n", s, msg);
803}
804
805static enum switchtec_fw_type
806switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
807{
808 switch ((unsigned long)info->part_id) {
809 case SWITCHTEC_FW_PART_ID_G3_BOOT: return SWITCHTEC_FW_TYPE_BOOT;
810 case SWITCHTEC_FW_PART_ID_G3_MAP0: return SWITCHTEC_FW_TYPE_MAP;
811 case SWITCHTEC_FW_PART_ID_G3_MAP1: return SWITCHTEC_FW_TYPE_MAP;
812 case SWITCHTEC_FW_PART_ID_G3_IMG0: return SWITCHTEC_FW_TYPE_IMG;
813 case SWITCHTEC_FW_PART_ID_G3_IMG1: return SWITCHTEC_FW_TYPE_IMG;
814 case SWITCHTEC_FW_PART_ID_G3_DAT0: return SWITCHTEC_FW_TYPE_CFG;
815 case SWITCHTEC_FW_PART_ID_G3_DAT1: return SWITCHTEC_FW_TYPE_CFG;
816 case SWITCHTEC_FW_PART_ID_G3_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
817 case SWITCHTEC_FW_PART_ID_G3_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
818
819 //Legacy
820 case 0xa8000000: return SWITCHTEC_FW_TYPE_BOOT;
821 case 0xa8020000: return SWITCHTEC_FW_TYPE_MAP;
822 case 0xa8060000: return SWITCHTEC_FW_TYPE_IMG;
823 case 0xa8210000: return SWITCHTEC_FW_TYPE_CFG;
824
825 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
826 }
827}
828
829static enum switchtec_fw_type
830switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
831{
832 switch (info->part_id) {
833 case SWITCHTEC_FW_PART_ID_G4_MAP0: return SWITCHTEC_FW_TYPE_MAP;
834 case SWITCHTEC_FW_PART_ID_G4_MAP1: return SWITCHTEC_FW_TYPE_MAP;
835 case SWITCHTEC_FW_PART_ID_G4_KEY0: return SWITCHTEC_FW_TYPE_KEY;
836 case SWITCHTEC_FW_PART_ID_G4_KEY1: return SWITCHTEC_FW_TYPE_KEY;
837 case SWITCHTEC_FW_PART_ID_G4_BL20: return SWITCHTEC_FW_TYPE_BL2;
838 case SWITCHTEC_FW_PART_ID_G4_BL21: return SWITCHTEC_FW_TYPE_BL2;
839 case SWITCHTEC_FW_PART_ID_G4_CFG0: return SWITCHTEC_FW_TYPE_CFG;
840 case SWITCHTEC_FW_PART_ID_G4_CFG1: return SWITCHTEC_FW_TYPE_CFG;
841 case SWITCHTEC_FW_PART_ID_G4_IMG0: return SWITCHTEC_FW_TYPE_IMG;
842 case SWITCHTEC_FW_PART_ID_G4_IMG1: return SWITCHTEC_FW_TYPE_IMG;
843 case SWITCHTEC_FW_PART_ID_G4_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
844 case SWITCHTEC_FW_PART_ID_G4_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
845 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
846 }
847}
848
849static enum switchtec_fw_type
850switchtec_fw_id_to_type_gen5(const struct switchtec_fw_image_info *info)
851{
852 switch (info->part_id) {
853 case SWITCHTEC_FW_PART_ID_G5_MAP0: return SWITCHTEC_FW_TYPE_MAP;
854 case SWITCHTEC_FW_PART_ID_G5_MAP1: return SWITCHTEC_FW_TYPE_MAP;
855 case SWITCHTEC_FW_PART_ID_G5_KEY0: return SWITCHTEC_FW_TYPE_KEY;
856 case SWITCHTEC_FW_PART_ID_G5_KEY1: return SWITCHTEC_FW_TYPE_KEY;
857 case SWITCHTEC_FW_PART_ID_G5_RIOT0: return SWITCHTEC_FW_TYPE_RIOT;
858 case SWITCHTEC_FW_PART_ID_G5_RIOT1: return SWITCHTEC_FW_TYPE_RIOT;
859 case SWITCHTEC_FW_PART_ID_G5_BL20: return SWITCHTEC_FW_TYPE_BL2;
860 case SWITCHTEC_FW_PART_ID_G5_BL21: return SWITCHTEC_FW_TYPE_BL2;
861 case SWITCHTEC_FW_PART_ID_G5_CFG0: return SWITCHTEC_FW_TYPE_CFG;
862 case SWITCHTEC_FW_PART_ID_G5_CFG1: return SWITCHTEC_FW_TYPE_CFG;
863 case SWITCHTEC_FW_PART_ID_G5_IMG0: return SWITCHTEC_FW_TYPE_IMG;
864 case SWITCHTEC_FW_PART_ID_G5_IMG1: return SWITCHTEC_FW_TYPE_IMG;
865 case SWITCHTEC_FW_PART_ID_G5_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
866 case SWITCHTEC_FW_PART_ID_G5_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
867 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
868 }
869}
870
871static enum switchtec_fw_type
872switchtec_fw_id_to_type_gen6(const struct switchtec_fw_image_info *info)
873{
874 switch (info->part_id) {
875 case SWITCHTEC_FW_PART_ID_G6_MAP0: return SWITCHTEC_FW_TYPE_MAP;
876 case SWITCHTEC_FW_PART_ID_G6_MAP1: return SWITCHTEC_FW_TYPE_MAP;
877 case SWITCHTEC_FW_PART_ID_G6_KEY0: return SWITCHTEC_FW_TYPE_KEY;
878 case SWITCHTEC_FW_PART_ID_G6_KEY1: return SWITCHTEC_FW_TYPE_KEY;
879 case SWITCHTEC_FW_PART_ID_G6_BL20: return SWITCHTEC_FW_TYPE_BL2;
880 case SWITCHTEC_FW_PART_ID_G6_BL21: return SWITCHTEC_FW_TYPE_BL2;
881 case SWITCHTEC_FW_PART_ID_G6_CFG0: return SWITCHTEC_FW_TYPE_CFG;
882 case SWITCHTEC_FW_PART_ID_G6_CFG1: return SWITCHTEC_FW_TYPE_CFG;
883 case SWITCHTEC_FW_PART_ID_G6_IMG0: return SWITCHTEC_FW_TYPE_IMG;
884 case SWITCHTEC_FW_PART_ID_G6_IMG1: return SWITCHTEC_FW_TYPE_IMG;
885 case SWITCHTEC_FW_PART_ID_G6_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
886 case SWITCHTEC_FW_PART_ID_G6_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
887 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
888 }
889}
890
891static enum switchtec_fw_type
892switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
893{
894 switch (info->gen) {
895 case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
896 case SWITCHTEC_GEN4: return switchtec_fw_id_to_type_gen4(info);
897 case SWITCHTEC_GEN5: return switchtec_fw_id_to_type_gen5(info);
898 case SWITCHTEC_GEN6: return switchtec_fw_id_to_type_gen6(info);
899 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
900 }
901}
902
903static int switchtec_fw_file_info_gen3(int fd,
904 struct switchtec_fw_image_info *info)
905{
906 struct switchtec_fw_image_header_gen3 hdr = {};
907 int ret;
908
909 ret = read(fd, &hdr, sizeof(hdr));
910 lseek(fd, 0, SEEK_SET);
911
912 if (ret != sizeof(hdr))
913 goto invalid_file;
914
915 if (strcmp(hdr.magic, "PMC") != 0)
916 goto invalid_file;
917
918 if (info == NULL)
919 return 0;
920
921 info->gen = SWITCHTEC_GEN3;
922 info->part_id = hdr.type;
923 info->image_crc = le32toh(hdr.image_crc);
924 version_to_string(hdr.version, info->version, sizeof(info->version));
925 info->image_len = le32toh(hdr.image_len);
926
927 info->type = switchtec_fw_id_to_type(info);
928
929 info->secure_version = 0;
930 info->signed_image = 0;
931
932 return 0;
933
934invalid_file:
935 errno = ENOEXEC;
936 return -errno;
937}
938
939static enum switchtec_fw_image_part_id_gen4 hdr_type2_id_gen4(uint32_t type)
940{
941 switch (type) {
942 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
943 return SWITCHTEC_FW_PART_ID_G4_MAP0;
944
945 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
946 return SWITCHTEC_FW_PART_ID_G4_KEY0;
947
948 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
949 return SWITCHTEC_FW_PART_ID_G4_BL20;
950
951 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
952 return SWITCHTEC_FW_PART_ID_G4_CFG0;
953
954 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
955 return SWITCHTEC_FW_PART_ID_G4_IMG0;
956
957 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
958 return SWITCHTEC_FW_PART_ID_G4_NVLOG;
959
960 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
961 return SWITCHTEC_FW_PART_ID_G4_SEEPROM;
962
963 default:
964 return -1;
965 }
966}
967
968static enum switchtec_fw_image_part_id_gen5 hdr_type2_id_gen5(uint32_t type)
969{
970 switch (type) {
971 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN5:
972 return SWITCHTEC_FW_PART_ID_G5_MAP0;
973
974 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5:
975 return SWITCHTEC_FW_PART_ID_G5_KEY0;
976
977 case SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5:
978 return SWITCHTEC_FW_PART_ID_G5_RIOT0;
979
980 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN5:
981 return SWITCHTEC_FW_PART_ID_G5_BL20;
982
983 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN5:
984 return SWITCHTEC_FW_PART_ID_G5_CFG0;
985
986 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN5:
987 return SWITCHTEC_FW_PART_ID_G5_IMG0;
988
989 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5:
990 return SWITCHTEC_FW_PART_ID_G5_NVLOG;
991
992 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5:
993 return SWITCHTEC_FW_PART_ID_G5_SEEPROM;
994
995 default:
996 return -1;
997 }
998}
999
1000static int switchtec_fw_file_info_gen45(int fd,
1001 struct switchtec_fw_image_info *info)
1002{
1003 int ret;
1004 struct switchtec_fw_metadata_gen4 hdr = {};
1005 uint8_t exp_zero[4] = {};
1006 uint32_t version;
1007 int part_id;
1008
1009 ret = read(fd, &hdr, sizeof(hdr));
1010 lseek(fd, 0, SEEK_SET);
1011
1012 if (ret != sizeof(hdr))
1013 goto invalid_file;
1014
1015 if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
1016 goto invalid_file;
1017
1018 if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
1019 goto invalid_file;
1020
1021 if (!info)
1022 return 0;
1023
1024 /* Non-zero 'fw-id' field means the image is for Gen5 or later */
1025 if (hdr.fw_id)
1026 part_id = hdr_type2_id_gen5(le32toh(hdr.type));
1027 else
1028 part_id = hdr_type2_id_gen4(le32toh(hdr.type));
1029
1030 if (part_id < 0)
1031 goto invalid_file;
1032
1033 info->part_id = part_id;
1034
1035 info->image_crc = le32toh(hdr.image_crc);
1036 version = le32toh(hdr.version);
1037 version_to_string(version, info->version, sizeof(info->version));
1038 info->image_len = le32toh(hdr.image_len);
1039 info->gen = switchtec_fw_version_to_gen(version);
1040
1041 info->type = switchtec_fw_id_to_type(info);
1042
1043 info->secure_version = le32toh(hdr.secure_version);
1044 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
1045
1046 return 0;
1047
1048invalid_file:
1049 errno = ENOEXEC;
1050 return -errno;
1051}
1052
1060{
1061 char magic[4];
1062 int ret;
1063
1064 ret = read(fd, &magic, sizeof(magic));
1065 lseek(fd, 0, SEEK_SET);
1066
1067 if (ret != sizeof(magic)) {
1068 errno = ENOEXEC;
1069 return -1;
1070 }
1071
1072 if (!strncmp(magic, "PMC", sizeof(magic))) {
1073 return switchtec_fw_file_info_gen3(fd, info);
1074 } else if (!strncmp(magic, "MSCC", sizeof(magic))) {
1075 return switchtec_fw_file_info_gen45(fd, info);
1076 } else if (!strncmp(magic, "DCBI", sizeof(magic))) {
1077 return 1;
1078 } else {
1079 errno = ENOEXEC;
1080 return -1;
1081 }
1082
1083 return 0;
1084}
1085
1094int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
1095 int img_fd)
1096{
1097 int ret;
1098 struct switchtec_fw_image_info info;
1099 struct switchtec_sn_ver_info sn_info = {};
1100
1101 if (switchtec_is_gen3(dev))
1102 return 0;
1103
1104 ret = switchtec_fw_file_info(img_fd, &info);
1105 if (ret)
1106 return 0;
1107
1108 if (!info.signed_image)
1109 return 0;
1110
1111 ret = switchtec_sn_ver_get(dev, &sn_info);
1112 if (ret) {
1113 sn_info.ver_bl2 = 0xffffffff;
1114 sn_info.ver_main = 0xffffffff;
1115 sn_info.ver_km = 0xffffffff;
1116 }
1117
1118 switch (info.type) {
1119 case SWITCHTEC_FW_TYPE_BL2:
1120 if (info.secure_version > sn_info.ver_bl2)
1121 return 1;
1122
1123 break;
1124 case SWITCHTEC_FW_TYPE_IMG:
1125 if (info.secure_version > sn_info.ver_main)
1126 return 1;
1127
1128 break;
1129 case SWITCHTEC_FW_TYPE_KEY:
1130 if (info.secure_version > sn_info.ver_km)
1131 return 1;
1132
1133 break;
1134 default:
1135 break;
1136 }
1137
1138 return 0;
1139}
1140
1147{
1148 switch (info->type) {
1149 case SWITCHTEC_FW_TYPE_BOOT: return "BOOT";
1150 case SWITCHTEC_FW_TYPE_MAP: return "MAP";
1151 case SWITCHTEC_FW_TYPE_IMG: return "IMG";
1152 case SWITCHTEC_FW_TYPE_CFG: return "CFG";
1153 case SWITCHTEC_FW_TYPE_KEY: return "KEY";
1154 case SWITCHTEC_FW_TYPE_RIOT: return "RIOT";
1155 case SWITCHTEC_FW_TYPE_BL2: return "BL2";
1156 case SWITCHTEC_FW_TYPE_NVLOG: return "NVLOG";
1157 case SWITCHTEC_FW_TYPE_SEEPROM: return "SEEPROM";
1158 default: return "UNKNOWN";
1159 }
1160}
1161
1162static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
1163 struct switchtec_fw_image_info *info)
1164{
1165 uint32_t map0_update_index;
1166 uint32_t map1_update_index;
1167 int ret;
1168
1169 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
1170 sizeof(uint32_t), &map0_update_index);
1171 if (ret < 0)
1172 return ret;
1173
1174 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
1175 sizeof(uint32_t), &map1_update_index);
1176 if (ret < 0)
1177 return ret;
1178
1179 info->active = 0;
1180 if (map0_update_index > map1_update_index) {
1181 if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
1182 info->active = 1;
1183 } else {
1184 if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
1185 info->active = 1;
1186 }
1187
1188 return 0;
1189}
1190
1191static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
1192 struct switchtec_fw_image_info *inf)
1193{
1194 struct switchtec_fw_footer_gen3 *metadata;
1195 unsigned long addr;
1196 int ret = 0;
1197
1198 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1199 return 1;
1200
1201 metadata = malloc(sizeof(*metadata));
1202 if (!metadata)
1203 return -1;
1204
1205 addr = inf->part_addr + inf->part_len - sizeof(*metadata);
1206
1207 ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
1208 if (ret < 0)
1209 goto err_out;
1210
1211 if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
1212 goto err_out;
1213
1214 version_to_string(metadata->version, inf->version,
1215 sizeof(inf->version));
1216 inf->part_body_offset = 0;
1217 inf->image_crc = metadata->image_crc;
1218 inf->image_len = metadata->image_len;
1219 inf->metadata = metadata;
1220
1221 return 0;
1222
1223err_out:
1224 free(metadata);
1225 return 1;
1226}
1227
1228static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
1229 struct switchtec_fw_image_info *inf)
1230{
1231 int ret = 0;
1232
1233 inf->read_only = switchtec_fw_is_boot_ro(dev);
1234
1235 switch (inf->part_id) {
1236 case SWITCHTEC_FW_PART_ID_G3_BOOT:
1237 inf->part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
1238 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1239 inf->active = true;
1240 break;
1241 case SWITCHTEC_FW_PART_ID_G3_MAP0:
1242 inf->part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
1243 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1244 ret = switchtec_fw_map_get_active(dev, inf);
1245 break;
1246 case SWITCHTEC_FW_PART_ID_G3_MAP1:
1247 inf->part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
1248 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1249 ret = switchtec_fw_map_get_active(dev, inf);
1250 break;
1251 default:
1252 ret = switchtec_flash_part(dev, inf, inf->part_id);
1253 inf->read_only = false;
1254 }
1255
1256 if (ret)
1257 return ret;
1258
1259 inf->valid = true;
1260
1261 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1262 return 1;
1263
1264 return switchtec_fw_info_metadata_gen3(dev, inf);
1265}
1266
1267static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
1268 struct switchtec_fw_image_info *inf)
1269{
1270 struct switchtec_fw_metadata_gen4 *metadata;
1271 struct {
1272 uint8_t subcmd;
1273 uint8_t part_id;
1274 } subcmd = {
1275 .subcmd = MRPC_PART_INFO_GET_METADATA,
1276 .part_id = inf->part_id,
1277 };
1278 int ret;
1279
1280 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
1281 return 1;
1282 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
1283 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1284
1285 metadata = malloc(sizeof(*metadata));
1286 if (!metadata)
1287 return -1;
1288
1289 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1290 metadata, sizeof(*metadata));
1291 if (ret)
1292 goto err_out;
1293
1294 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1295 goto err_out;
1296
1297 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1298 goto err_out;
1299
1300 version_to_string(le32toh(metadata->version), inf->version,
1301 sizeof(inf->version));
1302 inf->part_body_offset = le32toh(metadata->header_len);
1303 inf->image_crc = le32toh(metadata->image_crc);
1304 inf->image_len = le32toh(metadata->image_len);
1305 inf->metadata = metadata;
1306
1307 return 0;
1308
1309err_out:
1310 free(metadata);
1311 return -1;
1312}
1313
1314static int switchtec_fw_info_metadata_gen5(struct switchtec_dev *dev,
1315 struct switchtec_fw_image_info *inf)
1316{
1317 struct switchtec_fw_metadata_gen5 *metadata;
1318 struct {
1319 uint8_t subcmd;
1320 uint8_t part_id;
1321 } subcmd = {
1322 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN5,
1323 .part_id = inf->part_id,
1324 };
1325 int ret;
1326
1327 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_NVLOG)
1328 return 1;
1329 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_SEEPROM)
1330 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1331
1332 metadata = malloc(sizeof(*metadata));
1333 if (!metadata)
1334 return -1;
1335
1336 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1337 metadata, sizeof(*metadata));
1338 if (ret)
1339 goto err_out;
1340
1341 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1342 goto err_out;
1343
1344 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1345 goto err_out;
1346
1347 version_to_string(le32toh(metadata->version), inf->version,
1348 sizeof(inf->version));
1349 inf->part_body_offset = le32toh(metadata->header_len);
1350 inf->image_crc = le32toh(metadata->image_crc);
1351 inf->image_len = le32toh(metadata->image_len);
1352 inf->metadata = metadata;
1353
1354 return 0;
1355
1356err_out:
1357 free(metadata);
1358 return -1;
1359}
1360
1361static int switchtec_fw_info_metadata_gen6(struct switchtec_dev *dev,
1362 struct switchtec_fw_image_info *inf)
1363{
1364 struct switchtec_fw_metadata_gen6 *metadata;
1365 struct {
1366 uint8_t subcmd;
1367 uint8_t part_id;
1368 } subcmd = {
1369 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN6,
1370 .part_id = inf->part_id,
1371 };
1372 int ret;
1373
1374 if (inf->part_id == SWITCHTEC_FW_PART_ID_G6_NVLOG)
1375 return 1;
1376 if (inf->part_id == SWITCHTEC_FW_PART_ID_G6_SEEPROM)
1377 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM_GEN6;
1378
1379 metadata = malloc(sizeof(*metadata));
1380 if (!metadata)
1381 return -1;
1382
1383 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1384 metadata, sizeof(*metadata));
1385 if (ret)
1386 goto err_out;
1387
1388 version_to_string(le32toh(metadata->version), inf->version,
1389 sizeof(inf->version));
1390 inf->part_body_offset = le32toh(metadata->header_len);
1391 inf->image_crc = le32toh(metadata->image_crc);
1392 inf->image_len = le32toh(metadata->image_len);
1393 inf->metadata = metadata;
1394
1395 return 0;
1396
1397err_out:
1398 free(metadata);
1399 return -1;
1400}
1401
1403 uint32_t firmware_version;
1404 uint32_t flash_size;
1405 uint16_t device_id;
1406 uint8_t ecc_enable;
1407 uint8_t rsvd1;
1408 uint8_t running_bl2_flag;
1409 uint8_t running_cfg_flag;
1410 uint8_t running_img_flag;
1411 uint8_t running_key_flag;
1412 uint32_t rsvd2[12];
1414 uint32_t image_crc;
1415 uint32_t image_len;
1416 uint16_t image_version;
1417 uint8_t valid;
1418 uint8_t active;
1419 uint32_t part_start;
1420 uint32_t part_end;
1421 uint32_t part_offset;
1422 uint32_t part_size_dw;
1423 uint8_t read_only;
1424 uint8_t is_using;
1425 uint8_t rsvd[2];
1426 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1427 img0, img1, nvlog, vendor[8];
1428};
1429
1431 uint32_t firmware_version;
1432 uint32_t flash_size;
1433 uint16_t device_id;
1434 uint8_t ecc_enable;
1435 uint8_t rsvd1;
1436 uint8_t running_riot_flag;
1437 uint8_t running_bl2_flag;
1438 uint8_t running_cfg_flag;
1439 uint8_t running_img_flag;
1440 uint8_t running_key_flag;
1441 uint8_t rsvd2[3];
1442 uint8_t key_redundant_flag;
1443 uint8_t riot_redundant_flag;
1444 uint8_t bl2_redundant_flag;
1445 uint8_t cfg_redundant_flag;
1446 uint8_t img_redundant_flag;
1447 uint8_t rsvd3[3];
1448 uint32_t rsvd4[9];
1449 struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1,
1450 riot0, riot1, bl20, bl21,
1451 cfg0, cfg1, img0, img1, nvlog,
1452 vendor[8];
1453};
1454
1456 uint32_t firmware_version;
1457 uint32_t flash_size;
1458 uint16_t device_id;
1459 uint8_t ecc_enable;
1460 uint8_t rsvd1;
1461 uint8_t running_bl2_flag;
1462 uint8_t running_cfg_flag;
1463 uint8_t running_img_flag;
1464 uint8_t running_key_flag;
1465 uint8_t rsvd2[4];
1466 uint8_t key_redundant_flag;
1467 uint8_t bl2_redundant_flag;
1468 uint8_t cfg_redundant_flag;
1469 uint8_t img_redundant_flag;
1470 uint8_t rsvd3[2];
1471 uint32_t rsvd4[9];
1472 struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1, bl20,
1473 bl21, cfg0, cfg1, img0, img1,
1474 nvlog, vendor[8];
1475};
1476
1477static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
1478 struct switchtec_fw_image_info *inf,
1479 struct switchtec_flash_info_gen4 *all)
1480{
1481 struct switchtec_flash_part_info_gen4 *part_info;
1482 int ret;
1483
1484 switch (inf->part_id) {
1485 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1486 part_info = &all->map0;
1487 break;
1488 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1489 part_info = &all->map1;
1490 break;
1491 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1492 part_info = &all->keyman0;
1493 break;
1494 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1495 part_info = &all->keyman1;
1496 break;
1497 case SWITCHTEC_FW_PART_ID_G4_BL20:
1498 part_info = &all->bl20;
1499 break;
1500 case SWITCHTEC_FW_PART_ID_G4_BL21:
1501 part_info = &all->bl21;
1502 break;
1503 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1504 part_info = &all->img0;
1505 break;
1506 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1507 part_info = &all->img1;
1508 break;
1509 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1510 part_info = &all->cfg0;
1511 break;
1512 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1513 part_info = &all->cfg1;
1514 break;
1515 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1516 part_info = &all->nvlog;
1517 break;
1518 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1519 if (switchtec_gen(dev) < SWITCHTEC_GEN5)
1520 return 0;
1521
1522 inf->active = true;
1523 /* length is not applicable for SEEPROM image */
1524 inf->part_len = 0xffffffff;
1525
1526 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1527 if (!ret) {
1528 inf->running = true;
1529 inf->valid = true;
1530 }
1531
1532 return 0;
1533 default:
1534 errno = EINVAL;
1535 return -1;
1536 }
1537
1538 inf->part_addr = le32toh(part_info->part_start);
1539 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1540 inf->active = part_info->active;
1541 inf->running = part_info->is_using;
1542 inf->read_only = part_info->read_only;
1543 inf->valid = part_info->valid;
1544 if (!inf->valid)
1545 return 0;
1546
1547 return switchtec_fw_info_metadata_gen4(dev, inf);
1548}
1549
1550static int switchtec_fw_part_info_gen5(struct switchtec_dev *dev,
1551 struct switchtec_fw_image_info *inf,
1552 struct switchtec_flash_info_gen5 *all)
1553{
1554 struct switchtec_flash_part_info_gen4 *part_info;
1555 int ret;
1556
1557 switch (inf->part_id) {
1558 case SWITCHTEC_FW_PART_ID_G5_MAP0:
1559 part_info = &all->map0;
1560 break;
1561 case SWITCHTEC_FW_PART_ID_G5_MAP1:
1562 part_info = &all->map1;
1563 break;
1564 case SWITCHTEC_FW_PART_ID_G5_RIOT0:
1565 inf->redundant = all->riot_redundant_flag;
1566 part_info = &all->riot0;
1567 break;
1568 case SWITCHTEC_FW_PART_ID_G5_RIOT1:
1569 inf->redundant = all->riot_redundant_flag;
1570 part_info = &all->riot1;
1571 break;
1572 case SWITCHTEC_FW_PART_ID_G5_KEY0:
1573 inf->redundant = all->key_redundant_flag;
1574 part_info = &all->keyman0;
1575 break;
1576 case SWITCHTEC_FW_PART_ID_G5_KEY1:
1577 inf->redundant = all->key_redundant_flag;
1578 part_info = &all->keyman1;
1579 break;
1580 case SWITCHTEC_FW_PART_ID_G5_BL20:
1581 inf->redundant = all->bl2_redundant_flag;
1582 part_info = &all->bl20;
1583 break;
1584 case SWITCHTEC_FW_PART_ID_G5_BL21:
1585 inf->redundant = all->bl2_redundant_flag;
1586 part_info = &all->bl21;
1587 break;
1588 case SWITCHTEC_FW_PART_ID_G5_IMG0:
1589 inf->redundant = all->img_redundant_flag;
1590 part_info = &all->img0;
1591 break;
1592 case SWITCHTEC_FW_PART_ID_G5_IMG1:
1593 inf->redundant = all->img_redundant_flag;
1594 part_info = &all->img1;
1595 break;
1596 case SWITCHTEC_FW_PART_ID_G5_CFG0:
1597 inf->redundant = all->cfg_redundant_flag;
1598 part_info = &all->cfg0;
1599 break;
1600 case SWITCHTEC_FW_PART_ID_G5_CFG1:
1601 inf->redundant = all->cfg_redundant_flag;
1602 part_info = &all->cfg1;
1603 break;
1604 case SWITCHTEC_FW_PART_ID_G5_NVLOG:
1605 part_info = &all->nvlog;
1606 break;
1607 case SWITCHTEC_FW_PART_ID_G5_SEEPROM:
1608 inf->active = true;
1609 /* length is not applicable for SEEPROM image */
1610 inf->part_len = 0xffffffff;
1611
1612 ret = switchtec_fw_info_metadata_gen5(dev, inf);
1613 if (!ret) {
1614 inf->running = true;
1615 inf->valid = true;
1616 }
1617
1618 return 0;
1619 default:
1620 errno = EINVAL;
1621 return -1;
1622 }
1623
1624 inf->part_addr = le32toh(part_info->part_start);
1625 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1626 inf->active = part_info->active;
1627 inf->running = part_info->is_using;
1628 inf->read_only = part_info->read_only;
1629 inf->valid = part_info->valid;
1630 if (!inf->valid)
1631 return 0;
1632
1633 return switchtec_fw_info_metadata_gen5(dev, inf);
1634}
1635
1636static int switchtec_fw_part_info_gen6(struct switchtec_dev *dev,
1637 struct switchtec_fw_image_info *inf,
1638 struct switchtec_flash_info_gen6 *all)
1639{
1640 struct switchtec_flash_part_info_gen4 *part_info;
1641 int ret;
1642
1643 switch (inf->part_id) {
1644 case SWITCHTEC_FW_PART_ID_G6_MAP0:
1645 part_info = &all->map0;
1646 break;
1647 case SWITCHTEC_FW_PART_ID_G6_MAP1:
1648 part_info = &all->map1;
1649 break;
1650 case SWITCHTEC_FW_PART_ID_G6_KEY0:
1651 inf->redundant = all->key_redundant_flag;
1652 part_info = &all->keyman0;
1653 break;
1654 case SWITCHTEC_FW_PART_ID_G6_KEY1:
1655 inf->redundant = all->key_redundant_flag;
1656 part_info = &all->keyman1;
1657 break;
1658 case SWITCHTEC_FW_PART_ID_G6_BL20:
1659 inf->redundant = all->bl2_redundant_flag;
1660 part_info = &all->bl20;
1661 break;
1662 case SWITCHTEC_FW_PART_ID_G6_BL21:
1663 inf->redundant = all->bl2_redundant_flag;
1664 part_info = &all->bl21;
1665 break;
1666 case SWITCHTEC_FW_PART_ID_G6_IMG0:
1667 inf->redundant = all->img_redundant_flag;
1668 part_info = &all->img0;
1669 break;
1670 case SWITCHTEC_FW_PART_ID_G6_IMG1:
1671 inf->redundant = all->img_redundant_flag;
1672 part_info = &all->img1;
1673 break;
1674 case SWITCHTEC_FW_PART_ID_G6_CFG0:
1675 inf->redundant = all->cfg_redundant_flag;
1676 part_info = &all->cfg0;
1677 break;
1678 case SWITCHTEC_FW_PART_ID_G6_CFG1:
1679 inf->redundant = all->cfg_redundant_flag;
1680 part_info = &all->cfg1;
1681 break;
1682 case SWITCHTEC_FW_PART_ID_G6_NVLOG:
1683 part_info = &all->nvlog;
1684 break;
1685 case SWITCHTEC_FW_PART_ID_G6_SEEPROM:
1686 inf->active = true;
1687 /* length is not applicable for SEEPROM image */
1688 inf->part_len = 0xffffffff;
1689
1690 ret = switchtec_fw_info_metadata_gen6(dev, inf);
1691 if (!ret) {
1692 inf->running = true;
1693 inf->valid = true;
1694 }
1695
1696 return 0;
1697 default:
1698 errno = EINVAL;
1699 return -1;
1700 }
1701
1702 inf->part_addr = le32toh(part_info->part_start);
1703 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1704 inf->active = part_info->active;
1705 inf->running = part_info->is_using;
1706 inf->read_only = part_info->read_only;
1707 inf->valid = part_info->valid;
1708 if (!inf->valid)
1709 return 0;
1710
1711 return switchtec_fw_info_metadata_gen6(dev, inf);
1712}
1713
1723static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1724 struct switchtec_fw_image_info *info)
1725{
1726 int ret;
1727 int i;
1728 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1729 struct switchtec_flash_info_gen4 all_info_gen4;
1730 struct switchtec_flash_info_gen5 all_info_gen5;
1731 struct switchtec_flash_info_gen6 all_info_gen6;
1732
1733 if (info == NULL || nr_info == 0)
1734 return -EINVAL;
1735
1736 if (dev->gen == SWITCHTEC_GEN4) {
1737 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1738 sizeof(subcmd), &all_info_gen4,
1739 sizeof(all_info_gen4));
1740 if (ret)
1741 return ret;
1742 all_info_gen4.firmware_version =
1743 le32toh(all_info_gen4.firmware_version);
1744 all_info_gen4.flash_size = le32toh(all_info_gen4.flash_size);
1745 all_info_gen4.device_id = le16toh(all_info_gen4.device_id);
1746 } else if (dev->gen == SWITCHTEC_GEN5) {
1747 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1748 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1749 sizeof(subcmd), &all_info_gen5,
1750 sizeof(all_info_gen5));
1751 if (ret)
1752 return ret;
1753 all_info_gen5.firmware_version =
1754 le32toh(all_info_gen5.firmware_version);
1755 all_info_gen5.flash_size = le32toh(all_info_gen5.flash_size);
1756 all_info_gen5.device_id = le16toh(all_info_gen5.device_id);
1757 } else if (dev->gen == SWITCHTEC_GEN6) {
1758 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN6;
1759 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1760 sizeof(subcmd), &all_info_gen6,
1761 sizeof(all_info_gen6));
1762 if (ret)
1763 return ret;
1764 all_info_gen6.firmware_version =
1765 le32toh(all_info_gen6.firmware_version);
1766 all_info_gen6.flash_size = le32toh(all_info_gen6.flash_size);
1767 all_info_gen6.device_id = le16toh(all_info_gen6.device_id);
1768 }
1769
1770 for (i = 0; i < nr_info; i++) {
1771 struct switchtec_fw_image_info *inf = &info[i];
1772 ret = 0;
1773
1774 inf->gen = dev->gen;
1775 inf->type = switchtec_fw_id_to_type(inf);
1776 inf->active = false;
1777 inf->running = false;
1778 inf->valid = false;
1779
1780 switch (info->gen) {
1781 case SWITCHTEC_GEN3:
1782 ret = switchtec_fw_part_info_gen3(dev, inf);
1783 break;
1784 case SWITCHTEC_GEN4:
1785 ret = switchtec_fw_part_info_gen4(dev, inf,
1786 &all_info_gen4);
1787 break;
1788 case SWITCHTEC_GEN5:
1789 ret = switchtec_fw_part_info_gen5(dev, inf,
1790 &all_info_gen5);
1791 break;
1792 case SWITCHTEC_GEN6:
1793 ret = switchtec_fw_part_info_gen6(dev, inf,
1794 &all_info_gen6);
1795 break;
1796 default:
1797 errno = EINVAL;
1798 return -1;
1799 }
1800
1801 if (ret < 0)
1802 return ret;
1803
1804 if (ret) {
1805 inf->version[0] = 0;
1806 inf->image_crc = 0xFFFFFFFF;
1807 inf->metadata = NULL;
1808 }
1809 }
1810
1811 return nr_info;
1812}
1813
1820struct switchtec_fw_image_info *switchtec_fw_part_data_bl2(struct switchtec_dev *dev)
1821{
1822 struct switchtec_fw_image_info *inf;
1823 struct switchtec_fw_image_info *head;
1824 int ret;
1825
1826 struct switchtec_fw_metadata_gen6 *metadata;
1827
1828 struct {
1829 uint8_t subcmd;
1830 uint8_t part_id;
1831 } subcmd = {
1832 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN6,
1833 };
1834 inf = malloc(sizeof(*inf));
1835 if (!inf)
1836 return NULL;
1837 memset(inf, 0, sizeof(*inf));
1838 head = inf;
1839
1840 for (int i = 0; i <= 9; i++) {
1841 metadata = malloc(sizeof(*metadata));
1842 if (!metadata)
1843 goto err_free_list;
1844 subcmd.part_id = i;
1845 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1846 metadata, sizeof(*metadata));
1847 if (ret) {
1848 free(metadata);
1849 goto err_free_list;
1850 }
1851 version_to_string(le32toh(metadata->version), inf->version,
1852 sizeof(inf->version));
1853 inf->metadata = metadata;
1854 inf->next = malloc(sizeof(*inf));
1855 if (!inf->next)
1856 goto err_free_list;
1857 memset(inf->next, 0, sizeof(*inf));
1858 inf = inf->next;
1859 }
1860 return head;
1861
1862err_free_list:
1864 return NULL;
1865}
1866
1867int switchtec_get_device_id_bl2(struct switchtec_dev *dev,
1868 unsigned short *device_id)
1869{
1870 int ret;
1871 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1872 struct switchtec_flash_info_gen4 all_info;
1873 struct switchtec_flash_info_gen5 all_info_gen5;
1874
1875 if (dev->gen != SWITCHTEC_GEN_UNKNOWN)
1876 return -EINVAL;
1877
1878 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1879 sizeof(subcmd), &all_info,
1880 sizeof(all_info));
1881 if (!ret) {
1882 *device_id = le16toh(all_info.device_id);
1883 } else if (ret == ERR_SUBCMD_INVALID) {
1884 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1885 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1886 sizeof(subcmd), &all_info_gen5,
1887 sizeof(all_info_gen5));
1888 if (!ret)
1889 *device_id = le16toh(all_info_gen5.device_id);
1890 }
1891
1892 return ret;
1893}
1894
1895static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1896 uint8_t index)
1897{
1898 int ret;
1899 uint32_t result;
1900
1901 subcmd |= index << 8;
1902 subcmd = htole32(subcmd);
1903
1904 ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1905 &result, sizeof(result));
1906 if (ret)
1907 return -1;
1908
1909 return result;
1910}
1911
1912static int get_multicfg(struct switchtec_dev *dev,
1913 struct switchtec_fw_image_info *info,
1914 int *nr_mult)
1915{
1916 int ret;
1917 int i;
1918
1919 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1920 if (ret < 0)
1921 return ret;
1922
1923 if (!ret) {
1924 *nr_mult = 0;
1925 return 0;
1926 }
1927
1928 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1929 if (ret < 0)
1930 return ret;
1931
1932 if (*nr_mult > ret)
1933 *nr_mult = ret;
1934
1935 for (i = 0; i < *nr_mult; i++) {
1936 info[i].part_addr = multicfg_subcmd(dev,
1937 MRPC_MULTI_CFG_START_ADDR,
1938 i);
1939 info[i].part_len = multicfg_subcmd(dev,
1940 MRPC_MULTI_CFG_LENGTH, i);
1941 strcpy(info[i].version, "");
1942 info[i].image_crc = 0;
1943 info[i].active = 0;
1944 }
1945
1946 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1947 if (ret < 0)
1948 return ret;
1949
1950 if (ret < *nr_mult)
1951 info[ret].active = 1;
1952
1953 return 0;
1954}
1955
1956static const enum switchtec_fw_image_part_id_gen3
1957switchtec_fw_partitions_gen3[] = {
1958 SWITCHTEC_FW_PART_ID_G3_BOOT,
1959 SWITCHTEC_FW_PART_ID_G3_MAP0,
1960 SWITCHTEC_FW_PART_ID_G3_MAP1,
1961 SWITCHTEC_FW_PART_ID_G3_IMG0,
1962 SWITCHTEC_FW_PART_ID_G3_DAT0,
1963 SWITCHTEC_FW_PART_ID_G3_DAT1,
1964 SWITCHTEC_FW_PART_ID_G3_NVLOG,
1965 SWITCHTEC_FW_PART_ID_G3_IMG1,
1966};
1967
1968static const enum switchtec_fw_image_part_id_gen4
1969switchtec_fw_partitions_gen4[] = {
1970 SWITCHTEC_FW_PART_ID_G4_MAP0,
1971 SWITCHTEC_FW_PART_ID_G4_MAP1,
1972 SWITCHTEC_FW_PART_ID_G4_KEY0,
1973 SWITCHTEC_FW_PART_ID_G4_KEY1,
1974 SWITCHTEC_FW_PART_ID_G4_BL20,
1975 SWITCHTEC_FW_PART_ID_G4_BL21,
1976 SWITCHTEC_FW_PART_ID_G4_CFG0,
1977 SWITCHTEC_FW_PART_ID_G4_CFG1,
1978 SWITCHTEC_FW_PART_ID_G4_IMG0,
1979 SWITCHTEC_FW_PART_ID_G4_IMG1,
1980 SWITCHTEC_FW_PART_ID_G4_NVLOG,
1981 SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1982};
1983
1984static const enum switchtec_fw_image_part_id_gen5
1985switchtec_fw_partitions_gen5[] = {
1986 SWITCHTEC_FW_PART_ID_G5_MAP0,
1987 SWITCHTEC_FW_PART_ID_G5_MAP1,
1988 SWITCHTEC_FW_PART_ID_G5_KEY0,
1989 SWITCHTEC_FW_PART_ID_G5_KEY1,
1990 SWITCHTEC_FW_PART_ID_G5_RIOT0,
1991 SWITCHTEC_FW_PART_ID_G5_RIOT1,
1992 SWITCHTEC_FW_PART_ID_G5_BL20,
1993 SWITCHTEC_FW_PART_ID_G5_BL21,
1994 SWITCHTEC_FW_PART_ID_G5_CFG0,
1995 SWITCHTEC_FW_PART_ID_G5_CFG1,
1996 SWITCHTEC_FW_PART_ID_G5_IMG0,
1997 SWITCHTEC_FW_PART_ID_G5_IMG1,
1998 SWITCHTEC_FW_PART_ID_G5_NVLOG,
1999 SWITCHTEC_FW_PART_ID_G5_SEEPROM,
2000};
2001
2002static const enum switchtec_fw_image_part_id_gen6
2003switchtec_fw_partitions_gen6[] = {
2004 SWITCHTEC_FW_PART_ID_G6_MAP0,
2005 SWITCHTEC_FW_PART_ID_G6_MAP1,
2006 SWITCHTEC_FW_PART_ID_G6_KEY0,
2007 SWITCHTEC_FW_PART_ID_G6_KEY1,
2008 SWITCHTEC_FW_PART_ID_G6_BL20,
2009 SWITCHTEC_FW_PART_ID_G6_BL21,
2010 SWITCHTEC_FW_PART_ID_G6_CFG0,
2011 SWITCHTEC_FW_PART_ID_G6_CFG1,
2012 SWITCHTEC_FW_PART_ID_G6_IMG0,
2013 SWITCHTEC_FW_PART_ID_G6_IMG1,
2014 SWITCHTEC_FW_PART_ID_G6_NVLOG,
2015 SWITCHTEC_FW_PART_ID_G6_SEEPROM,
2016};
2017
2018static struct switchtec_fw_part_type *
2019switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
2020 struct switchtec_fw_image_info *info)
2021{
2022 switch (info->type) {
2023 case SWITCHTEC_FW_TYPE_BOOT: return &summary->boot;
2024 case SWITCHTEC_FW_TYPE_MAP: return &summary->map;
2025 case SWITCHTEC_FW_TYPE_IMG: return &summary->img;
2026 case SWITCHTEC_FW_TYPE_CFG: return &summary->cfg;
2027 case SWITCHTEC_FW_TYPE_NVLOG: return &summary->nvlog;
2028 case SWITCHTEC_FW_TYPE_SEEPROM: return &summary->seeprom;
2029 case SWITCHTEC_FW_TYPE_KEY: return &summary->key;
2030 case SWITCHTEC_FW_TYPE_BL2: return &summary->bl2;
2031 case SWITCHTEC_FW_TYPE_RIOT: return &summary->riot;
2032 default: return NULL;
2033 }
2034}
2035
2044int switchtec_sms_fmc_version_get(struct switchtec_dev *dev, uint32_t *info)
2045{
2046 uint32_t cmd = htole32(MRPC_PART_INFO_GET_SMS_FMC_VERSION_GEN6);
2047 int ret;
2048
2049 if (!dev || !info) {
2050 errno = EINVAL;
2051 return -1;
2052 }
2053
2054 ret = switchtec_cmd(dev, MRPC_PART_INFO, &cmd, sizeof(cmd),
2055 info, sizeof(*info));
2056 if (ret)
2057 return ret;
2058
2059 *info = le32toh(*info);
2060
2061 return 0;
2062}
2063
2065switchtec_fw_part_summary(struct switchtec_dev *dev)
2066{
2067 struct switchtec_fw_part_summary *summary;
2068 struct switchtec_fw_image_info **infp;
2069 struct switchtec_fw_part_type *type;
2070 int nr_info, nr_mcfg = 16;
2071 size_t st_sz;
2072 int ret, i;
2073
2074 switch (dev->gen) {
2075 case SWITCHTEC_GEN3:
2076 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
2077 break;
2078 case SWITCHTEC_GEN4:
2079 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
2080 break;
2081 case SWITCHTEC_GEN5:
2082 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen5);
2083 break;
2084 case SWITCHTEC_GEN6:
2085 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen6);
2086 break;
2087 default:
2088 errno = EINVAL;
2089 return NULL;
2090 }
2091
2092 st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
2093
2094 summary = malloc(st_sz);
2095 if (!summary)
2096 return NULL;
2097
2098 memset(summary, 0, st_sz);
2099 summary->nr_info = nr_info;
2100
2101 switch (dev->gen) {
2102 case SWITCHTEC_GEN3:
2103 for (i = 0; i < nr_info; i++)
2104 summary->all[i].part_id =
2105 switchtec_fw_partitions_gen3[i];
2106 break;
2107 case SWITCHTEC_GEN4:
2108 for (i = 0; i < nr_info; i++)
2109 summary->all[i].part_id =
2110 switchtec_fw_partitions_gen4[i];
2111 break;
2112 case SWITCHTEC_GEN5:
2113 for (i = 0; i < nr_info; i++)
2114 summary->all[i].part_id =
2115 switchtec_fw_partitions_gen5[i];
2116 break;
2117 case SWITCHTEC_GEN6:
2118 for (i = 0; i < nr_info; i++)
2119 summary->all[i].part_id =
2120 switchtec_fw_partitions_gen6[i];
2121 break;
2122 default:
2123 errno = EINVAL;
2124 free(summary);
2125 return NULL;
2126 }
2127
2128 ret = switchtec_fw_part_info(dev, nr_info, summary->all);
2129 if (ret != nr_info) {
2130 free(summary);
2131 return NULL;
2132 }
2133
2134 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
2135 if (ret) {
2136 nr_mcfg = 0;
2137 errno = 0;
2138 }
2139
2140 for (i = 0; i < nr_info; i++) {
2141 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
2142 if (type == NULL) {
2143 free(summary);
2144 return NULL;
2145 }
2146 if (summary->all[i].active)
2147 type->active = &summary->all[i];
2148 else
2149 type->inactive = &summary->all[i];
2150 }
2151
2152 infp = &summary->mult_cfg;
2153 for (; i < nr_info + nr_mcfg; i++) {
2154 *infp = &summary->all[i];
2155 infp = &summary->all[i].next;
2156 }
2157
2158 return summary;
2159}
2160
2166{
2167 int i;
2168
2169 for (i = 0; i < summary->nr_info; i++)
2170 free(summary->all[i].metadata);
2171
2172 free(summary);
2173}
2174
2180{
2181 struct switchtec_fw_image_info *tmp;
2182 while (1) {
2183 if (inf->metadata)
2184 free(inf->metadata);
2185
2186 if (inf->next) {
2187 tmp = inf;
2188 inf = inf->next;
2189 free(tmp);
2190 } else {
2191 return;
2192 }
2193 }
2194}
2195
2204int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
2205 size_t len, void *buf)
2206{
2207 int ret;
2208 struct {
2209 uint32_t addr;
2210 uint32_t length;
2211 } cmd;
2212 unsigned char *cbuf = buf;
2213 size_t read = 0;
2214
2215 while (len) {
2216 size_t chunk_len = len;
2217 if (chunk_len > MRPC_MAX_DATA_LEN-8)
2218 chunk_len = MRPC_MAX_DATA_LEN-8;
2219
2220 cmd.addr = htole32(addr);
2221 cmd.length = htole32(chunk_len);
2222
2223 ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
2224 cbuf, chunk_len);
2225 if (ret)
2226 return -1;
2227
2228 addr += chunk_len;
2229 len -= chunk_len;
2230 read += chunk_len;
2231 cbuf += chunk_len;
2232 }
2233
2234 return read;
2235}
2236
2248int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
2249 unsigned long addr, size_t len,
2250 void (*progress_callback)(int cur, int tot))
2251{
2252 int ret;
2253 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
2254 size_t read = 0;
2255 size_t total_len = len;
2256 size_t total_wrote;
2257 ssize_t wrote;
2258
2259 while (len) {
2260 size_t chunk_len = len;
2261 if (chunk_len > sizeof(buf))
2262 chunk_len = sizeof(buf);
2263
2264 ret = switchtec_fw_read(dev, addr, chunk_len, buf);
2265 if (ret < 0)
2266 return ret;
2267
2268 total_wrote = 0;
2269 while (total_wrote < ret) {
2270 wrote = write(fd, &buf[total_wrote],
2271 ret - total_wrote);
2272 if (wrote < 0)
2273 return -1;
2274 total_wrote += wrote;
2275 }
2276
2277 read += ret;
2278 addr += ret;
2279 len -= ret;
2280
2281 if (progress_callback)
2282 progress_callback(read, total_len);
2283 }
2284
2285 return read;
2286}
2287
2297int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
2298 struct switchtec_fw_image_info *info,
2299 void (*progress_callback)(int cur, int tot))
2300{
2301 return switchtec_fw_read_fd(dev, fd,
2302 info->part_addr + info->part_body_offset,
2303 info->image_len, progress_callback);
2304}
2305
2306static int switchtec_fw_img_write_hdr_gen3(int fd,
2307 struct switchtec_fw_image_info *info)
2308{
2309 struct switchtec_fw_footer_gen3 *ftr = info->metadata;
2310 struct switchtec_fw_image_header_gen3 hdr = {};
2311
2312 memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
2313 hdr.image_len = ftr->image_len;
2314 hdr.type = info->part_id;
2315 hdr.load_addr = ftr->load_addr;
2316 hdr.version = ftr->version;
2317 hdr.header_crc = ftr->header_crc;
2318 hdr.image_crc = ftr->image_crc;
2319
2320 if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
2321 hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
2322 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
2323 hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
2324 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
2325 hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
2326
2327 return write(fd, &hdr, sizeof(hdr));
2328}
2329
2330static int switchtec_fw_img_write_hdr_gen4(int fd,
2331 struct switchtec_fw_image_info *info)
2332{
2333 int ret;
2334 struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
2335
2336 ret = write(fd, hdr, sizeof(*hdr));
2337 if (ret < 0)
2338 return ret;
2339
2340 return lseek(fd, info->part_body_offset, SEEK_SET);
2341}
2342
2357{
2358 switch (info->gen) {
2359 case SWITCHTEC_GEN3: return switchtec_fw_img_write_hdr_gen3(fd, info);
2360 case SWITCHTEC_GEN4:
2361 case SWITCHTEC_GEN5:
2362 case SWITCHTEC_GEN6: return switchtec_fw_img_write_hdr_gen4(fd, info);
2363 default:
2364 errno = EINVAL;
2365 return -1;
2366 }
2367}
2368
2370 uint8_t subcmd;
2371 uint8_t set_get;
2372 uint8_t status;
2373 uint8_t reserved;
2374};
2375
2382int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
2383{
2384 struct switchtec_boot_ro subcmd = {
2385 .subcmd = MRPC_FWDNLD_BOOT_RO,
2386 .set_get = 0,
2387 };
2388
2389 struct {
2390 uint8_t status;
2391 uint8_t reserved[3];
2392 } result;
2393
2394 int ret;
2395
2396 if (!switchtec_is_gen3(dev)) {
2397 errno = ENOTSUP;
2398 return -1;
2399 }
2400
2401 ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
2402 &result, sizeof(result));
2403
2404 if (ret == ERR_SUBCMD_INVALID) {
2405 errno = 0;
2406 return 0;
2407 }
2408
2409 if (ret)
2410 return ret;
2411
2412 return result.status;
2413}
2414
2421int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
2422 enum switchtec_fw_ro ro)
2423{
2424 struct switchtec_boot_ro subcmd = {
2425 .subcmd = MRPC_FWDNLD_BOOT_RO,
2426 .set_get = 1,
2427 .status = ro,
2428 };
2429
2430 if (!switchtec_is_gen3(dev)) {
2431 errno = ENOTSUP;
2432 return -1;
2433 }
2434
2435 return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
2436 NULL, 0);
2437}
2438
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.
Definition platform.c:178
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
Definition fw.c:623
int switchtec_fw_img_get(struct switchtec_dev *dev, int fd, enum switchtec_fw_type_gen6 fw_type, int fw_slot, void(*progress_callback)(int cur, int tot))
Download fwimg file from device.
Definition fw.c:367
int switchtec_fw_img_write_hdr(int fd, struct switchtec_fw_image_info *info)
Write the header for a Switchtec firmware image file.
Definition fw.c:2356
int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr, size_t len, void *buf)
Read a Switchtec device's flash data.
Definition fw.c:2204
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.
Definition fw.c:2297
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.
Definition fw.c:1094
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.
Definition fw.c:2248
struct switchtec_fw_image_info * switchtec_fw_part_data_bl2(struct switchtec_dev *dev)
Return the firmware image information using supported metadata MRPC commands for the gen6 BL2 phase.
Definition fw.c:1820
int switchtec_sms_fmc_version_get(struct switchtec_dev *dev, uint32_t *info)
Return firmware summary information structure for the flash partitfons in the device.
Definition fw.c:2044
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition fw.c:2382
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition fw.c:1059
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.
Definition fw.c:531
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition fw.c:750
void switchtec_fw_image_info_free(struct switchtec_fw_image_info *inf)
Free a firmware image info data structure.
Definition fw.c:2179
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.
Definition fw.c:1723
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.
Definition fw.c:2421
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition fw.c:2165
int switchtec_fw_set_redundant_flag(struct switchtec_dev *dev, int keyman, int riot, int bl2, int cfg, int fw, int set)
Set the redundant image flag for the specified image types.
Definition fw.c:334
int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev, int toggle_bl2, int toggle_key, int toggle_fw, int toggle_cfg, int toggle_riotcore)
Toggle the active firmware partition for the main or configuration images.
Definition fw.c:454
const char * switchtec_fw_image_type(const struct switchtec_fw_image_info *info)
Return a string describing the type of a firmware image.
Definition fw.c:1146
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.
Definition fw.c:654
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.
Definition platform.c:298
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Definition mfg.c:2105
Definition fw.c:508
Information about a firmware image or partition.
Definition switchtec.h:305
enum switchtec_gen gen
Image generation.
Definition switchtec.h:306
size_t part_body_offset
Partition image body offset.
Definition switchtec.h:312
unsigned long image_crc
CRC checksum of the image.
Definition switchtec.h:314
char version[32]
Firmware/Config version.
Definition switchtec.h:309
size_t image_len
Length of the image.
Definition switchtec.h:313
unsigned long part_id
Image partition ID.
Definition switchtec.h:307
size_t part_addr
Address of the partition.
Definition switchtec.h:310
size_t part_len
Length of the partition.
Definition switchtec.h:311
enum switchtec_fw_type type
Image partition type.
Definition switchtec.h:308
Main Switchtec header.
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition switchtec.h:1085
switchtec_gen
The PCIe generations.
Definition switchtec.h:94
switchtec_fw_type_gen6
Definition switchtec.h:281
static int switchtec_is_gen6(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 6 device.
Definition switchtec.h:524
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:116
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:516
switchtec_fw_dlstatus
Firmware update status.
Definition switchtec.h:1054
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:500