108f7f19aSJason Zhu /*
208f7f19aSJason Zhu * (C) Copyright 2020 Rockchip Electronics Co., Ltd
308f7f19aSJason Zhu *
408f7f19aSJason Zhu * SPDX-License-Identifier: GPL-2.0+
508f7f19aSJason Zhu */
608f7f19aSJason Zhu #include <common.h>
708f7f19aSJason Zhu #include <malloc.h>
808f7f19aSJason Zhu #include <mapmem.h>
908f7f19aSJason Zhu #include <errno.h>
1008f7f19aSJason Zhu #include <command.h>
1108f7f19aSJason Zhu #include <blk.h>
1208f7f19aSJason Zhu #include <part.h>
1308f7f19aSJason Zhu #include <boot_rkimg.h>
14*17e05a56SJason Zhu #include <android_avb/rk_avb_ops_user.h>
1508f7f19aSJason Zhu
safe_memcmp(const void * s1,const void * s2,size_t n)1608f7f19aSJason Zhu static int safe_memcmp(const void *s1, const void *s2, size_t n)
1708f7f19aSJason Zhu {
1808f7f19aSJason Zhu const unsigned char *us1 = s1;
1908f7f19aSJason Zhu const unsigned char *us2 = s2;
2008f7f19aSJason Zhu int result = 0;
2108f7f19aSJason Zhu
2208f7f19aSJason Zhu if (0 == n)
2308f7f19aSJason Zhu return 0;
2408f7f19aSJason Zhu
2508f7f19aSJason Zhu /*
2608f7f19aSJason Zhu * Code snippet without data-dependent branch due to Nate Lawson
2708f7f19aSJason Zhu * (nate@root.org) of Root Labs.
2808f7f19aSJason Zhu */
2908f7f19aSJason Zhu while (n--)
3008f7f19aSJason Zhu result |= *us1++ ^ *us2++;
3108f7f19aSJason Zhu
3208f7f19aSJason Zhu return result != 0;
3308f7f19aSJason Zhu }
3408f7f19aSJason Zhu
htobe32(uint32_t in)3508f7f19aSJason Zhu static uint32_t htobe32(uint32_t in)
3608f7f19aSJason Zhu {
3708f7f19aSJason Zhu union {
3808f7f19aSJason Zhu uint32_t word;
3908f7f19aSJason Zhu uint8_t bytes[4];
4008f7f19aSJason Zhu } ret;
4108f7f19aSJason Zhu
4208f7f19aSJason Zhu ret.bytes[0] = (in >> 24) & 0xff;
4308f7f19aSJason Zhu ret.bytes[1] = (in >> 16) & 0xff;
4408f7f19aSJason Zhu ret.bytes[2] = (in >> 8) & 0xff;
4508f7f19aSJason Zhu ret.bytes[3] = in & 0xff;
4608f7f19aSJason Zhu
4708f7f19aSJason Zhu return ret.word;
4808f7f19aSJason Zhu }
4908f7f19aSJason Zhu
be32toh(uint32_t in)5008f7f19aSJason Zhu static uint32_t be32toh(uint32_t in)
5108f7f19aSJason Zhu {
5208f7f19aSJason Zhu uint8_t *d = (uint8_t *)∈
5308f7f19aSJason Zhu uint32_t ret;
5408f7f19aSJason Zhu
5508f7f19aSJason Zhu ret = ((uint32_t)d[0]) << 24;
5608f7f19aSJason Zhu ret |= ((uint32_t)d[1]) << 16;
5708f7f19aSJason Zhu ret |= ((uint32_t)d[2]) << 8;
5808f7f19aSJason Zhu ret |= ((uint32_t)d[3]);
5908f7f19aSJason Zhu
6008f7f19aSJason Zhu return ret;
6108f7f19aSJason Zhu }
6208f7f19aSJason Zhu
slot_set_unbootable(AvbABSlotData * slot)6308f7f19aSJason Zhu static void slot_set_unbootable(AvbABSlotData* slot)
6408f7f19aSJason Zhu {
6508f7f19aSJason Zhu slot->priority = 0;
6608f7f19aSJason Zhu slot->tries_remaining = 0;
6708f7f19aSJason Zhu slot->successful_boot = 0;
6808f7f19aSJason Zhu }
6908f7f19aSJason Zhu
7008f7f19aSJason Zhu /* Ensure all unbootable and/or illegal states are marked as the
7108f7f19aSJason Zhu * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
7208f7f19aSJason Zhu * and successful_boot=0.
7308f7f19aSJason Zhu */
slot_normalize(AvbABSlotData * slot)7408f7f19aSJason Zhu static void slot_normalize(AvbABSlotData* slot)
7508f7f19aSJason Zhu {
7608f7f19aSJason Zhu if (slot->priority > 0) {
7708f7f19aSJason Zhu if (slot->tries_remaining == 0 && !slot->successful_boot) {
7808f7f19aSJason Zhu /* We've exhausted all tries -> unbootable. */
7908f7f19aSJason Zhu slot_set_unbootable(slot);
8008f7f19aSJason Zhu }
8108f7f19aSJason Zhu if (slot->tries_remaining > 0 && slot->successful_boot) {
8208f7f19aSJason Zhu /* Illegal state - avb_ab_mark_slot_successful() will clear
8308f7f19aSJason Zhu * tries_remaining when setting successful_boot.
8408f7f19aSJason Zhu */
8508f7f19aSJason Zhu slot_set_unbootable(slot);
8608f7f19aSJason Zhu }
8708f7f19aSJason Zhu } else {
8808f7f19aSJason Zhu slot_set_unbootable(slot);
8908f7f19aSJason Zhu }
9008f7f19aSJason Zhu }
9108f7f19aSJason Zhu
9208f7f19aSJason Zhu /* Writes A/B metadata to disk only if it has changed - returns
9308f7f19aSJason Zhu * AVB_IO_RESULT_OK on success, error code otherwise.
9408f7f19aSJason Zhu */
save_metadata_if_changed(AvbABOps * ab_ops,AvbABData * ab_data,AvbABData * ab_data_orig)9508f7f19aSJason Zhu AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
9608f7f19aSJason Zhu AvbABData* ab_data,
9708f7f19aSJason Zhu AvbABData* ab_data_orig)
9808f7f19aSJason Zhu {
9908f7f19aSJason Zhu if (safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
10008f7f19aSJason Zhu debug("Writing A/B metadata to disk.\n");
10108f7f19aSJason Zhu return ab_ops->write_ab_metadata(ab_ops, ab_data);
10208f7f19aSJason Zhu }
10308f7f19aSJason Zhu return AVB_IO_RESULT_OK;
10408f7f19aSJason Zhu }
10508f7f19aSJason Zhu
avb_ab_data_verify_and_byteswap(const AvbABData * src,AvbABData * dest)10608f7f19aSJason Zhu bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
10708f7f19aSJason Zhu /* Ensure magic is correct. */
10808f7f19aSJason Zhu if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
10908f7f19aSJason Zhu printf("Magic is incorrect.\n");
11008f7f19aSJason Zhu return false;
11108f7f19aSJason Zhu }
11208f7f19aSJason Zhu
11308f7f19aSJason Zhu memcpy(dest, src, sizeof(AvbABData));
11408f7f19aSJason Zhu dest->crc32 = be32toh(dest->crc32);
11508f7f19aSJason Zhu
11608f7f19aSJason Zhu /* Ensure we don't attempt to access any fields if the major version
11708f7f19aSJason Zhu * is not supported.
11808f7f19aSJason Zhu */
11908f7f19aSJason Zhu if (dest->version_major > AVB_AB_MAJOR_VERSION) {
12008f7f19aSJason Zhu printf("No support for given major version.\n");
12108f7f19aSJason Zhu return false;
12208f7f19aSJason Zhu }
12308f7f19aSJason Zhu
12408f7f19aSJason Zhu /* Bail if CRC32 doesn't match. */
12508f7f19aSJason Zhu if (dest->crc32 !=
12608f7f19aSJason Zhu crc32(0, (const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
12708f7f19aSJason Zhu printf("CRC32 does not match.\n");
12808f7f19aSJason Zhu return false;
12908f7f19aSJason Zhu }
13008f7f19aSJason Zhu
13108f7f19aSJason Zhu return true;
13208f7f19aSJason Zhu }
13308f7f19aSJason Zhu
avb_ab_data_update_crc_and_byteswap(const AvbABData * src,AvbABData * dest)13408f7f19aSJason Zhu void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
13508f7f19aSJason Zhu AvbABData* dest)
13608f7f19aSJason Zhu {
13708f7f19aSJason Zhu memcpy(dest, src, sizeof(AvbABData));
13808f7f19aSJason Zhu dest->crc32 = htobe32(crc32(0, (const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
13908f7f19aSJason Zhu }
14008f7f19aSJason Zhu
avb_ab_data_init(AvbABData * data)14108f7f19aSJason Zhu void avb_ab_data_init(AvbABData* data)
14208f7f19aSJason Zhu {
14308f7f19aSJason Zhu memset(data, '\0', sizeof(AvbABData));
14408f7f19aSJason Zhu memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
14508f7f19aSJason Zhu data->version_major = AVB_AB_MAJOR_VERSION;
14608f7f19aSJason Zhu data->version_minor = AVB_AB_MINOR_VERSION;
14708f7f19aSJason Zhu data->last_boot = 0;
14808f7f19aSJason Zhu data->slots[0].priority = AVB_AB_MAX_PRIORITY;
14908f7f19aSJason Zhu data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
15008f7f19aSJason Zhu data->slots[0].successful_boot = 0;
15108f7f19aSJason Zhu data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
15208f7f19aSJason Zhu data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
15308f7f19aSJason Zhu data->slots[1].successful_boot = 0;
15408f7f19aSJason Zhu }
15508f7f19aSJason Zhu
15608f7f19aSJason Zhu /* The AvbABData struct is stored 2048 bytes into the 'misc' partition
15708f7f19aSJason Zhu * following the 'struct bootloader_message' field. The struct is
15808f7f19aSJason Zhu * compatible with the guidelines in bootable/recovery/bootloader.h -
15908f7f19aSJason Zhu * e.g. it is stored in the |slot_suffix| field, starts with a
16008f7f19aSJason Zhu * NUL-byte, and is 32 bytes long.
16108f7f19aSJason Zhu */
16208f7f19aSJason Zhu #define AB_METADATA_MISC_PARTITION_OFFSET 2048
16308f7f19aSJason Zhu
avb_ab_data_read(AvbABOps * ab_ops,AvbABData * data)16408f7f19aSJason Zhu AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data)
16508f7f19aSJason Zhu {
16608f7f19aSJason Zhu AvbOps* ops = ab_ops->ops;
16708f7f19aSJason Zhu AvbABData serialized;
16808f7f19aSJason Zhu AvbIOResult io_ret;
16908f7f19aSJason Zhu size_t num_bytes_read;
17008f7f19aSJason Zhu
17108f7f19aSJason Zhu io_ret = ops->read_from_partition(ops,
17208f7f19aSJason Zhu "misc",
17308f7f19aSJason Zhu AB_METADATA_MISC_PARTITION_OFFSET,
17408f7f19aSJason Zhu sizeof(AvbABData),
17508f7f19aSJason Zhu &serialized,
17608f7f19aSJason Zhu &num_bytes_read);
17708f7f19aSJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
17808f7f19aSJason Zhu return AVB_IO_RESULT_ERROR_OOM;
17908f7f19aSJason Zhu } else if (io_ret != AVB_IO_RESULT_OK ||
18008f7f19aSJason Zhu num_bytes_read != sizeof(AvbABData)) {
18108f7f19aSJason Zhu printf("Error reading A/B metadata.\n");
18208f7f19aSJason Zhu return AVB_IO_RESULT_ERROR_IO;
18308f7f19aSJason Zhu }
18408f7f19aSJason Zhu
18508f7f19aSJason Zhu if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
18608f7f19aSJason Zhu printf("Error validating A/B metadata from disk. "
18708f7f19aSJason Zhu "Resetting and writing new A/B metadata to disk.\n");
18808f7f19aSJason Zhu avb_ab_data_init(data);
18908f7f19aSJason Zhu return avb_ab_data_write(ab_ops, data);
19008f7f19aSJason Zhu }
19108f7f19aSJason Zhu
19208f7f19aSJason Zhu return AVB_IO_RESULT_OK;
19308f7f19aSJason Zhu }
19408f7f19aSJason Zhu
avb_ab_data_write(AvbABOps * ab_ops,const AvbABData * data)19508f7f19aSJason Zhu AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data)
19608f7f19aSJason Zhu {
19708f7f19aSJason Zhu AvbOps* ops = ab_ops->ops;
19808f7f19aSJason Zhu AvbABData serialized;
19908f7f19aSJason Zhu AvbIOResult io_ret;
20008f7f19aSJason Zhu
20108f7f19aSJason Zhu avb_ab_data_update_crc_and_byteswap(data, &serialized);
20208f7f19aSJason Zhu io_ret = ops->write_to_partition(ops,
20308f7f19aSJason Zhu "misc",
20408f7f19aSJason Zhu AB_METADATA_MISC_PARTITION_OFFSET,
20508f7f19aSJason Zhu sizeof(AvbABData),
20608f7f19aSJason Zhu &serialized);
20708f7f19aSJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
20808f7f19aSJason Zhu return AVB_IO_RESULT_ERROR_OOM;
20908f7f19aSJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) {
21008f7f19aSJason Zhu printf("Error writing A/B metadata.\n");
21108f7f19aSJason Zhu return AVB_IO_RESULT_ERROR_IO;
21208f7f19aSJason Zhu }
21308f7f19aSJason Zhu return AVB_IO_RESULT_OK;
21408f7f19aSJason Zhu }
21508f7f19aSJason Zhu
21608f7f19aSJason Zhu /* Helper function to load metadata - returns AVB_IO_RESULT_OK on
21708f7f19aSJason Zhu * success, error code otherwise.
21808f7f19aSJason Zhu */
load_metadata(AvbABOps * ab_ops,AvbABData * ab_data,AvbABData * ab_data_orig)21908f7f19aSJason Zhu AvbIOResult load_metadata(AvbABOps* ab_ops,
22008f7f19aSJason Zhu AvbABData* ab_data,
22108f7f19aSJason Zhu AvbABData* ab_data_orig) {
22208f7f19aSJason Zhu AvbIOResult io_ret;
22308f7f19aSJason Zhu
22408f7f19aSJason Zhu io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
22508f7f19aSJason Zhu if (io_ret != AVB_IO_RESULT_OK) {
22608f7f19aSJason Zhu printf("I/O error while loading A/B metadata.\n");
22708f7f19aSJason Zhu return io_ret;
22808f7f19aSJason Zhu }
22908f7f19aSJason Zhu *ab_data_orig = *ab_data;
23008f7f19aSJason Zhu
23108f7f19aSJason Zhu /* Ensure data is normalized, e.g. illegal states will be marked as
23208f7f19aSJason Zhu * unbootable and all unbootable states are represented with
23308f7f19aSJason Zhu * (priority=0, tries_remaining=0, successful_boot=0).
23408f7f19aSJason Zhu */
23508f7f19aSJason Zhu slot_normalize(&ab_data->slots[0]);
23608f7f19aSJason Zhu slot_normalize(&ab_data->slots[1]);
23708f7f19aSJason Zhu return AVB_IO_RESULT_OK;
23808f7f19aSJason Zhu }
23908f7f19aSJason Zhu
rk_avb_read_slot_count(char * slot_count)24008f7f19aSJason Zhu int rk_avb_read_slot_count(char *slot_count)
24108f7f19aSJason Zhu {
24208f7f19aSJason Zhu *slot_count = SLOT_NUM;
24308f7f19aSJason Zhu
24408f7f19aSJason Zhu return 0;
24508f7f19aSJason Zhu }
24608f7f19aSJason Zhu
rk_avb_read_slot_suffixes(char * slot_suffixes)24708f7f19aSJason Zhu int rk_avb_read_slot_suffixes(char *slot_suffixes)
24808f7f19aSJason Zhu {
24908f7f19aSJason Zhu memcpy(slot_suffixes, CURR_SYSTEM_SLOT_SUFFIX,
25008f7f19aSJason Zhu strlen(CURR_SYSTEM_SLOT_SUFFIX));
25108f7f19aSJason Zhu
25208f7f19aSJason Zhu return 0;
25308f7f19aSJason Zhu }
25408f7f19aSJason Zhu
avb_ab_mark_slot_active(AvbABOps * ab_ops,unsigned int slot_number)25508f7f19aSJason Zhu AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
25608f7f19aSJason Zhu unsigned int slot_number)
25708f7f19aSJason Zhu {
25808f7f19aSJason Zhu AvbABData ab_data, ab_data_orig;
25908f7f19aSJason Zhu unsigned int other_slot_number;
26008f7f19aSJason Zhu AvbIOResult ret;
26108f7f19aSJason Zhu
26208f7f19aSJason Zhu avb_assert(slot_number < 2);
26308f7f19aSJason Zhu
26408f7f19aSJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
26508f7f19aSJason Zhu if (ret != AVB_IO_RESULT_OK) {
26608f7f19aSJason Zhu goto out;
26708f7f19aSJason Zhu }
26808f7f19aSJason Zhu
26908f7f19aSJason Zhu /* Make requested slot top priority, unsuccessful, and with max tries. */
27008f7f19aSJason Zhu ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
27108f7f19aSJason Zhu ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
27208f7f19aSJason Zhu ab_data.slots[slot_number].successful_boot = 0;
27308f7f19aSJason Zhu
27408f7f19aSJason Zhu /* Ensure other slot doesn't have as high a priority. */
27508f7f19aSJason Zhu other_slot_number = 1 - slot_number;
27608f7f19aSJason Zhu if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
27708f7f19aSJason Zhu ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
27808f7f19aSJason Zhu }
27908f7f19aSJason Zhu
28008f7f19aSJason Zhu ret = AVB_IO_RESULT_OK;
28108f7f19aSJason Zhu
28208f7f19aSJason Zhu out:
28308f7f19aSJason Zhu if (ret == AVB_IO_RESULT_OK) {
28408f7f19aSJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
28508f7f19aSJason Zhu }
28608f7f19aSJason Zhu return ret;
28708f7f19aSJason Zhu }
28808f7f19aSJason Zhu
rk_avb_set_slot_active(unsigned int * slot_number)28908f7f19aSJason Zhu int rk_avb_set_slot_active(unsigned int *slot_number)
29008f7f19aSJason Zhu {
29108f7f19aSJason Zhu AvbOps* ops;
29208f7f19aSJason Zhu ops = avb_ops_user_new();
29308f7f19aSJason Zhu int ret = 0;
29408f7f19aSJason Zhu
29508f7f19aSJason Zhu if (ops == NULL) {
29608f7f19aSJason Zhu printf("avb_ops_user_new() failed!\n");
29708f7f19aSJason Zhu return -1;
29808f7f19aSJason Zhu }
29908f7f19aSJason Zhu
30008f7f19aSJason Zhu debug("set_slot_active\n");
30108f7f19aSJason Zhu if (avb_ab_mark_slot_active(ops->ab_ops, *slot_number) != 0) {
30208f7f19aSJason Zhu printf("set_slot_active error!\n");
30308f7f19aSJason Zhu ret = -1;
30408f7f19aSJason Zhu }
30508f7f19aSJason Zhu
30608f7f19aSJason Zhu avb_ops_user_free(ops);
30708f7f19aSJason Zhu return ret;
30808f7f19aSJason Zhu }
30908f7f19aSJason Zhu
slot_is_bootable(AvbABSlotData * slot)31008f7f19aSJason Zhu static bool slot_is_bootable(AvbABSlotData* slot) {
31108f7f19aSJason Zhu return (slot->priority > 0) &&
31208f7f19aSJason Zhu (slot->successful_boot || (slot->tries_remaining > 0));
31308f7f19aSJason Zhu }
31408f7f19aSJason Zhu
rk_avb_ab_slot_select(AvbABOps * ab_ops,char * select_slot)31508f7f19aSJason Zhu AvbABFlowResult rk_avb_ab_slot_select(AvbABOps* ab_ops,char* select_slot)
31608f7f19aSJason Zhu {
31708f7f19aSJason Zhu AvbABFlowResult ret = AVB_AB_FLOW_RESULT_OK;
31808f7f19aSJason Zhu AvbIOResult io_ret = AVB_IO_RESULT_OK;
31908f7f19aSJason Zhu AvbABData ab_data;
32008f7f19aSJason Zhu size_t slot_index_to_boot;
32108f7f19aSJason Zhu static int last_slot_index = -1;
32208f7f19aSJason Zhu
32308f7f19aSJason Zhu io_ret = ab_ops->read_ab_metadata(ab_ops, &ab_data);
32408f7f19aSJason Zhu if (io_ret != AVB_IO_RESULT_OK) {
32508f7f19aSJason Zhu printf("I/O error while loading A/B metadata.\n");
32608f7f19aSJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO;
32708f7f19aSJason Zhu goto out;
32808f7f19aSJason Zhu }
32908f7f19aSJason Zhu if (slot_is_bootable(&ab_data.slots[0]) && slot_is_bootable(&ab_data.slots[1])) {
33008f7f19aSJason Zhu if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
33108f7f19aSJason Zhu slot_index_to_boot = 1;
33208f7f19aSJason Zhu } else {
33308f7f19aSJason Zhu slot_index_to_boot = 0;
33408f7f19aSJason Zhu }
33508f7f19aSJason Zhu } else if(slot_is_bootable(&ab_data.slots[0])) {
33608f7f19aSJason Zhu slot_index_to_boot = 0;
33708f7f19aSJason Zhu } else if(slot_is_bootable(&ab_data.slots[1])) {
33808f7f19aSJason Zhu slot_index_to_boot = 1;
33908f7f19aSJason Zhu } else {
34008f7f19aSJason Zhu printf("No bootable slots found.\n");
34108f7f19aSJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
34208f7f19aSJason Zhu goto out;
34308f7f19aSJason Zhu }
34408f7f19aSJason Zhu
34508f7f19aSJason Zhu if (slot_index_to_boot == 0) {
34608f7f19aSJason Zhu strcpy(select_slot, "_a");
34708f7f19aSJason Zhu } else if(slot_index_to_boot == 1) {
34808f7f19aSJason Zhu strcpy(select_slot, "_b");
34908f7f19aSJason Zhu }
35008f7f19aSJason Zhu
35108f7f19aSJason Zhu if (last_slot_index != slot_index_to_boot) {
35208f7f19aSJason Zhu last_slot_index = slot_index_to_boot;
35308f7f19aSJason Zhu printf("A/B-slot: %s, successful: %d, tries-remain: %d\n",
35408f7f19aSJason Zhu select_slot,
35508f7f19aSJason Zhu ab_data.slots[slot_index_to_boot].successful_boot,
35608f7f19aSJason Zhu ab_data.slots[slot_index_to_boot].tries_remaining);
35708f7f19aSJason Zhu }
35808f7f19aSJason Zhu out:
35908f7f19aSJason Zhu return ret;
36008f7f19aSJason Zhu }
36108f7f19aSJason Zhu
avb_ab_mark_slot_unbootable(AvbABOps * ab_ops,unsigned int slot_number)36208f7f19aSJason Zhu AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
36308f7f19aSJason Zhu unsigned int slot_number)
36408f7f19aSJason Zhu {
36508f7f19aSJason Zhu AvbABData ab_data, ab_data_orig;
36608f7f19aSJason Zhu AvbIOResult ret;
36708f7f19aSJason Zhu
36808f7f19aSJason Zhu avb_assert(slot_number < 2);
36908f7f19aSJason Zhu
37008f7f19aSJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
37108f7f19aSJason Zhu if (ret != AVB_IO_RESULT_OK) {
37208f7f19aSJason Zhu goto out;
37308f7f19aSJason Zhu }
37408f7f19aSJason Zhu
37508f7f19aSJason Zhu slot_set_unbootable(&ab_data.slots[slot_number]);
37608f7f19aSJason Zhu
37708f7f19aSJason Zhu ret = AVB_IO_RESULT_OK;
37808f7f19aSJason Zhu
37908f7f19aSJason Zhu out:
38008f7f19aSJason Zhu if (ret == AVB_IO_RESULT_OK) {
38108f7f19aSJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
38208f7f19aSJason Zhu }
38308f7f19aSJason Zhu return ret;
38408f7f19aSJason Zhu }
38508f7f19aSJason Zhu
avb_ab_mark_slot_successful(AvbABOps * ab_ops,unsigned int slot_number)38608f7f19aSJason Zhu AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
38708f7f19aSJason Zhu unsigned int slot_number)
38808f7f19aSJason Zhu {
38908f7f19aSJason Zhu AvbABData ab_data, ab_data_orig;
39008f7f19aSJason Zhu AvbIOResult ret;
39108f7f19aSJason Zhu
39208f7f19aSJason Zhu avb_assert(slot_number < 2);
39308f7f19aSJason Zhu
39408f7f19aSJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
39508f7f19aSJason Zhu if (ret != AVB_IO_RESULT_OK) {
39608f7f19aSJason Zhu goto out;
39708f7f19aSJason Zhu }
39808f7f19aSJason Zhu
39908f7f19aSJason Zhu if (!slot_is_bootable(&ab_data.slots[slot_number])) {
40008f7f19aSJason Zhu printf("Cannot mark unbootable slot as successful.\n");
40108f7f19aSJason Zhu ret = AVB_IO_RESULT_OK;
40208f7f19aSJason Zhu goto out;
40308f7f19aSJason Zhu }
40408f7f19aSJason Zhu
40508f7f19aSJason Zhu ab_data.slots[slot_number].tries_remaining = 0;
40608f7f19aSJason Zhu ab_data.slots[slot_number].successful_boot = 1;
40708f7f19aSJason Zhu
40808f7f19aSJason Zhu ret = AVB_IO_RESULT_OK;
40908f7f19aSJason Zhu
41008f7f19aSJason Zhu out:
41108f7f19aSJason Zhu if (ret == AVB_IO_RESULT_OK) {
41208f7f19aSJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
41308f7f19aSJason Zhu }
41408f7f19aSJason Zhu return ret;
41508f7f19aSJason Zhu }
41608f7f19aSJason Zhu
rk_get_lastboot(void)41708f7f19aSJason Zhu int rk_get_lastboot(void)
41808f7f19aSJason Zhu {
41908f7f19aSJason Zhu
42008f7f19aSJason Zhu AvbIOResult io_ret = AVB_IO_RESULT_OK;
42108f7f19aSJason Zhu AvbABData ab_data;
42208f7f19aSJason Zhu int lastboot = -1;
42308f7f19aSJason Zhu AvbOps* ops;
42408f7f19aSJason Zhu
42508f7f19aSJason Zhu ops = avb_ops_user_new();
42608f7f19aSJason Zhu if (ops == NULL) {
42708f7f19aSJason Zhu printf("avb_ops_user_new() failed!\n");
42808f7f19aSJason Zhu return -1;
42908f7f19aSJason Zhu }
43008f7f19aSJason Zhu
43108f7f19aSJason Zhu io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data);
43208f7f19aSJason Zhu if (io_ret != AVB_IO_RESULT_OK) {
43308f7f19aSJason Zhu printf("I/O error while loading A/B metadata.\n");
43408f7f19aSJason Zhu goto out;
43508f7f19aSJason Zhu }
43608f7f19aSJason Zhu
43708f7f19aSJason Zhu lastboot = ab_data.last_boot;
43808f7f19aSJason Zhu out:
43908f7f19aSJason Zhu avb_ops_user_free(ops);
44008f7f19aSJason Zhu
44108f7f19aSJason Zhu return lastboot;
44208f7f19aSJason Zhu }
44308f7f19aSJason Zhu
rk_avb_get_current_slot(char * select_slot)44408f7f19aSJason Zhu int rk_avb_get_current_slot(char *select_slot)
44508f7f19aSJason Zhu {
44608f7f19aSJason Zhu AvbOps* ops;
44708f7f19aSJason Zhu int ret = 0;
44808f7f19aSJason Zhu
44908f7f19aSJason Zhu ops = avb_ops_user_new();
45008f7f19aSJason Zhu if (ops == NULL) {
45108f7f19aSJason Zhu printf("avb_ops_user_new() failed!\n");
45208f7f19aSJason Zhu return -1;
45308f7f19aSJason Zhu }
45408f7f19aSJason Zhu
45508f7f19aSJason Zhu if (rk_avb_ab_slot_select(ops->ab_ops, select_slot) != 0) {
45608f7f19aSJason Zhu #ifndef CONFIG_ANDROID_AVB
45708f7f19aSJason Zhu printf("###There is no bootable slot, bring up last_boot!###\n");
45808f7f19aSJason Zhu if (rk_get_lastboot() == 1)
45908f7f19aSJason Zhu memcpy(select_slot, "_b", 2);
46008f7f19aSJason Zhu else if(rk_get_lastboot() == 0)
46108f7f19aSJason Zhu memcpy(select_slot, "_a", 2);
46208f7f19aSJason Zhu else
46308f7f19aSJason Zhu #endif
46408f7f19aSJason Zhu return -1;
46508f7f19aSJason Zhu ret = 0;
46608f7f19aSJason Zhu }
46708f7f19aSJason Zhu
46808f7f19aSJason Zhu avb_ops_user_free(ops);
46908f7f19aSJason Zhu return ret;
47008f7f19aSJason Zhu }
47108f7f19aSJason Zhu
rk_avb_ab_have_bootable_slot(void)472*17e05a56SJason Zhu bool rk_avb_ab_have_bootable_slot(void)
473*17e05a56SJason Zhu {
474*17e05a56SJason Zhu char slot[3] = {0};
475*17e05a56SJason Zhu
476*17e05a56SJason Zhu if (rk_avb_get_current_slot(slot))
477*17e05a56SJason Zhu return false;
478*17e05a56SJason Zhu else
479*17e05a56SJason Zhu return true;
480*17e05a56SJason Zhu }
481*17e05a56SJason Zhu
rk_avb_append_part_slot(const char * part_name,char * new_name)48208f7f19aSJason Zhu int rk_avb_append_part_slot(const char *part_name, char *new_name)
48308f7f19aSJason Zhu {
48408f7f19aSJason Zhu char slot_suffix[3] = {0};
48508f7f19aSJason Zhu
48608f7f19aSJason Zhu if (!strcmp(part_name, "misc")) {
48708f7f19aSJason Zhu strcat(new_name, part_name);
48808f7f19aSJason Zhu return 0;
48908f7f19aSJason Zhu }
49008f7f19aSJason Zhu
49108f7f19aSJason Zhu if (rk_avb_get_current_slot(slot_suffix)) {
49208f7f19aSJason Zhu printf("%s: failed to get slot suffix !\n", __func__);
49308f7f19aSJason Zhu return -1;
49408f7f19aSJason Zhu }
49508f7f19aSJason Zhu
49608f7f19aSJason Zhu strcpy(new_name, part_name);
49708f7f19aSJason Zhu strcat(new_name, slot_suffix);
49808f7f19aSJason Zhu
49908f7f19aSJason Zhu return 0;
50008f7f19aSJason Zhu }
501