FWU: Add FWU metadata access driver for MTD storage regions
[platform/kernel/u-boot.git] / lib / fwu_updates / fwu_mtd.c
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 <uuid.h>
14 #include <vsprintf.h>
15
16 #include <dm/ofnode.h>
17
18 struct fwu_mtd_image_info
19 fwu_mtd_images[CONFIG_FWU_NUM_BANKS * CONFIG_FWU_NUM_IMAGES_PER_BANK];
20
21 static 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
32 int 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
110 static 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
159 int 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. */
178                 if (i != CONFIG_FWU_NUM_IMAGES_PER_BANK - 1 && l)
179                         buf[l - 1] = '&';
180                 len -= l;
181                 buf += l;
182         }
183
184         return ret;
185 }