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