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