Switchtec Userspace PROJECT_NUMBER = 4.2
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 uint32_t image_len;
159 uint32_t type;
160 uint32_t load_addr;
161 uint32_t version;
162 uint32_t rsvd[9];
163 uint32_t header_crc;
164 uint32_t image_crc;
165};
166
167static uint32_t get_fw_tx_id(struct switchtec_dev *dev)
168{
169 if (switchtec_is_gen5(dev))
170 return MRPC_FW_TX_GEN5;
171 else
172 return MRPC_FW_TX;
173}
174
175static int switchtec_fw_dlstatus(struct switchtec_dev *dev,
176 enum switchtec_fw_dlstatus *status,
177 enum mrpc_bg_status *bgstatus)
178{
179 uint32_t cmd = MRPC_FWDNLD;
180 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
181 struct {
182 uint8_t dlstatus;
183 uint8_t bgstatus;
184 uint16_t reserved;
185 } result;
186 int ret;
187
188 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
189 cmd = get_fw_tx_id(dev);
190
191 ret = switchtec_cmd(dev, cmd, &subcmd, sizeof(subcmd),
192 &result, sizeof(result));
193
194 if (ret)
195 return ret;
196
197 if (status != NULL)
198 *status = result.dlstatus;
199
200 if (bgstatus != NULL)
201 *bgstatus = result.bgstatus;
202
203 return 0;
204}
205
206static int switchtec_fw_wait(struct switchtec_dev *dev,
207 enum switchtec_fw_dlstatus *status)
208{
209 enum mrpc_bg_status bgstatus;
210 int ret;
211
212 do {
213 // Delay slightly to avoid interrupting the firmware too much
214 usleep(5000);
215
216 ret = switchtec_fw_dlstatus(dev, status, &bgstatus);
217 if (ret < 0)
218 return ret;
219
220 if (bgstatus == MRPC_BG_STAT_OFFSET)
221 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
222
223 if (bgstatus == MRPC_BG_STAT_ERROR) {
224 if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
225 *status != SWITCHTEC_DLSTAT_COMPLETES &&
226 *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
227 *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
228 return *status;
229 else
230 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
231 }
232
233 } while (bgstatus == MRPC_BG_STAT_INPROGRESS);
234
235 return 0;
236}
237
248int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev,
249 int toggle_bl2, int toggle_key,
250 int toggle_fw, int toggle_cfg)
251{
252 uint32_t cmd_id;
253 struct {
254 uint8_t subcmd;
255 uint8_t toggle_fw;
256 uint8_t toggle_cfg;
257 uint8_t toggle_bl2;
258 uint8_t toggle_key;
259 } cmd;
260
261 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) {
262 cmd_id = get_fw_tx_id(dev);
263 cmd.subcmd = MRPC_FW_TX_TOGGLE;
264 } else {
265 cmd_id = MRPC_FWDNLD;
266 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
267 }
268
269 cmd.toggle_bl2 = !!toggle_bl2;
270 cmd.toggle_key = !!toggle_key;
271 cmd.toggle_fw = !!toggle_fw;
272 cmd.toggle_cfg = !!toggle_cfg;
273
274 return switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
275 NULL, 0);
276}
277
278struct cmd_fwdl {
280 uint8_t subcmd;
281 uint8_t dont_activate;
282 uint8_t reserved[2];
283 uint32_t offset;
284 uint32_t img_length;
285 uint32_t blk_length;
286 } hdr;
287 uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
288};
289
301int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
302 int dont_activate, int force,
303 void (*progress_callback)(int cur, int tot))
304{
305 enum switchtec_fw_dlstatus status;
306 enum mrpc_bg_status bgstatus;
307 ssize_t image_size, offset = 0;
308 int ret;
309 struct cmd_fwdl cmd = {};
310 uint32_t cmd_id = MRPC_FWDNLD;
311
312 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
313 cmd_id = get_fw_tx_id(dev);
314
315 image_size = lseek(img_fd, 0, SEEK_END);
316 if (image_size < 0)
317 return -errno;
318 lseek(img_fd, 0, SEEK_SET);
319
320 switchtec_fw_dlstatus(dev, &status, &bgstatus);
321
322 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
323 errno = EBUSY;
324 return -EBUSY;
325 }
326
327 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
328 errno = EBUSY;
329 return -EBUSY;
330 }
331
332 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
333 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
334 else
335 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
336
337 cmd.hdr.dont_activate = !!dont_activate;
338 cmd.hdr.img_length = htole32(image_size);
339
340 while (offset < image_size) {
341 ssize_t blklen = read(img_fd, &cmd.data,
342 sizeof(cmd.data));
343
344 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
345 continue;
346
347 if (blklen < 0)
348 return -errno;
349
350 if (blklen == 0)
351 break;
352
353 cmd.hdr.offset = htole32(offset);
354 cmd.hdr.blk_length = htole32(blklen);
355
356 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
357 NULL, 0);
358
359 if (ret)
360 return ret;
361
362 ret = switchtec_fw_wait(dev, &status);
363 if (ret != 0)
364 return ret;
365
366 offset += le32toh(cmd.hdr.blk_length);
367
368 if (progress_callback)
369 progress_callback(offset, image_size);
370
371 }
372
373 if (status == SWITCHTEC_DLSTAT_COMPLETES)
374 return 0;
375
376 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
377 return 0;
378
379 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
380 return 0;
381
382 if (status == 0)
383 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
384
385 return status;
386}
387
394{
395 uint8_t major = (version >> 24) & 0xff;
396
397 switch (major) {
398 case 1:
399 case 2: return SWITCHTEC_GEN3;
400 case 3:
401 case 4:
402 case 5: return SWITCHTEC_GEN4;
403 case 6:
404 case 7:
405 case 8: return SWITCHTEC_GEN5;
406 default: return SWITCHTEC_GEN_UNKNOWN;
407 }
408}
409
421int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
422 int dont_activate, int force,
423 void (*progress_callback)(int cur, int tot))
424{
425 enum switchtec_fw_dlstatus status;
426 enum mrpc_bg_status bgstatus;
427 ssize_t image_size, offset = 0;
428 int ret;
429 struct cmd_fwdl cmd = {};
430 uint32_t cmd_id = MRPC_FWDNLD;
431
432 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
433 cmd_id = get_fw_tx_id(dev);
434
435 ret = fseek(fimg, 0, SEEK_END);
436 if (ret)
437 return -errno;
438 image_size = ftell(fimg);
439 if (image_size < 0)
440 return -errno;
441 ret = fseek(fimg, 0, SEEK_SET);
442 if (ret)
443 return -errno;
444
445 switchtec_fw_dlstatus(dev, &status, &bgstatus);
446
447 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
448 errno = EBUSY;
449 return -EBUSY;
450 }
451
452 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
453 errno = EBUSY;
454 return -EBUSY;
455 }
456
457 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
458 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
459 else
460 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
461
462 cmd.hdr.dont_activate = !!dont_activate;
463 cmd.hdr.img_length = htole32(image_size);
464
465 while (offset < image_size) {
466 ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
467
468 if (blklen == 0) {
469 ret = ferror(fimg);
470 if (ret)
471 return ret;
472 break;
473 }
474
475 cmd.hdr.offset = htole32(offset);
476 cmd.hdr.blk_length = htole32(blklen);
477
478 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
479 NULL, 0);
480
481 if (ret)
482 return ret;
483
484 ret = switchtec_fw_wait(dev, &status);
485 if (ret != 0)
486 return ret;
487
488 offset += le32toh(cmd.hdr.blk_length);
489
490 if (progress_callback)
491 progress_callback(offset, image_size);
492 }
493
494 if (status == SWITCHTEC_DLSTAT_COMPLETES)
495 return 0;
496
497 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
498 return 0;
499
500 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
501 return 0;
502
503 if (status == 0)
504 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
505
506 return status;
507}
508
517void switchtec_fw_perror(const char *s, int ret)
518{
519 const char *msg;
520
521 if (ret <= 0) {
522 perror(s);
523 return;
524 }
525
526 switch(ret) {
527 case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
528 msg = "Header incorrect"; break;
529 case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
530 msg = "Offset incorrect"; break;
531 case SWITCHTEC_DLSTAT_CRC_INCORRECT:
532 msg = "CRC incorrect"; break;
533 case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
534 msg = "Length incorrect"; break;
535 case SWITCHTEC_DLSTAT_HARDWARE_ERR:
536 msg = "Hardware Error"; break;
537 case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
538 msg = "Package length less than 32 bytes"; break;
539 case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
540 msg = "Signature memory allocation failed"; break;
541 case SWITCHTEC_DLSTAT_SEEPROM:
542 msg = "SEEPROM download failed"; break;
543 case SWITCHTEC_DLSTAT_READONLY_PARTITION:
544 msg = "Programming a read-only partition"; break;
545 case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
546 msg = "Download Timeout"; break;
547 case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
548 msg = "SEEPROM or related TWI bus isn't enabled"; break;
549 case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
550 msg = "Programming a running partition"; break;
551 case SWITCHTEC_DLSTAT_NOT_ALLOWED:
552 msg = "Programming not allowed over this interface"; break;
553 case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
554 msg = "Activation failed due to XML version mismatch"; break;
555 case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
556 msg = "Activation failed due to unknown error"; break;
557 case SWITCHTEC_DLSTAT_ERROR_OFFSET:
558 msg = "Data offset error during programming"; break;
559 case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
560 msg = "Failed to program to flash"; break;
561
562 case SWITCHTEC_DLSTAT_NO_FILE:
563 msg = "No Image Transferred"; break;
564 default:
565 fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
566 return;
567 }
568
569 fprintf(stderr, "%s: %s\n", s, msg);
570}
571
572static enum switchtec_fw_type
573switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
574{
575 switch ((unsigned long)info->part_id) {
576 case SWITCHTEC_FW_PART_ID_G3_BOOT: return SWITCHTEC_FW_TYPE_BOOT;
577 case SWITCHTEC_FW_PART_ID_G3_MAP0: return SWITCHTEC_FW_TYPE_MAP;
578 case SWITCHTEC_FW_PART_ID_G3_MAP1: return SWITCHTEC_FW_TYPE_MAP;
579 case SWITCHTEC_FW_PART_ID_G3_IMG0: return SWITCHTEC_FW_TYPE_IMG;
580 case SWITCHTEC_FW_PART_ID_G3_IMG1: return SWITCHTEC_FW_TYPE_IMG;
581 case SWITCHTEC_FW_PART_ID_G3_DAT0: return SWITCHTEC_FW_TYPE_CFG;
582 case SWITCHTEC_FW_PART_ID_G3_DAT1: return SWITCHTEC_FW_TYPE_CFG;
583 case SWITCHTEC_FW_PART_ID_G3_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
584 case SWITCHTEC_FW_PART_ID_G3_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
585
586 //Legacy
587 case 0xa8000000: return SWITCHTEC_FW_TYPE_BOOT;
588 case 0xa8020000: return SWITCHTEC_FW_TYPE_MAP;
589 case 0xa8060000: return SWITCHTEC_FW_TYPE_IMG;
590 case 0xa8210000: return SWITCHTEC_FW_TYPE_CFG;
591
592 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
593 }
594}
595
596static enum switchtec_fw_type
597switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
598{
599 switch (info->part_id) {
600 case SWITCHTEC_FW_PART_ID_G4_MAP0: return SWITCHTEC_FW_TYPE_MAP;
601 case SWITCHTEC_FW_PART_ID_G4_MAP1: return SWITCHTEC_FW_TYPE_MAP;
602 case SWITCHTEC_FW_PART_ID_G4_KEY0: return SWITCHTEC_FW_TYPE_KEY;
603 case SWITCHTEC_FW_PART_ID_G4_KEY1: return SWITCHTEC_FW_TYPE_KEY;
604 case SWITCHTEC_FW_PART_ID_G4_BL20: return SWITCHTEC_FW_TYPE_BL2;
605 case SWITCHTEC_FW_PART_ID_G4_BL21: return SWITCHTEC_FW_TYPE_BL2;
606 case SWITCHTEC_FW_PART_ID_G4_CFG0: return SWITCHTEC_FW_TYPE_CFG;
607 case SWITCHTEC_FW_PART_ID_G4_CFG1: return SWITCHTEC_FW_TYPE_CFG;
608 case SWITCHTEC_FW_PART_ID_G4_IMG0: return SWITCHTEC_FW_TYPE_IMG;
609 case SWITCHTEC_FW_PART_ID_G4_IMG1: return SWITCHTEC_FW_TYPE_IMG;
610 case SWITCHTEC_FW_PART_ID_G4_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
611 case SWITCHTEC_FW_PART_ID_G4_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
612 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
613 }
614}
615
616static enum switchtec_fw_type
617switchtec_fw_id_to_type_gen5(const struct switchtec_fw_image_info *info)
618{
619 switch (info->part_id) {
620 case SWITCHTEC_FW_PART_ID_G5_MAP0: return SWITCHTEC_FW_TYPE_MAP;
621 case SWITCHTEC_FW_PART_ID_G5_MAP1: return SWITCHTEC_FW_TYPE_MAP;
622 case SWITCHTEC_FW_PART_ID_G5_KEY0: return SWITCHTEC_FW_TYPE_KEY;
623 case SWITCHTEC_FW_PART_ID_G5_KEY1: return SWITCHTEC_FW_TYPE_KEY;
624 case SWITCHTEC_FW_PART_ID_G5_RIOT0: return SWITCHTEC_FW_TYPE_RIOT;
625 case SWITCHTEC_FW_PART_ID_G5_RIOT1: return SWITCHTEC_FW_TYPE_RIOT;
626 case SWITCHTEC_FW_PART_ID_G5_BL20: return SWITCHTEC_FW_TYPE_BL2;
627 case SWITCHTEC_FW_PART_ID_G5_BL21: return SWITCHTEC_FW_TYPE_BL2;
628 case SWITCHTEC_FW_PART_ID_G5_CFG0: return SWITCHTEC_FW_TYPE_CFG;
629 case SWITCHTEC_FW_PART_ID_G5_CFG1: return SWITCHTEC_FW_TYPE_CFG;
630 case SWITCHTEC_FW_PART_ID_G5_IMG0: return SWITCHTEC_FW_TYPE_IMG;
631 case SWITCHTEC_FW_PART_ID_G5_IMG1: return SWITCHTEC_FW_TYPE_IMG;
632 case SWITCHTEC_FW_PART_ID_G5_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
633 case SWITCHTEC_FW_PART_ID_G5_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
634 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
635 }
636}
637
638static enum switchtec_fw_type
639switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
640{
641 switch (info->gen) {
642 case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
643 case SWITCHTEC_GEN4: return switchtec_fw_id_to_type_gen4(info);
644 case SWITCHTEC_GEN5: return switchtec_fw_id_to_type_gen5(info);
645 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
646 }
647}
648
649static int switchtec_fw_file_info_gen3(int fd,
650 struct switchtec_fw_image_info *info)
651{
652 struct switchtec_fw_image_header_gen3 hdr = {};
653 int ret;
654
655 ret = read(fd, &hdr, sizeof(hdr));
656 lseek(fd, 0, SEEK_SET);
657
658 if (ret != sizeof(hdr))
659 goto invalid_file;
660
661 if (strcmp(hdr.magic, "PMC") != 0)
662 goto invalid_file;
663
664 if (info == NULL)
665 return 0;
666
667 info->gen = SWITCHTEC_GEN3;
668 info->part_id = hdr.type;
669 info->image_crc = le32toh(hdr.image_crc);
670 version_to_string(hdr.version, info->version, sizeof(info->version));
671 info->image_len = le32toh(hdr.image_len);
672
673 info->type = switchtec_fw_id_to_type(info);
674
675 info->secure_version = 0;
676 info->signed_image = 0;
677
678 return 0;
679
680invalid_file:
681 errno = ENOEXEC;
682 return -errno;
683}
684
685static enum switchtec_fw_image_part_id_gen4 hdr_type2_id_gen4(uint32_t type)
686{
687 switch (type) {
688 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
689 return SWITCHTEC_FW_PART_ID_G4_MAP0;
690
691 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
692 return SWITCHTEC_FW_PART_ID_G4_KEY0;
693
694 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
695 return SWITCHTEC_FW_PART_ID_G4_BL20;
696
697 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
698 return SWITCHTEC_FW_PART_ID_G4_CFG0;
699
700 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
701 return SWITCHTEC_FW_PART_ID_G4_IMG0;
702
703 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
704 return SWITCHTEC_FW_PART_ID_G4_NVLOG;
705
706 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
707 return SWITCHTEC_FW_PART_ID_G4_SEEPROM;
708
709 default:
710 return -1;
711 }
712}
713
714static enum switchtec_fw_image_part_id_gen5 hdr_type2_id_gen5(uint32_t type)
715{
716 switch (type) {
717 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN5:
718 return SWITCHTEC_FW_PART_ID_G5_MAP0;
719
720 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5:
721 return SWITCHTEC_FW_PART_ID_G5_KEY0;
722
723 case SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5:
724 return SWITCHTEC_FW_PART_ID_G5_RIOT0;
725
726 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN5:
727 return SWITCHTEC_FW_PART_ID_G5_BL20;
728
729 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN5:
730 return SWITCHTEC_FW_PART_ID_G5_CFG0;
731
732 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN5:
733 return SWITCHTEC_FW_PART_ID_G5_IMG0;
734
735 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5:
736 return SWITCHTEC_FW_PART_ID_G5_NVLOG;
737
738 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5:
739 return SWITCHTEC_FW_PART_ID_G5_SEEPROM;
740
741 default:
742 return -1;
743 }
744}
745
746static int switchtec_fw_file_info_gen45(int fd,
747 struct switchtec_fw_image_info *info)
748{
749 int ret;
750 struct switchtec_fw_metadata_gen4 hdr = {};
751 uint8_t exp_zero[4] = {};
752 uint32_t version;
753 int part_id;
754
755 ret = read(fd, &hdr, sizeof(hdr));
756 lseek(fd, 0, SEEK_SET);
757
758 if (ret != sizeof(hdr))
759 goto invalid_file;
760
761 if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
762 goto invalid_file;
763
764 if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
765 goto invalid_file;
766
767 if (!info)
768 return 0;
769
770 /* Non-zero 'fw-id' field means the image is for Gen5 or later */
771 if (hdr.fw_id)
772 part_id = hdr_type2_id_gen5(le32toh(hdr.type));
773 else
774 part_id = hdr_type2_id_gen4(le32toh(hdr.type));
775
776 if (part_id < 0)
777 goto invalid_file;
778
779 info->part_id = part_id;
780
781 info->image_crc = le32toh(hdr.image_crc);
782 version = le32toh(hdr.version);
783 version_to_string(version, info->version, sizeof(info->version));
784 info->image_len = le32toh(hdr.image_len);
785 info->gen = switchtec_fw_version_to_gen(version);
786
787 info->type = switchtec_fw_id_to_type(info);
788
789 info->secure_version = le32toh(hdr.secure_version);
790 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
791
792 return 0;
793
794invalid_file:
795 errno = ENOEXEC;
796 return -errno;
797}
798
806{
807 char magic[4];
808 int ret;
809
810 ret = read(fd, &magic, sizeof(magic));
811 lseek(fd, 0, SEEK_SET);
812
813 if (ret != sizeof(magic)) {
814 errno = ENOEXEC;
815 return -1;
816 }
817
818 if (!strncmp(magic, "PMC", sizeof(magic))) {
819 return switchtec_fw_file_info_gen3(fd, info);
820 } else if (!strncmp(magic, "MSCC", sizeof(magic))) {
821 return switchtec_fw_file_info_gen45(fd, info);
822 } else {
823 errno = ENOEXEC;
824 return -1;
825 }
826
827 return 0;
828}
829
838int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
839 int img_fd)
840{
841 int ret;
842 struct switchtec_fw_image_info info;
843 struct switchtec_sn_ver_info sn_info = {};
844
845 if (switchtec_is_gen3(dev))
846 return 0;
847
848 ret = switchtec_fw_file_info(img_fd, &info);
849 if (ret)
850 return 0;
851
852 if (!info.signed_image)
853 return 0;
854
855 ret = switchtec_sn_ver_get(dev, &sn_info);
856 if (ret) {
857 sn_info.ver_bl2 = 0xffffffff;
858 sn_info.ver_main = 0xffffffff;
859 sn_info.ver_km = 0xffffffff;
860 }
861
862 switch (info.type) {
863 case SWITCHTEC_FW_TYPE_BL2:
864 if (info.secure_version > sn_info.ver_bl2)
865 return 1;
866
867 break;
868 case SWITCHTEC_FW_TYPE_IMG:
869 if (info.secure_version > sn_info.ver_main)
870 return 1;
871
872 break;
873 case SWITCHTEC_FW_TYPE_KEY:
874 if (info.secure_version > sn_info.ver_km)
875 return 1;
876
877 break;
878 default:
879 break;
880 }
881
882 return 0;
883}
884
891{
892 switch (info->type) {
893 case SWITCHTEC_FW_TYPE_BOOT: return "BOOT";
894 case SWITCHTEC_FW_TYPE_MAP: return "MAP";
895 case SWITCHTEC_FW_TYPE_IMG: return "IMG";
896 case SWITCHTEC_FW_TYPE_CFG: return "CFG";
897 case SWITCHTEC_FW_TYPE_KEY: return "KEY";
898 case SWITCHTEC_FW_TYPE_RIOT: return "RIOT";
899 case SWITCHTEC_FW_TYPE_BL2: return "BL2";
900 case SWITCHTEC_FW_TYPE_NVLOG: return "NVLOG";
901 case SWITCHTEC_FW_TYPE_SEEPROM: return "SEEPROM";
902 default: return "UNKNOWN";
903 }
904}
905
906static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
907 struct switchtec_fw_image_info *info)
908{
909 uint32_t map0_update_index;
910 uint32_t map1_update_index;
911 int ret;
912
913 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
914 sizeof(uint32_t), &map0_update_index);
915 if (ret < 0)
916 return ret;
917
918 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
919 sizeof(uint32_t), &map1_update_index);
920 if (ret < 0)
921 return ret;
922
923 info->active = 0;
924 if (map0_update_index > map1_update_index) {
925 if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
926 info->active = 1;
927 } else {
928 if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
929 info->active = 1;
930 }
931
932 return 0;
933}
934
935static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
936 struct switchtec_fw_image_info *inf)
937{
938 struct switchtec_fw_footer_gen3 *metadata;
939 unsigned long addr;
940 int ret = 0;
941
942 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
943 return 1;
944
945 metadata = malloc(sizeof(*metadata));
946 if (!metadata)
947 return -1;
948
949 addr = inf->part_addr + inf->part_len - sizeof(*metadata);
950
951 ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
952 if (ret < 0)
953 goto err_out;
954
955 if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
956 goto err_out;
957
958 version_to_string(metadata->version, inf->version,
959 sizeof(inf->version));
960 inf->part_body_offset = 0;
961 inf->image_crc = metadata->image_crc;
962 inf->image_len = metadata->image_len;
963 inf->metadata = metadata;
964
965 return 0;
966
967err_out:
968 free(metadata);
969 return 1;
970}
971
972static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
973 struct switchtec_fw_image_info *inf)
974{
975 int ret = 0;
976
977 inf->read_only = switchtec_fw_is_boot_ro(dev);
978
979 switch (inf->part_id) {
980 case SWITCHTEC_FW_PART_ID_G3_BOOT:
981 inf->part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
982 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
983 inf->active = true;
984 break;
985 case SWITCHTEC_FW_PART_ID_G3_MAP0:
986 inf->part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
987 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
988 ret = switchtec_fw_map_get_active(dev, inf);
989 break;
990 case SWITCHTEC_FW_PART_ID_G3_MAP1:
991 inf->part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
992 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
993 ret = switchtec_fw_map_get_active(dev, inf);
994 break;
995 default:
996 ret = switchtec_flash_part(dev, inf, inf->part_id);
997 inf->read_only = false;
998 }
999
1000 if (ret)
1001 return ret;
1002
1003 inf->valid = true;
1004
1005 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1006 return 1;
1007
1008 return switchtec_fw_info_metadata_gen3(dev, inf);
1009}
1010
1011static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
1012 struct switchtec_fw_image_info *inf)
1013{
1014 struct switchtec_fw_metadata_gen4 *metadata;
1015 struct {
1016 uint8_t subcmd;
1017 uint8_t part_id;
1018 } subcmd = {
1019 .subcmd = MRPC_PART_INFO_GET_METADATA,
1020 .part_id = inf->part_id,
1021 };
1022 int ret;
1023
1024 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
1025 return 1;
1026 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
1027 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1028
1029 metadata = malloc(sizeof(*metadata));
1030 if (!metadata)
1031 return -1;
1032
1033 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1034 metadata, sizeof(*metadata));
1035 if (ret)
1036 goto err_out;
1037
1038 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1039 goto err_out;
1040
1041 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1042 goto err_out;
1043
1044 version_to_string(le32toh(metadata->version), inf->version,
1045 sizeof(inf->version));
1046 inf->part_body_offset = le32toh(metadata->header_len);
1047 inf->image_crc = le32toh(metadata->image_crc);
1048 inf->image_len = le32toh(metadata->image_len);
1049 inf->metadata = metadata;
1050
1051 return 0;
1052
1053err_out:
1054 free(metadata);
1055 return -1;
1056}
1057
1058static int switchtec_fw_info_metadata_gen5(struct switchtec_dev *dev,
1059 struct switchtec_fw_image_info *inf)
1060{
1061 struct switchtec_fw_metadata_gen5 *metadata;
1062 struct {
1063 uint8_t subcmd;
1064 uint8_t part_id;
1065 } subcmd = {
1066 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN5,
1067 .part_id = inf->part_id,
1068 };
1069 int ret;
1070
1071 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_NVLOG)
1072 return 1;
1073 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_SEEPROM)
1074 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1075
1076 metadata = malloc(sizeof(*metadata));
1077 if (!metadata)
1078 return -1;
1079
1080 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1081 metadata, sizeof(*metadata));
1082 if (ret)
1083 goto err_out;
1084
1085 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1086 goto err_out;
1087
1088 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1089 goto err_out;
1090
1091 version_to_string(le32toh(metadata->version), inf->version,
1092 sizeof(inf->version));
1093 inf->part_body_offset = le32toh(metadata->header_len);
1094 inf->image_crc = le32toh(metadata->image_crc);
1095 inf->image_len = le32toh(metadata->image_len);
1096 inf->metadata = metadata;
1097
1098 return 0;
1099
1100err_out:
1101 free(metadata);
1102 return -1;
1103}
1104
1106 uint32_t firmware_version;
1107 uint32_t flash_size;
1108 uint16_t device_id;
1109 uint8_t ecc_enable;
1110 uint8_t rsvd1;
1111 uint8_t running_bl2_flag;
1112 uint8_t running_cfg_flag;
1113 uint8_t running_img_flag;
1114 uint8_t running_key_flag;
1115 uint32_t rsvd2[12];
1117 uint32_t image_crc;
1118 uint32_t image_len;
1119 uint16_t image_version;
1120 uint8_t valid;
1121 uint8_t active;
1122 uint32_t part_start;
1123 uint32_t part_end;
1124 uint32_t part_offset;
1125 uint32_t part_size_dw;
1126 uint8_t read_only;
1127 uint8_t is_using;
1128 uint8_t rsvd[2];
1129 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1130 img0, img1, nvlog, vendor[8];
1131};
1132
1134 uint32_t firmware_version;
1135 uint32_t flash_size;
1136 uint16_t device_id;
1137 uint8_t ecc_enable;
1138 uint8_t rsvd1;
1139 uint8_t running_riot_flag;
1140 uint8_t running_bl2_flag;
1141 uint8_t running_cfg_flag;
1142 uint8_t running_img_flag;
1143 uint8_t running_key_flag;
1144 uint8_t rsvd2[3];
1145 uint8_t key_redundant_flag;
1146 uint8_t riot_redundant_flag;
1147 uint8_t bl2_redundant_flag;
1148 uint8_t cfg_redundant_flag;
1149 uint8_t img_redundant_flag;
1150 uint8_t rsvd3[3];
1151 uint32_t rsvd4[9];
1152 struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1,
1153 riot0, riot1, bl20, bl21,
1154 cfg0, cfg1, img0, img1, nvlog,
1155 vendor[8];
1156};
1157
1158static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
1159 struct switchtec_fw_image_info *inf,
1160 struct switchtec_flash_info_gen4 *all)
1161{
1162 struct switchtec_flash_part_info_gen4 *part_info;
1163 int ret;
1164
1165 switch(inf->part_id) {
1166 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1167 part_info = &all->map0;
1168 break;
1169 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1170 part_info = &all->map1;
1171 break;
1172 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1173 part_info = &all->keyman0;
1174 break;
1175 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1176 part_info = &all->keyman1;
1177 break;
1178 case SWITCHTEC_FW_PART_ID_G4_BL20:
1179 part_info = &all->bl20;
1180 break;
1181 case SWITCHTEC_FW_PART_ID_G4_BL21:
1182 part_info = &all->bl21;
1183 break;
1184 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1185 part_info = &all->img0;
1186 break;
1187 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1188 part_info = &all->img1;
1189 break;
1190 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1191 part_info = &all->cfg0;
1192 break;
1193 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1194 part_info = &all->cfg1;
1195 break;
1196 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1197 part_info = &all->nvlog;
1198 break;
1199 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1200 if (switchtec_gen(dev) < SWITCHTEC_GEN5)
1201 return 0;
1202
1203 inf->active = true;
1204 /* length is not applicable for SEEPROM image */
1205 inf->part_len = 0xffffffff;
1206
1207 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1208 if (!ret) {
1209 inf->running = true;
1210 inf->valid = true;
1211 }
1212
1213 return 0;
1214 default:
1215 errno = EINVAL;
1216 return -1;
1217 }
1218
1219 inf->part_addr = le32toh(part_info->part_start);
1220 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1221 inf->active = part_info->active;
1222 inf->running = part_info->is_using;
1223 inf->read_only = part_info->read_only;
1224 inf->valid = part_info->valid;
1225 if (!inf->valid)
1226 return 0;
1227
1228 return switchtec_fw_info_metadata_gen4(dev, inf);
1229}
1230
1231static int switchtec_fw_part_info_gen5(struct switchtec_dev *dev,
1232 struct switchtec_fw_image_info *inf,
1233 struct switchtec_flash_info_gen5 *all)
1234{
1235 struct switchtec_flash_part_info_gen4 *part_info;
1236 int ret;
1237
1238 switch(inf->part_id) {
1239 case SWITCHTEC_FW_PART_ID_G5_MAP0:
1240 part_info = &all->map0;
1241 break;
1242 case SWITCHTEC_FW_PART_ID_G5_MAP1:
1243 part_info = &all->map1;
1244 break;
1245 case SWITCHTEC_FW_PART_ID_G5_RIOT0:
1246 part_info = &all->riot0;
1247 break;
1248 case SWITCHTEC_FW_PART_ID_G5_RIOT1:
1249 part_info = &all->riot1;
1250 break;
1251 case SWITCHTEC_FW_PART_ID_G5_KEY0:
1252 part_info = &all->keyman0;
1253 break;
1254 case SWITCHTEC_FW_PART_ID_G5_KEY1:
1255 part_info = &all->keyman1;
1256 break;
1257 case SWITCHTEC_FW_PART_ID_G5_BL20:
1258 part_info = &all->bl20;
1259 break;
1260 case SWITCHTEC_FW_PART_ID_G5_BL21:
1261 part_info = &all->bl21;
1262 break;
1263 case SWITCHTEC_FW_PART_ID_G5_IMG0:
1264 part_info = &all->img0;
1265 break;
1266 case SWITCHTEC_FW_PART_ID_G5_IMG1:
1267 part_info = &all->img1;
1268 break;
1269 case SWITCHTEC_FW_PART_ID_G5_CFG0:
1270 part_info = &all->cfg0;
1271 break;
1272 case SWITCHTEC_FW_PART_ID_G5_CFG1:
1273 part_info = &all->cfg1;
1274 break;
1275 case SWITCHTEC_FW_PART_ID_G5_NVLOG:
1276 part_info = &all->nvlog;
1277 break;
1278 case SWITCHTEC_FW_PART_ID_G5_SEEPROM:
1279 inf->active = true;
1280 /* length is not applicable for SEEPROM image */
1281 inf->part_len = 0xffffffff;
1282
1283 ret = switchtec_fw_info_metadata_gen5(dev, inf);
1284 if (!ret) {
1285 inf->running = true;
1286 inf->valid = true;
1287 }
1288
1289 return 0;
1290 default:
1291 errno = EINVAL;
1292 return -1;
1293 }
1294
1295 inf->part_addr = le32toh(part_info->part_start);
1296 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1297 inf->active = part_info->active;
1298 inf->running = part_info->is_using;
1299 inf->read_only = part_info->read_only;
1300 inf->valid = part_info->valid;
1301 if (!inf->valid)
1302 return 0;
1303
1304 return switchtec_fw_info_metadata_gen5(dev, inf);
1305}
1306
1316static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1317 struct switchtec_fw_image_info *info)
1318{
1319 int ret;
1320 int i;
1321 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1322 struct switchtec_flash_info_gen4 all_info_gen4;
1323 struct switchtec_flash_info_gen5 all_info_gen5;
1324
1325 if (info == NULL || nr_info == 0)
1326 return -EINVAL;
1327
1328 if (dev->gen == SWITCHTEC_GEN4) {
1329 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1330 sizeof(subcmd), &all_info_gen4,
1331 sizeof(all_info_gen4));
1332 if (ret)
1333 return ret;
1334 all_info_gen4.firmware_version =
1335 le32toh(all_info_gen4.firmware_version);
1336 all_info_gen4.flash_size = le32toh(all_info_gen4.flash_size);
1337 all_info_gen4.device_id = le16toh(all_info_gen4.device_id);
1338 } else if (dev->gen == SWITCHTEC_GEN5) {
1339 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1340 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1341 sizeof(subcmd), &all_info_gen5,
1342 sizeof(all_info_gen5));
1343 if (ret)
1344 return ret;
1345 all_info_gen5.firmware_version =
1346 le32toh(all_info_gen5.firmware_version);
1347 all_info_gen5.flash_size = le32toh(all_info_gen5.flash_size);
1348 all_info_gen5.device_id = le16toh(all_info_gen5.device_id);
1349 }
1350
1351 for (i = 0; i < nr_info; i++) {
1352 struct switchtec_fw_image_info *inf = &info[i];
1353 ret = 0;
1354
1355 inf->gen = dev->gen;
1356 inf->type = switchtec_fw_id_to_type(inf);
1357 inf->active = false;
1358 inf->running = false;
1359 inf->valid = false;
1360
1361 switch (info->gen) {
1362 case SWITCHTEC_GEN3:
1363 ret = switchtec_fw_part_info_gen3(dev, inf);
1364 break;
1365 case SWITCHTEC_GEN4:
1366 ret = switchtec_fw_part_info_gen4(dev, inf,
1367 &all_info_gen4);
1368 break;
1369 case SWITCHTEC_GEN5:
1370 ret = switchtec_fw_part_info_gen5(dev, inf,
1371 &all_info_gen5);
1372 break;
1373 default:
1374 errno = EINVAL;
1375 return -1;
1376 }
1377
1378 if (ret < 0)
1379 return ret;
1380
1381 if (ret) {
1382 inf->version[0] = 0;
1383 inf->image_crc = 0xFFFFFFFF;
1384 inf->metadata = NULL;
1385 }
1386 }
1387
1388 return nr_info;
1389}
1390
1391int switchtec_get_device_id_bl2(struct switchtec_dev *dev,
1392 unsigned short *device_id)
1393{
1394 int ret;
1395 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1396 struct switchtec_flash_info_gen4 all_info;
1397 struct switchtec_flash_info_gen5 all_info_gen5;
1398
1399 if (dev->gen != SWITCHTEC_GEN_UNKNOWN)
1400 return -EINVAL;
1401
1402 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1403 sizeof(subcmd), &all_info,
1404 sizeof(all_info));
1405 if (!ret) {
1406 *device_id = le16toh(all_info.device_id);
1407 } else if (ret == ERR_SUBCMD_INVALID) {
1408 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1409 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1410 sizeof(subcmd), &all_info_gen5,
1411 sizeof(all_info_gen5));
1412 if (!ret)
1413 *device_id = le16toh(all_info_gen5.device_id);
1414 }
1415
1416 return ret;
1417}
1418
1419static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1420 uint8_t index)
1421{
1422 int ret;
1423 uint32_t result;
1424
1425 subcmd |= index << 8;
1426 subcmd = htole32(subcmd);
1427
1428 ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1429 &result, sizeof(result));
1430 if (ret)
1431 return -1;
1432
1433 return result;
1434}
1435
1436static int get_multicfg(struct switchtec_dev *dev,
1437 struct switchtec_fw_image_info *info,
1438 int *nr_mult)
1439{
1440 int ret;
1441 int i;
1442
1443 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1444 if (ret < 0)
1445 return ret;
1446
1447 if (!ret) {
1448 *nr_mult = 0;
1449 return 0;
1450 }
1451
1452 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1453 if (ret < 0)
1454 return ret;
1455
1456 if (*nr_mult > ret)
1457 *nr_mult = ret;
1458
1459 for (i = 0; i < *nr_mult; i++) {
1460 info[i].part_addr = multicfg_subcmd(dev,
1461 MRPC_MULTI_CFG_START_ADDR,
1462 i);
1463 info[i].part_len = multicfg_subcmd(dev,
1464 MRPC_MULTI_CFG_LENGTH, i);
1465 strcpy(info[i].version, "");
1466 info[i].image_crc = 0;
1467 info[i].active = 0;
1468 }
1469
1470 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1471 if (ret < 0)
1472 return ret;
1473
1474 if (ret < *nr_mult)
1475 info[ret].active = 1;
1476
1477 return 0;
1478}
1479
1480static const enum switchtec_fw_image_part_id_gen3
1481switchtec_fw_partitions_gen3[] = {
1482 SWITCHTEC_FW_PART_ID_G3_BOOT,
1483 SWITCHTEC_FW_PART_ID_G3_MAP0,
1484 SWITCHTEC_FW_PART_ID_G3_MAP1,
1485 SWITCHTEC_FW_PART_ID_G3_IMG0,
1486 SWITCHTEC_FW_PART_ID_G3_DAT0,
1487 SWITCHTEC_FW_PART_ID_G3_DAT1,
1488 SWITCHTEC_FW_PART_ID_G3_NVLOG,
1489 SWITCHTEC_FW_PART_ID_G3_IMG1,
1490};
1491
1492static const enum switchtec_fw_image_part_id_gen4
1493switchtec_fw_partitions_gen4[] = {
1494 SWITCHTEC_FW_PART_ID_G4_MAP0,
1495 SWITCHTEC_FW_PART_ID_G4_MAP1,
1496 SWITCHTEC_FW_PART_ID_G4_KEY0,
1497 SWITCHTEC_FW_PART_ID_G4_KEY1,
1498 SWITCHTEC_FW_PART_ID_G4_BL20,
1499 SWITCHTEC_FW_PART_ID_G4_BL21,
1500 SWITCHTEC_FW_PART_ID_G4_CFG0,
1501 SWITCHTEC_FW_PART_ID_G4_CFG1,
1502 SWITCHTEC_FW_PART_ID_G4_IMG0,
1503 SWITCHTEC_FW_PART_ID_G4_IMG1,
1504 SWITCHTEC_FW_PART_ID_G4_NVLOG,
1505 SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1506};
1507
1508static const enum switchtec_fw_image_part_id_gen5
1509switchtec_fw_partitions_gen5[] = {
1510 SWITCHTEC_FW_PART_ID_G5_MAP0,
1511 SWITCHTEC_FW_PART_ID_G5_MAP1,
1512 SWITCHTEC_FW_PART_ID_G5_KEY0,
1513 SWITCHTEC_FW_PART_ID_G5_KEY1,
1514 SWITCHTEC_FW_PART_ID_G5_RIOT0,
1515 SWITCHTEC_FW_PART_ID_G5_RIOT1,
1516 SWITCHTEC_FW_PART_ID_G5_BL20,
1517 SWITCHTEC_FW_PART_ID_G5_BL21,
1518 SWITCHTEC_FW_PART_ID_G5_CFG0,
1519 SWITCHTEC_FW_PART_ID_G5_CFG1,
1520 SWITCHTEC_FW_PART_ID_G5_IMG0,
1521 SWITCHTEC_FW_PART_ID_G5_IMG1,
1522 SWITCHTEC_FW_PART_ID_G5_NVLOG,
1523 SWITCHTEC_FW_PART_ID_G5_SEEPROM,
1524};
1525
1526static struct switchtec_fw_part_type *
1527switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
1528 struct switchtec_fw_image_info *info)
1529{
1530 switch (info->type) {
1531 case SWITCHTEC_FW_TYPE_BOOT: return &summary->boot;
1532 case SWITCHTEC_FW_TYPE_MAP: return &summary->map;
1533 case SWITCHTEC_FW_TYPE_IMG: return &summary->img;
1534 case SWITCHTEC_FW_TYPE_CFG: return &summary->cfg;
1535 case SWITCHTEC_FW_TYPE_NVLOG: return &summary->nvlog;
1536 case SWITCHTEC_FW_TYPE_SEEPROM: return &summary->seeprom;
1537 case SWITCHTEC_FW_TYPE_KEY: return &summary->key;
1538 case SWITCHTEC_FW_TYPE_BL2: return &summary->bl2;
1539 case SWITCHTEC_FW_TYPE_RIOT: return &summary->riot;
1540 default: return NULL;
1541 }
1542}
1543
1553switchtec_fw_part_summary(struct switchtec_dev *dev)
1554{
1555 struct switchtec_fw_part_summary *summary;
1556 struct switchtec_fw_image_info **infp;
1557 struct switchtec_fw_part_type *type;
1558 int nr_info, nr_mcfg = 16;
1559 size_t st_sz;
1560 int ret, i;
1561
1562 switch (dev->gen) {
1563 case SWITCHTEC_GEN3:
1564 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1565 break;
1566 case SWITCHTEC_GEN4:
1567 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1568 break;
1569 case SWITCHTEC_GEN5:
1570 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen5);
1571 break;
1572 default:
1573 errno = EINVAL;
1574 return NULL;
1575 }
1576
1577 st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
1578
1579 summary = malloc(st_sz);
1580 if (!summary)
1581 return NULL;
1582
1583 memset(summary, 0, st_sz);
1584 summary->nr_info = nr_info;
1585
1586 switch (dev->gen) {
1587 case SWITCHTEC_GEN3:
1588 for (i = 0; i < nr_info; i++)
1589 summary->all[i].part_id =
1590 switchtec_fw_partitions_gen3[i];
1591 break;
1592 case SWITCHTEC_GEN4:
1593 for (i = 0; i < nr_info; i++)
1594 summary->all[i].part_id =
1595 switchtec_fw_partitions_gen4[i];
1596 break;
1597 case SWITCHTEC_GEN5:
1598 for (i = 0; i < nr_info; i++)
1599 summary->all[i].part_id =
1600 switchtec_fw_partitions_gen5[i];
1601 break;
1602 default:
1603 errno = EINVAL;
1604 return NULL;
1605 }
1606
1607 ret = switchtec_fw_part_info(dev, nr_info, summary->all);
1608 if (ret != nr_info) {
1609 free(summary);
1610 return NULL;
1611 }
1612
1613 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1614 if (ret) {
1615 nr_mcfg = 0;
1616 errno = 0;
1617 }
1618
1619 for (i = 0; i < nr_info; i++) {
1620 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1621 if (type == NULL) {
1622 free(summary);
1623 return NULL;
1624 }
1625 if (summary->all[i].active)
1626 type->active = &summary->all[i];
1627 else
1628 type->inactive = &summary->all[i];
1629 }
1630
1631 infp = &summary->mult_cfg;
1632 for (; i < nr_info + nr_mcfg; i++) {
1633 *infp = &summary->all[i];
1634 infp = &summary->all[i].next;
1635 }
1636
1637 return summary;
1638}
1639
1645{
1646 int i;
1647
1648 for (i = 0; i < summary->nr_info; i++)
1649 free(summary->all[i].metadata);
1650
1651 free(summary);
1652}
1653
1662int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
1663 size_t len, void *buf)
1664{
1665 int ret;
1666 struct {
1667 uint32_t addr;
1668 uint32_t length;
1669 } cmd;
1670 unsigned char *cbuf = buf;
1671 size_t read = 0;
1672
1673 while(len) {
1674 size_t chunk_len = len;
1675 if (chunk_len > MRPC_MAX_DATA_LEN-8)
1676 chunk_len = MRPC_MAX_DATA_LEN-8;
1677
1678 cmd.addr = htole32(addr);
1679 cmd.length = htole32(chunk_len);
1680
1681 ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
1682 cbuf, chunk_len);
1683 if (ret)
1684 return -1;
1685
1686 addr += chunk_len;
1687 len -= chunk_len;
1688 read += chunk_len;
1689 cbuf += chunk_len;
1690 }
1691
1692 return read;
1693}
1694
1706int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
1707 unsigned long addr, size_t len,
1708 void (*progress_callback)(int cur, int tot))
1709{
1710 int ret;
1711 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1712 size_t read = 0;
1713 size_t total_len = len;
1714 size_t total_wrote;
1715 ssize_t wrote;
1716
1717 while(len) {
1718 size_t chunk_len = len;
1719 if (chunk_len > sizeof(buf))
1720 chunk_len = sizeof(buf);
1721
1722 ret = switchtec_fw_read(dev, addr, chunk_len, buf);
1723 if (ret < 0)
1724 return ret;
1725
1726 total_wrote = 0;
1727 while (total_wrote < ret) {
1728 wrote = write(fd, &buf[total_wrote],
1729 ret - total_wrote);
1730 if (wrote < 0)
1731 return -1;
1732 total_wrote += wrote;
1733 }
1734
1735 read += ret;
1736 addr += ret;
1737 len -= ret;
1738
1739 if (progress_callback)
1740 progress_callback(read, total_len);
1741 }
1742
1743 return read;
1744}
1745
1755int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
1756 struct switchtec_fw_image_info *info,
1757 void (*progress_callback)(int cur, int tot))
1758{
1759 return switchtec_fw_read_fd(dev, fd,
1760 info->part_addr + info->part_body_offset,
1761 info->image_len, progress_callback);
1762}
1763
1764static int switchtec_fw_img_write_hdr_gen3(int fd,
1765 struct switchtec_fw_image_info *info)
1766{
1767 struct switchtec_fw_footer_gen3 *ftr = info->metadata;
1768 struct switchtec_fw_image_header_gen3 hdr = {};
1769
1770 memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
1771 hdr.image_len = ftr->image_len;
1772 hdr.type = info->part_id;
1773 hdr.load_addr = ftr->load_addr;
1774 hdr.version = ftr->version;
1775 hdr.header_crc = ftr->header_crc;
1776 hdr.image_crc = ftr->image_crc;
1777
1778 if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1779 hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1780 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1781 hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1782 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1783 hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1784
1785 return write(fd, &hdr, sizeof(hdr));
1786}
1787
1788static int switchtec_fw_img_write_hdr_gen4(int fd,
1789 struct switchtec_fw_image_info *info)
1790{
1791 int ret;
1792 struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
1793
1794 ret = write(fd, hdr, sizeof(*hdr));
1795 if (ret < 0)
1796 return ret;
1797
1798 return lseek(fd, info->part_body_offset, SEEK_SET);
1799}
1800
1815{
1816 switch (info->gen) {
1817 case SWITCHTEC_GEN3: return switchtec_fw_img_write_hdr_gen3(fd, info);
1818 case SWITCHTEC_GEN4:
1819 case SWITCHTEC_GEN5: return switchtec_fw_img_write_hdr_gen4(fd, info);
1820 default:
1821 errno = EINVAL;
1822 return -1;
1823 }
1824}
1825
1827 uint8_t subcmd;
1828 uint8_t set_get;
1829 uint8_t status;
1830 uint8_t reserved;
1831};
1832
1839int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
1840{
1841 struct switchtec_boot_ro subcmd = {
1842 .subcmd = MRPC_FWDNLD_BOOT_RO,
1843 .set_get = 0,
1844 };
1845
1846 struct {
1847 uint8_t status;
1848 uint8_t reserved[3];
1849 } result;
1850
1851 int ret;
1852
1853 if (!switchtec_is_gen3(dev)) {
1854 errno = ENOTSUP;
1855 return -1;
1856 }
1857
1858 ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1859 &result, sizeof(result));
1860
1861 if (ret == ERR_SUBCMD_INVALID) {
1862 errno = 0;
1863 return 0;
1864 }
1865
1866 if (ret)
1867 return ret;
1868
1869 return result.status;
1870}
1871
1878int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
1879 enum switchtec_fw_ro ro)
1880{
1881 struct switchtec_boot_ro subcmd = {
1882 .subcmd = MRPC_FWDNLD_BOOT_RO,
1883 .set_get = 1,
1884 .status = ro,
1885 };
1886
1887 if (!switchtec_is_gen3(dev)) {
1888 errno = ENOTSUP;
1889 return -1;
1890 }
1891
1892 return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1893 NULL, 0);
1894}
1895
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:393
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:1814
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:1662
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:1755
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:838
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:248
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:1706
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition fw.c:1839
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition fw.c:805
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:301
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition fw.c:517
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:1316
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:1878
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition fw.c:1644
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:890
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:421
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:1553
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:1697
Definition fw.c:278
Information about a firmware image or partition.
Definition switchtec.h:252
enum switchtec_gen gen
Image generation.
Definition switchtec.h:253
size_t part_body_offset
Partition image body offset.
Definition switchtec.h:259
unsigned long image_crc
CRC checksum of the image.
Definition switchtec.h:261
char version[32]
Firmware/Config version.
Definition switchtec.h:256
size_t image_len
Length of the image.
Definition switchtec.h:260
unsigned long part_id
Image partition ID.
Definition switchtec.h:254
size_t part_addr
Address of the partition.
Definition switchtec.h:257
size_t part_len
Length of the partition.
Definition switchtec.h:258
enum switchtec_fw_type type
Image partition type.
Definition switchtec.h:255
Main Switchtec header.
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition switchtec.h:835
switchtec_gen
The PCIe generations.
Definition switchtec.h:86
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:106
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:441
switchtec_fw_dlstatus
Firmware update status.
Definition switchtec.h:804
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:425