configs: Resync with savedefconfig
[platform/kernel/u-boot.git] / drivers / fwu-mdata / gpt_blk.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5
6 #define LOG_CATEGORY UCLASS_FWU_MDATA
7
8 #include <blk.h>
9 #include <dm.h>
10 #include <efi_loader.h>
11 #include <fwu.h>
12 #include <fwu_mdata.h>
13 #include <log.h>
14 #include <memalign.h>
15 #include <part.h>
16 #include <part_efi.h>
17
18 #include <dm/device-internal.h>
19 #include <linux/errno.h>
20 #include <linux/types.h>
21
22 enum {
23         MDATA_READ = 1,
24         MDATA_WRITE,
25 };
26
27 static int gpt_get_mdata_partitions(struct blk_desc *desc,
28                                     uint mdata_parts[2])
29 {
30         int i, ret;
31         u32 nparts;
32         efi_guid_t part_type_guid;
33         struct disk_partition info;
34         const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID;
35
36         nparts = 0;
37         for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
38                 if (part_get_info(desc, i, &info))
39                         continue;
40                 uuid_str_to_bin(info.type_guid, part_type_guid.b,
41                                 UUID_STR_FORMAT_GUID);
42
43                 if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) {
44                         if (nparts < 2)
45                                 mdata_parts[nparts] = i;
46                         ++nparts;
47                 }
48         }
49
50         if (nparts != 2) {
51                 log_debug("Expect two copies of the FWU metadata instead of %d\n",
52                           nparts);
53                 ret = -EINVAL;
54         } else {
55                 ret = 0;
56         }
57
58         return ret;
59 }
60
61 static int gpt_get_mdata_disk_part(struct blk_desc *desc,
62                                    struct disk_partition *info,
63                                    u32 part_num)
64 {
65         int ret;
66         char *mdata_guid_str = "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23";
67
68         ret = part_get_info(desc, part_num, info);
69         if (ret < 0) {
70                 log_debug("Unable to get the partition info for the FWU metadata part %d\n",
71                           part_num);
72                 return -ENOENT;
73         }
74
75         /* Check that it is indeed the FWU metadata partition */
76         if (!strncmp(info->type_guid, mdata_guid_str, UUID_STR_LEN))
77                 return 0;
78
79         return -ENOENT;
80 }
81
82 static int gpt_read_write_mdata(struct blk_desc *desc,
83                                 struct fwu_mdata *mdata,
84                                 u8 access, u32 part_num)
85 {
86         int ret;
87         u32 len, blk_start, blkcnt;
88         struct disk_partition info;
89
90         ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1,
91                                      desc->blksz);
92
93         if (!mdata)
94                 return -ENOMEM;
95
96         ret = gpt_get_mdata_disk_part(desc, &info, part_num);
97         if (ret < 0) {
98                 printf("Unable to get the FWU metadata partition\n");
99                 return -ENOENT;
100         }
101
102         len = sizeof(*mdata);
103         blkcnt = BLOCK_CNT(len, desc);
104         if (blkcnt > info.size) {
105                 log_debug("Block count exceeds FWU metadata partition size\n");
106                 return -ERANGE;
107         }
108
109         blk_start = info.start;
110         if (access == MDATA_READ) {
111                 if (blk_dread(desc, blk_start, blkcnt, mdata_aligned) != blkcnt) {
112                         log_debug("Error reading FWU metadata from the device\n");
113                         return -EIO;
114                 }
115                 memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata));
116         } else {
117                 if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) {
118                         log_debug("Error writing FWU metadata to the device\n");
119                         return -EIO;
120                 }
121         }
122
123         return 0;
124 }
125
126 static int fwu_gpt_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
127 {
128         int ret;
129         struct blk_desc *desc;
130         uint mdata_parts[2];
131         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
132
133         desc = dev_get_uclass_plat(priv->blk_dev);
134
135         ret = gpt_get_mdata_partitions(desc, mdata_parts);
136         if (ret < 0) {
137                 log_debug("Error getting the FWU metadata partitions\n");
138                 return -ENOENT;
139         }
140
141         /* First write the primary partition */
142         ret = gpt_read_write_mdata(desc, mdata, MDATA_WRITE, mdata_parts[0]);
143         if (ret < 0) {
144                 log_debug("Updating primary FWU metadata partition failed\n");
145                 return ret;
146         }
147
148         /* And now the replica */
149         ret = gpt_read_write_mdata(desc, mdata, MDATA_WRITE, mdata_parts[1]);
150         if (ret < 0) {
151                 log_debug("Updating secondary FWU metadata partition failed\n");
152                 return ret;
153         }
154
155         return 0;
156 }
157
158 static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata *mdata)
159 {
160         int ret;
161         uint mdata_parts[2];
162
163         ret = gpt_get_mdata_partitions(desc, mdata_parts);
164
165         if (ret < 0) {
166                 log_debug("Error getting the FWU metadata partitions\n");
167                 return -ENOENT;
168         }
169
170         ret = gpt_read_write_mdata(desc, mdata, MDATA_READ, mdata_parts[0]);
171         if (ret < 0) {
172                 log_debug("Failed to read the FWU metadata from the device\n");
173                 return -EIO;
174         }
175
176         ret = fwu_verify_mdata(mdata, 1);
177         if (!ret)
178                 return 0;
179
180         /*
181          * Verification of the primary FWU metadata copy failed.
182          * Try to read the replica.
183          */
184         memset(mdata, '\0', sizeof(struct fwu_mdata));
185         ret = gpt_read_write_mdata(desc, mdata, MDATA_READ, mdata_parts[1]);
186         if (ret < 0) {
187                 log_debug("Failed to read the FWU metadata from the device\n");
188                 return -EIO;
189         }
190
191         ret = fwu_verify_mdata(mdata, 0);
192         if (!ret)
193                 return 0;
194
195         /* Both the FWU metadata copies are corrupted. */
196         return -EIO;
197 }
198
199 static int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
200 {
201         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
202
203         return gpt_get_mdata(dev_get_uclass_plat(priv->blk_dev), mdata);
204 }
205
206 static int fwu_gpt_get_mdata_partitions(struct udevice *dev, uint *mdata_parts)
207 {
208         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
209
210         return gpt_get_mdata_partitions(dev_get_uclass_plat(priv->blk_dev),
211                                         mdata_parts);
212 }
213
214 static int fwu_gpt_read_mdata_partition(struct udevice *dev,
215                                         struct fwu_mdata *mdata, uint part_num)
216 {
217         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
218
219         return gpt_read_write_mdata(dev_get_uclass_plat(priv->blk_dev),
220                                     mdata, MDATA_READ, part_num);
221 }
222
223 static int fwu_gpt_write_mdata_partition(struct udevice *dev,
224                                         struct fwu_mdata *mdata, uint part_num)
225 {
226         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
227
228         return gpt_read_write_mdata(dev_get_uclass_plat(priv->blk_dev),
229                                     mdata, MDATA_WRITE, part_num);
230 }
231
232 static int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
233 {
234         u32 phandle;
235         int ret, size;
236         struct udevice *parent;
237         const fdt32_t *phandle_p = NULL;
238
239         phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);
240         if (!phandle_p) {
241                 log_debug("fwu-mdata-store property not found\n");
242                 return -ENOENT;
243         }
244
245         phandle = fdt32_to_cpu(*phandle_p);
246
247         ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
248                                           &parent);
249         if (ret)
250                 return ret;
251
252         return blk_get_from_parent(parent, mdata_dev);
253 }
254
255 static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
256 {
257         int ret;
258         struct udevice *mdata_dev = NULL;
259         struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
260
261         ret = fwu_get_mdata_device(dev, &mdata_dev);
262         if (ret)
263                 return ret;
264
265         priv->blk_dev = mdata_dev;
266
267         return 0;
268 }
269
270 static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
271         .get_mdata = fwu_gpt_get_mdata,
272         .update_mdata = fwu_gpt_update_mdata,
273         .get_mdata_part_num = fwu_gpt_get_mdata_partitions,
274         .read_mdata_partition = fwu_gpt_read_mdata_partition,
275         .write_mdata_partition = fwu_gpt_write_mdata_partition,
276 };
277
278 static const struct udevice_id fwu_mdata_ids[] = {
279         { .compatible = "u-boot,fwu-mdata-gpt" },
280         { }
281 };
282
283 U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
284         .name           = "fwu-mdata-gpt-blk",
285         .id             = UCLASS_FWU_MDATA,
286         .of_match       = fwu_mdata_ids,
287         .ops            = &fwu_gpt_blk_ops,
288         .probe          = fwu_mdata_gpt_blk_probe,
289         .priv_auto      = sizeof(struct fwu_mdata_gpt_blk_priv),
290 };