1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <android_ab.h>
8
9 #include <android_bootloader_message.h>
10 #include <android_image.h>
11 #include <boot_rkimg.h>
12 #include <common.h>
13 #include <malloc.h>
14 #include <android_avb/avb_ops_user.h>
15 #include <android_avb/rk_avb_ops_user.h>
16 #include <u-boot/crc.h>
17 #include <boot_rkimg.h>
18
19 /** android_boot_control_compute_crc - Compute the CRC-32 of the bootloader
20 * control struct. Only the bytes up to the crc32_le field are considered for
21 * the CRC-32 calculation.
22 */
android_boot_control_compute_crc(struct android_bootloader_control * abc)23 static uint32_t android_boot_control_compute_crc(
24 struct android_bootloader_control *abc)
25 {
26 return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
27 }
28
29 /** android_boot_control_default - Initialize android_bootloader_control to the
30 * default value which allows to boot all slots in order from the first one.
31 * This value should be used when the bootloader message is corrupted, but not
32 * when a valid message indicates that all slots are unbootable.
33 */
android_boot_control_default(struct android_bootloader_control * abc)34 void android_boot_control_default(struct android_bootloader_control *abc)
35 {
36 int i;
37 const struct android_slot_metadata metadata = {
38 .priority = 15,
39 .tries_remaining = 7,
40 .successful_boot = 0,
41 .verity_corrupted = 0,
42 .reserved = 0
43 };
44 memcpy(abc->slot_suffix, "a\0\0\0", 4);
45 abc->magic = ANDROID_BOOT_CTRL_MAGIC;
46 abc->version = ANDROID_BOOT_CTRL_VERSION;
47 abc->nb_slot = ARRAY_SIZE(abc->slot_info);
48 memset(abc->reserved0, 0, sizeof(abc->reserved0));
49 for (i = 0; i < abc->nb_slot; ++i) {
50 abc->slot_info[i] = metadata;
51 }
52 memset(abc->reserved1, 0, sizeof(abc->reserved1));
53 abc->crc32_le = android_boot_control_compute_crc(abc);
54 }
55
56 /** android_boot_control_create_from_disk
57 * Load the boot_control struct from disk into newly allocated memory. This
58 * function allocates and returns an integer number of disk blocks, based on the
59 * block size of the passed device to help performing a read-modify-write
60 * operation on the boot_control struct. The boot_control struct offset (2 KiB)
61 * must be a multiple of the device block size, for simplicity.
62 * @dev_desc: device where to read the boot_control struct from.
63 * @part_info: partition in 'dev_desc' where to read from, normally the "misc"
64 * partition should be used.
65 */
android_boot_control_create_from_disk(struct blk_desc * dev_desc,const disk_partition_t * part_info)66 static void *android_boot_control_create_from_disk(
67 struct blk_desc *dev_desc,
68 const disk_partition_t *part_info)
69 {
70 ulong abc_offset, abc_blocks;
71 void *buf;
72
73 abc_offset = offsetof(struct android_bootloader_message_ab,
74 slot_suffix);
75 if (abc_offset % part_info->blksz) {
76 printf("ANDROID: Boot control block not block aligned.\n");
77 return NULL;
78 }
79 abc_offset /= part_info->blksz;
80
81 abc_blocks = DIV_ROUND_UP(sizeof(struct android_bootloader_control),
82 part_info->blksz);
83 if (abc_offset + abc_blocks > part_info->size) {
84 printf("ANDROID: boot control partition too small. Need at"
85 " least %lu blocks but have %lu blocks.\n",
86 abc_offset + abc_blocks, part_info->size);
87 return NULL;
88 }
89 buf = malloc(abc_blocks * part_info->blksz);
90 if (!buf)
91 return NULL;
92
93 if (blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
94 buf) != abc_blocks) {
95 printf("ANDROID: Could not read from boot control partition\n");
96 free(buf);
97 return NULL;
98 }
99 debug("ANDROID: Loaded ABC, %lu blocks.\n", abc_blocks);
100 return buf;
101 }
102
103 /** android_boot_control_store
104 * Store the loaded boot_control block back to the same location it was read
105 * from with android_boot_control_create_from_misc().
106 *
107 * @abc_data_block: pointer to the boot_control struct and the extra bytes after
108 * it up to the nearest block boundary.
109 * @dev_desc: device where we should write the boot_control struct.
110 * @part_info: partition on the 'dev_desc' where to write.
111 * @return 0 on success and -1 on error.
112 */
android_boot_control_store(void * abc_data_block,struct blk_desc * dev_desc,const disk_partition_t * part_info)113 static int android_boot_control_store(void *abc_data_block,
114 struct blk_desc *dev_desc,
115 const disk_partition_t *part_info)
116 {
117 ulong abc_offset, abc_blocks;
118
119 abc_offset = offsetof(struct android_bootloader_message_ab,
120 slot_suffix) / part_info->blksz;
121 abc_blocks = DIV_ROUND_UP(sizeof(struct android_bootloader_control),
122 part_info->blksz);
123 if (blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
124 abc_data_block) != abc_blocks) {
125 printf("ANDROID: Could not write back the misc partition\n");
126 return -1;
127 }
128 return 0;
129 }
130
131 /** android_boot_compare_slots - compares two slots returning which slot is
132 * should we boot from among the two.
133 * @a: The first bootable slot metadata
134 * @b: The second bootable slot metadata
135 * @return negative if the slot "a" is better, positive of the slot "b" is
136 * better or 0 if they are equally good.
137 */
android_ab_compare_slots(const struct android_slot_metadata * a,const struct android_slot_metadata * b)138 static int android_ab_compare_slots(const struct android_slot_metadata *a,
139 const struct android_slot_metadata *b)
140 {
141 /* Higher priority is better */
142 if (a->priority != b->priority)
143 return b->priority - a->priority;
144
145 /* Higher successful_boot value is better, in case of same priority. */
146 if (a->successful_boot != b->successful_boot)
147 return b->successful_boot - a->successful_boot;
148
149 /* Higher tries_remaining is better to ensure round-robin. */
150 if (a->tries_remaining != b->tries_remaining)
151 return b->tries_remaining - a->tries_remaining;
152
153 return 0;
154 }
155
android_ab_select(struct blk_desc * dev_desc,disk_partition_t * part_info)156 int android_ab_select(struct blk_desc *dev_desc, disk_partition_t *part_info)
157 {
158 struct android_bootloader_control *abc;
159 u32 crc32_le;
160 int slot, i;
161 bool store_needed = false;
162 char slot_suffix[4];
163
164 abc = android_boot_control_create_from_disk(dev_desc, part_info);
165 if (!abc) {
166 /* This condition represents an actual problem with the code
167 * or the board setup, like an invalid partition information.
168 * Signal a repair mode and do not try to boot from either
169 * slot.
170 */
171 return -1;
172 }
173
174 crc32_le = android_boot_control_compute_crc(abc);
175 if (abc->crc32_le != crc32_le) {
176 printf("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x), "
177 "re-initializing A/B metadata.\n",
178 crc32_le, abc->crc32_le);
179 android_boot_control_default(abc);
180 store_needed = true;
181 }
182
183 if (abc->magic != ANDROID_BOOT_CTRL_MAGIC) {
184 printf("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
185 free(abc);
186 return -1;
187 }
188
189 if (abc->version > ANDROID_BOOT_CTRL_VERSION) {
190 printf("ANDROID: Unsupported A/B metadata version: %.8x\n",
191 abc->version);
192 free(abc);
193 return -1;
194 }
195
196 /* At this point a valid boot control metadata is stored in abc,
197 * followed by other reserved data in the same block.
198 * We select a with the higher priority slot that
199 * - is not marked as corrupted and
200 * - either has tries_remaining > 0 or successful_boot is true.
201 * If the slot selected has a false successful_boot, we also decrement
202 * the tries_remaining until it eventually becomes unbootable because
203 * tries_remaining reaches 0. This mechanism produces a bootloader
204 * induced rollback, typically right after a failed update.
205 */
206
207 /* Safety check: limit the number of slots. */
208 if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
209 abc->nb_slot = ARRAY_SIZE(abc->slot_info);
210 store_needed = true;
211 }
212
213 slot = -1;
214 for (i = 0; i < abc->nb_slot; ++i) {
215 if (abc->slot_info[i].verity_corrupted ||
216 !abc->slot_info[i].tries_remaining) {
217 debug("ANDROID: unbootable slot %d tries: %d, "
218 "corrupt: %d\n",
219 i,
220 abc->slot_info[i].tries_remaining,
221 abc->slot_info[i].verity_corrupted);
222 continue;
223 }
224 debug("ANDROID: bootable slot %d pri: %d, tries: %d, "
225 "corrupt: %d, successful: %d\n",
226 i,
227 abc->slot_info[i].priority,
228 abc->slot_info[i].tries_remaining,
229 abc->slot_info[i].verity_corrupted,
230 abc->slot_info[i].successful_boot);
231
232 if (slot < 0 ||
233 android_ab_compare_slots(&abc->slot_info[i],
234 &abc->slot_info[slot]) < 0) {
235 slot = i;
236 }
237 }
238
239 if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
240 printf("ANDROID: Attempting slot %c, tries remaining %d\n",
241 ANDROID_BOOT_SLOT_NAME(slot),
242 abc->slot_info[slot].tries_remaining);
243 abc->slot_info[slot].tries_remaining--;
244 store_needed = true;
245 }
246
247 if (slot >= 0) {
248 /* Legacy user-space requires this field to be set in the BCB.
249 * Newer releases load this the slot suffix from the command
250 * line or the device tree.
251 */
252 memset(slot_suffix, 0, sizeof(slot_suffix));
253 slot_suffix[0] = ANDROID_BOOT_SLOT_NAME(slot);
254 if (memcmp(abc->slot_suffix, slot_suffix,
255 sizeof(slot_suffix))) {
256 memcpy(abc->slot_suffix, slot_suffix,
257 sizeof(slot_suffix));
258 store_needed = true;
259 }
260 }
261
262 if (store_needed) {
263 abc->crc32_le = android_boot_control_compute_crc(abc);
264 android_boot_control_store(abc, dev_desc, part_info);
265 }
266 free(abc);
267
268 if (slot < 0)
269 return -1;
270 return slot;
271 }
272
read_misc_virtual_ab_message(struct misc_virtual_ab_message * message)273 int read_misc_virtual_ab_message(struct misc_virtual_ab_message *message)
274 {
275 struct blk_desc *dev_desc;
276 disk_partition_t part_info;
277 u32 bcb_offset = (ANDROID_VIRTUAL_AB_METADATA_OFFSET_IN_MISC >> 9);
278 int cnt, ret;
279
280 if (!message) {
281 debug("%s: message is NULL!\n", __func__);
282 return -1;
283 }
284
285 dev_desc = rockchip_get_bootdev();
286 if (!dev_desc) {
287 debug("%s: dev_desc is NULL!\n", __func__);
288 return -1;
289 }
290
291 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info);
292 if (ret < 0) {
293 debug("%s: Could not found misc partition\n",
294 __func__);
295 return -1;
296 }
297
298 cnt = DIV_ROUND_UP(sizeof(struct misc_virtual_ab_message), dev_desc->blksz);
299 if (blk_dread(dev_desc, part_info.start + bcb_offset, cnt, message) != cnt) {
300 debug("%s: could not read from misc partition\n", __func__);
301 return -1;
302 }
303
304 return 0;
305 }
306
write_misc_virtual_ab_message(struct misc_virtual_ab_message * message)307 int write_misc_virtual_ab_message(struct misc_virtual_ab_message *message)
308 {
309 struct blk_desc *dev_desc;
310 disk_partition_t part_info;
311 u32 bcb_offset = (ANDROID_VIRTUAL_AB_METADATA_OFFSET_IN_MISC >> 9);
312 int cnt, ret;
313
314 if (!message) {
315 debug("%s: message is NULL!\n", __func__);
316 return -1;
317 }
318
319 dev_desc = rockchip_get_bootdev();
320 if (!dev_desc) {
321 debug("%s: dev_desc is NULL!\n", __func__);
322 return -1;
323 }
324
325 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info);
326 if (ret < 0) {
327 debug("%s: Could not found misc partition\n",
328 __func__);
329 return -1;
330 }
331
332 cnt = DIV_ROUND_UP(sizeof(struct misc_virtual_ab_message), dev_desc->blksz);
333 ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, message);
334 if (ret != cnt)
335 debug("%s: blk_dwrite write failed, ret=%d\n", __func__, ret);
336
337 return 0;
338 }
339
ab_is_support_dynamic_partition(struct blk_desc * dev_desc)340 int ab_is_support_dynamic_partition(struct blk_desc *dev_desc)
341 {
342 disk_partition_t super_part_info;
343 disk_partition_t boot_part_info;
344 int part_num;
345 int is_dp = 0;
346 char *super_dp = NULL;
347 char *super_info = "androidboot.super_partition=";
348
349 memset(&super_part_info, 0x0, sizeof(super_part_info));
350 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_SUPER,
351 &super_part_info);
352 if (part_num < 0) {
353 memset(&boot_part_info, 0x0, sizeof(boot_part_info));
354 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_BOOT,
355 &boot_part_info);
356 if (part_num < 0) {
357 is_dp = 0;
358 } else {
359 andr_img_hdr hdr;
360 ulong hdr_blocks = sizeof(struct andr_img_hdr) /
361 boot_part_info.blksz;
362
363 memset(&hdr, 0x0, sizeof(hdr));
364 if (blk_dread(dev_desc, boot_part_info.start, hdr_blocks, &hdr) !=
365 hdr_blocks) {
366 is_dp = 0;
367 } else {
368 debug("hdr cmdline=%s\n", hdr.cmdline);
369 super_dp = strstr(hdr.cmdline, super_info);
370 if (super_dp)
371 is_dp = 1;
372 else
373 is_dp = 0;
374 }
375 }
376 } else {
377 debug("Find super partition, the firmware support dynamic partition\n");
378 is_dp = 1;
379 }
380
381 debug("%s is_dp=%d\n", __func__, is_dp);
382 return is_dp;
383 }
384
get_partition_unique_uuid(char * partition,char * guid_buf,size_t guid_buf_size)385 static int get_partition_unique_uuid(char *partition,
386 char *guid_buf,
387 size_t guid_buf_size)
388 {
389 struct blk_desc *dev_desc;
390 disk_partition_t part_info;
391
392 dev_desc = rockchip_get_bootdev();
393 if (!dev_desc) {
394 printf("%s: Could not find device\n", __func__);
395 return -1;
396 }
397
398 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
399 printf("Could not find \"%s\" partition\n", partition);
400 return -1;
401 }
402
403 if (guid_buf && guid_buf_size > 0)
404 memcpy(guid_buf, part_info.uuid, guid_buf_size);
405
406 return 0;
407 }
408
ab_update_root_uuid(void)409 static void ab_update_root_uuid(void)
410 {
411 /*
412 * In android a/b & avb process, the system.img is mandory and the
413 * "root=" will be added in vbmeta.img.
414 *
415 * In linux a/b & avb process, the system is NOT mandory and the
416 * "root=" will not be added in vbmeta.img but in kernel dts bootargs.
417 * (Parsed and dropped late, i.e. "root=" is not available now/always).
418 *
419 * To compatible with the above two processes, test the existence of
420 * "root=" and create it for linux ab & avb.
421 */
422 char root_partuuid[70] = "root=PARTUUID=";
423 char *boot_args = env_get("bootargs");
424 char guid_buf[UUID_SIZE] = {0};
425 struct blk_desc *dev_desc;
426
427 dev_desc = rockchip_get_bootdev();
428 if (!dev_desc) {
429 printf("%s: Could not find device\n", __func__);
430 return;
431 }
432
433 if (ab_is_support_dynamic_partition(dev_desc))
434 return;
435
436 if (!strstr(boot_args, "root=")) {
437 get_partition_unique_uuid(ANDROID_PARTITION_SYSTEM,
438 guid_buf, UUID_SIZE);
439 strcat(root_partuuid, guid_buf);
440 env_update("bootargs", root_partuuid);
441 }
442 }
443
ab_update_root_partition(void)444 void ab_update_root_partition(void)
445 {
446 char *boot_args = env_get("bootargs");
447 char root_part_dev[64] = {0};
448 disk_partition_t part_info;
449 struct blk_desc *dev_desc;
450 const char *part_type;
451 int part_num;
452
453 dev_desc = rockchip_get_bootdev();
454 if (!dev_desc)
455 return;
456
457 if (ab_is_support_dynamic_partition(dev_desc))
458 return;
459
460 /* Get 'system' partition device number. */
461 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_SYSTEM, &part_info);
462 if (part_num < 0) {
463 printf("%s: Failed to get partition '%s'.\n", __func__, ANDROID_PARTITION_SYSTEM);
464 return;
465 }
466
467 /* Get partition type. */
468 part_type = part_get_type(dev_desc);
469 if (!part_type)
470 return;
471
472 /* Judge the partition device type. */
473 switch (dev_desc->if_type) {
474 case IF_TYPE_MMC:
475 if (strstr(part_type, "ENV"))
476 snprintf(root_part_dev, 64, "root=/dev/mmcblk0p%d", part_num);
477 else if (strstr(part_type, "EFI"))
478 ab_update_root_uuid();
479 break;
480 case IF_TYPE_MTD:
481 if (dev_desc->devnum == BLK_MTD_NAND || dev_desc->devnum == BLK_MTD_SPI_NAND) {
482 if (strstr(boot_args, "rootfstype=squashfs") || strstr(boot_args, "rootfstype=erofs"))
483 snprintf(root_part_dev, 64, "ubi.mtd=%d root=/dev/ubiblock0_0", part_num - 1);
484 else if (strstr(boot_args, "rootfstype=ubifs"))
485 snprintf(root_part_dev, 64, "ubi.mtd=%d root=ubi0:system", part_num - 1);
486 } else if (dev_desc->devnum == BLK_MTD_SPI_NOR) {
487 snprintf(root_part_dev, 64, "root=/dev/mtdblock%d", part_num - 1);
488 }
489 break;
490 default:
491 printf("%s: Not found part type, failed to set root part device.\n", __func__);
492 return;
493 }
494
495 env_update("bootargs", root_part_dev);
496 }
497
ab_get_slot_suffix(char * slot_suffix)498 int ab_get_slot_suffix(char *slot_suffix)
499 {
500 /* TODO: get from pre-loader or misc partition */
501 if (rk_avb_get_current_slot(slot_suffix)) {
502 printf("rk_avb_get_current_slot() failed\n");
503 return -1;
504 }
505
506 if (slot_suffix[0] != '_') {
507 #ifndef CONFIG_ANDROID_AVB
508 printf("###There is no bootable slot, bring up lastboot!###\n");
509 if (rk_get_lastboot() == 1)
510 memcpy(slot_suffix, "_b", 2);
511 else if (rk_get_lastboot() == 0)
512 memcpy(slot_suffix, "_a", 2);
513 else
514 #endif
515 return -1;
516 }
517
518 return 0;
519 }
520
ab_decrease_tries(void)521 int ab_decrease_tries(void)
522 {
523 AvbABData ab_data_orig;
524 AvbABData ab_data;
525 char slot_suffix[3] = {0};
526 AvbOps *ops;
527 size_t slot_index = 0;
528
529 if (ab_get_slot_suffix(slot_suffix))
530 return -1;
531
532 if (!strncmp(slot_suffix, "_a", 2))
533 slot_index = 0;
534 else if (!strncmp(slot_suffix, "_b", 2))
535 slot_index = 1;
536 else
537 slot_index = 0;
538
539 ops = avb_ops_user_new();
540 if (!ops) {
541 printf("avb_ops_user_new() failed!\n");
542 return -1;
543 }
544
545 if (load_metadata(ops->ab_ops, &ab_data, &ab_data_orig)) {
546 printf("Can not load metadata\n");
547 return -1;
548 }
549
550 /* ... and decrement tries remaining, if applicable. */
551 if (!ab_data.slots[slot_index].successful_boot &&
552 ab_data.slots[slot_index].tries_remaining > 0)
553 ab_data.slots[slot_index].tries_remaining -= 1;
554
555 if (save_metadata_if_changed(ops->ab_ops, &ab_data, &ab_data_orig)) {
556 printf("Can not save metadata\n");
557 return -1;
558 }
559
560 return 0;
561 }
562
563 /*
564 * In android A/B system, there is no recovery partition,
565 * but in the linux system, we need the recovery to update system.
566 * This function is used to find firmware in recovery partition
567 * when enable CONFIG_ANDROID_AB.
568 */
ab_can_find_recovery_part(void)569 bool ab_can_find_recovery_part(void)
570 {
571 disk_partition_t part_info;
572 struct blk_desc *dev_desc;
573 int part_num;
574
575 dev_desc = rockchip_get_bootdev();
576 if (!dev_desc) {
577 printf("%s: Could not find device\n", __func__);
578 return false;
579 }
580
581 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_RECOVERY,
582 &part_info);
583 if (part_num < 0)
584 return false;
585 else
586 return true;
587 }
588