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