xref: /rk3399_rockchip-uboot/lib/avb/rk_avb_user/rk_ab_ops_user.c (revision 894688431927c1b73c64860c8aa71463c2593ea2)
1 /*
2  * (C) Copyright 2020 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 #include <common.h>
7 #include <malloc.h>
8 #include <mapmem.h>
9 #include <errno.h>
10 #include <command.h>
11 #include <blk.h>
12 #include <part.h>
13 #include <android_avb/avb_ops_user.h>
14 #include <android_avb/libavb_ab.h>
15 #include <android_avb/rk_avb_ops_user.h>
16 #include <boot_rkimg.h>
17 
18 static int safe_memcmp(const void *s1, const void *s2, size_t n)
19 {
20 	const unsigned char *us1 = s1;
21 	const unsigned char *us2 = s2;
22 	int result = 0;
23 
24 	if (0 == n)
25 		return 0;
26 
27 	/*
28 	 * Code snippet without data-dependent branch due to Nate Lawson
29 	 * (nate@root.org) of Root Labs.
30 	 */
31 	while (n--)
32 		result |= *us1++ ^ *us2++;
33 
34 	return result != 0;
35 }
36 
37 static uint32_t htobe32(uint32_t in)
38 {
39 	union {
40 		uint32_t word;
41 		uint8_t bytes[4];
42 	} ret;
43 
44 	ret.bytes[0] = (in >> 24) & 0xff;
45 	ret.bytes[1] = (in >> 16) & 0xff;
46 	ret.bytes[2] = (in >> 8) & 0xff;
47 	ret.bytes[3] = in & 0xff;
48 
49 	return ret.word;
50 }
51 
52 static uint32_t be32toh(uint32_t in)
53 {
54 	uint8_t *d = (uint8_t *)&in;
55 	uint32_t ret;
56 
57 	ret = ((uint32_t)d[0]) << 24;
58 	ret |= ((uint32_t)d[1]) << 16;
59 	ret |= ((uint32_t)d[2]) << 8;
60 	ret |= ((uint32_t)d[3]);
61 
62 	return ret;
63 }
64 
65 static void slot_set_unbootable(AvbABSlotData* slot)
66 {
67         slot->priority = 0;
68         slot->tries_remaining = 0;
69         slot->successful_boot = 0;
70 }
71 
72 /* Ensure all unbootable and/or illegal states are marked as the
73  * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
74  * and successful_boot=0.
75  */
76 static void slot_normalize(AvbABSlotData* slot)
77 {
78         if (slot->priority > 0) {
79                 if (slot->tries_remaining == 0 && !slot->successful_boot) {
80                 /* We've exhausted all tries -> unbootable. */
81                 slot_set_unbootable(slot);
82         }
83         if (slot->tries_remaining > 0 && slot->successful_boot) {
84                 /* Illegal state - avb_ab_mark_slot_successful() will clear
85                  * tries_remaining when setting successful_boot.
86                  */
87                 slot_set_unbootable(slot);
88         }
89         } else {
90                 slot_set_unbootable(slot);
91         }
92 }
93 
94 /* Writes A/B metadata to disk only if it has changed - returns
95  * AVB_IO_RESULT_OK on success, error code otherwise.
96  */
97 AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
98                                      AvbABData* ab_data,
99                                      AvbABData* ab_data_orig)
100 {
101         if (safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
102                 debug("Writing A/B metadata to disk.\n");
103                 return ab_ops->write_ab_metadata(ab_ops, ab_data);
104         }
105         return AVB_IO_RESULT_OK;
106 }
107 
108 bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
109         /* Ensure magic is correct. */
110         if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
111                 printf("Magic is incorrect.\n");
112                 return false;
113         }
114 
115         memcpy(dest, src, sizeof(AvbABData));
116         dest->crc32 = be32toh(dest->crc32);
117 
118         /* Ensure we don't attempt to access any fields if the major version
119          * is not supported.
120          */
121         if (dest->version_major > AVB_AB_MAJOR_VERSION) {
122                 printf("No support for given major version.\n");
123                 return false;
124         }
125 
126         /* Bail if CRC32 doesn't match. */
127         if (dest->crc32 !=
128                 crc32(0, (const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
129                 printf("CRC32 does not match.\n");
130                 return false;
131         }
132 
133         return true;
134 }
135 
136 void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
137                                          AvbABData* dest)
138 {
139         memcpy(dest, src, sizeof(AvbABData));
140         dest->crc32 = htobe32(crc32(0, (const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
141 }
142 
143 void avb_ab_data_init(AvbABData* data)
144 {
145         memset(data, '\0', sizeof(AvbABData));
146         memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
147         data->version_major = AVB_AB_MAJOR_VERSION;
148         data->version_minor = AVB_AB_MINOR_VERSION;
149         data->last_boot = 0;
150         data->slots[0].priority = AVB_AB_MAX_PRIORITY;
151         data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
152         data->slots[0].successful_boot = 0;
153         data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
154         data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
155         data->slots[1].successful_boot = 0;
156 }
157 
158 /* The AvbABData struct is stored 2048 bytes into the 'misc' partition
159  * following the 'struct bootloader_message' field. The struct is
160  * compatible with the guidelines in bootable/recovery/bootloader.h -
161  * e.g. it is stored in the |slot_suffix| field, starts with a
162  * NUL-byte, and is 32 bytes long.
163  */
164 #define AB_METADATA_MISC_PARTITION_OFFSET 2048
165 
166 AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data)
167 {
168         AvbOps* ops = ab_ops->ops;
169         AvbABData serialized;
170         AvbIOResult io_ret;
171         size_t num_bytes_read;
172 
173         io_ret = ops->read_from_partition(ops,
174                                           "misc",
175                                           AB_METADATA_MISC_PARTITION_OFFSET,
176                                           sizeof(AvbABData),
177                                           &serialized,
178                                           &num_bytes_read);
179         if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
180                 return AVB_IO_RESULT_ERROR_OOM;
181         } else if (io_ret != AVB_IO_RESULT_OK ||
182                   num_bytes_read != sizeof(AvbABData)) {
183                 printf("Error reading A/B metadata.\n");
184                 return AVB_IO_RESULT_ERROR_IO;
185         }
186 
187         if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
188                 printf("Error validating A/B metadata from disk. "
189                           "Resetting and writing new A/B metadata to disk.\n");
190                 avb_ab_data_init(data);
191                 return avb_ab_data_write(ab_ops, data);
192         }
193 
194         return AVB_IO_RESULT_OK;
195 }
196 
197 AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data)
198 {
199         AvbOps* ops = ab_ops->ops;
200         AvbABData serialized;
201         AvbIOResult io_ret;
202 
203         avb_ab_data_update_crc_and_byteswap(data, &serialized);
204         io_ret = ops->write_to_partition(ops,
205                                          "misc",
206                                          AB_METADATA_MISC_PARTITION_OFFSET,
207                                          sizeof(AvbABData),
208                                          &serialized);
209         if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
210                 return AVB_IO_RESULT_ERROR_OOM;
211         } else if (io_ret != AVB_IO_RESULT_OK) {
212                 printf("Error writing A/B metadata.\n");
213                 return AVB_IO_RESULT_ERROR_IO;
214         }
215         return AVB_IO_RESULT_OK;
216 }
217 
218 /* Helper function to load metadata - returns AVB_IO_RESULT_OK on
219  * success, error code otherwise.
220  */
221 AvbIOResult load_metadata(AvbABOps* ab_ops,
222                           AvbABData* ab_data,
223                           AvbABData* ab_data_orig) {
224         AvbIOResult io_ret;
225 
226         io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
227         if (io_ret != AVB_IO_RESULT_OK) {
228                 printf("I/O error while loading A/B metadata.\n");
229                 return io_ret;
230         }
231         *ab_data_orig = *ab_data;
232 
233         /* Ensure data is normalized, e.g. illegal states will be marked as
234          * unbootable and all unbootable states are represented with
235          * (priority=0, tries_remaining=0, successful_boot=0).
236          */
237         slot_normalize(&ab_data->slots[0]);
238         slot_normalize(&ab_data->slots[1]);
239         return AVB_IO_RESULT_OK;
240 }
241 
242 int rk_avb_read_slot_count(char *slot_count)
243 {
244 	*slot_count = SLOT_NUM;
245 
246 	return 0;
247 }
248 
249 int rk_avb_read_slot_suffixes(char *slot_suffixes)
250 {
251 	memcpy(slot_suffixes, CURR_SYSTEM_SLOT_SUFFIX,
252 	       strlen(CURR_SYSTEM_SLOT_SUFFIX));
253 
254 	return 0;
255 }
256 
257 AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
258                                     unsigned int slot_number)
259 {
260         AvbABData ab_data, ab_data_orig;
261         unsigned int other_slot_number;
262         AvbIOResult ret;
263 
264         avb_assert(slot_number < 2);
265 
266         ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
267         if (ret != AVB_IO_RESULT_OK) {
268                 goto out;
269         }
270 
271         /* Make requested slot top priority, unsuccessful, and with max tries. */
272         ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
273         ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
274         ab_data.slots[slot_number].successful_boot = 0;
275 
276         /* Ensure other slot doesn't have as high a priority. */
277         other_slot_number = 1 - slot_number;
278         if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
279                 ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
280         }
281 
282         ret = AVB_IO_RESULT_OK;
283 
284 out:
285         if (ret == AVB_IO_RESULT_OK) {
286                 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
287         }
288         return ret;
289 }
290 
291 int rk_avb_set_slot_active(unsigned int *slot_number)
292 {
293 	AvbOps* ops;
294 	ops = avb_ops_user_new();
295 	int ret = 0;
296 
297 	if (ops == NULL) {
298 		printf("avb_ops_user_new() failed!\n");
299 		return -1;
300 	}
301 
302 	debug("set_slot_active\n");
303 	if (avb_ab_mark_slot_active(ops->ab_ops, *slot_number) != 0) {
304 		printf("set_slot_active error!\n");
305 		ret = -1;
306 	}
307 
308 	avb_ops_user_free(ops);
309 	return ret;
310 }
311 
312 static bool slot_is_bootable(AvbABSlotData* slot) {
313 	return (slot->priority > 0) &&
314 	       (slot->successful_boot || (slot->tries_remaining > 0));
315 }
316 
317 AvbABFlowResult rk_avb_ab_slot_select(AvbABOps* ab_ops,char* select_slot)
318 {
319 	AvbABFlowResult ret = AVB_AB_FLOW_RESULT_OK;
320 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
321 	AvbABData ab_data;
322 	size_t slot_index_to_boot;
323 	static int last_slot_index = -1;
324 
325 	io_ret = ab_ops->read_ab_metadata(ab_ops, &ab_data);
326 	if (io_ret != AVB_IO_RESULT_OK) {
327 		printf("I/O error while loading A/B metadata.\n");
328 		ret = AVB_AB_FLOW_RESULT_ERROR_IO;
329 		goto out;
330 	}
331 	if (slot_is_bootable(&ab_data.slots[0]) && slot_is_bootable(&ab_data.slots[1])) {
332 		if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
333 			slot_index_to_boot = 1;
334 		} else {
335 			slot_index_to_boot = 0;
336 		}
337 	} else if(slot_is_bootable(&ab_data.slots[0])) {
338 		slot_index_to_boot = 0;
339 	} else if(slot_is_bootable(&ab_data.slots[1])) {
340 		slot_index_to_boot = 1;
341 	} else {
342 		printf("No bootable slots found.\n");
343 		ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
344 		goto out;
345 	}
346 
347 	if (slot_index_to_boot == 0) {
348 		strcpy(select_slot, "_a");
349 	} else if(slot_index_to_boot == 1) {
350 		strcpy(select_slot, "_b");
351 	}
352 
353 	if (last_slot_index != slot_index_to_boot) {
354 		last_slot_index = slot_index_to_boot;
355 		printf("A/B-slot: %s, successful: %d, tries-remain: %d\n",
356 		       select_slot,
357 		       ab_data.slots[slot_index_to_boot].successful_boot,
358 		       ab_data.slots[slot_index_to_boot].tries_remaining);
359 	}
360 out:
361 	return ret;
362 }
363 
364 AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
365                                         unsigned int slot_number)
366 {
367         AvbABData ab_data, ab_data_orig;
368         AvbIOResult ret;
369 
370         avb_assert(slot_number < 2);
371 
372         ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
373         if (ret != AVB_IO_RESULT_OK) {
374                 goto out;
375         }
376 
377         slot_set_unbootable(&ab_data.slots[slot_number]);
378 
379         ret = AVB_IO_RESULT_OK;
380 
381 out:
382         if (ret == AVB_IO_RESULT_OK) {
383                 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
384         }
385         return ret;
386 }
387 
388 AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
389                                         unsigned int slot_number)
390 {
391         AvbABData ab_data, ab_data_orig;
392         AvbIOResult ret;
393 
394         avb_assert(slot_number < 2);
395 
396         ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
397         if (ret != AVB_IO_RESULT_OK) {
398                 goto out;
399         }
400 
401         if (!slot_is_bootable(&ab_data.slots[slot_number])) {
402                 printf("Cannot mark unbootable slot as successful.\n");
403                 ret = AVB_IO_RESULT_OK;
404                 goto out;
405         }
406 
407         ab_data.slots[slot_number].tries_remaining = 0;
408         ab_data.slots[slot_number].successful_boot = 1;
409 
410         ret = AVB_IO_RESULT_OK;
411 
412 out:
413         if (ret == AVB_IO_RESULT_OK) {
414                 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
415         }
416         return ret;
417 }
418 
419 int rk_get_lastboot(void)
420 {
421 
422 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
423 	AvbABData ab_data;
424 	int lastboot = -1;
425 	AvbOps* ops;
426 
427 	ops = avb_ops_user_new();
428 	if (ops == NULL) {
429 		printf("avb_ops_user_new() failed!\n");
430 		return -1;
431 	}
432 
433 	io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data);
434 	if (io_ret != AVB_IO_RESULT_OK) {
435 		printf("I/O error while loading A/B metadata.\n");
436 		goto out;
437 	}
438 
439 	lastboot = ab_data.last_boot;
440 out:
441 	avb_ops_user_free(ops);
442 
443 	return lastboot;
444 }
445 
446 int rk_avb_get_current_slot(char *select_slot)
447 {
448 	AvbOps* ops;
449 	int ret = 0;
450 
451 	ops = avb_ops_user_new();
452 	if (ops == NULL) {
453 		printf("avb_ops_user_new() failed!\n");
454 		return -1;
455 	}
456 
457 	if (rk_avb_ab_slot_select(ops->ab_ops, select_slot) != 0) {
458 #ifndef CONFIG_ANDROID_AVB
459 		printf("###There is no bootable slot, bring up last_boot!###\n");
460 		if (rk_get_lastboot() == 1)
461 			memcpy(select_slot, "_b", 2);
462 		else if(rk_get_lastboot() == 0)
463 			memcpy(select_slot, "_a", 2);
464 		else
465 #endif
466 			return -1;
467 		ret = 0;
468 	}
469 
470 	avb_ops_user_free(ops);
471 	return ret;
472 }
473 
474 int rk_avb_append_part_slot(const char *part_name, char *new_name)
475 {
476 	char slot_suffix[3] = {0};
477 
478 	if (!strcmp(part_name, "misc")) {
479 		strcat(new_name, part_name);
480 		return 0;
481 	}
482 
483 	if (rk_avb_get_current_slot(slot_suffix)) {
484 		printf("%s: failed to get slot suffix !\n", __func__);
485 		return -1;
486 	}
487 
488 	strcpy(new_name, part_name);
489 	strcat(new_name, slot_suffix);
490 
491 	return 0;
492 }