Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
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 
66 enum 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 
120 static 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 
151 static 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  if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
165  *status != SWITCHTEC_DLSTAT_COMPLETES &&
166  *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
167  *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
168  return *status;
169  if (bgstatus == MRPC_BG_STAT_ERROR)
170  return SWITCHTEC_DLSTAT_HARDWARE_ERR;
171 
172  } while (bgstatus == MRPC_BG_STAT_INPROGRESS);
173 
174  return 0;
175 }
176 
187 int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev,
188  int toggle_bl2, int toggle_key,
189  int toggle_fw, int toggle_cfg)
190 {
191  uint32_t cmd_id;
192  struct {
193  uint8_t subcmd;
194  uint8_t toggle_fw;
195  uint8_t toggle_cfg;
196  uint8_t toggle_bl2;
197  uint8_t toggle_key;
198  } cmd;
199 
200  if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) {
201  cmd_id = MRPC_FW_TX;
202  cmd.subcmd = MRPC_FW_TX_TOGGLE;
203  } else {
204  cmd_id = MRPC_FWDNLD;
205  cmd.subcmd = MRPC_FWDNLD_TOGGLE;
206  }
207 
208  cmd.toggle_bl2 = !!toggle_bl2;
209  cmd.toggle_key = !!toggle_key;
210  cmd.toggle_fw = !!toggle_fw;
211  cmd.toggle_cfg = !!toggle_cfg;
212 
213  return switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
214  NULL, 0);
215 }
216 
217 static enum switchtec_fw_part_type_gen4
218 switchtec_fw_type_gen4(enum switchtec_fw_type type)
219 {
220  switch (type) {
221  case SWITCHTEC_FW_TYPE_MAP:
222  return SWITCHTEC_FW_IMG_TYPE_MAP_GEN4;
223  case SWITCHTEC_FW_TYPE_IMG:
224  return SWITCHTEC_FW_IMG_TYPE_IMG_GEN4;
225  case SWITCHTEC_FW_TYPE_CFG:
226  return SWITCHTEC_FW_IMG_TYPE_CFG_GEN4;
227  case SWITCHTEC_FW_TYPE_NVLOG:
228  return SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4;
229  case SWITCHTEC_FW_TYPE_SEEPROM:
230  return SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4;
231  case SWITCHTEC_FW_TYPE_KEY:
232  return SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4;
233  case SWITCHTEC_FW_TYPE_BL2:
234  return SWITCHTEC_FW_IMG_TYPE_BL2_GEN4;
235  default:
236  return SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN4;
237  };
238 }
239 
249 int switchtec_fw_setup_redundancy(struct switchtec_dev *dev,
250  enum switchtec_fw_redundancy redund,
251  enum switchtec_fw_type type)
252 {
253  int ret;
254 
255  struct set_fw_redundancy{
256  uint8_t sub_cmd;
257  uint8_t part_type;
258  uint8_t flag;
259  uint8_t rsvd;
260  } cmd = {
261  .sub_cmd = MRPC_FWDNLD_SET_REDUNDANCY,
262  .part_type = switchtec_fw_type_gen4(type),
263  .flag = redund,
264  };
265 
266  if (switchtec_is_gen3(dev)) {
267  errno = ENOTSUP;
268  return -1;
269  }
270 
271  ret = switchtec_cmd(dev, MRPC_FWDNLD, &cmd, sizeof(cmd), NULL, 0);
272 
273  return ret;
274 }
275 
276 struct cmd_fwdl {
277  struct cmd_fwdl_hdr {
278  uint8_t subcmd;
279  uint8_t dont_activate;
280  uint8_t reserved[2];
281  uint32_t offset;
282  uint32_t img_length;
283  uint32_t blk_length;
284  } hdr;
285  uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
286 };
287 
299 int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
300  int dont_activate, int force,
301  void (*progress_callback)(int cur, int tot))
302 {
303  enum switchtec_fw_dlstatus status;
304  enum mrpc_bg_status bgstatus;
305  ssize_t image_size, offset = 0;
306  int ret;
307  struct cmd_fwdl cmd = {};
308  uint32_t cmd_id = MRPC_FWDNLD;
309 
310  if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
311  cmd_id = MRPC_FW_TX;
312 
313  image_size = lseek(img_fd, 0, SEEK_END);
314  if (image_size < 0)
315  return -errno;
316  lseek(img_fd, 0, SEEK_SET);
317 
318  switchtec_fw_dlstatus(dev, &status, &bgstatus);
319 
320  if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
321  errno = EBUSY;
322  return -EBUSY;
323  }
324 
325  if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
326  errno = EBUSY;
327  return -EBUSY;
328  }
329 
330  if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
331  cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
332  else
333  cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
334 
335  cmd.hdr.dont_activate = !!dont_activate;
336  cmd.hdr.img_length = htole32(image_size);
337 
338  while (offset < image_size) {
339  ssize_t blklen = read(img_fd, &cmd.data,
340  sizeof(cmd.data));
341 
342  if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
343  continue;
344 
345  if (blklen < 0)
346  return -errno;
347 
348  if (blklen == 0)
349  break;
350 
351  cmd.hdr.offset = htole32(offset);
352  cmd.hdr.blk_length = htole32(blklen);
353 
354  ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
355  NULL, 0);
356 
357  if (ret)
358  return ret;
359 
360  ret = switchtec_fw_wait(dev, &status);
361  if (ret != 0)
362  return ret;
363 
364  offset += cmd.hdr.blk_length;
365 
366  if (progress_callback)
367  progress_callback(offset, image_size);
368 
369  }
370 
371  if (status == SWITCHTEC_DLSTAT_COMPLETES)
372  return 0;
373 
374  if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
375  return 0;
376 
377  if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
378  return 0;
379 
380  if (status == 0)
381  return SWITCHTEC_DLSTAT_HARDWARE_ERR;
382 
383  return status;
384 }
385 
397 int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
398  int dont_activate, int force,
399  void (*progress_callback)(int cur, int tot))
400 {
401  enum switchtec_fw_dlstatus status;
402  enum mrpc_bg_status bgstatus;
403  ssize_t image_size, offset = 0;
404  int ret;
405  struct cmd_fwdl cmd = {};
406  uint32_t cmd_id = MRPC_FWDNLD;
407 
408  if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
409  cmd_id = MRPC_FW_TX;
410 
411  ret = fseek(fimg, 0, SEEK_END);
412  if (ret)
413  return -errno;
414  image_size = ftell(fimg);
415  if (image_size < 0)
416  return -errno;
417  ret = fseek(fimg, 0, SEEK_SET);
418  if (ret)
419  return -errno;
420 
421  switchtec_fw_dlstatus(dev, &status, &bgstatus);
422 
423  if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
424  errno = EBUSY;
425  return -EBUSY;
426  }
427 
428  if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
429  errno = EBUSY;
430  return -EBUSY;
431  }
432 
433  if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
434  cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
435  else
436  cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
437 
438  cmd.hdr.dont_activate = !!dont_activate;
439  cmd.hdr.img_length = htole32(image_size);
440 
441  while (offset < image_size) {
442  ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
443 
444  if (blklen == 0) {
445  ret = ferror(fimg);
446  if (ret)
447  return ret;
448  break;
449  }
450 
451  cmd.hdr.offset = htole32(offset);
452  cmd.hdr.blk_length = htole32(blklen);
453 
454  ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
455  NULL, 0);
456 
457  if (ret)
458  return ret;
459 
460  ret = switchtec_fw_wait(dev, &status);
461  if (ret != 0)
462  return ret;
463 
464  offset += cmd.hdr.blk_length;
465 
466  if (progress_callback)
467  progress_callback(offset, image_size);
468  }
469 
470  if (status == SWITCHTEC_DLSTAT_COMPLETES)
471  return 0;
472 
473  if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
474  return 0;
475 
476  if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
477  return 0;
478 
479  if (status == 0)
480  return SWITCHTEC_DLSTAT_HARDWARE_ERR;
481 
482  return status;
483 }
484 
493 void switchtec_fw_perror(const char *s, int ret)
494 {
495  const char *msg;
496 
497  if (ret <= 0) {
498  perror(s);
499  return;
500  }
501 
502  switch(ret) {
503  case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
504  msg = "Header incorrect"; break;
505  case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
506  msg = "Offset incorrect"; break;
507  case SWITCHTEC_DLSTAT_CRC_INCORRECT:
508  msg = "CRC incorrect"; break;
509  case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
510  msg = "Length incorrect"; break;
511  case SWITCHTEC_DLSTAT_HARDWARE_ERR:
512  msg = "Hardware Error"; break;
513  case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
514  msg = "Download Timeout"; break;
515  case SWITCHTEC_DLSTAT_NO_FILE:
516  msg = "No Image Transferred"; break;
517  default:
518  fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
519  return;
520  }
521 
522  fprintf(stderr, "%s: %s\n", s, msg);
523 }
524 
525 static enum switchtec_fw_type
526 switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
527 {
528  switch ((unsigned long)info->part_id) {
529  case SWITCHTEC_FW_PART_ID_G3_BOOT: return SWITCHTEC_FW_TYPE_BOOT;
530  case SWITCHTEC_FW_PART_ID_G3_MAP0: return SWITCHTEC_FW_TYPE_MAP;
531  case SWITCHTEC_FW_PART_ID_G3_MAP1: return SWITCHTEC_FW_TYPE_MAP;
532  case SWITCHTEC_FW_PART_ID_G3_IMG0: return SWITCHTEC_FW_TYPE_IMG;
533  case SWITCHTEC_FW_PART_ID_G3_IMG1: return SWITCHTEC_FW_TYPE_IMG;
534  case SWITCHTEC_FW_PART_ID_G3_DAT0: return SWITCHTEC_FW_TYPE_CFG;
535  case SWITCHTEC_FW_PART_ID_G3_DAT1: return SWITCHTEC_FW_TYPE_CFG;
536  case SWITCHTEC_FW_PART_ID_G3_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
537  case SWITCHTEC_FW_PART_ID_G3_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
538 
539  //Legacy
540  case 0xa8000000: return SWITCHTEC_FW_TYPE_BOOT;
541  case 0xa8020000: return SWITCHTEC_FW_TYPE_MAP;
542  case 0xa8060000: return SWITCHTEC_FW_TYPE_IMG;
543  case 0xa8210000: return SWITCHTEC_FW_TYPE_CFG;
544 
545  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
546  }
547 }
548 
549 static enum switchtec_fw_type
550 switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
551 {
552  switch (info->part_id) {
553  case SWITCHTEC_FW_PART_ID_G4_MAP0: return SWITCHTEC_FW_TYPE_MAP;
554  case SWITCHTEC_FW_PART_ID_G4_MAP1: return SWITCHTEC_FW_TYPE_MAP;
555  case SWITCHTEC_FW_PART_ID_G4_KEY0: return SWITCHTEC_FW_TYPE_KEY;
556  case SWITCHTEC_FW_PART_ID_G4_KEY1: return SWITCHTEC_FW_TYPE_KEY;
557  case SWITCHTEC_FW_PART_ID_G4_BL20: return SWITCHTEC_FW_TYPE_BL2;
558  case SWITCHTEC_FW_PART_ID_G4_BL21: return SWITCHTEC_FW_TYPE_BL2;
559  case SWITCHTEC_FW_PART_ID_G4_CFG0: return SWITCHTEC_FW_TYPE_CFG;
560  case SWITCHTEC_FW_PART_ID_G4_CFG1: return SWITCHTEC_FW_TYPE_CFG;
561  case SWITCHTEC_FW_PART_ID_G4_IMG0: return SWITCHTEC_FW_TYPE_IMG;
562  case SWITCHTEC_FW_PART_ID_G4_IMG1: return SWITCHTEC_FW_TYPE_IMG;
563  case SWITCHTEC_FW_PART_ID_G4_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
564  case SWITCHTEC_FW_PART_ID_G4_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
565  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
566  }
567 }
568 
569 static enum switchtec_fw_type
570 switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
571 {
572  switch (info->gen) {
573  case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
574  case SWITCHTEC_GEN4: return switchtec_fw_id_to_type_gen4(info);
575  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
576  }
577 }
578 
579 static int switchtec_fw_file_info_gen3(int fd,
580  struct switchtec_fw_image_info *info)
581 {
582  struct switchtec_fw_image_header_gen3 hdr = {};
583  int ret;
584 
585  ret = read(fd, &hdr, sizeof(hdr));
586  lseek(fd, 0, SEEK_SET);
587 
588  if (ret != sizeof(hdr))
589  goto invalid_file;
590 
591  if (strcmp(hdr.magic, "PMC") != 0)
592  goto invalid_file;
593 
594  if (info == NULL)
595  return 0;
596 
597  info->gen = SWITCHTEC_GEN3;
598  info->part_id = hdr.type;
599  info->image_crc = le32toh(hdr.image_crc);
600  version_to_string(hdr.version, info->version, sizeof(info->version));
601  info->image_len = le32toh(hdr.image_len);
602 
603  info->type = switchtec_fw_id_to_type(info);
604 
605  info->secure_version = 0;
606 
607  return 0;
608 
609 invalid_file:
610  errno = ENOEXEC;
611  return -errno;
612 }
613 
614 static int switchtec_fw_file_info_gen4(int fd,
615  struct switchtec_fw_image_info *info)
616 {
617  int ret;
618  struct switchtec_fw_metadata_gen4 hdr = {};
619 
620  ret = read(fd, &hdr, sizeof(hdr));
621  lseek(fd, 0, SEEK_SET);
622 
623  if (ret != sizeof(hdr))
624  goto invalid_file;
625 
626  if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
627  goto invalid_file;
628 
629  if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
630  goto invalid_file;
631 
632  if (!info)
633  return 0;
634 
635  info->gen = SWITCHTEC_GEN4;
636 
637  switch (hdr.type) {
638  case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
639  info->part_id = SWITCHTEC_FW_PART_ID_G4_MAP0;
640  break;
641  case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
642  info->part_id = SWITCHTEC_FW_PART_ID_G4_KEY0;
643  break;
644  case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
645  info->part_id = SWITCHTEC_FW_PART_ID_G4_BL20;
646  break;
647  case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
648  info->part_id = SWITCHTEC_FW_PART_ID_G4_CFG0;
649  break;
650  case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
651  info->part_id = SWITCHTEC_FW_PART_ID_G4_IMG0;
652  break;
653  case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
654  info->part_id = SWITCHTEC_FW_PART_ID_G4_NVLOG;
655  break;
656  case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
657  info->part_id = SWITCHTEC_FW_PART_ID_G4_SEEPROM;
658  break;
659  default:
660  goto invalid_file;
661  };
662 
663  info->image_crc = le32toh(hdr.image_crc);
664  version_to_string(hdr.version, info->version, sizeof(info->version));
665  info->image_len = le32toh(hdr.image_len);
666 
667  info->type = switchtec_fw_id_to_type(info);
668 
669  info->secure_version = le32toh(hdr.secure_version);
670  return 0;
671 
672 invalid_file:
673  errno = ENOEXEC;
674  return -errno;
675 }
676 
684 {
685  char magic[4];
686  int ret;
687 
688  ret = read(fd, &magic, sizeof(magic));
689  lseek(fd, 0, SEEK_SET);
690 
691  if (ret != sizeof(magic)) {
692  errno = ENOEXEC;
693  return -1;
694  }
695 
696  if (!strncmp(magic, "PMC", sizeof(magic))) {
697  switchtec_fw_file_info_gen3(fd, info);
698  } else if (!strncmp(magic, "MSCC", sizeof(magic))) {
699  switchtec_fw_file_info_gen4(fd, info);
700  } else {
701  errno = ENOEXEC;
702  return -1;
703  }
704 
705  return 0;
706 }
707 
716 int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
717  int img_fd)
718 {
719  int ret;
720  struct switchtec_fw_image_info info;
721  struct switchtec_sn_ver_info sn_info = {};
722 
723  if (switchtec_is_gen3(dev))
724  return 0;
725 
726  ret = switchtec_fw_file_info(img_fd, &info);
727  if (ret)
728  return 0;
729 
730  ret = switchtec_sn_ver_get(dev, &sn_info);
731  if (ret) {
732  sn_info.ver_bl2 = 0xffffffff;
733  sn_info.ver_main = 0xffffffff;
734  sn_info.ver_km = 0xffffffff;
735  }
736 
737  switch (info.type) {
738  case SWITCHTEC_FW_TYPE_BL2:
739  if (info.secure_version > sn_info.ver_bl2)
740  return 1;
741 
742  break;
743  case SWITCHTEC_FW_TYPE_IMG:
744  if (info.secure_version > sn_info.ver_main)
745  return 1;
746 
747  break;
748  case SWITCHTEC_FW_TYPE_KEY:
749  if (info.secure_version > sn_info.ver_km)
750  return 1;
751 
752  break;
753  default:
754  break;
755  }
756 
757  return 0;
758 }
759 
765 const char *switchtec_fw_image_type(const struct switchtec_fw_image_info *info)
766 {
767  switch (info->type) {
768  case SWITCHTEC_FW_TYPE_BOOT: return "BOOT";
769  case SWITCHTEC_FW_TYPE_MAP: return "MAP";
770  case SWITCHTEC_FW_TYPE_IMG: return "IMG";
771  case SWITCHTEC_FW_TYPE_CFG: return "CFG";
772  case SWITCHTEC_FW_TYPE_KEY: return "KEY";
773  case SWITCHTEC_FW_TYPE_BL2: return "BL2";
774  case SWITCHTEC_FW_TYPE_NVLOG: return "NVLOG";
775  case SWITCHTEC_FW_TYPE_SEEPROM: return "SEEPROM";
776  default: return "UNKNOWN";
777  }
778 }
779 
780 static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
781  struct switchtec_fw_image_info *info)
782 {
783  uint32_t map0_update_index;
784  uint32_t map1_update_index;
785  int ret;
786 
787  ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
788  sizeof(uint32_t), &map0_update_index);
789  if (ret < 0)
790  return ret;
791 
792  ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
793  sizeof(uint32_t), &map1_update_index);
794  if (ret < 0)
795  return ret;
796 
797  info->active = 0;
798  if (map0_update_index < map1_update_index) {
799  if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
800  info->active = 1;
801  } else {
802  if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
803  info->active = 1;
804  }
805 
806  return 0;
807 }
808 
809 static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
810  struct switchtec_fw_image_info *inf)
811 {
812  struct switchtec_fw_footer_gen3 *metadata;
813  unsigned long addr;
814  int ret = 0;
815 
816  if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
817  return 1;
818 
819  metadata = malloc(sizeof(*metadata));
820  if (!metadata)
821  return -1;
822 
823  addr = inf->part_addr + inf->part_len - sizeof(*metadata);
824 
825  ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
826  if (ret < 0)
827  goto err_out;
828 
829  if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
830  goto err_out;
831 
832  version_to_string(metadata->version, inf->version,
833  sizeof(inf->version));
834  inf->part_body_offset = 0;
835  inf->image_crc = metadata->image_crc;
836  inf->image_len = metadata->image_len;
837  inf->metadata = metadata;
838 
839  return 0;
840 
841 err_out:
842  free(metadata);
843  return 1;
844 }
845 
846 static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
847  struct switchtec_fw_image_info *inf)
848 {
849  int ret = 0;
850 
851  inf->read_only = switchtec_fw_is_boot_ro(dev);
852 
853  switch (inf->part_id) {
854  case SWITCHTEC_FW_PART_ID_G3_BOOT:
855  inf->part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
856  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
857  inf->active = true;
858  break;
859  case SWITCHTEC_FW_PART_ID_G3_MAP0:
860  inf->part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
861  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
862  ret = switchtec_fw_map_get_active(dev, inf);
863  break;
864  case SWITCHTEC_FW_PART_ID_G3_MAP1:
865  inf->part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
866  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
867  ret = switchtec_fw_map_get_active(dev, inf);
868  break;
869  default:
870  ret = switchtec_flash_part(dev, inf, inf->part_id);
871  inf->read_only = false;
872  }
873 
874  if (ret)
875  return ret;
876 
877  inf->valid = true;
878 
879  if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
880  return 1;
881 
882  return switchtec_fw_info_metadata_gen3(dev, inf);
883 }
884 
885 static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
886  struct switchtec_fw_image_info *inf)
887 {
888  struct switchtec_fw_metadata_gen4 *metadata;
889  struct {
890  uint8_t subcmd;
891  uint8_t part_id;
892  } subcmd = {
893  .subcmd = MRPC_PART_INFO_GET_METADATA,
894  .part_id = inf->part_id,
895  };
896  int ret;
897 
898  if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
899  return 1;
900 
901  metadata = malloc(sizeof(*metadata));
902  if (!metadata)
903  return -1;
904 
905  ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
906  metadata, sizeof(*metadata));
907  if (ret)
908  goto err_out;
909 
910  if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
911  goto err_out;
912 
913  if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
914  goto err_out;
915 
916  version_to_string(metadata->version, inf->version,
917  sizeof(inf->version));
918  inf->part_body_offset = metadata->header_len;
919  inf->image_crc = metadata->image_crc;
920  inf->image_len = metadata->image_len;
921  inf->metadata = metadata;
922 
923  return 0;
924 
925 err_out:
926  free(metadata);
927  return -1;
928 }
929 
931  uint32_t firmware_version;
932  uint32_t flash_size;
933  uint16_t device_id;
934  uint8_t ecc_enable;
935  uint8_t rsvd1;
936  uint8_t running_bl2_flag;
937  uint8_t running_cfg_flag;
938  uint8_t running_img_flag;
939  uint8_t running_key_flag;
940  uint8_t redundancy_key_flag;
941  uint8_t redundancy_bl2_flag;
942  uint8_t redundancy_cfg_flag;
943  uint8_t redundancy_img_flag;
944  uint32_t rsvd2[11];
946  uint32_t image_crc;
947  uint32_t image_len;
948  uint16_t image_version;
949  uint8_t valid;
950  uint8_t active;
951  uint32_t part_start;
952  uint32_t part_end;
953  uint32_t part_offset;
954  uint32_t part_size_dw;
955  uint8_t read_only;
956  uint8_t is_using;
957  uint8_t rsvd[2];
958  } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
959  img0, img1, nvlog, vendor[8];
960 };
961 
962 static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
963  struct switchtec_fw_image_info *inf,
964  struct switchtec_flash_info_gen4 *all)
965 {
966  struct switchtec_flash_part_info_gen4 *part_info;
967 
968  switch(inf->part_id) {
969  case SWITCHTEC_FW_PART_ID_G4_MAP0:
970  part_info = &all->map0;
971  break;
972  case SWITCHTEC_FW_PART_ID_G4_MAP1:
973  part_info = &all->map1;
974  break;
975  case SWITCHTEC_FW_PART_ID_G4_KEY0:
976  part_info = &all->keyman0;
977  inf->redundant = all->redundancy_key_flag;
978  break;
979  case SWITCHTEC_FW_PART_ID_G4_KEY1:
980  part_info = &all->keyman1;
981  inf->redundant = all->redundancy_key_flag;
982  break;
983  case SWITCHTEC_FW_PART_ID_G4_BL20:
984  part_info = &all->bl20;
985  inf->redundant = all->redundancy_bl2_flag;
986  break;
987  case SWITCHTEC_FW_PART_ID_G4_BL21:
988  part_info = &all->bl21;
989  inf->redundant = all->redundancy_bl2_flag;
990  break;
991  case SWITCHTEC_FW_PART_ID_G4_IMG0:
992  part_info = &all->img0;
993  inf->redundant = all->redundancy_img_flag;
994  break;
995  case SWITCHTEC_FW_PART_ID_G4_IMG1:
996  part_info = &all->img1;
997  inf->redundant = all->redundancy_img_flag;
998  break;
999  case SWITCHTEC_FW_PART_ID_G4_CFG0:
1000  part_info = &all->cfg0;
1001  inf->redundant = all->redundancy_cfg_flag;
1002  break;
1003  case SWITCHTEC_FW_PART_ID_G4_CFG1:
1004  part_info = &all->cfg1;
1005  inf->redundant = all->redundancy_cfg_flag;
1006  break;
1007  case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1008  part_info = &all->nvlog;
1009  break;
1010  default:
1011  errno = EINVAL;
1012  return -1;
1013  }
1014 
1015  inf->part_addr = part_info->part_start;
1016  inf->part_len = part_info->part_size_dw * 4;
1017  inf->active = part_info->active;
1018  inf->running = part_info->is_using;
1019  inf->read_only = part_info->read_only;
1020  inf->valid = part_info->valid;
1021  if (!inf->valid)
1022  return 0;
1023 
1024  return switchtec_fw_info_metadata_gen4(dev, inf);
1025 }
1026 
1036 static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1037  struct switchtec_fw_image_info *info)
1038 {
1039  int ret;
1040  int i;
1041  uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1042  struct switchtec_flash_info_gen4 all_info;
1043 
1044  if (info == NULL || nr_info == 0)
1045  return -EINVAL;
1046 
1047  if (dev->gen == SWITCHTEC_GEN4) {
1048  ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1049  sizeof(subcmd), &all_info,
1050  sizeof(all_info));
1051  if (ret)
1052  return ret;
1053  }
1054 
1055  for (i = 0; i < nr_info; i++) {
1056  struct switchtec_fw_image_info *inf = &info[i];
1057  ret = 0;
1058 
1059  inf->gen = dev->gen;
1060  inf->type = switchtec_fw_id_to_type(inf);
1061  inf->active = false;
1062  inf->running = false;
1063  inf->valid = false;
1064 
1065  switch (info->gen) {
1066  case SWITCHTEC_GEN3:
1067  ret = switchtec_fw_part_info_gen3(dev, inf);
1068  break;
1069  case SWITCHTEC_GEN4:
1070  ret = switchtec_fw_part_info_gen4(dev, inf, &all_info);
1071  break;
1072  default:
1073  errno = EINVAL;
1074  return -1;
1075  }
1076 
1077  if (ret < 0)
1078  return ret;
1079 
1080  if (ret) {
1081  inf->version[0] = 0;
1082  inf->image_crc = 0xFFFFFFFF;
1083  inf->metadata = NULL;
1084  }
1085  }
1086 
1087  return nr_info;
1088 }
1089 
1090 static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1091  uint8_t index)
1092 {
1093  int ret;
1094  uint32_t result;
1095 
1096  subcmd |= index << 8;
1097 
1098  ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1099  &result, sizeof(result));
1100  if (ret)
1101  return -1;
1102 
1103  return result;
1104 }
1105 
1106 static int get_multicfg(struct switchtec_dev *dev,
1107  struct switchtec_fw_image_info *info,
1108  int *nr_mult)
1109 {
1110  int ret;
1111  int i;
1112 
1113  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1114  if (ret < 0)
1115  return ret;
1116 
1117  if (!ret) {
1118  *nr_mult = 0;
1119  return 0;
1120  }
1121 
1122  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1123  if (ret < 0)
1124  return ret;
1125 
1126  if (*nr_mult > ret)
1127  *nr_mult = ret;
1128 
1129  for (i = 0; i < *nr_mult; i++) {
1130  info[i].part_addr = multicfg_subcmd(dev,
1131  MRPC_MULTI_CFG_START_ADDR,
1132  i);
1133  info[i].part_len = multicfg_subcmd(dev,
1134  MRPC_MULTI_CFG_LENGTH, i);
1135  strcpy(info[i].version, "");
1136  info[i].image_crc = 0;
1137  info[i].active = 0;
1138  }
1139 
1140  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1141  if (ret < 0)
1142  return ret;
1143 
1144  if (ret < *nr_mult)
1145  info[ret].active = 1;
1146 
1147  return 0;
1148 }
1149 
1150 static const enum switchtec_fw_image_part_id_gen3
1151 switchtec_fw_partitions_gen3[] = {
1152  SWITCHTEC_FW_PART_ID_G3_BOOT,
1153  SWITCHTEC_FW_PART_ID_G3_MAP0,
1154  SWITCHTEC_FW_PART_ID_G3_MAP1,
1155  SWITCHTEC_FW_PART_ID_G3_IMG0,
1156  SWITCHTEC_FW_PART_ID_G3_DAT0,
1157  SWITCHTEC_FW_PART_ID_G3_DAT1,
1158  SWITCHTEC_FW_PART_ID_G3_NVLOG,
1159  SWITCHTEC_FW_PART_ID_G3_IMG1,
1160 };
1161 
1162 static const enum switchtec_fw_image_part_id_gen4
1163 switchtec_fw_partitions_gen4[] = {
1164  SWITCHTEC_FW_PART_ID_G4_MAP0,
1165  SWITCHTEC_FW_PART_ID_G4_MAP1,
1166  SWITCHTEC_FW_PART_ID_G4_KEY0,
1167  SWITCHTEC_FW_PART_ID_G4_KEY1,
1168  SWITCHTEC_FW_PART_ID_G4_BL20,
1169  SWITCHTEC_FW_PART_ID_G4_BL21,
1170  SWITCHTEC_FW_PART_ID_G4_CFG0,
1171  SWITCHTEC_FW_PART_ID_G4_CFG1,
1172  SWITCHTEC_FW_PART_ID_G4_IMG0,
1173  SWITCHTEC_FW_PART_ID_G4_IMG1,
1174  SWITCHTEC_FW_PART_ID_G4_NVLOG,
1175 };
1176 
1177 static struct switchtec_fw_part_type *
1178 switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
1179  struct switchtec_fw_image_info *info)
1180 {
1181  switch (info->type) {
1182  case SWITCHTEC_FW_TYPE_BOOT: return &summary->boot;
1183  case SWITCHTEC_FW_TYPE_MAP: return &summary->map;
1184  case SWITCHTEC_FW_TYPE_IMG: return &summary->img;
1185  case SWITCHTEC_FW_TYPE_CFG: return &summary->cfg;
1186  case SWITCHTEC_FW_TYPE_NVLOG: return &summary->nvlog;
1187  case SWITCHTEC_FW_TYPE_SEEPROM: return &summary->seeprom;
1188  case SWITCHTEC_FW_TYPE_KEY: return &summary->key;
1189  case SWITCHTEC_FW_TYPE_BL2: return &summary->bl2;
1190  default: return NULL;
1191  }
1192 }
1193 
1203 switchtec_fw_part_summary(struct switchtec_dev *dev)
1204 {
1205  struct switchtec_fw_part_summary *summary;
1206  struct switchtec_fw_image_info **infp;
1207  struct switchtec_fw_part_type *type;
1208  int nr_info, nr_mcfg = 16;
1209  size_t st_sz;
1210  int ret, i;
1211 
1212  switch (dev->gen) {
1213  case SWITCHTEC_GEN3:
1214  nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1215  break;
1216  case SWITCHTEC_GEN4:
1217  nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1218  break;
1219  default:
1220  errno = EINVAL;
1221  return NULL;
1222  }
1223 
1224  st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
1225 
1226  summary = malloc(st_sz);
1227  if (!summary)
1228  return NULL;
1229 
1230  memset(summary, 0, st_sz);
1231  summary->nr_info = nr_info;
1232 
1233  switch (dev->gen) {
1234  case SWITCHTEC_GEN3:
1235  for (i = 0; i < nr_info; i++)
1236  summary->all[i].part_id =
1237  switchtec_fw_partitions_gen3[i];
1238  break;
1239  case SWITCHTEC_GEN4:
1240  for (i = 0; i < nr_info; i++)
1241  summary->all[i].part_id =
1242  switchtec_fw_partitions_gen4[i];
1243  break;
1244  default:
1245  errno = EINVAL;
1246  return NULL;
1247  }
1248 
1249  ret = switchtec_fw_part_info(dev, nr_info, summary->all);
1250  if (ret != nr_info) {
1251  free(summary);
1252  return NULL;
1253  }
1254 
1255  ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1256  if (ret) {
1257  nr_mcfg = 0;
1258  errno = 0;
1259  }
1260 
1261  for (i = 0; i < nr_info; i++) {
1262  type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1263  if (summary->all[i].active)
1264  type->active = &summary->all[i];
1265  else
1266  type->inactive = &summary->all[i];
1267  }
1268 
1269  infp = &summary->mult_cfg;
1270  for (; i < nr_info + nr_mcfg; i++) {
1271  *infp = &summary->all[i];
1272  infp = &summary->all[i].next;
1273  }
1274 
1275  return summary;
1276 }
1277 
1283 {
1284  int i;
1285 
1286  for (i = 0; i < summary->nr_info; i++)
1287  free(summary->all[i].metadata);
1288 
1289  free(summary);
1290 }
1291 
1300 int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
1301  size_t len, void *buf)
1302 {
1303  int ret;
1304  struct {
1305  uint32_t addr;
1306  uint32_t length;
1307  } cmd;
1308  unsigned char *cbuf = buf;
1309  size_t read = 0;
1310 
1311  while(len) {
1312  size_t chunk_len = len;
1313  if (chunk_len > MRPC_MAX_DATA_LEN-8)
1314  chunk_len = MRPC_MAX_DATA_LEN-8;
1315 
1316  cmd.addr = htole32(addr);
1317  cmd.length = htole32(chunk_len);
1318 
1319  ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
1320  cbuf, chunk_len);
1321  if (ret)
1322  return -1;
1323 
1324  addr += chunk_len;
1325  len -= chunk_len;
1326  read += chunk_len;
1327  cbuf += chunk_len;
1328  }
1329 
1330  return read;
1331 }
1332 
1344 int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
1345  unsigned long addr, size_t len,
1346  void (*progress_callback)(int cur, int tot))
1347 {
1348  int ret;
1349  unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1350  size_t read = 0;
1351  size_t total_len = len;
1352  size_t total_wrote;
1353  ssize_t wrote;
1354 
1355  while(len) {
1356  size_t chunk_len = len;
1357  if (chunk_len > sizeof(buf))
1358  chunk_len = sizeof(buf);
1359 
1360  ret = switchtec_fw_read(dev, addr, chunk_len, buf);
1361  if (ret < 0)
1362  return ret;
1363 
1364  total_wrote = 0;
1365  while (total_wrote < ret) {
1366  wrote = write(fd, &buf[total_wrote],
1367  ret - total_wrote);
1368  if (wrote < 0)
1369  return -1;
1370  total_wrote += wrote;
1371  }
1372 
1373  read += ret;
1374  addr += ret;
1375  len -= ret;
1376 
1377  if (progress_callback)
1378  progress_callback(read, total_len);
1379  }
1380 
1381  return read;
1382 }
1383 
1393 int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
1394  struct switchtec_fw_image_info *info,
1395  void (*progress_callback)(int cur, int tot))
1396 {
1397  return switchtec_fw_read_fd(dev, fd,
1398  info->part_addr + info->part_body_offset,
1399  info->image_len, progress_callback);
1400 }
1401 
1402 static int switchtec_fw_img_write_hdr_gen3(int fd,
1403  struct switchtec_fw_image_info *info)
1404 {
1405  struct switchtec_fw_footer_gen3 *ftr = info->metadata;
1406  struct switchtec_fw_image_header_gen3 hdr = {};
1407 
1408  memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
1409  hdr.image_len = ftr->image_len;
1410  hdr.type = info->part_id;
1411  hdr.load_addr = ftr->load_addr;
1412  hdr.version = ftr->version;
1413  hdr.header_crc = ftr->header_crc;
1414  hdr.image_crc = ftr->image_crc;
1415 
1416  if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1417  hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1418  else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1419  hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1420  else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1421  hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1422 
1423  return write(fd, &hdr, sizeof(hdr));
1424 }
1425 
1426 static int switchtec_fw_img_write_hdr_gen4(int fd,
1427  struct switchtec_fw_image_info *info)
1428 {
1429  int ret;
1430  struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
1431 
1432  ret = write(fd, hdr, sizeof(*hdr));
1433  if (ret < 0)
1434  return ret;
1435 
1436  return lseek(fd, info->part_body_offset, SEEK_SET);
1437 }
1438 
1453 {
1454  switch (info->gen) {
1455  case SWITCHTEC_GEN3: return switchtec_fw_img_write_hdr_gen3(fd, info);
1456  case SWITCHTEC_GEN4: return switchtec_fw_img_write_hdr_gen4(fd, info);
1457  default:
1458  errno = EINVAL;
1459  return -1;
1460  }
1461 }
1462 
1464  uint8_t subcmd;
1465  uint8_t set_get;
1466  uint8_t status;
1467  uint8_t reserved;
1468 };
1469 
1476 int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
1477 {
1478  struct switchtec_boot_ro subcmd = {
1479  .subcmd = MRPC_FWDNLD_BOOT_RO,
1480  .set_get = 0,
1481  };
1482 
1483  struct {
1484  uint8_t status;
1485  uint8_t reserved[3];
1486  } result;
1487 
1488  int ret;
1489 
1490  if (!switchtec_is_gen3(dev)) {
1491  errno = ENOTSUP;
1492  return -1;
1493  }
1494 
1495  ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1496  &result, sizeof(result));
1497 
1498  if (ret == ERR_SUBCMD_INVALID) {
1499  errno = 0;
1500  return 0;
1501  }
1502 
1503  if (ret)
1504  return ret;
1505 
1506  return result.status;
1507 }
1508 
1515 int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
1516  enum switchtec_fw_ro ro)
1517 {
1518  struct switchtec_boot_ro subcmd = {
1519  .subcmd = MRPC_FWDNLD_BOOT_RO,
1520  .set_get = 1,
1521  .status = ro,
1522  };
1523 
1524  if (!switchtec_is_gen3(dev)) {
1525  errno = ENOTSUP;
1526  return -1;
1527  }
1528 
1529  return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1530  NULL, 0);
1531 }
1532 
char version[32]
Firmware/Config version.
Definition: switchtec.h:217
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:397
size_t part_addr
Address of the partition.
Definition: switchtec.h:218
unsigned long image_crc
CRC checksum of the image.
Definition: switchtec.h:222
enum switchtec_fw_type type
Image partition type.
Definition: switchtec.h:216
Information about a firmware image or partition.
Definition: switchtec.h:213
switchtec_boot_phase
Device boot phase.
Definition: switchtec.h:102
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:187
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:1452
unsigned long part_id
Image partition ID.
Definition: switchtec.h:215
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Definition: mfg.c:127
size_t image_len
Length of the image.
Definition: switchtec.h:221
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:299
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&#39;s flash data into a file.
Definition: fw.c:1344
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition: fw.c:493
Main Switchtec header.
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&#39;s flash image body into a file.
Definition: fw.c:1393
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:251
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:716
enum switchtec_gen gen
Image generation.
Definition: switchtec.h:214
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition: switchtec.h:668
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition: fw.c:1282
size_t part_body_offset
Partition image body offset.
Definition: switchtec.h:220
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition: fw.c:1476
int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr, size_t len, void *buf)
Read a Switchtec device&#39;s flash data.
Definition: fw.c:1300
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition: fw.c:683
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:249
switchtec_fw_dlstatus
Firmware update status.
Definition: switchtec.h:649
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:765
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:1203
size_t part_len
Length of the partition.
Definition: switchtec.h:219
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition: switchtec.h:366
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:1036
int switchtec_fw_set_boot_ro(struct switchtec_dev *dev, enum switchtec_fw_ro ro)
Set or clear a boot partition&#39;s read-only flag.
Definition: fw.c:1515
Definition: fw.c:276
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:132