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