diff options
author | Joshua Watt <jpewhacker@gmail.com> | 2023-07-03 18:07:13 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-07-17 23:20:08 +0300 |
commit | 3430f24bc69d61eadf5b09999d58c468ac67c9fe (patch) | |
tree | 2be4c8232f5cb3637da9c7cc501f3c8eb9d8f3f0 /boot/android_ab.c | |
parent | 55a424437226f9ef50c3e829dafa6b494377d018 (diff) | |
download | u-boot-3430f24bc69d61eadf5b09999d58c468ac67c9fe.tar.xz |
android_ab: Try backup booloader_message
Some devices keep 2 copies of the bootloader_message in the misc
partition and write each in sequence when updating. This ensures that
there is always one valid copy of the bootloader_message. Teach u-boot
to optionally try a backup bootloader_message from a specified offset if
the primary one fails its CRC check.
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Diffstat (limited to 'boot/android_ab.c')
-rw-r--r-- | boot/android_ab.c | 77 |
1 files changed, 65 insertions, 12 deletions
diff --git a/boot/android_ab.c b/boot/android_ab.c index 60ae002978..73b55c196c 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -85,11 +85,13 @@ static int ab_control_default(struct bootloader_control *abc) */ static int ab_control_create_from_disk(struct blk_desc *dev_desc, const struct disk_partition *part_info, - struct bootloader_control **abc) + struct bootloader_control **abc, + ulong offset) { ulong abc_offset, abc_blocks, ret; - abc_offset = offsetof(struct bootloader_message_ab, slot_suffix); + abc_offset = offset + + offsetof(struct bootloader_message_ab, slot_suffix); if (abc_offset % part_info->blksz) { log_err("ANDROID: Boot control block not block aligned.\n"); return -EINVAL; @@ -135,11 +137,12 @@ static int ab_control_create_from_disk(struct blk_desc *dev_desc, */ static int ab_control_store(struct blk_desc *dev_desc, const struct disk_partition *part_info, - struct bootloader_control *abc) + struct bootloader_control *abc, ulong offset) { ulong abc_offset, abc_blocks, ret; - abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) / + abc_offset = offset + + offsetof(struct bootloader_message_ab, slot_suffix) / part_info->blksz; abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control), part_info->blksz); @@ -189,8 +192,11 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, int slot, i, ret; bool store_needed = false; char slot_suffix[4]; +#if ANDROID_AB_BACKUP_OFFSET + struct bootloader_control *backup_abc = NULL; +#endif - ret = ab_control_create_from_disk(dev_desc, part_info, &abc); + ret = ab_control_create_from_disk(dev_desc, part_info, &abc, 0); if (ret < 0) { /* * This condition represents an actual problem with the code or @@ -200,22 +206,53 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, return ret; } +#if ANDROID_AB_BACKUP_OFFSET + ret = ab_control_create_from_disk(dev_desc, part_info, &backup_abc, + ANDROID_AB_BACKUP_OFFSET); + if (ret < 0) { + free(abc); + return ret; + } +#endif + crc32_le = ab_control_compute_crc(abc); if (abc->crc32_le != crc32_le) { log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),", crc32_le, abc->crc32_le); - log_err("re-initializing A/B metadata.\n"); - - ret = ab_control_default(abc); - if (ret < 0) { - free(abc); - return -ENODATA; +#if ANDROID_AB_BACKUP_OFFSET + crc32_le = ab_control_compute_crc(backup_abc); + if (backup_abc->crc32_le != crc32_le) { + log_err("ANDROID: Invalid backup CRC-32 ") + log_err("expected %.8x, found %.8x),", + crc32_le, backup_abc->crc32_le); +#endif + + log_err("re-initializing A/B metadata.\n"); + + ret = ab_control_default(abc); + if (ret < 0) { +#if ANDROID_AB_BACKUP_OFFSET + free(backup_abc); +#endif + free(abc); + return -ENODATA; + } +#if ANDROID_AB_BACKUP_OFFSET + } else { + /* + * Backup is valid. Copy it to the primary + */ + memcpy(abc, backup_abc, sizeof(*abc)); } +#endif store_needed = true; } if (abc->magic != BOOT_CTRL_MAGIC) { log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic); +#if ANDROID_AB_BACKUP_OFFSET + free(backup_abc); +#endif free(abc); return -ENODATA; } @@ -223,6 +260,9 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, if (abc->version > BOOT_CTRL_VERSION) { log_err("ANDROID: Unsupported A/B metadata version: %.8x\n", abc->version); +#if ANDROID_AB_BACKUP_OFFSET + free(backup_abc); +#endif free(abc); return -ENODATA; } @@ -297,8 +337,21 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, if (store_needed) { abc->crc32_le = ab_control_compute_crc(abc); - ab_control_store(dev_desc, part_info, abc); + ab_control_store(dev_desc, part_info, abc, 0); } + +#if ANDROID_AB_BACKUP_OFFSET + /* + * If the backup doesn't match the primary, write the primary + * to the backup offset + */ + if (memcmp(backup_abc, abc, sizeof(*abc)) != 0) { + ab_control_store(dev_desc, part_info, abc, + ANDROID_AB_BACKUP_OFFSET); + } + free(backup_abc); +#endif + free(abc); if (slot < 0) |