blob: 0045c8133a8e164f1fdd4c0f9b683de0f13f26e0 [file] [log] [blame]
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +03001// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright (C) 2017 The Android Open Source Project
4 */
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +03005#include <android_ab.h>
6#include <android_bootloader_message.h>
Simon Glass655306c2020-05-10 11:39:58 -06007#include <blk.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -07009#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060010#include <part.h>
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030011#include <memalign.h>
Simon Glass655306c2020-05-10 11:39:58 -060012#include <linux/err.h>
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030013#include <u-boot/crc.h>
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030014
15/**
Dmitry Rokosova0a62162024-10-17 17:12:06 +030016 * ab_control_compute_crc() - Compute the CRC32 of the bootloader control.
17 *
18 * @abc: Bootloader control block
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030019 *
20 * Only the bytes up to the crc32_le field are considered for the CRC-32
21 * calculation.
22 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010023 * Return: crc32 sum
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030024 */
25static uint32_t ab_control_compute_crc(struct bootloader_control *abc)
26{
27 return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
28}
29
30/**
Dmitry Rokosova0a62162024-10-17 17:12:06 +030031 * ab_control_default() - Initialize bootloader_control to the default value.
32 *
33 * @abc: Bootloader control block
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030034 *
35 * It allows us to boot all slots in order from the first one. This value
36 * should be used when the bootloader message is corrupted, but not when
37 * a valid message indicates that all slots are unbootable.
38 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010039 * Return: 0 on success and a negative on error
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030040 */
41static int ab_control_default(struct bootloader_control *abc)
42{
43 int i;
44 const struct slot_metadata metadata = {
45 .priority = 15,
46 .tries_remaining = 7,
47 .successful_boot = 0,
48 .verity_corrupted = 0,
49 .reserved = 0
50 };
51
52 if (!abc)
53 return -EFAULT;
54
55 memcpy(abc->slot_suffix, "a\0\0\0", 4);
56 abc->magic = BOOT_CTRL_MAGIC;
57 abc->version = BOOT_CTRL_VERSION;
58 abc->nb_slot = NUM_SLOTS;
59 memset(abc->reserved0, 0, sizeof(abc->reserved0));
60 for (i = 0; i < abc->nb_slot; ++i)
61 abc->slot_info[i] = metadata;
62
63 memset(abc->reserved1, 0, sizeof(abc->reserved1));
64 abc->crc32_le = ab_control_compute_crc(abc);
65
66 return 0;
67}
68
69/**
Dmitry Rokosova0a62162024-10-17 17:12:06 +030070 * ab_control_create_from_disk() - Load the boot_control from disk into memory.
71 *
72 * @dev_desc: Device where to read the boot_control struct from
73 * @part_info: Partition in 'dev_desc' where to read from, normally
74 * the "misc" partition should be used
75 * @abc: pointer to pointer to bootloader_control data
76 * @offset: boot_control struct offset
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030077 *
78 * This function allocates and returns an integer number of disk blocks,
79 * based on the block size of the passed device to help performing a
80 * read-modify-write operation on the boot_control struct.
81 * The boot_control struct offset (2 KiB) must be a multiple of the device
82 * block size, for simplicity.
83 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010084 * Return: 0 on success and a negative on error
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030085 */
86static int ab_control_create_from_disk(struct blk_desc *dev_desc,
Simon Glassc1c4a8f2020-05-10 11:39:57 -060087 const struct disk_partition *part_info,
Joshua Wattad3ae7d2023-07-03 10:07:13 -050088 struct bootloader_control **abc,
89 ulong offset)
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030090{
91 ulong abc_offset, abc_blocks, ret;
92
Joshua Wattad3ae7d2023-07-03 10:07:13 -050093 abc_offset = offset +
94 offsetof(struct bootloader_message_ab, slot_suffix);
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +030095 if (abc_offset % part_info->blksz) {
96 log_err("ANDROID: Boot control block not block aligned.\n");
97 return -EINVAL;
98 }
99 abc_offset /= part_info->blksz;
100
101 abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
102 part_info->blksz);
103 if (abc_offset + abc_blocks > part_info->size) {
104 log_err("ANDROID: boot control partition too small. Need at");
105 log_err(" least %lu blocks but have %lu blocks.\n",
106 abc_offset + abc_blocks, part_info->size);
107 return -EINVAL;
108 }
109 *abc = malloc_cache_aligned(abc_blocks * part_info->blksz);
110 if (!*abc)
111 return -ENOMEM;
112
113 ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
114 *abc);
115 if (IS_ERR_VALUE(ret)) {
116 log_err("ANDROID: Could not read from boot ctrl partition\n");
117 free(*abc);
118 return -EIO;
119 }
120
121 log_debug("ANDROID: Loaded ABC, %lu blocks\n", abc_blocks);
122
123 return 0;
124}
125
126/**
Dmitry Rokosova0a62162024-10-17 17:12:06 +0300127 * ab_control_store() - Store the loaded boot_control block.
128 *
129 * @dev_desc: Device where we should write the boot_control struct
130 * @part_info: Partition on the 'dev_desc' where to write
131 * @abc Pointer to the boot control struct and the extra bytes after
132 * it up to the nearest block boundary
133 * @offset: boot_control struct offset
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300134 *
135 * Store back to the same location it was read from with
136 * ab_control_create_from_misc().
137 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100138 * Return: 0 on success and a negative on error
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300139 */
140static int ab_control_store(struct blk_desc *dev_desc,
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600141 const struct disk_partition *part_info,
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500142 struct bootloader_control *abc, ulong offset)
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300143{
144 ulong abc_offset, abc_blocks, ret;
145
Joshua Watta16890e2024-08-28 08:37:57 -0600146 if (offset % part_info->blksz) {
147 log_err("ANDROID: offset not block aligned\n");
148 return -EINVAL;
149 }
150
151 abc_offset = (offset +
152 offsetof(struct bootloader_message_ab, slot_suffix)) /
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300153 part_info->blksz;
154 abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
155 part_info->blksz);
156 ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
157 abc);
158 if (IS_ERR_VALUE(ret)) {
159 log_err("ANDROID: Could not write back the misc partition\n");
160 return -EIO;
161 }
162
163 return 0;
164}
165
166/**
Dmitry Rokosova0a62162024-10-17 17:12:06 +0300167 * ab_compare_slots() - Compare two slots.
168 *
169 * @a: The first bootable slot metadata
170 * @b: The second bootable slot metadata
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300171 *
172 * The function determines slot which is should we boot from among the two.
173 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100174 * Return: Negative if the slot "a" is better, positive of the slot "b" is
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300175 * better or 0 if they are equally good.
176 */
177static int ab_compare_slots(const struct slot_metadata *a,
178 const struct slot_metadata *b)
179{
180 /* Higher priority is better */
181 if (a->priority != b->priority)
182 return b->priority - a->priority;
183
184 /* Higher successful_boot value is better, in case of same priority */
185 if (a->successful_boot != b->successful_boot)
186 return b->successful_boot - a->successful_boot;
187
188 /* Higher tries_remaining is better to ensure round-robin */
189 if (a->tries_remaining != b->tries_remaining)
190 return b->tries_remaining - a->tries_remaining;
191
192 return 0;
193}
194
Joshua Watt9d5251c2023-06-23 17:05:48 -0500195int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info,
196 bool dec_tries)
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300197{
198 struct bootloader_control *abc = NULL;
Colin McAllister61aa03c2024-03-12 07:57:29 -0500199 struct bootloader_control *backup_abc = NULL;
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300200 u32 crc32_le;
201 int slot, i, ret;
202 bool store_needed = false;
Colin McAllister61aa03c2024-03-12 07:57:29 -0500203 bool valid_backup = false;
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300204 char slot_suffix[4];
205
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500206 ret = ab_control_create_from_disk(dev_desc, part_info, &abc, 0);
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300207 if (ret < 0) {
208 /*
209 * This condition represents an actual problem with the code or
210 * the board setup, like an invalid partition information.
211 * Signal a repair mode and do not try to boot from either slot.
212 */
213 return ret;
214 }
215
Colin McAllister61aa03c2024-03-12 07:57:29 -0500216 if (CONFIG_ANDROID_AB_BACKUP_OFFSET) {
217 ret = ab_control_create_from_disk(dev_desc, part_info, &backup_abc,
218 CONFIG_ANDROID_AB_BACKUP_OFFSET);
219 if (ret < 0) {
220 free(abc);
221 return ret;
222 }
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500223 }
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500224
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300225 crc32_le = ab_control_compute_crc(abc);
226 if (abc->crc32_le != crc32_le) {
227 log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),",
228 crc32_le, abc->crc32_le);
Colin McAllister61aa03c2024-03-12 07:57:29 -0500229 if (CONFIG_ANDROID_AB_BACKUP_OFFSET) {
230 crc32_le = ab_control_compute_crc(backup_abc);
231 if (backup_abc->crc32_le != crc32_le) {
232 log_err(" ANDROID: Invalid backup CRC-32 ");
233 log_err("(expected %.8x, found %.8x),",
234 crc32_le, backup_abc->crc32_le);
235 } else {
236 valid_backup = true;
237 log_info(" copying A/B metadata from backup.\n");
238 memcpy(abc, backup_abc, sizeof(*abc));
239 }
240 }
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500241
Colin McAllister61aa03c2024-03-12 07:57:29 -0500242 if (!valid_backup) {
243 log_err(" re-initializing A/B metadata.\n");
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500244 ret = ab_control_default(abc);
245 if (ret < 0) {
Colin McAllister61aa03c2024-03-12 07:57:29 -0500246 if (CONFIG_ANDROID_AB_BACKUP_OFFSET)
247 free(backup_abc);
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500248 free(abc);
249 return -ENODATA;
250 }
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300251 }
252 store_needed = true;
253 }
254
255 if (abc->magic != BOOT_CTRL_MAGIC) {
256 log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
Colin McAllister61aa03c2024-03-12 07:57:29 -0500257 if (CONFIG_ANDROID_AB_BACKUP_OFFSET)
258 free(backup_abc);
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300259 free(abc);
260 return -ENODATA;
261 }
262
263 if (abc->version > BOOT_CTRL_VERSION) {
264 log_err("ANDROID: Unsupported A/B metadata version: %.8x\n",
265 abc->version);
Colin McAllister61aa03c2024-03-12 07:57:29 -0500266 if (CONFIG_ANDROID_AB_BACKUP_OFFSET)
267 free(backup_abc);
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300268 free(abc);
269 return -ENODATA;
270 }
271
272 /*
273 * At this point a valid boot control metadata is stored in abc,
274 * followed by other reserved data in the same block. We select a with
275 * the higher priority slot that
276 * - is not marked as corrupted and
277 * - either has tries_remaining > 0 or successful_boot is true.
278 * If the selected slot has a false successful_boot, we also decrement
279 * the tries_remaining until it eventually becomes unbootable because
280 * tries_remaining reaches 0. This mechanism produces a bootloader
281 * induced rollback, typically right after a failed update.
282 */
283
284 /* Safety check: limit the number of slots. */
285 if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
286 abc->nb_slot = ARRAY_SIZE(abc->slot_info);
287 store_needed = true;
288 }
289
290 slot = -1;
291 for (i = 0; i < abc->nb_slot; ++i) {
292 if (abc->slot_info[i].verity_corrupted ||
293 !abc->slot_info[i].tries_remaining) {
294 log_debug("ANDROID: unbootable slot %d tries: %d, ",
295 i, abc->slot_info[i].tries_remaining);
296 log_debug("corrupt: %d\n",
297 abc->slot_info[i].verity_corrupted);
298 continue;
299 }
300 log_debug("ANDROID: bootable slot %d pri: %d, tries: %d, ",
301 i, abc->slot_info[i].priority,
302 abc->slot_info[i].tries_remaining);
303 log_debug("corrupt: %d, successful: %d\n",
304 abc->slot_info[i].verity_corrupted,
305 abc->slot_info[i].successful_boot);
306
307 if (slot < 0 ||
308 ab_compare_slots(&abc->slot_info[i],
309 &abc->slot_info[slot]) < 0) {
310 slot = i;
311 }
312 }
313
314 if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
315 log_err("ANDROID: Attempting slot %c, tries remaining %d\n",
316 BOOT_SLOT_NAME(slot),
317 abc->slot_info[slot].tries_remaining);
Joshua Watt9d5251c2023-06-23 17:05:48 -0500318 if (dec_tries) {
319 abc->slot_info[slot].tries_remaining--;
320 store_needed = true;
321 }
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300322 }
323
324 if (slot >= 0) {
325 /*
326 * Legacy user-space requires this field to be set in the BCB.
327 * Newer releases load this slot suffix from the command line
328 * or the device tree.
329 */
330 memset(slot_suffix, 0, sizeof(slot_suffix));
331 slot_suffix[0] = BOOT_SLOT_NAME(slot);
332 if (memcmp(abc->slot_suffix, slot_suffix,
333 sizeof(slot_suffix))) {
334 memcpy(abc->slot_suffix, slot_suffix,
335 sizeof(slot_suffix));
336 store_needed = true;
337 }
338 }
339
340 if (store_needed) {
341 abc->crc32_le = ab_control_compute_crc(abc);
Alexey Romanov8cf36232023-12-25 13:22:45 +0300342 ret = ab_control_store(dev_desc, part_info, abc, 0);
343 if (ret < 0) {
Colin McAllister61aa03c2024-03-12 07:57:29 -0500344 if (CONFIG_ANDROID_AB_BACKUP_OFFSET)
345 free(backup_abc);
Alexey Romanov8cf36232023-12-25 13:22:45 +0300346 free(abc);
347 return ret;
348 }
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300349 }
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500350
Colin McAllister61aa03c2024-03-12 07:57:29 -0500351 if (CONFIG_ANDROID_AB_BACKUP_OFFSET) {
352 /*
353 * If the backup doesn't match the primary, write the primary
354 * to the backup offset
355 */
356 if (memcmp(backup_abc, abc, sizeof(*abc)) != 0) {
357 ret = ab_control_store(dev_desc, part_info, abc,
358 CONFIG_ANDROID_AB_BACKUP_OFFSET);
359 if (ret < 0) {
360 free(backup_abc);
361 free(abc);
362 return ret;
363 }
Alexey Romanov8cf36232023-12-25 13:22:45 +0300364 }
Colin McAllister61aa03c2024-03-12 07:57:29 -0500365 free(backup_abc);
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500366 }
Joshua Wattad3ae7d2023-07-03 10:07:13 -0500367
Ruslan Trofymenko3b7dc912019-07-05 15:37:32 +0300368 free(abc);
369
370 if (slot < 0)
371 return -EINVAL;
372
373 return slot;
374}