1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <blk.h>
7 #include <dfu.h>
8 #include <efi.h>
9 #include <efi_loader.h>
10 #include <fwu.h>
11 #include <log.h>
12 #include <part.h>
13 
14 #include <linux/errno.h>
15 
get_gpt_dfu_identifier(struct blk_desc * desc,efi_guid_t * image_guid)16 static int get_gpt_dfu_identifier(struct blk_desc *desc, efi_guid_t *image_guid)
17 {
18 	int i;
19 	struct disk_partition info;
20 	efi_guid_t unique_part_guid;
21 
22 	for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
23 		if (part_get_info(desc, i, &info))
24 			continue;
25 		uuid_str_to_bin(info.uuid, unique_part_guid.b,
26 				UUID_STR_FORMAT_GUID);
27 
28 		if (!guidcmp(&unique_part_guid, image_guid))
29 			return i;
30 	}
31 
32 	log_err("No partition found with image_guid %pUs\n", image_guid);
33 	return -ENOENT;
34 }
35 
fwu_alt_num_for_dfu_dev(struct dfu_entity * dfu,int dev_num,int part,unsigned char dfu_dev,u8 * alt_num)36 static int fwu_alt_num_for_dfu_dev(struct dfu_entity *dfu, int dev_num,
37 				   int part, unsigned char dfu_dev,
38 				   u8 *alt_num)
39 {
40 	int ret;
41 
42 	switch(dfu_dev) {
43 	case DFU_DEV_MMC:
44 		if (dfu->layout == DFU_RAW_ADDR &&
45 		    dfu->data.mmc.dev_num == dev_num &&
46 		    dfu->data.mmc.part == part) {
47 			*alt_num = dfu->alt;
48 			ret = 0;
49 		} else {
50 			ret = -ENOENT;
51 		}
52 		break;
53 	default:
54 		ret = -ENOENT;
55 	}
56 
57 	return ret;
58 }
59 
fwu_gpt_get_alt_num(struct blk_desc * desc,efi_guid_t * image_guid,u8 * alt_num,unsigned char dfu_dev)60 static int fwu_gpt_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
61 			       u8 *alt_num, unsigned char dfu_dev)
62 {
63 	int ret = -1;
64 	int i, part, dev_num;
65 	struct dfu_entity *dfu;
66 
67 	dev_num = desc->devnum;
68 	part = get_gpt_dfu_identifier(desc, image_guid);
69 	if (part < 0)
70 		return -ENOENT;
71 
72 	ret = dfu_init_env_entities(NULL, NULL);
73 	if (ret)
74 		goto out;
75 
76 	i = 0;
77 	while (true) {
78 		dfu = dfu_get_entity(i++);
79 		if (!dfu) {
80 			ret = -ENOENT;
81 			break;
82 		}
83 
84 		if (dfu->dev_type != dfu_dev)
85 			continue;
86 
87 		ret = fwu_alt_num_for_dfu_dev(dfu, dev_num, part, dfu_dev,
88 					      alt_num);
89 		if (!ret)
90 			break;
91 	}
92 
93 out:
94 	dfu_free_entities();
95 
96 	return ret;
97 }
98 
99 /**
100  * fwu_plat_get_alt_num() - Get the DFU alt number
101  * @dev: FWU metadata device
102  * @image_guid: GUID value of the image for which the alt num is to
103  *              be obtained
104  * @alt_num: The DFU alt number for the image that is to be updated
105  *
106  * Get the DFU alt number for the image that is to be updated. The
107  * image is identified with the image_guid parameter that is passed
108  * to the function.
109  *
110  * Note: This is a weak function and platforms can override this with
111  * their own implementation for obtaining the alt number value.
112  *
113  * Return: 0 if OK, -ve on error
114  *
115  */
fwu_plat_get_alt_num(struct udevice * dev,efi_guid_t * image_guid,u8 * alt_num)116 __weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
117 				u8 *alt_num)
118 {
119 	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
120 
121 	return fwu_gpt_get_alt_num(dev_get_uclass_plat(priv->blk_dev),
122 				   image_guid, alt_num, DFU_DEV_MMC);
123 }
124