Switchtec Userspace PROJECT_NUMBER = 3.1
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
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
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
78 char magic[4];
79 char sub_magic[4];
80 uint32_t hdr_version;
81 uint32_t secure_version;
82 uint32_t header_len;
83 uint32_t metadata_len;
84 uint32_t image_len;
85 uint32_t type;
86 uint32_t rsvd;
87 uint32_t version;
88 uint32_t sequence;
89 uint32_t reserved1;
90 uint8_t date_str[8];
91 uint8_t time_str[8];
92 uint8_t img_str[16];
93 uint8_t rsvd1[4];
94 uint32_t image_crc;
95 uint8_t public_key_modulus[512];
96 uint8_t public_key_exponent[4];
97 uint8_t uart_port;
98 uint8_t uart_rate;
99 uint8_t bist_enable;
100 uint8_t bist_gpio_pin_cfg;
101 uint8_t bist_gpio_level_cfg;
102 uint8_t rsvd2[3];
103 uint32_t xml_version;
104 uint32_t relocatable_img_len;
105 uint32_t link_addr;
106 uint32_t header_crc;
107};
108
110 char magic[4];
111 uint32_t image_len;
112 uint32_t type;
113 uint32_t load_addr;
114 uint32_t version;
115 uint32_t rsvd[9];
116 uint32_t header_crc;
117 uint32_t image_crc;
118};
119
120static int switchtec_fw_dlstatus(struct switchtec_dev *dev,
121 enum switchtec_fw_dlstatus *status,
122 enum mrpc_bg_status *bgstatus)
123{
124 uint32_t cmd = MRPC_FWDNLD;
125 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
126 struct {
127 uint8_t dlstatus;
128 uint8_t bgstatus;
129 uint16_t reserved;
130 } result;
131 int ret;
132
133 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
134 cmd = MRPC_FW_TX;
135
136 ret = switchtec_cmd(dev, cmd, &subcmd, sizeof(subcmd),
137 &result, sizeof(result));
138
139 if (ret)
140 return ret;
141
142 if (status != NULL)
143 *status = result.dlstatus;
144
145 if (bgstatus != NULL)
146 *bgstatus = result.bgstatus;
147
148 return 0;
149}
150
151static int switchtec_fw_wait(struct switchtec_dev *dev,
152 enum switchtec_fw_dlstatus *status)
153{
154 enum mrpc_bg_status bgstatus;
155 int ret;
156
157 do {
158 // Delay slightly to avoid interrupting the firmware too much
159 usleep(5000);
160
161 ret = switchtec_fw_dlstatus(dev, status, &bgstatus);
162 if (ret < 0)
163 return ret;
164
165 if (bgstatus == MRPC_BG_STAT_OFFSET)
166 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
167
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)
173 return *status;
174 else
175 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
176 }
177
178 } while (bgstatus == MRPC_BG_STAT_INPROGRESS);
179
180 return 0;
181}
182
193int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev,
194 int toggle_bl2, int toggle_key,
195 int toggle_fw, int toggle_cfg)
196{
197 uint32_t cmd_id;
198 struct {
199 uint8_t subcmd;
200 uint8_t toggle_fw;
201 uint8_t toggle_cfg;
202 uint8_t toggle_bl2;
203 uint8_t toggle_key;
204 } cmd;
205
206 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) {
207 cmd_id = MRPC_FW_TX;
208 cmd.subcmd = MRPC_FW_TX_TOGGLE;
209 } else {
210 cmd_id = MRPC_FWDNLD;
211 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
212 }
213
214 cmd.toggle_bl2 = !!toggle_bl2;
215 cmd.toggle_key = !!toggle_key;
216 cmd.toggle_fw = !!toggle_fw;
217 cmd.toggle_cfg = !!toggle_cfg;
218
219 return switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
220 NULL, 0);
221}
222
223static enum switchtec_fw_part_type_gen4
224switchtec_fw_type_gen4(enum switchtec_fw_type type)
225{
226 switch (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;
241 default:
242 return SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN4;
243 };
244}
245
255int switchtec_fw_setup_redundancy(struct switchtec_dev *dev,
256 enum switchtec_fw_redundancy redund,
257 enum switchtec_fw_type type)
258{
259 int ret;
260
261 struct set_fw_redundancy{
262 uint8_t sub_cmd;
263 uint8_t part_type;
264 uint8_t flag;
265 uint8_t rsvd;
266 } cmd = {
267 .sub_cmd = MRPC_FWDNLD_SET_REDUNDANCY,
268 .part_type = switchtec_fw_type_gen4(type),
269 .flag = redund,
270 };
271
272 if (switchtec_is_gen3(dev)) {
273 errno = ENOTSUP;
274 return -1;
275 }
276
277 ret = switchtec_cmd(dev, MRPC_FWDNLD, &cmd, sizeof(cmd), NULL, 0);
278
279 return ret;
280}
281
282struct cmd_fwdl {
284 uint8_t subcmd;
285 uint8_t dont_activate;
286 uint8_t reserved[2];
287 uint32_t offset;
288 uint32_t img_length;
289 uint32_t blk_length;
290 } hdr;
291 uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
292};
293
305int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
306 int dont_activate, int force,
307 void (*progress_callback)(int cur, int tot))
308{
309 enum switchtec_fw_dlstatus status;
310 enum mrpc_bg_status bgstatus;
311 ssize_t image_size, offset = 0;
312 int ret;
313 struct cmd_fwdl cmd = {};
314 uint32_t cmd_id = MRPC_FWDNLD;
315
316 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
317 cmd_id = MRPC_FW_TX;
318
319 image_size = lseek(img_fd, 0, SEEK_END);
320 if (image_size < 0)
321 return -errno;
322 lseek(img_fd, 0, SEEK_SET);
323
324 switchtec_fw_dlstatus(dev, &status, &bgstatus);
325
326 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
327 errno = EBUSY;
328 return -EBUSY;
329 }
330
331 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
332 errno = EBUSY;
333 return -EBUSY;
334 }
335
336 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
337 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
338 else
339 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
340
341 cmd.hdr.dont_activate = !!dont_activate;
342 cmd.hdr.img_length = htole32(image_size);
343
344 while (offset < image_size) {
345 ssize_t blklen = read(img_fd, &cmd.data,
346 sizeof(cmd.data));
347
348 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
349 continue;
350
351 if (blklen < 0)
352 return -errno;
353
354 if (blklen == 0)
355 break;
356
357 cmd.hdr.offset = htole32(offset);
358 cmd.hdr.blk_length = htole32(blklen);
359
360 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
361 NULL, 0);
362
363 if (ret)
364 return ret;
365
366 ret = switchtec_fw_wait(dev, &status);
367 if (ret != 0)
368 return ret;
369
370 offset += le32toh(cmd.hdr.blk_length);
371
372 if (progress_callback)
373 progress_callback(offset, image_size);
374
375 }
376
377 if (status == SWITCHTEC_DLSTAT_COMPLETES)
378 return 0;
379
380 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
381 return 0;
382
383 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
384 return 0;
385
386 if (status == 0)
387 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
388
389 return status;
390}
391
398{
399 uint8_t major = (version >> 24) & 0xff;
400
401 switch (major) {
402 case 1:
403 case 2: return SWITCHTEC_GEN3;
404 case 3:
405 case 4:
406 case 5: return SWITCHTEC_GEN4;
407 case 6:
408 case 7:
409 case 8: return SWITCHTEC_GEN5;
410 default: return SWITCHTEC_GEN_UNKNOWN;
411 }
412}
413
425int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
426 int dont_activate, int force,
427 void (*progress_callback)(int cur, int tot))
428{
429 enum switchtec_fw_dlstatus status;
430 enum mrpc_bg_status bgstatus;
431 ssize_t image_size, offset = 0;
432 int ret;
433 struct cmd_fwdl cmd = {};
434 uint32_t cmd_id = MRPC_FWDNLD;
435
436 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
437 cmd_id = MRPC_FW_TX;
438
439 ret = fseek(fimg, 0, SEEK_END);
440 if (ret)
441 return -errno;
442 image_size = ftell(fimg);
443 if (image_size < 0)
444 return -errno;
445 ret = fseek(fimg, 0, SEEK_SET);
446 if (ret)
447 return -errno;
448
449 switchtec_fw_dlstatus(dev, &status, &bgstatus);
450
451 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
452 errno = EBUSY;
453 return -EBUSY;
454 }
455
456 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
457 errno = EBUSY;
458 return -EBUSY;
459 }
460
461 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
462 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
463 else
464 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
465
466 cmd.hdr.dont_activate = !!dont_activate;
467 cmd.hdr.img_length = htole32(image_size);
468
469 while (offset < image_size) {
470 ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
471
472 if (blklen == 0) {
473 ret = ferror(fimg);
474 if (ret)
475 return ret;
476 break;
477 }
478
479 cmd.hdr.offset = htole32(offset);
480 cmd.hdr.blk_length = htole32(blklen);
481
482 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
483 NULL, 0);
484
485 if (ret)
486 return ret;
487
488 ret = switchtec_fw_wait(dev, &status);
489 if (ret != 0)
490 return ret;
491
492 offset += le32toh(cmd.hdr.blk_length);
493
494 if (progress_callback)
495 progress_callback(offset, image_size);
496 }
497
498 if (status == SWITCHTEC_DLSTAT_COMPLETES)
499 return 0;
500
501 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
502 return 0;
503
504 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
505 return 0;
506
507 if (status == 0)
508 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
509
510 return status;
511}
512
521void switchtec_fw_perror(const char *s, int ret)
522{
523 const char *msg;
524
525 if (ret <= 0) {
526 perror(s);
527 return;
528 }
529
530 switch(ret) {
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;
565
566 case SWITCHTEC_DLSTAT_NO_FILE:
567 msg = "No Image Transferred"; break;
568 default:
569 fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
570 return;
571 }
572
573 fprintf(stderr, "%s: %s\n", s, msg);
574}
575
576static enum switchtec_fw_type
577switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
578{
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;
589
590 //Legacy
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;
595
596 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
597 }
598}
599
600static enum switchtec_fw_type
601switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
602{
603 switch (info->part_id) {
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;
617 }
618}
619
620static enum switchtec_fw_type
621switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
622{
623 switch (info->gen) {
624 case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
625 case SWITCHTEC_GEN4:
626 case SWITCHTEC_GEN5: return switchtec_fw_id_to_type_gen4(info);
627 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
628 }
629}
630
631static int switchtec_fw_file_info_gen3(int fd,
632 struct switchtec_fw_image_info *info)
633{
634 struct switchtec_fw_image_header_gen3 hdr = {};
635 int ret;
636
637 ret = read(fd, &hdr, sizeof(hdr));
638 lseek(fd, 0, SEEK_SET);
639
640 if (ret != sizeof(hdr))
641 goto invalid_file;
642
643 if (strcmp(hdr.magic, "PMC") != 0)
644 goto invalid_file;
645
646 if (info == NULL)
647 return 0;
648
649 info->gen = SWITCHTEC_GEN3;
650 info->part_id = hdr.type;
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);
654
655 info->type = switchtec_fw_id_to_type(info);
656
657 info->secure_version = 0;
658 info->signed_image = 0;
659
660 return 0;
661
662invalid_file:
663 errno = ENOEXEC;
664 return -errno;
665}
666
667static int switchtec_fw_file_info_gen4(int fd,
668 struct switchtec_fw_image_info *info)
669{
670 int ret;
671 struct switchtec_fw_metadata_gen4 hdr = {};
672 uint8_t exp_zero[4] = {};
673 uint32_t version;
674
675 ret = read(fd, &hdr, sizeof(hdr));
676 lseek(fd, 0, SEEK_SET);
677
678 if (ret != sizeof(hdr))
679 goto invalid_file;
680
681 if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
682 goto invalid_file;
683
684 if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
685 goto invalid_file;
686
687 if (!info)
688 return 0;
689
690 switch (le32toh(hdr.type)) {
691 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
692 info->part_id = SWITCHTEC_FW_PART_ID_G4_MAP0;
693 break;
694 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
695 info->part_id = SWITCHTEC_FW_PART_ID_G4_KEY0;
696 break;
697 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
698 info->part_id = SWITCHTEC_FW_PART_ID_G4_BL20;
699 break;
700 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
701 info->part_id = SWITCHTEC_FW_PART_ID_G4_CFG0;
702 break;
703 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
704 info->part_id = SWITCHTEC_FW_PART_ID_G4_IMG0;
705 break;
706 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
707 info->part_id = SWITCHTEC_FW_PART_ID_G4_NVLOG;
708 break;
709 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
710 info->part_id = SWITCHTEC_FW_PART_ID_G4_SEEPROM;
711 break;
712 default:
713 goto invalid_file;
714 };
715
716 info->image_crc = le32toh(hdr.image_crc);
717 version = le32toh(hdr.version);
718 version_to_string(version, info->version, sizeof(info->version));
719 info->image_len = le32toh(hdr.image_len);
720 info->gen = switchtec_fw_version_to_gen(version);
721
722 info->type = switchtec_fw_id_to_type(info);
723
724 info->secure_version = le32toh(hdr.secure_version);
725 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
726
727 return 0;
728
729invalid_file:
730 errno = ENOEXEC;
731 return -errno;
732}
733
741{
742 char magic[4];
743 int ret;
744
745 ret = read(fd, &magic, sizeof(magic));
746 lseek(fd, 0, SEEK_SET);
747
748 if (ret != sizeof(magic)) {
749 errno = ENOEXEC;
750 return -1;
751 }
752
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);
757 } else {
758 errno = ENOEXEC;
759 return -1;
760 }
761
762 return 0;
763}
764
773int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
774 int img_fd)
775{
776 int ret;
777 struct switchtec_fw_image_info info;
778 struct switchtec_sn_ver_info sn_info = {};
779
780 if (switchtec_is_gen3(dev))
781 return 0;
782
783 ret = switchtec_fw_file_info(img_fd, &info);
784 if (ret)
785 return 0;
786
787 if (!info.signed_image)
788 return 0;
789
790 ret = switchtec_sn_ver_get(dev, &sn_info);
791 if (ret) {
792 sn_info.ver_bl2 = 0xffffffff;
793 sn_info.ver_main = 0xffffffff;
794 sn_info.ver_km = 0xffffffff;
795 }
796
797 switch (info.type) {
798 case SWITCHTEC_FW_TYPE_BL2:
799 if (info.secure_version > sn_info.ver_bl2)
800 return 1;
801
802 break;
803 case SWITCHTEC_FW_TYPE_IMG:
804 if (info.secure_version > sn_info.ver_main)
805 return 1;
806
807 break;
808 case SWITCHTEC_FW_TYPE_KEY:
809 if (info.secure_version > sn_info.ver_km)
810 return 1;
811
812 break;
813 default:
814 break;
815 }
816
817 return 0;
818}
819
826{
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";
837 }
838}
839
840static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
841 struct switchtec_fw_image_info *info)
842{
843 uint32_t map0_update_index;
844 uint32_t map1_update_index;
845 int ret;
846
847 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
848 sizeof(uint32_t), &map0_update_index);
849 if (ret < 0)
850 return ret;
851
852 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
853 sizeof(uint32_t), &map1_update_index);
854 if (ret < 0)
855 return ret;
856
857 info->active = 0;
858 if (map0_update_index > map1_update_index) {
859 if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
860 info->active = 1;
861 } else {
862 if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
863 info->active = 1;
864 }
865
866 return 0;
867}
868
869static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
870 struct switchtec_fw_image_info *inf)
871{
872 struct switchtec_fw_footer_gen3 *metadata;
873 unsigned long addr;
874 int ret = 0;
875
876 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
877 return 1;
878
879 metadata = malloc(sizeof(*metadata));
880 if (!metadata)
881 return -1;
882
883 addr = inf->part_addr + inf->part_len - sizeof(*metadata);
884
885 ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
886 if (ret < 0)
887 goto err_out;
888
889 if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
890 goto err_out;
891
892 version_to_string(metadata->version, inf->version,
893 sizeof(inf->version));
894 inf->part_body_offset = 0;
895 inf->image_crc = metadata->image_crc;
896 inf->image_len = metadata->image_len;
897 inf->metadata = metadata;
898
899 return 0;
900
901err_out:
902 free(metadata);
903 return 1;
904}
905
906static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
907 struct switchtec_fw_image_info *inf)
908{
909 int ret = 0;
910
911 inf->read_only = switchtec_fw_is_boot_ro(dev);
912
913 switch (inf->part_id) {
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;
917 inf->active = true;
918 break;
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);
923 break;
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);
928 break;
929 default:
930 ret = switchtec_flash_part(dev, inf, inf->part_id);
931 inf->read_only = false;
932 }
933
934 if (ret)
935 return ret;
936
937 inf->valid = true;
938
939 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
940 return 1;
941
942 return switchtec_fw_info_metadata_gen3(dev, inf);
943}
944
945static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
946 struct switchtec_fw_image_info *inf)
947{
948 struct switchtec_fw_metadata_gen4 *metadata;
949 struct {
950 uint8_t subcmd;
951 uint8_t part_id;
952 } subcmd = {
953 .subcmd = MRPC_PART_INFO_GET_METADATA,
954 .part_id = inf->part_id,
955 };
956 int ret;
957
958 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
959 return 1;
960 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
961 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
962
963 metadata = malloc(sizeof(*metadata));
964 if (!metadata)
965 return -1;
966
967 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
968 metadata, sizeof(*metadata));
969 if (ret)
970 goto err_out;
971
972 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
973 goto err_out;
974
975 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
976 goto err_out;
977
978 version_to_string(le32toh(metadata->version), inf->version,
979 sizeof(inf->version));
980 inf->part_body_offset = le32toh(metadata->header_len);
981 inf->image_crc = le32toh(metadata->image_crc);
982 inf->image_len = le32toh(metadata->image_len);
983 inf->metadata = metadata;
984
985 return 0;
986
987err_out:
988 free(metadata);
989 return -1;
990}
991
993 uint32_t firmware_version;
994 uint32_t flash_size;
995 uint16_t device_id;
996 uint8_t ecc_enable;
997 uint8_t rsvd1;
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;
1006 uint32_t rsvd2[11];
1008 uint32_t image_crc;
1009 uint32_t image_len;
1010 uint16_t image_version;
1011 uint8_t valid;
1012 uint8_t active;
1013 uint32_t part_start;
1014 uint32_t part_end;
1015 uint32_t part_offset;
1016 uint32_t part_size_dw;
1017 uint8_t read_only;
1018 uint8_t is_using;
1019 uint8_t rsvd[2];
1020 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1021 img0, img1, nvlog, vendor[8];
1022};
1023
1024static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
1025 struct switchtec_fw_image_info *inf,
1026 struct switchtec_flash_info_gen4 *all)
1027{
1028 struct switchtec_flash_part_info_gen4 *part_info;
1029 int ret;
1030
1031 switch(inf->part_id) {
1032 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1033 part_info = &all->map0;
1034 break;
1035 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1036 part_info = &all->map1;
1037 break;
1038 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1039 part_info = &all->keyman0;
1040 inf->redundant = all->redundancy_key_flag;
1041 break;
1042 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1043 part_info = &all->keyman1;
1044 inf->redundant = all->redundancy_key_flag;
1045 break;
1046 case SWITCHTEC_FW_PART_ID_G4_BL20:
1047 part_info = &all->bl20;
1048 inf->redundant = all->redundancy_bl2_flag;
1049 break;
1050 case SWITCHTEC_FW_PART_ID_G4_BL21:
1051 part_info = &all->bl21;
1052 inf->redundant = all->redundancy_bl2_flag;
1053 break;
1054 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1055 part_info = &all->img0;
1056 inf->redundant = all->redundancy_img_flag;
1057 break;
1058 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1059 part_info = &all->img1;
1060 inf->redundant = all->redundancy_img_flag;
1061 break;
1062 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1063 part_info = &all->cfg0;
1064 inf->redundant = all->redundancy_cfg_flag;
1065 break;
1066 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1067 part_info = &all->cfg1;
1068 inf->redundant = all->redundancy_cfg_flag;
1069 break;
1070 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1071 part_info = &all->nvlog;
1072 break;
1073 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1074 if (switchtec_gen(dev) < SWITCHTEC_GEN5)
1075 return 0;
1076
1077 inf->active = true;
1078 /* length is not applicable for SEEPROM image */
1079 inf->part_len = 0xffffffff;
1080
1081 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1082 if (!ret) {
1083 inf->running = true;
1084 inf->valid = true;
1085 }
1086
1087 return 0;
1088 default:
1089 errno = EINVAL;
1090 return -1;
1091 }
1092
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;
1099 if (!inf->valid)
1100 return 0;
1101
1102 return switchtec_fw_info_metadata_gen4(dev, inf);
1103}
1104
1114static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1115 struct switchtec_fw_image_info *info)
1116{
1117 int ret;
1118 int i;
1119 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1120 struct switchtec_flash_info_gen4 all_info;
1121
1122 if (info == NULL || nr_info == 0)
1123 return -EINVAL;
1124
1125 if (dev->gen > SWITCHTEC_GEN3) {
1126 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1127 sizeof(subcmd), &all_info,
1128 sizeof(all_info));
1129 if (ret)
1130 return ret;
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);
1134 }
1135
1136 for (i = 0; i < nr_info; i++) {
1137 struct switchtec_fw_image_info *inf = &info[i];
1138 ret = 0;
1139
1140 inf->gen = dev->gen;
1141 inf->type = switchtec_fw_id_to_type(inf);
1142 inf->active = false;
1143 inf->running = false;
1144 inf->valid = false;
1145
1146 switch (info->gen) {
1147 case SWITCHTEC_GEN3:
1148 ret = switchtec_fw_part_info_gen3(dev, inf);
1149 break;
1150 case SWITCHTEC_GEN4:
1151 case SWITCHTEC_GEN5:
1152 ret = switchtec_fw_part_info_gen4(dev, inf, &all_info);
1153 break;
1154 default:
1155 errno = EINVAL;
1156 return -1;
1157 }
1158
1159 if (ret < 0)
1160 return ret;
1161
1162 if (ret) {
1163 inf->version[0] = 0;
1164 inf->image_crc = 0xFFFFFFFF;
1165 inf->metadata = NULL;
1166 }
1167 }
1168
1169 return nr_info;
1170}
1171
1172static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1173 uint8_t index)
1174{
1175 int ret;
1176 uint32_t result;
1177
1178 subcmd |= index << 8;
1179 subcmd = htole32(subcmd);
1180
1181 ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1182 &result, sizeof(result));
1183 if (ret)
1184 return -1;
1185
1186 return result;
1187}
1188
1189static int get_multicfg(struct switchtec_dev *dev,
1190 struct switchtec_fw_image_info *info,
1191 int *nr_mult)
1192{
1193 int ret;
1194 int i;
1195
1196 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1197 if (ret < 0)
1198 return ret;
1199
1200 if (!ret) {
1201 *nr_mult = 0;
1202 return 0;
1203 }
1204
1205 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1206 if (ret < 0)
1207 return ret;
1208
1209 if (*nr_mult > ret)
1210 *nr_mult = ret;
1211
1212 for (i = 0; i < *nr_mult; i++) {
1213 info[i].part_addr = multicfg_subcmd(dev,
1214 MRPC_MULTI_CFG_START_ADDR,
1215 i);
1216 info[i].part_len = multicfg_subcmd(dev,
1217 MRPC_MULTI_CFG_LENGTH, i);
1218 strcpy(info[i].version, "");
1219 info[i].image_crc = 0;
1220 info[i].active = 0;
1221 }
1222
1223 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1224 if (ret < 0)
1225 return ret;
1226
1227 if (ret < *nr_mult)
1228 info[ret].active = 1;
1229
1230 return 0;
1231}
1232
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,
1243};
1244
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,
1259};
1260
1261static struct switchtec_fw_part_type *
1262switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
1263 struct switchtec_fw_image_info *info)
1264{
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;
1275 }
1276}
1277
1287switchtec_fw_part_summary(struct switchtec_dev *dev)
1288{
1289 struct switchtec_fw_part_summary *summary;
1290 struct switchtec_fw_image_info **infp;
1291 struct switchtec_fw_part_type *type;
1292 int nr_info, nr_mcfg = 16;
1293 size_t st_sz;
1294 int ret, i;
1295
1296 switch (dev->gen) {
1297 case SWITCHTEC_GEN3:
1298 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1299 break;
1300 case SWITCHTEC_GEN4:
1301 case SWITCHTEC_GEN5:
1302 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1303 break;
1304 default:
1305 errno = EINVAL;
1306 return NULL;
1307 }
1308
1309 st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
1310
1311 summary = malloc(st_sz);
1312 if (!summary)
1313 return NULL;
1314
1315 memset(summary, 0, st_sz);
1316 summary->nr_info = nr_info;
1317
1318 switch (dev->gen) {
1319 case SWITCHTEC_GEN3:
1320 for (i = 0; i < nr_info; i++)
1321 summary->all[i].part_id =
1322 switchtec_fw_partitions_gen3[i];
1323 break;
1324 case SWITCHTEC_GEN4:
1325 case SWITCHTEC_GEN5:
1326 for (i = 0; i < nr_info; i++)
1327 summary->all[i].part_id =
1328 switchtec_fw_partitions_gen4[i];
1329 break;
1330 default:
1331 errno = EINVAL;
1332 return NULL;
1333 }
1334
1335 ret = switchtec_fw_part_info(dev, nr_info, summary->all);
1336 if (ret != nr_info) {
1337 free(summary);
1338 return NULL;
1339 }
1340
1341 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1342 if (ret) {
1343 nr_mcfg = 0;
1344 errno = 0;
1345 }
1346
1347 for (i = 0; i < nr_info; i++) {
1348 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1349 if (type == NULL) {
1350 free(summary);
1351 return NULL;
1352 }
1353 if (summary->all[i].active)
1354 type->active = &summary->all[i];
1355 else
1356 type->inactive = &summary->all[i];
1357 }
1358
1359 infp = &summary->mult_cfg;
1360 for (; i < nr_info + nr_mcfg; i++) {
1361 *infp = &summary->all[i];
1362 infp = &summary->all[i].next;
1363 }
1364
1365 return summary;
1366}
1367
1373{
1374 int i;
1375
1376 for (i = 0; i < summary->nr_info; i++)
1377 free(summary->all[i].metadata);
1378
1379 free(summary);
1380}
1381
1390int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
1391 size_t len, void *buf)
1392{
1393 int ret;
1394 struct {
1395 uint32_t addr;
1396 uint32_t length;
1397 } cmd;
1398 unsigned char *cbuf = buf;
1399 size_t read = 0;
1400
1401 while(len) {
1402 size_t chunk_len = len;
1403 if (chunk_len > MRPC_MAX_DATA_LEN-8)
1404 chunk_len = MRPC_MAX_DATA_LEN-8;
1405
1406 cmd.addr = htole32(addr);
1407 cmd.length = htole32(chunk_len);
1408
1409 ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
1410 cbuf, chunk_len);
1411 if (ret)
1412 return -1;
1413
1414 addr += chunk_len;
1415 len -= chunk_len;
1416 read += chunk_len;
1417 cbuf += chunk_len;
1418 }
1419
1420 return read;
1421}
1422
1434int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
1435 unsigned long addr, size_t len,
1436 void (*progress_callback)(int cur, int tot))
1437{
1438 int ret;
1439 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1440 size_t read = 0;
1441 size_t total_len = len;
1442 size_t total_wrote;
1443 ssize_t wrote;
1444
1445 while(len) {
1446 size_t chunk_len = len;
1447 if (chunk_len > sizeof(buf))
1448 chunk_len = sizeof(buf);
1449
1450 ret = switchtec_fw_read(dev, addr, chunk_len, buf);
1451 if (ret < 0)
1452 return ret;
1453
1454 total_wrote = 0;
1455 while (total_wrote < ret) {
1456 wrote = write(fd, &buf[total_wrote],
1457 ret - total_wrote);
1458 if (wrote < 0)
1459 return -1;
1460 total_wrote += wrote;
1461 }
1462
1463 read += ret;
1464 addr += ret;
1465 len -= ret;
1466
1467 if (progress_callback)
1468 progress_callback(read, total_len);
1469 }
1470
1471 return read;
1472}
1473
1483int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
1484 struct switchtec_fw_image_info *info,
1485 void (*progress_callback)(int cur, int tot))
1486{
1487 return switchtec_fw_read_fd(dev, fd,
1488 info->part_addr + info->part_body_offset,
1489 info->image_len, progress_callback);
1490}
1491
1492static int switchtec_fw_img_write_hdr_gen3(int fd,
1493 struct switchtec_fw_image_info *info)
1494{
1495 struct switchtec_fw_footer_gen3 *ftr = info->metadata;
1496 struct switchtec_fw_image_header_gen3 hdr = {};
1497
1498 memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
1499 hdr.image_len = ftr->image_len;
1500 hdr.type = info->part_id;
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;
1505
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;
1512
1513 return write(fd, &hdr, sizeof(hdr));
1514}
1515
1516static int switchtec_fw_img_write_hdr_gen4(int fd,
1517 struct switchtec_fw_image_info *info)
1518{
1519 int ret;
1520 struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
1521
1522 ret = write(fd, hdr, sizeof(*hdr));
1523 if (ret < 0)
1524 return ret;
1525
1526 return lseek(fd, info->part_body_offset, SEEK_SET);
1527}
1528
1543{
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);
1548 default:
1549 errno = EINVAL;
1550 return -1;
1551 }
1552}
1553
1555 uint8_t subcmd;
1556 uint8_t set_get;
1557 uint8_t status;
1558 uint8_t reserved;
1559};
1560
1567int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
1568{
1569 struct switchtec_boot_ro subcmd = {
1570 .subcmd = MRPC_FWDNLD_BOOT_RO,
1571 .set_get = 0,
1572 };
1573
1574 struct {
1575 uint8_t status;
1576 uint8_t reserved[3];
1577 } result;
1578
1579 int ret;
1580
1581 if (!switchtec_is_gen3(dev)) {
1582 errno = ENOTSUP;
1583 return -1;
1584 }
1585
1586 ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1587 &result, sizeof(result));
1588
1589 if (ret == ERR_SUBCMD_INVALID) {
1590 errno = 0;
1591 return 0;
1592 }
1593
1594 if (ret)
1595 return ret;
1596
1597 return result.status;
1598}
1599
1606int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
1607 enum switchtec_fw_ro ro)
1608{
1609 struct switchtec_boot_ro subcmd = {
1610 .subcmd = MRPC_FWDNLD_BOOT_RO,
1611 .set_get = 1,
1612 .status = ro,
1613 };
1614
1615 if (!switchtec_is_gen3(dev)) {
1616 errno = ENOTSUP;
1617 return -1;
1618 }
1619
1620 return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1621 NULL, 0);
1622}
1623
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:164
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
Definition fw.c:397
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:1542
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:1390
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:1483
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:773
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.
Definition fw.c:193
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:1434
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.
Definition fw.c:255
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition fw.c:1567
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition fw.c:740
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:305
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition fw.c:521
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:1114
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:1606
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition fw.c:1372
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:825
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:425
struct switchtec_fw_part_summary * switchtec_fw_part_summary(struct switchtec_dev *dev)
Return firmware summary information structure for the flash partitfons in the device.
Definition fw.c:1287
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:283
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Definition mfg.c:1003
Definition fw.c:282
Information about a firmware image or partition.
Definition switchtec.h:251
enum switchtec_gen gen
Image generation.
Definition switchtec.h:252
size_t part_body_offset
Partition image body offset.
Definition switchtec.h:258
unsigned long image_crc
CRC checksum of the image.
Definition switchtec.h:260
char version[32]
Firmware/Config version.
Definition switchtec.h:255
size_t image_len
Length of the image.
Definition switchtec.h:259
unsigned long part_id
Image partition ID.
Definition switchtec.h:253
size_t part_addr
Address of the partition.
Definition switchtec.h:256
size_t part_len
Length of the partition.
Definition switchtec.h:257
enum switchtec_fw_type type
Image partition type.
Definition switchtec.h:254
Main Switchtec header.
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition switchtec.h:815
switchtec_gen
The PCIe generations.
Definition switchtec.h:86
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:106
switchtec_fw_dlstatus
Firmware update status.
Definition switchtec.h:784
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:423