fwu_mtd.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2023, Linaro Limited
  4. */
  5. #include <dm.h>
  6. #include <dfu.h>
  7. #include <fwu.h>
  8. #include <fwu_mdata.h>
  9. #include <log.h>
  10. #include <malloc.h>
  11. #include <mtd.h>
  12. #include <uuid.h>
  13. #include <vsprintf.h>
  14. #include <dm/ofnode.h>
  15. struct fwu_mtd_image_info
  16. fwu_mtd_images[CONFIG_FWU_NUM_BANKS * CONFIG_FWU_NUM_IMAGES_PER_BANK];
  17. static struct fwu_mtd_image_info *mtd_img_by_uuid(const char *uuidbuf)
  18. {
  19. int num_images = ARRAY_SIZE(fwu_mtd_images);
  20. for (int i = 0; i < num_images; i++)
  21. if (!strcmp(uuidbuf, fwu_mtd_images[i].uuidbuf))
  22. return &fwu_mtd_images[i];
  23. return NULL;
  24. }
  25. int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
  26. const char *mtd_dev)
  27. {
  28. struct fwu_mtd_image_info *mtd_img_info;
  29. char uuidbuf[UUID_STR_LEN + 1];
  30. fdt_addr_t offset, size = 0;
  31. struct dfu_entity *dfu;
  32. int i, nalt, ret;
  33. mtd_probe_devices();
  34. uuid_bin_to_str(image_id->b, uuidbuf, UUID_STR_FORMAT_STD);
  35. mtd_img_info = mtd_img_by_uuid(uuidbuf);
  36. if (!mtd_img_info) {
  37. log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
  38. return -ENOENT;
  39. }
  40. offset = mtd_img_info->start;
  41. size = mtd_img_info->size;
  42. ret = dfu_init_env_entities(NULL, NULL);
  43. if (ret)
  44. return -ENOENT;
  45. nalt = 0;
  46. list_for_each_entry(dfu, &dfu_list, list)
  47. nalt++;
  48. if (!nalt) {
  49. log_warning("No entities in dfu_alt_info\n");
  50. dfu_free_entities();
  51. return -ENOENT;
  52. }
  53. ret = -ENOENT;
  54. for (i = 0; i < nalt; i++) {
  55. dfu = dfu_get_entity(i);
  56. /* Only MTD RAW access */
  57. if (!dfu || dfu->dev_type != DFU_DEV_MTD ||
  58. dfu->layout != DFU_RAW_ADDR ||
  59. dfu->data.mtd.start != offset ||
  60. dfu->data.mtd.size != size)
  61. continue;
  62. *alt_num = dfu->alt;
  63. ret = 0;
  64. break;
  65. }
  66. dfu_free_entities();
  67. log_debug("%s: %s -> %d\n", __func__, uuidbuf, *alt_num);
  68. return ret;
  69. }
  70. /**
  71. * fwu_plat_get_alt_num() - Get the DFU Alt Num for the image from the platform
  72. * @dev: FWU device
  73. * @image_id: Image GUID for which DFU alt number needs to be retrieved
  74. * @alt_num: Pointer to the alt_num
  75. *
  76. * Get the DFU alt number from the platform for the image specified by the
  77. * image GUID.
  78. *
  79. * Note: This is a weak function and platforms can override this with
  80. * their own implementation for obtaining the alt number value.
  81. *
  82. * Return: 0 if OK, -ve on error
  83. */
  84. __weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_id,
  85. u8 *alt_num)
  86. {
  87. return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
  88. }
  89. static int gen_image_alt_info(char *buf, size_t len, int sidx,
  90. struct fwu_image_entry *img, struct mtd_info *mtd)
  91. {
  92. char *p = buf, *end = buf + len;
  93. int i;
  94. p += snprintf(p, end - p, "mtd %s", mtd->name);
  95. if (end < p) {
  96. log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
  97. return -E2BIG;
  98. }
  99. /*
  100. * List the image banks in the FWU mdata and search the corresponding
  101. * partition based on partition's uuid.
  102. */
  103. for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
  104. struct fwu_mtd_image_info *mtd_img_info;
  105. struct fwu_image_bank_info *bank;
  106. char uuidbuf[UUID_STR_LEN + 1];
  107. u32 offset, size;
  108. /* Query a partition by image UUID */
  109. bank = &img->img_bank_info[i];
  110. uuid_bin_to_str(bank->image_uuid.b, uuidbuf, UUID_STR_FORMAT_STD);
  111. mtd_img_info = mtd_img_by_uuid(uuidbuf);
  112. if (!mtd_img_info) {
  113. log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
  114. break;
  115. }
  116. offset = mtd_img_info->start;
  117. size = mtd_img_info->size;
  118. p += snprintf(p, end - p, "%sbank%d raw %x %x",
  119. i == 0 ? "=" : ";", i, offset, size);
  120. if (end < p) {
  121. log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
  122. return -E2BIG;
  123. }
  124. }
  125. if (i == CONFIG_FWU_NUM_BANKS)
  126. return 0;
  127. return -ENOENT;
  128. }
  129. int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
  130. {
  131. struct fwu_mdata mdata;
  132. int i, l, ret;
  133. ret = fwu_get_mdata(&mdata);
  134. if (ret < 0) {
  135. log_err("Failed to get the FWU mdata.\n");
  136. return ret;
  137. }
  138. for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
  139. ret = gen_image_alt_info(buf, len, i * CONFIG_FWU_NUM_BANKS,
  140. &mdata.img_entry[i], mtd);
  141. if (ret)
  142. break;
  143. l = strlen(buf);
  144. /* Replace the last ';' with '&' if there is another image. */
  145. if (i != CONFIG_FWU_NUM_IMAGES_PER_BANK - 1 && l) {
  146. buf[l] = '&';
  147. buf++;
  148. }
  149. len -= l;
  150. buf += l;
  151. }
  152. return ret;
  153. }