Velocity Userspace
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 };
75 
77  char magic[4];
78  char sub_magic[4];
79  uint32_t hdr_version;
80  uint32_t secure_version;
81  uint32_t header_len;
82  uint32_t metadata_len;
83  uint32_t image_len;
84  uint32_t type;
85  uint32_t rsvd;
86  uint32_t version;
87  uint32_t sequence;
88  uint32_t reserved1;
89  uint8_t date_str[8];
90  uint8_t time_str[8];
91  uint8_t img_str[16];
92  uint8_t rsvd1[4];
93  uint32_t image_crc;
94  uint8_t public_key_modulus[512];
95  uint8_t public_key_exponent[4];
96  uint8_t uart_port;
97  uint8_t uart_rate : 6;
98  uint8_t uart_parity : 2;
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 struct cmd_fwdl {
224  struct cmd_fwdl_hdr {
225  uint8_t subcmd;
226  uint8_t dont_activate;
227  uint8_t reserved[2];
228  uint32_t offset;
229  uint32_t img_length;
230  uint32_t blk_length;
231  } hdr;
232  uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
233 };
234 
246 int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
247  int dont_activate, int force,
248  void (*progress_callback)(int cur, int tot))
249 {
250  enum switchtec_fw_dlstatus status;
251  enum mrpc_bg_status bgstatus;
252  ssize_t image_size, offset = 0;
253  int ret;
254  struct cmd_fwdl cmd = {};
255  uint32_t cmd_id = MRPC_FWDNLD;
256 
257  if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
258  cmd_id = MRPC_FW_TX;
259 
260  image_size = lseek(img_fd, 0, SEEK_END);
261  if (image_size < 0)
262  return -errno;
263  lseek(img_fd, 0, SEEK_SET);
264 
265  switchtec_fw_dlstatus(dev, &status, &bgstatus);
266 
267  if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
268  errno = EBUSY;
269  return -EBUSY;
270  }
271 
272  if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
273  errno = EBUSY;
274  return -EBUSY;
275  }
276 
277  if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
278  cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
279  else
280  cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
281 
282  cmd.hdr.dont_activate = !!dont_activate;
283  cmd.hdr.img_length = htole32(image_size);
284 
285  while (offset < image_size) {
286  ssize_t blklen = read(img_fd, &cmd.data,
287  sizeof(cmd.data));
288 
289  if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
290  continue;
291 
292  if (blklen < 0)
293  return -errno;
294 
295  if (blklen == 0)
296  break;
297 
298  cmd.hdr.offset = htole32(offset);
299  cmd.hdr.blk_length = htole32(blklen);
300 
301  ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
302  NULL, 0);
303 
304  if (ret)
305  return ret;
306 
307  ret = switchtec_fw_wait(dev, &status);
308  if (ret != 0)
309  return ret;
310 
311  offset += le32toh(cmd.hdr.blk_length);
312 
313  if (progress_callback)
314  progress_callback(offset, image_size);
315 
316  }
317 
318  if (status == SWITCHTEC_DLSTAT_COMPLETES)
319  return 0;
320 
321  if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
322  return 0;
323 
324  if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
325  return 0;
326 
327  if (status == 0)
328  return SWITCHTEC_DLSTAT_HARDWARE_ERR;
329 
330  return status;
331 }
332 
338 enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
339 {
340  uint8_t major = (version >> 24) & 0xff;
341 
342  switch (major) {
343  case 1:
344  case 2: return SWITCHTEC_GEN3;
345  case 3:
346  case 4:
347  case 5: return SWITCHTEC_GEN4;
348  case 6:
349  case 7:
350  case 8: return SWITCHTEC_GEN5;
351  default: return SWITCHTEC_GEN_UNKNOWN;
352  }
353 }
354 
366 int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
367  int dont_activate, int force,
368  void (*progress_callback)(int cur, int tot))
369 {
370  enum switchtec_fw_dlstatus status;
371  enum mrpc_bg_status bgstatus;
372  ssize_t image_size, offset = 0;
373  int ret;
374  struct cmd_fwdl cmd = {};
375  uint32_t cmd_id = MRPC_FWDNLD;
376 
377  if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
378  cmd_id = MRPC_FW_TX;
379 
380  ret = fseek(fimg, 0, SEEK_END);
381  if (ret)
382  return -errno;
383  image_size = ftell(fimg);
384  if (image_size < 0)
385  return -errno;
386  ret = fseek(fimg, 0, SEEK_SET);
387  if (ret)
388  return -errno;
389 
390  switchtec_fw_dlstatus(dev, &status, &bgstatus);
391 
392  if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
393  errno = EBUSY;
394  return -EBUSY;
395  }
396 
397  if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
398  errno = EBUSY;
399  return -EBUSY;
400  }
401 
402  if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
403  cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
404  else
405  cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
406 
407  cmd.hdr.dont_activate = !!dont_activate;
408  cmd.hdr.img_length = htole32(image_size);
409 
410  while (offset < image_size) {
411  ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
412 
413  if (blklen == 0) {
414  ret = ferror(fimg);
415  if (ret)
416  return ret;
417  break;
418  }
419 
420  cmd.hdr.offset = htole32(offset);
421  cmd.hdr.blk_length = htole32(blklen);
422 
423  ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
424  NULL, 0);
425 
426  if (ret)
427  return ret;
428 
429  ret = switchtec_fw_wait(dev, &status);
430  if (ret != 0)
431  return ret;
432 
433  offset += le32toh(cmd.hdr.blk_length);
434 
435  if (progress_callback)
436  progress_callback(offset, image_size);
437  }
438 
439  if (status == SWITCHTEC_DLSTAT_COMPLETES)
440  return 0;
441 
442  if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
443  return 0;
444 
445  if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
446  return 0;
447 
448  if (status == 0)
449  return SWITCHTEC_DLSTAT_HARDWARE_ERR;
450 
451  return status;
452 }
453 
462 void switchtec_fw_perror(const char *s, int ret)
463 {
464  const char *msg;
465 
466  if (ret <= 0) {
467  perror(s);
468  return;
469  }
470 
471  switch(ret) {
472  case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
473  msg = "Header incorrect"; break;
474  case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
475  msg = "Offset incorrect"; break;
476  case SWITCHTEC_DLSTAT_CRC_INCORRECT:
477  msg = "CRC incorrect"; break;
478  case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
479  msg = "Length incorrect"; break;
480  case SWITCHTEC_DLSTAT_HARDWARE_ERR:
481  msg = "Hardware Error"; break;
482  case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
483  msg = "Package length less than 32 bytes"; break;
484  case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
485  msg = "Signature memory allocation failed"; break;
486  case SWITCHTEC_DLSTAT_SEEPROM:
487  msg = "SEEPROM download failed"; break;
488  case SWITCHTEC_DLSTAT_READONLY_PARTITION:
489  msg = "Programming a read-only partition"; break;
490  case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
491  msg = "Download Timeout"; break;
492  case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
493  msg = "SEEPROM or related TWI bus isn't enabled"; break;
494  case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
495  msg = "Programming a running partition"; break;
496  case SWITCHTEC_DLSTAT_NOT_ALLOWED:
497  msg = "Programming not allowed over this interface"; break;
498  case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
499  msg = "Activation failed due to XML version mismatch"; break;
500  case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
501  msg = "Activation failed due to unknown error"; break;
502  case SWITCHTEC_DLSTAT_ERROR_OFFSET:
503  msg = "Data offset error during programming"; break;
504  case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
505  msg = "Failed to program to flash"; break;
506  case SWITCHTEC_DLSTAT_METADATA_LEN_INCORRECT:
507  msg = "Image transfer metadata length incorrect"; break;
508  case SWITCHTEC_DLSTAT_FLM_NOT_INIT:
509  msg = "MRPC command not Supported as flash is not initialized";
510  break;
511 
512 
513  case SWITCHTEC_DLSTAT_NO_FILE:
514  msg = "No Image Transferred"; break;
515  default:
516  fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
517  return;
518  }
519 
520  fprintf(stderr, "%s: %s\n", s, msg);
521 }
522 
523 static enum switchtec_fw_type
524 switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
525 {
526  switch ((unsigned long)info->part_id) {
527  case SWITCHTEC_FW_PART_ID_G3_BOOT: return SWITCHTEC_FW_TYPE_BOOT;
528  case SWITCHTEC_FW_PART_ID_G3_MAP0: return SWITCHTEC_FW_TYPE_MAP;
529  case SWITCHTEC_FW_PART_ID_G3_MAP1: return SWITCHTEC_FW_TYPE_MAP;
530  case SWITCHTEC_FW_PART_ID_G3_IMG0: return SWITCHTEC_FW_TYPE_IMG;
531  case SWITCHTEC_FW_PART_ID_G3_IMG1: return SWITCHTEC_FW_TYPE_IMG;
532  case SWITCHTEC_FW_PART_ID_G3_DAT0: return SWITCHTEC_FW_TYPE_CFG;
533  case SWITCHTEC_FW_PART_ID_G3_DAT1: return SWITCHTEC_FW_TYPE_CFG;
534  case SWITCHTEC_FW_PART_ID_G3_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
535  case SWITCHTEC_FW_PART_ID_G3_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
536 
537  //Legacy
538  case 0xa8000000: return SWITCHTEC_FW_TYPE_BOOT;
539  case 0xa8020000: return SWITCHTEC_FW_TYPE_MAP;
540  case 0xa8060000: return SWITCHTEC_FW_TYPE_IMG;
541  case 0xa8210000: return SWITCHTEC_FW_TYPE_CFG;
542 
543  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
544  }
545 }
546 
547 static enum switchtec_fw_type
548 switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
549 {
550  switch (info->part_id) {
551  case SWITCHTEC_FW_PART_ID_G4_MAP0: return SWITCHTEC_FW_TYPE_MAP;
552  case SWITCHTEC_FW_PART_ID_G4_MAP1: return SWITCHTEC_FW_TYPE_MAP;
553  case SWITCHTEC_FW_PART_ID_G4_KEY0: return SWITCHTEC_FW_TYPE_KEY;
554  case SWITCHTEC_FW_PART_ID_G4_KEY1: return SWITCHTEC_FW_TYPE_KEY;
555  case SWITCHTEC_FW_PART_ID_G4_BL20: return SWITCHTEC_FW_TYPE_BL2;
556  case SWITCHTEC_FW_PART_ID_G4_BL21: return SWITCHTEC_FW_TYPE_BL2;
557  case SWITCHTEC_FW_PART_ID_G4_CFG0: return SWITCHTEC_FW_TYPE_CFG;
558  case SWITCHTEC_FW_PART_ID_G4_CFG1: return SWITCHTEC_FW_TYPE_CFG;
559  case SWITCHTEC_FW_PART_ID_G4_IMG0: return SWITCHTEC_FW_TYPE_IMG;
560  case SWITCHTEC_FW_PART_ID_G4_IMG1: return SWITCHTEC_FW_TYPE_IMG;
561  case SWITCHTEC_FW_PART_ID_G4_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
562  case SWITCHTEC_FW_PART_ID_G4_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
563  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
564  }
565 }
566 
567 static enum switchtec_fw_type
568 switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
569 {
570  switch (info->gen) {
571  case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
572  case SWITCHTEC_GEN4:
573  case SWITCHTEC_GEN5: return switchtec_fw_id_to_type_gen4(info);
574  default: return SWITCHTEC_FW_TYPE_UNKNOWN;
575  }
576 }
577 
578 static int switchtec_fw_file_info_gen3(int fd,
579  struct switchtec_fw_image_info *info)
580 {
581  struct switchtec_fw_image_header_gen3 hdr = {};
582  int ret;
583 
584  ret = read(fd, &hdr, sizeof(hdr));
585  lseek(fd, 0, SEEK_SET);
586 
587  if (ret != sizeof(hdr))
588  goto invalid_file;
589 
590  if (strcmp(hdr.magic, "PMC") != 0)
591  goto invalid_file;
592 
593  if (info == NULL)
594  return 0;
595 
596  info->gen = SWITCHTEC_GEN3;
597  info->part_id = hdr.type;
598  info->image_crc = le32toh(hdr.image_crc);
599  version_to_string(hdr.version, info->version, sizeof(info->version));
600  info->image_len = le32toh(hdr.image_len);
601 
602  info->type = switchtec_fw_id_to_type(info);
603 
604  info->secure_version = 0;
605  info->signed_image = 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  uint8_t exp_zero[4] = {};
620  uint32_t version;
621 
622  ret = read(fd, &hdr, sizeof(hdr));
623  lseek(fd, 0, SEEK_SET);
624 
625  if (ret != sizeof(hdr))
626  goto invalid_file;
627 
628  if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
629  goto invalid_file;
630 
631  if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
632  goto invalid_file;
633 
634  if (!info)
635  return 0;
636 
637  switch (le32toh(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 = le32toh(hdr.version);
665  version_to_string(version, info->version, sizeof(info->version));
666  info->image_len = le32toh(hdr.image_len);
667  info->gen = switchtec_fw_version_to_gen(version);
668 
669  info->type = switchtec_fw_id_to_type(info);
670 
671  info->secure_version = le32toh(hdr.secure_version);
672  info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
673 
674  return 0;
675 
676 invalid_file:
677  errno = ENOEXEC;
678  return -errno;
679 }
680 
688 {
689  char magic[4];
690  int ret;
691 
692  ret = read(fd, &magic, sizeof(magic));
693  lseek(fd, 0, SEEK_SET);
694 
695  if (ret != sizeof(magic)) {
696  errno = ENOEXEC;
697  return -1;
698  }
699 
700  if (!strncmp(magic, "PMC", sizeof(magic))) {
701  return switchtec_fw_file_info_gen3(fd, info);
702  } else if (!strncmp(magic, "MSCC", sizeof(magic))) {
703  return switchtec_fw_file_info_gen4(fd, info);
704  } else {
705  errno = ENOEXEC;
706  return -1;
707  }
708 
709  return 0;
710 }
711 
720 int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
721  int img_fd)
722 {
723  int ret;
724  struct switchtec_fw_image_info info;
725  struct switchtec_sn_ver_info sn_info = {};
726 
727  if (switchtec_is_gen3(dev))
728  return 0;
729 
730  ret = switchtec_fw_file_info(img_fd, &info);
731  if (ret)
732  return 0;
733 
734  if (!info.signed_image)
735  return 0;
736 
737  ret = switchtec_sn_ver_get(dev, &sn_info);
738  if (ret) {
739  sn_info.ver_bl2 = 0xffffffff;
740  sn_info.ver_main = 0xffffffff;
741  sn_info.ver_km = 0xffffffff;
742  }
743 
744  switch (info.type) {
745  case SWITCHTEC_FW_TYPE_BL2:
746  if (info.secure_version > sn_info.ver_bl2)
747  return 1;
748 
749  break;
750  case SWITCHTEC_FW_TYPE_IMG:
751  if (info.secure_version > sn_info.ver_main)
752  return 1;
753 
754  break;
755  case SWITCHTEC_FW_TYPE_KEY:
756  if (info.secure_version > sn_info.ver_km)
757  return 1;
758 
759  break;
760  default:
761  break;
762  }
763 
764  return 0;
765 }
766 
772 const char *switchtec_fw_image_type(const struct switchtec_fw_image_info *info)
773 {
774  switch (info->type) {
775  case SWITCHTEC_FW_TYPE_BOOT: return "BOOT";
776  case SWITCHTEC_FW_TYPE_MAP: return "MAP";
777  case SWITCHTEC_FW_TYPE_IMG: return "IMG";
778  case SWITCHTEC_FW_TYPE_CFG: return "CFG";
779  case SWITCHTEC_FW_TYPE_KEY: return "KEY";
780  case SWITCHTEC_FW_TYPE_BL2: return "BL2";
781  case SWITCHTEC_FW_TYPE_NVLOG: return "NVLOG";
782  case SWITCHTEC_FW_TYPE_SEEPROM: return "SEEPROM";
783  default: return "UNKNOWN";
784  }
785 }
786 
787 static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
788  struct switchtec_fw_image_info *info)
789 {
790  uint32_t map0_update_index;
791  uint32_t map1_update_index;
792  int ret;
793 
794  ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
795  sizeof(uint32_t), &map0_update_index);
796  if (ret < 0)
797  return ret;
798 
799  ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
800  sizeof(uint32_t), &map1_update_index);
801  if (ret < 0)
802  return ret;
803 
804  info->active = 0;
805  if (map0_update_index > map1_update_index) {
806  if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
807  info->active = 1;
808  } else {
809  if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
810  info->active = 1;
811  }
812 
813  return 0;
814 }
815 
816 static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
817  struct switchtec_fw_image_info *inf)
818 {
819  struct switchtec_fw_footer_gen3 *metadata;
820  unsigned long addr;
821  int ret = 0;
822 
823  if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
824  return 1;
825 
826  metadata = malloc(sizeof(*metadata));
827  if (!metadata)
828  return -1;
829 
830  addr = inf->part_addr + inf->part_len - sizeof(*metadata);
831 
832  ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
833  if (ret < 0)
834  goto err_out;
835 
836  if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
837  goto err_out;
838 
839  version_to_string(metadata->version, inf->version,
840  sizeof(inf->version));
841  inf->part_body_offset = 0;
842  inf->image_crc = metadata->image_crc;
843  inf->image_len = metadata->image_len;
844  inf->metadata = metadata;
845 
846  return 0;
847 
848 err_out:
849  free(metadata);
850  return 1;
851 }
852 
853 static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
854  struct switchtec_fw_image_info *inf)
855 {
856  int ret = 0;
857 
858  inf->read_only = switchtec_fw_is_boot_ro(dev);
859 
860  switch (inf->part_id) {
861  case SWITCHTEC_FW_PART_ID_G3_BOOT:
862  inf->part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
863  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
864  inf->active = true;
865  break;
866  case SWITCHTEC_FW_PART_ID_G3_MAP0:
867  inf->part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
868  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
869  ret = switchtec_fw_map_get_active(dev, inf);
870  break;
871  case SWITCHTEC_FW_PART_ID_G3_MAP1:
872  inf->part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
873  inf->part_len = SWITCHTEC_FLASH_PART_LEN;
874  ret = switchtec_fw_map_get_active(dev, inf);
875  break;
876  default:
877  ret = switchtec_flash_part(dev, inf, inf->part_id);
878  inf->read_only = false;
879  }
880 
881  if (ret)
882  return ret;
883 
884  inf->valid = true;
885 
886  if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
887  return 1;
888 
889  return switchtec_fw_info_metadata_gen3(dev, inf);
890 }
891 
892 static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
893  struct switchtec_fw_image_info *inf)
894 {
895  struct switchtec_fw_metadata_gen4 *metadata;
896  struct {
897  uint8_t subcmd;
898  uint8_t part_id;
899  } subcmd = {
900  .subcmd = MRPC_PART_INFO_GET_METADATA,
901  .part_id = inf->part_id,
902  };
903  int ret;
904 
905  if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
906  return 1;
907  if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
908  subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
909 
910  metadata = malloc(sizeof(*metadata));
911  if (!metadata)
912  return -1;
913 
914  ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
915  metadata, sizeof(*metadata));
916  if (ret)
917  goto err_out;
918 
919  if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
920  goto err_out;
921 
922  if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
923  goto err_out;
924 
925  version_to_string(le32toh(metadata->version), inf->version,
926  sizeof(inf->version));
927  inf->part_body_offset = le32toh(metadata->header_len);
928  inf->image_crc = le32toh(metadata->image_crc);
929  inf->image_len = le32toh(metadata->image_len);
930  inf->metadata = metadata;
931 
932  return 0;
933 
934 err_out:
935  free(metadata);
936  return -1;
937 }
938 
940  uint32_t firmware_version;
941  uint32_t flash_size;
942  uint16_t device_id;
943  uint8_t ecc_enable;
944  uint8_t rsvd1;
945  uint8_t running_bl2_flag;
946  uint8_t running_cfg_flag;
947  uint8_t running_img_flag;
948  uint8_t running_key_flag;
949  uint32_t rsvd2[12];
951  uint32_t image_crc;
952  uint32_t image_len;
953  uint16_t image_version;
954  uint8_t valid;
955  uint8_t active;
956  uint32_t part_start;
957  uint32_t part_end;
958  uint32_t part_offset;
959  uint32_t part_size_dw;
960  uint8_t read_only;
961  uint8_t is_using;
962  uint8_t rsvd[2];
963  } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
964  img0, img1, nvlog, vendor[8];
965 };
966 
967 static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
968  struct switchtec_fw_image_info *inf,
969  struct switchtec_flash_info_gen4 *all)
970 {
971  struct switchtec_flash_part_info_gen4 *part_info;
972  int ret;
973 
974  switch(inf->part_id) {
975  case SWITCHTEC_FW_PART_ID_G4_MAP0:
976  part_info = &all->map0;
977  break;
978  case SWITCHTEC_FW_PART_ID_G4_MAP1:
979  part_info = &all->map1;
980  break;
981  case SWITCHTEC_FW_PART_ID_G4_KEY0:
982  part_info = &all->keyman0;
983  break;
984  case SWITCHTEC_FW_PART_ID_G4_KEY1:
985  part_info = &all->keyman1;
986  break;
987  case SWITCHTEC_FW_PART_ID_G4_BL20:
988  part_info = &all->bl20;
989  break;
990  case SWITCHTEC_FW_PART_ID_G4_BL21:
991  part_info = &all->bl21;
992  break;
993  case SWITCHTEC_FW_PART_ID_G4_IMG0:
994  part_info = &all->img0;
995  break;
996  case SWITCHTEC_FW_PART_ID_G4_IMG1:
997  part_info = &all->img1;
998  break;
999  case SWITCHTEC_FW_PART_ID_G4_CFG0:
1000  part_info = &all->cfg0;
1001  break;
1002  case SWITCHTEC_FW_PART_ID_G4_CFG1:
1003  part_info = &all->cfg1;
1004  break;
1005  case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1006  part_info = &all->nvlog;
1007  break;
1008  case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1009  if (switchtec_gen(dev) < SWITCHTEC_GEN5)
1010  return 0;
1011 
1012  inf->active = true;
1013  /* length is not applicable for SEEPROM image */
1014  inf->part_len = 0xffffffff;
1015 
1016  ret = switchtec_fw_info_metadata_gen4(dev, inf);
1017  if (!ret) {
1018  inf->running = true;
1019  inf->valid = true;
1020  }
1021 
1022  return 0;
1023  default:
1024  errno = EINVAL;
1025  return -1;
1026  }
1027 
1028  inf->part_addr = le32toh(part_info->part_start);
1029  inf->part_len = le32toh(part_info->part_size_dw) * 4;
1030  inf->active = part_info->active;
1031  inf->running = part_info->is_using;
1032  inf->read_only = part_info->read_only;
1033  inf->valid = part_info->valid;
1034  if (!inf->valid)
1035  return 0;
1036 
1037  return switchtec_fw_info_metadata_gen4(dev, inf);
1038 }
1039 
1049 static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1050  struct switchtec_fw_image_info *info)
1051 {
1052  int ret;
1053  int i;
1054  uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1055  struct switchtec_flash_info_gen4 all_info;
1056 
1057  if (info == NULL || nr_info == 0)
1058  return -EINVAL;
1059 
1060  if (dev->gen > SWITCHTEC_GEN3) {
1061  ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1062  sizeof(subcmd), &all_info,
1063  sizeof(all_info));
1064  if (ret)
1065  return ret;
1066  all_info.firmware_version = le32toh(all_info.firmware_version);
1067  all_info.flash_size = le32toh(all_info.flash_size);
1068  all_info.device_id = le16toh(all_info.device_id);
1069  }
1070 
1071  for (i = 0; i < nr_info; i++) {
1072  struct switchtec_fw_image_info *inf = &info[i];
1073  ret = 0;
1074 
1075  inf->gen = dev->gen;
1076  inf->type = switchtec_fw_id_to_type(inf);
1077  inf->active = false;
1078  inf->running = false;
1079  inf->valid = false;
1080 
1081  switch (info->gen) {
1082  case SWITCHTEC_GEN3:
1083  ret = switchtec_fw_part_info_gen3(dev, inf);
1084  break;
1085  case SWITCHTEC_GEN4:
1086  case SWITCHTEC_GEN5:
1087  ret = switchtec_fw_part_info_gen4(dev, inf, &all_info);
1088  break;
1089  default:
1090  errno = EINVAL;
1091  return -1;
1092  }
1093 
1094  if (ret < 0)
1095  return ret;
1096 
1097  if (ret) {
1098  inf->version[0] = 0;
1099  inf->image_crc = 0xFFFFFFFF;
1100  inf->metadata = NULL;
1101  }
1102  }
1103 
1104  return nr_info;
1105 }
1106 
1107 int switchtec_get_device_id_bl2(struct switchtec_dev *dev,
1108  unsigned short *device_id)
1109 {
1110  int ret;
1111  uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1112  struct switchtec_flash_info_gen4 all_info;
1113 
1114  if (dev->gen != SWITCHTEC_GEN_UNKNOWN)
1115  return -EINVAL;
1116 
1117  ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1118  sizeof(subcmd), &all_info,
1119  sizeof(all_info));
1120  if (ret)
1121  return ret;
1122 
1123  *device_id = le16toh(all_info.device_id);
1124 
1125  return 0;
1126 }
1127 
1128 static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1129  uint8_t index)
1130 {
1131  int ret;
1132  uint32_t result;
1133 
1134  subcmd |= index << 8;
1135  subcmd = htole32(subcmd);
1136 
1137  ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1138  &result, sizeof(result));
1139  if (ret)
1140  return -1;
1141 
1142  return result;
1143 }
1144 
1145 static int get_multicfg(struct switchtec_dev *dev,
1146  struct switchtec_fw_image_info *info,
1147  int *nr_mult)
1148 {
1149  int ret;
1150  int i;
1151 
1152  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1153  if (ret < 0)
1154  return ret;
1155 
1156  if (!ret) {
1157  *nr_mult = 0;
1158  return 0;
1159  }
1160 
1161  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1162  if (ret < 0)
1163  return ret;
1164 
1165  if (*nr_mult > ret)
1166  *nr_mult = ret;
1167 
1168  for (i = 0; i < *nr_mult; i++) {
1169  info[i].part_addr = multicfg_subcmd(dev,
1170  MRPC_MULTI_CFG_START_ADDR,
1171  i);
1172  info[i].part_len = multicfg_subcmd(dev,
1173  MRPC_MULTI_CFG_LENGTH, i);
1174  strcpy(info[i].version, "");
1175  info[i].image_crc = 0;
1176  info[i].active = 0;
1177  }
1178 
1179  ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1180  if (ret < 0)
1181  return ret;
1182 
1183  if (ret < *nr_mult)
1184  info[ret].active = 1;
1185 
1186  return 0;
1187 }
1188 
1189 static const enum switchtec_fw_image_part_id_gen3
1190 switchtec_fw_partitions_gen3[] = {
1191  SWITCHTEC_FW_PART_ID_G3_BOOT,
1192  SWITCHTEC_FW_PART_ID_G3_MAP0,
1193  SWITCHTEC_FW_PART_ID_G3_MAP1,
1194  SWITCHTEC_FW_PART_ID_G3_IMG0,
1195  SWITCHTEC_FW_PART_ID_G3_DAT0,
1196  SWITCHTEC_FW_PART_ID_G3_DAT1,
1197  SWITCHTEC_FW_PART_ID_G3_NVLOG,
1198  SWITCHTEC_FW_PART_ID_G3_IMG1,
1199 };
1200 
1201 static const enum switchtec_fw_image_part_id_gen4
1202 switchtec_fw_partitions_gen4[] = {
1203  SWITCHTEC_FW_PART_ID_G4_MAP0,
1204  SWITCHTEC_FW_PART_ID_G4_MAP1,
1205  SWITCHTEC_FW_PART_ID_G4_KEY0,
1206  SWITCHTEC_FW_PART_ID_G4_KEY1,
1207  SWITCHTEC_FW_PART_ID_G4_BL20,
1208  SWITCHTEC_FW_PART_ID_G4_BL21,
1209  SWITCHTEC_FW_PART_ID_G4_CFG0,
1210  SWITCHTEC_FW_PART_ID_G4_CFG1,
1211  SWITCHTEC_FW_PART_ID_G4_IMG0,
1212  SWITCHTEC_FW_PART_ID_G4_IMG1,
1213  SWITCHTEC_FW_PART_ID_G4_NVLOG,
1214  SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1215 };
1216 
1217 static struct switchtec_fw_part_type *
1218 switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
1219  struct switchtec_fw_image_info *info)
1220 {
1221  switch (info->type) {
1222  case SWITCHTEC_FW_TYPE_BOOT: return &summary->boot;
1223  case SWITCHTEC_FW_TYPE_MAP: return &summary->map;
1224  case SWITCHTEC_FW_TYPE_IMG: return &summary->img;
1225  case SWITCHTEC_FW_TYPE_CFG: return &summary->cfg;
1226  case SWITCHTEC_FW_TYPE_NVLOG: return &summary->nvlog;
1227  case SWITCHTEC_FW_TYPE_SEEPROM: return &summary->seeprom;
1228  case SWITCHTEC_FW_TYPE_KEY: return &summary->key;
1229  case SWITCHTEC_FW_TYPE_BL2: return &summary->bl2;
1230  default: return NULL;
1231  }
1232 }
1233 
1243 switchtec_fw_part_summary(struct switchtec_dev *dev)
1244 {
1245  struct switchtec_fw_part_summary *summary;
1246  struct switchtec_fw_image_info **infp;
1247  struct switchtec_fw_part_type *type;
1248  int nr_info, nr_mcfg = 16;
1249  size_t st_sz;
1250  int ret, i;
1251 
1252  switch (dev->gen) {
1253  case SWITCHTEC_GEN3:
1254  nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1255  break;
1256  case SWITCHTEC_GEN4:
1257  case SWITCHTEC_GEN5:
1258  nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1259  break;
1260  default:
1261  errno = EINVAL;
1262  return NULL;
1263  }
1264 
1265  st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
1266 
1267  summary = malloc(st_sz);
1268  if (!summary)
1269  return NULL;
1270 
1271  memset(summary, 0, st_sz);
1272  summary->nr_info = nr_info;
1273 
1274  switch (dev->gen) {
1275  case SWITCHTEC_GEN3:
1276  for (i = 0; i < nr_info; i++)
1277  summary->all[i].part_id =
1278  switchtec_fw_partitions_gen3[i];
1279  break;
1280  case SWITCHTEC_GEN4:
1281  case SWITCHTEC_GEN5:
1282  for (i = 0; i < nr_info; i++)
1283  summary->all[i].part_id =
1284  switchtec_fw_partitions_gen4[i];
1285  break;
1286  default:
1287  errno = EINVAL;
1288  return NULL;
1289  }
1290 
1291  ret = switchtec_fw_part_info(dev, nr_info, summary->all);
1292  if (ret != nr_info) {
1293  free(summary);
1294  return NULL;
1295  }
1296 
1297  ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1298  if (ret) {
1299  nr_mcfg = 0;
1300  errno = 0;
1301  }
1302 
1303  for (i = 0; i < nr_info; i++) {
1304  type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1305  if (type == NULL) {
1306  free(summary);
1307  return NULL;
1308  }
1309  if (summary->all[i].active)
1310  type->active = &summary->all[i];
1311  else
1312  type->inactive = &summary->all[i];
1313  }
1314 
1315  infp = &summary->mult_cfg;
1316  for (; i < nr_info + nr_mcfg; i++) {
1317  *infp = &summary->all[i];
1318  infp = &summary->all[i].next;
1319  }
1320 
1321  return summary;
1322 }
1323 
1329 {
1330  int i;
1331 
1332  for (i = 0; i < summary->nr_info; i++)
1333  free(summary->all[i].metadata);
1334 
1335  free(summary);
1336 }
1337 
1346 int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
1347  size_t len, void *buf)
1348 {
1349  int ret;
1350  struct {
1351  uint32_t addr;
1352  uint32_t length;
1353  } cmd;
1354  unsigned char *cbuf = buf;
1355  size_t read = 0;
1356 
1357  while(len) {
1358  size_t chunk_len = len;
1359  if (chunk_len > MRPC_MAX_DATA_LEN-8)
1360  chunk_len = MRPC_MAX_DATA_LEN-8;
1361 
1362  cmd.addr = htole32(addr);
1363  cmd.length = htole32(chunk_len);
1364 
1365  ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
1366  cbuf, chunk_len);
1367  if (ret)
1368  return -1;
1369 
1370  addr += chunk_len;
1371  len -= chunk_len;
1372  read += chunk_len;
1373  cbuf += chunk_len;
1374  }
1375 
1376  return read;
1377 }
1378 
1390 int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
1391  unsigned long addr, size_t len,
1392  void (*progress_callback)(int cur, int tot))
1393 {
1394  int ret;
1395  unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1396  size_t read = 0;
1397  size_t total_len = len;
1398  size_t total_wrote;
1399  ssize_t wrote;
1400 
1401  while(len) {
1402  size_t chunk_len = len;
1403  if (chunk_len > sizeof(buf))
1404  chunk_len = sizeof(buf);
1405 
1406  ret = switchtec_fw_read(dev, addr, chunk_len, buf);
1407  if (ret < 0)
1408  return ret;
1409 
1410  total_wrote = 0;
1411  while (total_wrote < ret) {
1412  wrote = write(fd, &buf[total_wrote],
1413  ret - total_wrote);
1414  if (wrote < 0)
1415  return -1;
1416  total_wrote += wrote;
1417  }
1418 
1419  read += ret;
1420  addr += ret;
1421  len -= ret;
1422 
1423  if (progress_callback)
1424  progress_callback(read, total_len);
1425  }
1426 
1427  return read;
1428 }
1429 
1439 int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
1440  struct switchtec_fw_image_info *info,
1441  void (*progress_callback)(int cur, int tot))
1442 {
1443  return switchtec_fw_read_fd(dev, fd,
1444  info->part_addr + info->part_body_offset,
1445  info->image_len, progress_callback);
1446 }
1447 
1448 static int switchtec_fw_img_write_hdr_gen3(int fd,
1449  struct switchtec_fw_image_info *info)
1450 {
1451  struct switchtec_fw_footer_gen3 *ftr = info->metadata;
1452  struct switchtec_fw_image_header_gen3 hdr = {};
1453 
1454  memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
1455  hdr.image_len = ftr->image_len;
1456  hdr.type = info->part_id;
1457  hdr.load_addr = ftr->load_addr;
1458  hdr.version = ftr->version;
1459  hdr.header_crc = ftr->header_crc;
1460  hdr.image_crc = ftr->image_crc;
1461 
1462  if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1463  hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1464  else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1465  hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1466  else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1467  hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1468 
1469  return write(fd, &hdr, sizeof(hdr));
1470 }
1471 
1472 static int switchtec_fw_img_write_hdr_gen4(int fd,
1473  struct switchtec_fw_image_info *info)
1474 {
1475  int ret;
1476  struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
1477 
1478  ret = write(fd, hdr, sizeof(*hdr));
1479  if (ret < 0)
1480  return ret;
1481 
1482  return lseek(fd, info->part_body_offset, SEEK_SET);
1483 }
1484 
1499 {
1500  switch (info->gen) {
1501  case SWITCHTEC_GEN3: return switchtec_fw_img_write_hdr_gen3(fd, info);
1502  case SWITCHTEC_GEN4:
1503  case SWITCHTEC_GEN5: return switchtec_fw_img_write_hdr_gen4(fd, info);
1504  default:
1505  errno = EINVAL;
1506  return -1;
1507  }
1508 }
1509 
1511  uint8_t subcmd;
1512  uint8_t set_get;
1513  uint8_t status;
1514  uint8_t reserved;
1515 };
1516 
1523 int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
1524 {
1525  struct switchtec_boot_ro subcmd = {
1526  .subcmd = MRPC_FWDNLD_BOOT_RO,
1527  .set_get = 0,
1528  };
1529 
1530  struct {
1531  uint8_t status;
1532  uint8_t reserved[3];
1533  } result;
1534 
1535  int ret;
1536 
1537  if (!switchtec_is_gen3(dev)) {
1538  errno = ENOTSUP;
1539  return -1;
1540  }
1541 
1542  ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1543  &result, sizeof(result));
1544 
1545  if (ret == ERR_SUBCMD_INVALID) {
1546  errno = 0;
1547  return 0;
1548  }
1549 
1550  if (ret)
1551  return ret;
1552 
1553  return result.status;
1554 }
1555 
1562 int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
1563  enum switchtec_fw_ro ro)
1564 {
1565  struct switchtec_boot_ro subcmd = {
1566  .subcmd = MRPC_FWDNLD_BOOT_RO,
1567  .set_get = 1,
1568  .status = ro,
1569  };
1570 
1571  if (!switchtec_is_gen3(dev)) {
1572  errno = ENOTSUP;
1573  return -1;
1574  }
1575 
1576  return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1577  NULL, 0);
1578 }
1579 
switchtec_fw_write_file
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:366
switchtec_fw_image_info::image_crc
unsigned long image_crc
CRC checksum of the image.
Definition: switchtec.h:294
switchtec.h
Main Switchtec header.
switchtec_fw_version_to_gen
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
Definition: fw.c:338
cmd_fwdl
Definition: fw.c:223
cmd_fwdl::cmd_fwdl_hdr
Definition: fw.c:224
switchtec_fw_img_write_hdr
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:1498
switchtec_fw_image_info::image_len
size_t image_len
Length of the image.
Definition: switchtec.h:293
switchtec_fw_toggle_active_partition
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
switchtec_sn_ver_get
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Definition: mfg.c:2022
switchtec_is_gen3
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition: switchtec.h:457
switchtec_fw_image_info::gen
enum switchtec_gen gen
Image generation.
Definition: switchtec.h:286
switchtec_fw_metadata_gen4
Definition: fw.c:76
switchtec_fw_image_info
Information about a firmware image or partition.
Definition: switchtec.h:285
switchtec_boot_phase
switchtec_boot_phase
Device boot phase.
Definition: switchtec.h:117
switchtec_fw_write_fd
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:246
switchtec_fw_perror
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition: fw.c:462
switchtec_fw_image_info::part_id
unsigned long part_id
Image partition ID.
Definition: switchtec.h:287
switchtec_fw_dlstatus
switchtec_fw_dlstatus
Firmware update status.
Definition: switchtec.h:848
switchtec_fw_read_fd
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:1390
switchtec_fw_image_info::version
char version[32]
Firmware/Config version.
Definition: switchtec.h:289
switchtec_fw_image_info::part_body_offset
size_t part_body_offset
Partition image body offset.
Definition: switchtec.h:292
switchtec_fw_is_boot_ro
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition: fw.c:1523
switchtec_sn_ver_info
Definition: mfg.h:132
switchtec_fw_file_info
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition: fw.c:687
switchtec_fw_body_read_fd
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:1439
switchtec_flash_part
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
switchtec_fw_file_secure_version_newer
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:720
switchtec_fw_image_info::part_len
size_t part_len
Length of the partition.
Definition: switchtec.h:291
switchtec_fw_ro
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition: switchtec.h:882
switchtec_fw_part_summary
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:1243
switchtec_fw_part_summary_free
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition: fw.c:1328
switchtec_fw_part_info
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:1049
switchtec_fw_read
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:1346
switchtec_flash_info_gen4
Definition: fw.c:939
switchtec_fw_image_type
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:772
switchtec_fw_image_info::type
enum switchtec_fw_type type
Image partition type.
Definition: switchtec.h:288
switchtec_fw_set_boot_ro
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:1562
switchtec_gen
switchtec_gen
The PCIe generations.
Definition: switchtec.h:89
switchtec_flash_info_gen4::switchtec_flash_part_info_gen4
Definition: fw.c:950
switchtec_boot_ro
Definition: fw.c:1510
switchtec_fw_image_header_gen3
Definition: fw.c:109
switchtec_fw_part_summary
Definition: switchtec.h:308
switchtec_fw_image_info::part_addr
size_t part_addr
Address of the partition.
Definition: switchtec.h:290
switchtec_cmd
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