xref: /rk3399_rockchip-uboot/common/spl/spl_ab.c (revision 0cc16201bcd31e46860fe6f43e044aa6ef8958dd)
1*0cc16201SJason Zhu // SPDX-License-Identifier: GPL-2.0
2*0cc16201SJason Zhu /*
3*0cc16201SJason Zhu  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*0cc16201SJason Zhu  */
5*0cc16201SJason Zhu 
6*0cc16201SJason Zhu #include <common.h>
7*0cc16201SJason Zhu #include <blk.h>
8*0cc16201SJason Zhu #include <spl_ab.h>
9*0cc16201SJason Zhu 
10*0cc16201SJason Zhu int safe_memcmp(const void *s1, const void *s2, size_t n)
11*0cc16201SJason Zhu {
12*0cc16201SJason Zhu 	const unsigned char *us1 = s1;
13*0cc16201SJason Zhu 	const unsigned char *us2 = s2;
14*0cc16201SJason Zhu 	int result = 0;
15*0cc16201SJason Zhu 
16*0cc16201SJason Zhu 	if (0 == n)
17*0cc16201SJason Zhu 		return 0;
18*0cc16201SJason Zhu 
19*0cc16201SJason Zhu 	/*
20*0cc16201SJason Zhu 	 * Code snippet without data-dependent branch due to Nate Lawson
21*0cc16201SJason Zhu 	 * (nate@root.org) of Root Labs.
22*0cc16201SJason Zhu 	 */
23*0cc16201SJason Zhu 	while (n--)
24*0cc16201SJason Zhu 		result |= *us1++ ^ *us2++;
25*0cc16201SJason Zhu 
26*0cc16201SJason Zhu 	return result != 0;
27*0cc16201SJason Zhu }
28*0cc16201SJason Zhu 
29*0cc16201SJason Zhu static uint32_t htobe32(uint32_t in)
30*0cc16201SJason Zhu {
31*0cc16201SJason Zhu 	union {
32*0cc16201SJason Zhu 		uint32_t word;
33*0cc16201SJason Zhu 		uint8_t bytes[4];
34*0cc16201SJason Zhu 	} ret;
35*0cc16201SJason Zhu 
36*0cc16201SJason Zhu 	ret.bytes[0] = (in >> 24) & 0xff;
37*0cc16201SJason Zhu 	ret.bytes[1] = (in >> 16) & 0xff;
38*0cc16201SJason Zhu 	ret.bytes[2] = (in >> 8) & 0xff;
39*0cc16201SJason Zhu 	ret.bytes[3] = in & 0xff;
40*0cc16201SJason Zhu 
41*0cc16201SJason Zhu 	return ret.word;
42*0cc16201SJason Zhu }
43*0cc16201SJason Zhu 
44*0cc16201SJason Zhu static uint32_t be32toh(uint32_t in)
45*0cc16201SJason Zhu {
46*0cc16201SJason Zhu 	uint8_t *d = (uint8_t *)&in;
47*0cc16201SJason Zhu 	uint32_t ret;
48*0cc16201SJason Zhu 
49*0cc16201SJason Zhu 	ret = ((uint32_t)d[0]) << 24;
50*0cc16201SJason Zhu 	ret |= ((uint32_t)d[1]) << 16;
51*0cc16201SJason Zhu 	ret |= ((uint32_t)d[2]) << 8;
52*0cc16201SJason Zhu 	ret |= ((uint32_t)d[3]);
53*0cc16201SJason Zhu 
54*0cc16201SJason Zhu 	return ret;
55*0cc16201SJason Zhu }
56*0cc16201SJason Zhu 
57*0cc16201SJason Zhu static bool spl_ab_data_verify_and_byteswap(const AvbABData *src,
58*0cc16201SJason Zhu 					    AvbABData *dest)
59*0cc16201SJason Zhu {
60*0cc16201SJason Zhu 	/* Ensure magic is correct. */
61*0cc16201SJason Zhu 	if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
62*0cc16201SJason Zhu 		printf("Magic is incorrect.\n");
63*0cc16201SJason Zhu 		return false;
64*0cc16201SJason Zhu 	}
65*0cc16201SJason Zhu 
66*0cc16201SJason Zhu 	memcpy(dest, src, sizeof(AvbABData));
67*0cc16201SJason Zhu 	dest->crc32 = be32toh(dest->crc32);
68*0cc16201SJason Zhu 
69*0cc16201SJason Zhu 	/* Ensure we don't attempt to access any fields if the major version
70*0cc16201SJason Zhu 	 * is not supported.
71*0cc16201SJason Zhu 	 */
72*0cc16201SJason Zhu 	if (dest->version_major > AVB_AB_MAJOR_VERSION) {
73*0cc16201SJason Zhu 		printf("No support for given major version.\n");
74*0cc16201SJason Zhu 		return false;
75*0cc16201SJason Zhu 	}
76*0cc16201SJason Zhu 
77*0cc16201SJason Zhu 	/* Bail if CRC32 doesn't match. */
78*0cc16201SJason Zhu 	if (dest->crc32 !=
79*0cc16201SJason Zhu 		crc32(0, (const uint8_t *)dest,
80*0cc16201SJason Zhu 		      sizeof(AvbABData) - sizeof(uint32_t))) {
81*0cc16201SJason Zhu 		printf("CRC32 does not match.\n");
82*0cc16201SJason Zhu 		return false;
83*0cc16201SJason Zhu 	}
84*0cc16201SJason Zhu 
85*0cc16201SJason Zhu 	return true;
86*0cc16201SJason Zhu }
87*0cc16201SJason Zhu 
88*0cc16201SJason Zhu static void spl_ab_data_update_crc_and_byteswap(const AvbABData *src,
89*0cc16201SJason Zhu 						AvbABData *dest)
90*0cc16201SJason Zhu {
91*0cc16201SJason Zhu 	memcpy(dest, src, sizeof(AvbABData));
92*0cc16201SJason Zhu 	dest->crc32 = htobe32(crc32(0, (const uint8_t *)dest,
93*0cc16201SJason Zhu 			    sizeof(AvbABData) - sizeof(uint32_t)));
94*0cc16201SJason Zhu }
95*0cc16201SJason Zhu 
96*0cc16201SJason Zhu static void spl_ab_data_init(AvbABData *data)
97*0cc16201SJason Zhu {
98*0cc16201SJason Zhu 	memset(data, '\0', sizeof(AvbABData));
99*0cc16201SJason Zhu 	memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
100*0cc16201SJason Zhu 	data->version_major = AVB_AB_MAJOR_VERSION;
101*0cc16201SJason Zhu 	data->version_minor = AVB_AB_MINOR_VERSION;
102*0cc16201SJason Zhu 	data->last_boot = 0;
103*0cc16201SJason Zhu 	data->slots[0].priority = AVB_AB_MAX_PRIORITY;
104*0cc16201SJason Zhu 	data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
105*0cc16201SJason Zhu 	data->slots[0].successful_boot = 0;
106*0cc16201SJason Zhu 	data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
107*0cc16201SJason Zhu 	data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
108*0cc16201SJason Zhu 	data->slots[1].successful_boot = 0;
109*0cc16201SJason Zhu }
110*0cc16201SJason Zhu 
111*0cc16201SJason Zhu static int spl_read_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
112*0cc16201SJason Zhu 				char *partition)
113*0cc16201SJason Zhu {
114*0cc16201SJason Zhu 	disk_partition_t part_info;
115*0cc16201SJason Zhu 	char temp[512];
116*0cc16201SJason Zhu 	int ret;
117*0cc16201SJason Zhu 
118*0cc16201SJason Zhu 	if (!dev_desc || !partition || !ab_data)
119*0cc16201SJason Zhu 		return -EFAULT;
120*0cc16201SJason Zhu 
121*0cc16201SJason Zhu 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
122*0cc16201SJason Zhu 		return -ENOENT;
123*0cc16201SJason Zhu 
124*0cc16201SJason Zhu 	ret = blk_dread(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
125*0cc16201SJason Zhu 			temp);
126*0cc16201SJason Zhu 	if (ret != 1)
127*0cc16201SJason Zhu 		return -ENODEV;
128*0cc16201SJason Zhu 
129*0cc16201SJason Zhu 	if (sizeof(AvbABData) > 512)
130*0cc16201SJason Zhu 		return -ENOMEM;
131*0cc16201SJason Zhu 
132*0cc16201SJason Zhu 	memcpy(ab_data, temp, sizeof(AvbABData));
133*0cc16201SJason Zhu 
134*0cc16201SJason Zhu 	return 0;
135*0cc16201SJason Zhu }
136*0cc16201SJason Zhu 
137*0cc16201SJason Zhu static int spl_write_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
138*0cc16201SJason Zhu 				 char *partition)
139*0cc16201SJason Zhu {
140*0cc16201SJason Zhu 	disk_partition_t part_info;
141*0cc16201SJason Zhu 	char temp[512];
142*0cc16201SJason Zhu 	int ret;
143*0cc16201SJason Zhu 
144*0cc16201SJason Zhu 	if (!dev_desc || !partition || !ab_data)
145*0cc16201SJason Zhu 		return -EFAULT;
146*0cc16201SJason Zhu 
147*0cc16201SJason Zhu 	if (sizeof(AvbABData) > 512)
148*0cc16201SJason Zhu 		return -ENOMEM;
149*0cc16201SJason Zhu 
150*0cc16201SJason Zhu 	memcpy(temp, ab_data, sizeof(AvbABData));
151*0cc16201SJason Zhu 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
152*0cc16201SJason Zhu 		return -ENOENT;
153*0cc16201SJason Zhu 
154*0cc16201SJason Zhu 	ret = blk_dwrite(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
155*0cc16201SJason Zhu 			 temp);
156*0cc16201SJason Zhu 	if (ret != 1)
157*0cc16201SJason Zhu 		return -ENODEV;
158*0cc16201SJason Zhu 
159*0cc16201SJason Zhu 	return 0;
160*0cc16201SJason Zhu }
161*0cc16201SJason Zhu 
162*0cc16201SJason Zhu static int spl_ab_data_write(struct blk_desc *dev_desc, AvbABData *ab_data,
163*0cc16201SJason Zhu 			     char *partition)
164*0cc16201SJason Zhu {
165*0cc16201SJason Zhu 	AvbABData serialized;
166*0cc16201SJason Zhu 
167*0cc16201SJason Zhu 	spl_ab_data_update_crc_and_byteswap(ab_data, &serialized);
168*0cc16201SJason Zhu 
169*0cc16201SJason Zhu 	return spl_write_ab_metadata(dev_desc, &serialized, partition);
170*0cc16201SJason Zhu }
171*0cc16201SJason Zhu 
172*0cc16201SJason Zhu static int spl_ab_data_read(struct blk_desc *dev_desc, AvbABData *ab_data,
173*0cc16201SJason Zhu 			    char *partition)
174*0cc16201SJason Zhu {
175*0cc16201SJason Zhu 	int ret;
176*0cc16201SJason Zhu 	AvbABData serialized;
177*0cc16201SJason Zhu 
178*0cc16201SJason Zhu 	ret = spl_read_ab_metadata(dev_desc, &serialized, partition);
179*0cc16201SJason Zhu 	if (ret)
180*0cc16201SJason Zhu 		return ret;
181*0cc16201SJason Zhu 
182*0cc16201SJason Zhu 	if (!spl_ab_data_verify_and_byteswap(&serialized, ab_data)) {
183*0cc16201SJason Zhu 		printf("Error validating A/B metadata from disk. "
184*0cc16201SJason Zhu 		       "Resetting and writing new A/B metadata to disk.\n");
185*0cc16201SJason Zhu 		spl_ab_data_init(ab_data);
186*0cc16201SJason Zhu 		spl_ab_data_write(dev_desc, ab_data, partition);
187*0cc16201SJason Zhu 	}
188*0cc16201SJason Zhu 
189*0cc16201SJason Zhu 	return 0;
190*0cc16201SJason Zhu }
191*0cc16201SJason Zhu 
192*0cc16201SJason Zhu static bool spl_slot_is_bootable(AvbABSlotData *slot)
193*0cc16201SJason Zhu {
194*0cc16201SJason Zhu 	return slot->priority > 0 &&
195*0cc16201SJason Zhu 		(slot->successful_boot || (slot->tries_remaining > 0));
196*0cc16201SJason Zhu }
197*0cc16201SJason Zhu 
198*0cc16201SJason Zhu static int spl_get_lastboot(AvbABData *ab_data)
199*0cc16201SJason Zhu {
200*0cc16201SJason Zhu 	return ab_data->last_boot;
201*0cc16201SJason Zhu }
202*0cc16201SJason Zhu 
203*0cc16201SJason Zhu int spl_get_current_slot(struct blk_desc *dev_desc, char *partition, char *slot)
204*0cc16201SJason Zhu {
205*0cc16201SJason Zhu 	size_t slot_index_to_boot;
206*0cc16201SJason Zhu 	AvbABData ab_data;
207*0cc16201SJason Zhu 	int ret;
208*0cc16201SJason Zhu 
209*0cc16201SJason Zhu 	ret = spl_ab_data_read(dev_desc, &ab_data, partition);
210*0cc16201SJason Zhu 	if (ret)
211*0cc16201SJason Zhu 		return ret;
212*0cc16201SJason Zhu 
213*0cc16201SJason Zhu 	if (spl_slot_is_bootable(&ab_data.slots[0]) &&
214*0cc16201SJason Zhu 	    spl_slot_is_bootable(&ab_data.slots[1])) {
215*0cc16201SJason Zhu 		if (ab_data.slots[1].priority > ab_data.slots[0].priority)
216*0cc16201SJason Zhu 			slot_index_to_boot = 1;
217*0cc16201SJason Zhu 		else
218*0cc16201SJason Zhu 			slot_index_to_boot = 0;
219*0cc16201SJason Zhu 	} else if (spl_slot_is_bootable(&ab_data.slots[0])) {
220*0cc16201SJason Zhu 		slot_index_to_boot = 0;
221*0cc16201SJason Zhu 	} else if (spl_slot_is_bootable(&ab_data.slots[1])) {
222*0cc16201SJason Zhu 		slot_index_to_boot = 1;
223*0cc16201SJason Zhu 	} else {
224*0cc16201SJason Zhu 		printf("No bootable slots found, use lastboot.\n");
225*0cc16201SJason Zhu 		if (spl_get_lastboot(&ab_data) == 0) {
226*0cc16201SJason Zhu 			memcpy(slot, "_a", 2);
227*0cc16201SJason Zhu 			goto out;
228*0cc16201SJason Zhu 		} else if (spl_get_lastboot(&ab_data) == 1) {
229*0cc16201SJason Zhu 			memcpy(slot, "_b", 2);
230*0cc16201SJason Zhu 			goto out;
231*0cc16201SJason Zhu 		} else {
232*0cc16201SJason Zhu 			return -ENODEV;
233*0cc16201SJason Zhu 		}
234*0cc16201SJason Zhu 	}
235*0cc16201SJason Zhu 
236*0cc16201SJason Zhu 	if (slot_index_to_boot == 0)
237*0cc16201SJason Zhu 		memcpy(slot, "_a", 2);
238*0cc16201SJason Zhu 	else if (slot_index_to_boot == 1)
239*0cc16201SJason Zhu 		memcpy(slot, "_b", 2);
240*0cc16201SJason Zhu 
241*0cc16201SJason Zhu out:
242*0cc16201SJason Zhu 	return 0;
243*0cc16201SJason Zhu }
244*0cc16201SJason Zhu 
245*0cc16201SJason Zhu int spl_get_partitions_sector(struct blk_desc *dev_desc, char *partition,
246*0cc16201SJason Zhu 			       u32 *sectors)
247*0cc16201SJason Zhu {
248*0cc16201SJason Zhu 	disk_partition_t part_info;
249*0cc16201SJason Zhu 	char part[10] = {0};
250*0cc16201SJason Zhu 	char slot[3] = {0};
251*0cc16201SJason Zhu 
252*0cc16201SJason Zhu 	if (!partition || !sectors)
253*0cc16201SJason Zhu 		return -EFAULT;
254*0cc16201SJason Zhu 
255*0cc16201SJason Zhu 	spl_get_current_slot(dev_desc, "misc", slot);
256*0cc16201SJason Zhu 	if (strlen(partition) > 8)
257*0cc16201SJason Zhu 		return -ENOMEM;
258*0cc16201SJason Zhu 
259*0cc16201SJason Zhu 	strcat(part, partition);
260*0cc16201SJason Zhu 	strcat(part, slot);
261*0cc16201SJason Zhu 	if (part_get_info_by_name(dev_desc, part, &part_info) < 0)
262*0cc16201SJason Zhu 		return -ENODEV;
263*0cc16201SJason Zhu 
264*0cc16201SJason Zhu 	*sectors = part_info.start;
265*0cc16201SJason Zhu 
266*0cc16201SJason Zhu 	return 0;
267*0cc16201SJason Zhu }
268