diff --git a/boot_control_avb.c b/boot_control_avb.c index af648d7..2e025a0 100644 --- a/boot_control_avb.c +++ b/boot_control_avb.c @@ -26,12 +26,12 @@ #include #include +#include +#include #include #include -#include "boot_control_avb.h" - static AvbOps* ops = NULL; static void module_init(boot_control_module_t* module) { @@ -115,9 +115,9 @@ static int module_isSlotBootable(struct boot_control_module* module, return -EIO; } - is_bootable = (ab_data.slot_info[slot].priority > 0) && - (ab_data.slot_info[slot].successful_boot || - (ab_data.slot_info[slot].tries_remaining > 0)); + is_bootable = (ab_data.slots[slot].priority > 0) && + (ab_data.slots[slot].successful_boot || + (ab_data.slots[slot].tries_remaining > 0)); return is_bootable ? 1 : 0; } @@ -135,7 +135,7 @@ static int module_isSlotMarkedSuccessful(struct boot_control_module* module, return -EIO; } - is_marked_successful = ab_data.slot_info[slot].successful_boot; + is_marked_successful = ab_data.slots[slot].successful_boot; return is_marked_successful ? 1 : 0; } @@ -149,24 +149,12 @@ static const char* module_getSuffix(boot_control_module_t* module, return suffix[slot]; } -static bool module_setSnapshotMergeStatus(uint8_t status) { - if (avb_ab_set_snapshot_merge_status(ops->ab_ops, status) == AVB_IO_RESULT_OK) - return true; - else - return false; -} - -static uint8_t module_getSnapshotMergeStatus(void) { - return avb_ab_get_snapshot_merge_status(ops->ab_ops); -} - static struct hw_module_methods_t module_methods = { .open = NULL, }; -private_boot_control_t HAL_MODULE_INFO_SYM = { - .base = { - .common = +boot_control_module_t HAL_MODULE_INFO_SYM = { + .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1, @@ -176,17 +164,14 @@ private_boot_control_t HAL_MODULE_INFO_SYM = { .author = "The Android Open Source Project", .methods = &module_methods, }, - .init = module_init, - .getNumberSlots = module_getNumberSlots, - .getCurrentSlot = module_getCurrentSlot, - .markBootSuccessful = module_markBootSuccessful, - .setActiveBootSlot = module_setActiveBootSlot, - .setSlotAsUnbootable = module_setSlotAsUnbootable, - .isSlotBootable = module_isSlotBootable, - .getSuffix = module_getSuffix, - .isSlotMarkedSuccessful = module_isSlotMarkedSuccessful, - .getActiveBootSlot = module_getActiveBootSlot, - }, - .SetSnapshotMergeStatus = module_setSnapshotMergeStatus, - .GetSnapshotMergeStatus = module_getSnapshotMergeStatus, + .init = module_init, + .getNumberSlots = module_getNumberSlots, + .getCurrentSlot = module_getCurrentSlot, + .markBootSuccessful = module_markBootSuccessful, + .setActiveBootSlot = module_setActiveBootSlot, + .setSlotAsUnbootable = module_setSlotAsUnbootable, + .isSlotBootable = module_isSlotBootable, + .getSuffix = module_getSuffix, + .isSlotMarkedSuccessful = module_isSlotMarkedSuccessful, + .getActiveBootSlot = module_getActiveBootSlot, }; diff --git a/boot_control_avb.h b/boot_control_avb.h deleted file mode 100644 index d348a4e..0000000 --- a/boot_control_avb.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef BOOT_CONTROL_AVB_H_ -#define BOOT_CONTROL_AVB_H_ - -//#include -#include -#include - -typedef struct private_boot_control { - boot_control_module_t base; - bool (*SetSnapshotMergeStatus)(uint8_t status); - uint8_t (*GetSnapshotMergeStatus)(void); -} private_boot_control_t; - -#endif /* BOOT_CONTROL_AVB_H_*/ diff --git a/libavb_ab/avb_ab_flow.c b/libavb_ab/avb_ab_flow.c index c7c723e..734c168 100644 --- a/libavb_ab/avb_ab_flow.c +++ b/libavb_ab/avb_ab_flow.c @@ -26,22 +26,24 @@ bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) { /* Ensure magic is correct. */ - if (src->magic != BOOT_CTRL_MAGIC) { + if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { avb_error("Magic is incorrect.\n"); return false; } avb_memcpy(dest, src, sizeof(AvbABData)); + dest->crc32 = avb_be32toh(dest->crc32); + /* Ensure we don't attempt to access any fields if the major version * is not supported. */ - if (dest->version_major > BOOT_CTRL_VERSION) { + if (dest->version_major > AVB_AB_MAJOR_VERSION) { avb_error("No support for given major version.\n"); return false; } /* Bail if CRC32 doesn't match. */ - if (dest->crc32_le != + if (dest->crc32 != avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) { avb_error("CRC32 does not match.\n"); return false; @@ -53,25 +55,23 @@ bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) { void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, AvbABData* dest) { avb_memcpy(dest, src, sizeof(AvbABData)); - dest->crc32_le = avb_crc32((const uint8_t*)dest, - sizeof(AvbABData) - sizeof(uint32_t)); + dest->crc32 = avb_htobe32( + avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))); } void avb_ab_data_init(AvbABData* data) { avb_memset(data, '\0', sizeof(AvbABData)); - data->magic = BOOT_CTRL_MAGIC; - data->version_major = BOOT_CTRL_VERSION; - data->nb_slot = 2; - data->slot_info[0].priority = AVB_AB_MAX_PRIORITY; - data->slot_info[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - data->slot_info[0].successful_boot = 0; - data->slot_info[1].priority = AVB_AB_MAX_PRIORITY - 1; - data->slot_info[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - data->slot_info[1].successful_boot = 0; - avb_memcpy(data->slot_suffix, "_a", 2); + avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); + data->version_major = AVB_AB_MAJOR_VERSION; + data->version_minor = AVB_AB_MINOR_VERSION; + data->slots[0].priority = AVB_AB_MAX_PRIORITY; + data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; + data->slots[0].successful_boot = 0; + data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; + data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; + data->slots[1].successful_boot = 0; } - /* The AvbABData struct is stored 2048 bytes into the 'misc' partition * following the 'struct bootloader_message' field. The struct is * compatible with the guidelines in bootable/recovery/bootloader.h - @@ -152,12 +152,17 @@ static void slot_normalize(AvbABSlotData* slot) { /* We've exhausted all tries -> unbootable. */ slot_set_unbootable(slot); } + if (slot->tries_remaining > 0 && slot->successful_boot) { + /* Illegal state - avb_ab_mark_slot_successful() will clear + * tries_remaining when setting successful_boot. + */ + slot_set_unbootable(slot); + } } else { slot_set_unbootable(slot); } } - static const char* slot_suffixes[2] = {"_a", "_b"}; /* Helper function to load metadata - returns AVB_IO_RESULT_OK on @@ -179,8 +184,8 @@ static AvbIOResult load_metadata(AvbABOps* ab_ops, * unbootable and all unbootable states are represented with * (priority=0, tries_remaining=0, successful_boot=0). */ - slot_normalize(&ab_data->slot_info[0]); - slot_normalize(&ab_data->slot_info[1]); + slot_normalize(&ab_data->slots[0]); + slot_normalize(&ab_data->slots[1]); return AVB_IO_RESULT_OK; } @@ -222,7 +227,7 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, /* Validate all bootable slots. */ for (n = 0; n < 2; n++) { - if (slot_is_bootable(&ab_data.slot_info[n])) { + if (slot_is_bootable(&ab_data.slots[n])) { AvbSlotVerifyResult verify_result; bool set_slot_unbootable = false; @@ -286,21 +291,21 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, avb_slot_verify_result_to_string(verify_result), " - setting unbootable.\n", NULL); - slot_set_unbootable(&ab_data.slot_info[n]); + slot_set_unbootable(&ab_data.slots[n]); } } } - if (slot_is_bootable(&ab_data.slot_info[0]) && - slot_is_bootable(&ab_data.slot_info[1])) { - if (ab_data.slot_info[1].priority > ab_data.slot_info[0].priority) { + if (slot_is_bootable(&ab_data.slots[0]) && + slot_is_bootable(&ab_data.slots[1])) { + if (ab_data.slots[1].priority > ab_data.slots[0].priority) { slot_index_to_boot = 1; } else { slot_index_to_boot = 0; } - } else if (slot_is_bootable(&ab_data.slot_info[0])) { + } else if (slot_is_bootable(&ab_data.slots[0])) { slot_index_to_boot = 0; - } else if (slot_is_bootable(&ab_data.slot_info[1])) { + } else if (slot_is_bootable(&ab_data.slots[1])) { slot_index_to_boot = 1; } else { /* No bootable slots! */ @@ -365,9 +370,9 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, } /* ... and decrement tries remaining, if applicable. */ - if (!ab_data.slot_info[slot_index_to_boot].successful_boot && - ab_data.slot_info[slot_index_to_boot].tries_remaining > 0) { - ab_data.slot_info[slot_index_to_boot].tries_remaining -= 1; + if (!ab_data.slots[slot_index_to_boot].successful_boot && + ab_data.slots[slot_index_to_boot].tries_remaining > 0) { + ab_data.slots[slot_index_to_boot].tries_remaining -= 1; } out: @@ -407,7 +412,11 @@ AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, unsigned int other_slot_number; AvbIOResult ret; - avb_assert(slot_number < 2); + //avb_assert(slot_number < 2); + if (slot_number >= 2) { + ret = AVB_IO_RESULT_ERROR_IO; + goto out; + } ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); if (ret != AVB_IO_RESULT_OK) { @@ -415,14 +424,14 @@ AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, } /* Make requested slot top priority, unsuccessful, and with max tries. */ - ab_data.slot_info[slot_number].priority = AVB_AB_MAX_PRIORITY; - ab_data.slot_info[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - ab_data.slot_info[slot_number].successful_boot = 0; + ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY; + ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; + ab_data.slots[slot_number].successful_boot = 0; /* Ensure other slot doesn't have as high a priority. */ other_slot_number = 1 - slot_number; - if (ab_data.slot_info[other_slot_number].priority == AVB_AB_MAX_PRIORITY) { - ab_data.slot_info[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1; + if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) { + ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1; } ret = AVB_IO_RESULT_OK; @@ -444,7 +453,7 @@ unsigned int avb_ab_get_active_slot(AvbABOps* ab_ops) { } for (unsigned int i = 0; i < 2; i++) { - if (ab_data_orig.slot_info[i].priority == AVB_AB_MAX_PRIORITY) + if (ab_data_orig.slots[i].priority == AVB_AB_MAX_PRIORITY) return i; } @@ -452,44 +461,23 @@ unsigned int avb_ab_get_active_slot(AvbABOps* ab_ops) { return 0; } - AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops, unsigned int slot_number) { AvbABData ab_data, ab_data_orig; AvbIOResult ret; - avb_assert(slot_number < 2); - - ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); - if (ret != AVB_IO_RESULT_OK) { + //avb_assert(slot_number < 2); + if (slot_number >= 2) { + ret = AVB_IO_RESULT_ERROR_IO; goto out; } - slot_set_unbootable(&ab_data.slot_info[slot_number]); - - ret = AVB_IO_RESULT_OK; - -out: - if (ret == AVB_IO_RESULT_OK) { - ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); - } - return ret; -} - -AvbIOResult avb_ab_set_snapshot_merge_status(AvbABOps* ab_ops, - uint8_t merge_status) { - AvbABData ab_data, ab_data_orig; - AvbIOResult ret; - - if (merge_status > CANCELLED) - merge_status = UNKNOWN; - ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); if (ret != AVB_IO_RESULT_OK) { goto out; } - ab_data.merge_status = merge_status; + slot_set_unbootable(&ab_data.slots[slot_number]); ret = AVB_IO_RESULT_OK; @@ -500,22 +488,6 @@ AvbIOResult avb_ab_set_snapshot_merge_status(AvbABOps* ab_ops, return ret; } -uint8_t avb_ab_get_snapshot_merge_status(AvbABOps* ab_ops) { - AvbABData ab_data, ab_data_orig; - AvbIOResult ret; - uint8_t status = UNKNOWN; - - ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); - if (ret != AVB_IO_RESULT_OK) { - goto out; - } - - status = ab_data.merge_status; - -out: - return status; -} - AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops, unsigned int slot_number) { AvbABData ab_data, ab_data_orig; @@ -528,14 +500,14 @@ AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops, goto out; } - if (!slot_is_bootable(&ab_data.slot_info[slot_number])) { + if (!slot_is_bootable(&ab_data.slots[slot_number])) { avb_error("Cannot mark unbootable slot as successful.\n"); ret = AVB_IO_RESULT_OK; goto out; } - ab_data.slot_info[slot_number].tries_remaining = 0; - ab_data.slot_info[slot_number].successful_boot = 1; + ab_data.slots[slot_number].tries_remaining = 0; + ab_data.slots[slot_number].successful_boot = 1; ret = AVB_IO_RESULT_OK; diff --git a/libavb_ab/avb_ab_flow.h b/libavb_ab/avb_ab_flow.h index a15cd7a..ec27b2d 100644 --- a/libavb_ab/avb_ab_flow.h +++ b/libavb_ab/avb_ab_flow.h @@ -36,63 +36,69 @@ extern "C" { #endif -#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */ -#define BOOT_CTRL_VERSION 1 +/* Magic for the A/B struct when serialized. */ +#define AVB_AB_MAGIC "\0AB0" +#define AVB_AB_MAGIC_LEN 4 + +/* Versioning for the on-disk A/B metadata - keep in sync with avbtool. */ +#define AVB_AB_MAJOR_VERSION 1 +#define AVB_AB_MINOR_VERSION 0 + +/* Size of AvbABData struct. */ +#define AVB_AB_DATA_SIZE 32 /* Maximum values for slot data */ #define AVB_AB_MAX_PRIORITY 15 #define AVB_AB_MAX_TRIES_REMAINING 7 -typedef struct slot_metadata { - // Slot priority with 15 meaning highest priority, 1 lowest - // priority and 0 the slot is unbootable. - uint8_t priority : 4; - // Number of times left attempting to boot this slot. - uint8_t tries_remaining : 3; - // 1 if this slot has booted successfully, 0 otherwise. - uint8_t successful_boot : 1; - // 1 if this slot is corrupted from a dm-verity corruption, 0 - // otherwise. - uint8_t verity_corrupted : 1; - // Reserved for further use. - uint8_t reserved : 7; -} __attribute__((packed)) slot_metadata_t; - -/* Bootloader Control AB +/* Struct used for recording per-slot metadata. * - * This struct can be used to manage A/B metadata. It is designed to - * be put in the 'slot_suffix' field of the 'bootloader_message' - * structure described above. It is encouraged to use the - * 'bootloader_control' structure to store the A/B metadata, but not - * mandatory. + * When serialized, data is stored in network byte-order. */ -typedef struct bootloader_control { - // NUL terminated active slot suffix. - char slot_suffix[4]; - // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). - uint32_t magic; - - // Version of struct being used (see BOOT_CTRL_VERSION). - uint8_t version_major; // version; - // Number of slots being managed. - uint8_t nb_slot : 3; - // Number of times left attempting to boot recovery. - uint8_t recovery_tries_remaining : 3; - // Status of any pending snapshot merge of dynamic partitions. - uint8_t merge_status : 3; - // Ensure 4-bytes alignment for slot_info field. - uint8_t reserved0[1]; - // Per-slot information. Up to 4 slots. - struct slot_metadata slot_info[4]; - // Reserved for further use. - uint8_t reserved1[8]; - // CRC32 of all 28 bytes preceding this field (little endian - // format). - uint32_t crc32_le; -} AVB_ATTR_PACKED bootloader_control; - -typedef struct slot_metadata AvbABSlotData; -typedef struct bootloader_control AvbABData; +typedef struct AvbABSlotData { + /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY, + * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY + * being the highest. The special value 0 is used to indicate the + * slot is unbootable. + */ + uint8_t priority; + + /* Number of times left attempting to boot this slot ranging from 0 + * to AVB_AB_MAX_TRIES_REMAINING. + */ + uint8_t tries_remaining; + + /* Non-zero if this slot has booted successfully, 0 otherwise. */ + uint8_t successful_boot; + + /* Reserved for future use. */ + uint8_t reserved[1]; +} AVB_ATTR_PACKED AvbABSlotData; + +/* Struct used for recording A/B metadata. + * + * When serialized, data is stored in network byte-order. + */ +typedef struct AvbABData { + /* Magic number used for identification - see AVB_AB_MAGIC. */ + uint8_t magic[AVB_AB_MAGIC_LEN]; + + /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */ + uint8_t version_major; + uint8_t version_minor; + + /* Padding to ensure |slots| field start eight bytes in. */ + uint8_t reserved1[2]; + + /* Per-slot metadata. */ + AvbABSlotData slots[2]; + + /* Reserved for future use. */ + uint8_t reserved2[12]; + + /* CRC32 of all 28 bytes preceding this field. */ + uint32_t crc32; +} AVB_ATTR_PACKED AvbABData; /* Copies |src| to |dest|, byte-swapping fields in the * process. Returns false if the data is invalid (e.g. wrong magic, @@ -138,14 +144,6 @@ typedef enum { AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT } AvbABFlowResult; -typedef enum { - NONE = 0, - UNKNOWN, - SNAPSHOTTED, - MERGING, - CANCELLED, -} SnapMergeStatus; - /* Get a textual representation of |result|. */ const char* avb_ab_flow_result_to_string(AvbABFlowResult result); @@ -263,20 +261,6 @@ AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops, AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops, unsigned int slot_number); -/* Set the snapshot merge status of virtual a/b OTA update. - * true on success, false on failure. - * - * This function is typically used by the virtual a/b ota update - */ -AvbIOResult avb_ab_set_snapshot_merge_status(AvbABOps* ab_ops, - uint8_t merge_status); - -/* Get the snapshot merge status of virtual a/b OTA update. - * - * This function is typically used by the virtual a/b ota update - */ -uint8_t avb_ab_get_snapshot_merge_status(AvbABOps* ab_ops); - #ifdef __cplusplus } #endif diff --git a/libavb_ab/avb_ab_ops.h b/libavb_ab/avb_ab_ops.h index 99ccc81..8d8fde7 100644 --- a/libavb_ab/avb_ab_ops.h +++ b/libavb_ab/avb_ab_ops.h @@ -39,7 +39,7 @@ extern "C" { struct AvbABOps; typedef struct AvbABOps AvbABOps; -struct bootloader_control; +struct AvbABData; /* High-level operations/functions/methods for A/B that are platform * dependent. @@ -59,8 +59,7 @@ struct AvbABOps { * Implementations will typically want to use avb_ab_data_read() * here to use the 'misc' partition for persistent storage. */ - AvbIOResult (*read_ab_metadata)(AvbABOps* ab_ops, - struct bootloader_control* data); + AvbIOResult (*read_ab_metadata)(AvbABOps* ab_ops, struct AvbABData* data); /* Writes A/B metadata to persistent storage. This will byteswap and * update the CRC as needed. Returns AVB_IO_RESULT_OK on success, @@ -70,7 +69,7 @@ struct AvbABOps { * here to use the 'misc' partition for persistent storage. */ AvbIOResult (*write_ab_metadata)(AvbABOps* ab_ops, - const struct bootloader_control* data); + const struct AvbABData* data); }; #ifdef __cplusplus