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 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
390 struct blk_desc *dev_desc;
391 disk_partition_t part_info;
392
393 dev_desc = rockchip_get_bootdev();
394 if (!dev_desc) {
395 printf("%s: Could not find device\n", __func__);
396 return -1;
397 }
398
399 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
400 printf("Could not find \"%s\" partition\n", partition);
401 return -1;
402 }
403
404 if (guid_buf && guid_buf_size > 0)
405 memcpy(guid_buf, part_info.uuid, guid_buf_size);
406
407 return 0;
408 #else
409 printf("WARN: Get partition uuid requires CONFIG_PARTITION_UUIDS enabled\n");
410 return -1;
411 #endif
412 }
413
ab_update_root_uuid(void)414 static void ab_update_root_uuid(void)
415 {
416 /*
417 * In android a/b & avb process, the system.img is mandory and the
418 * "root=" will be added in vbmeta.img.
419 *
420 * In linux a/b & avb process, the system is NOT mandory and the
421 * "root=" will not be added in vbmeta.img but in kernel dts bootargs.
422 * (Parsed and dropped late, i.e. "root=" is not available now/always).
423 *
424 * To compatible with the above two processes, test the existence of
425 * "root=" and create it for linux ab & avb.
426 */
427 char root_partuuid[70] = "root=PARTUUID=";
428 char *boot_args = env_get("bootargs");
429 char guid_buf[UUID_SIZE] = {0};
430 struct blk_desc *dev_desc;
431
432 dev_desc = rockchip_get_bootdev();
433 if (!dev_desc) {
434 printf("%s: Could not find device\n", __func__);
435 return;
436 }
437
438 if (ab_is_support_dynamic_partition(dev_desc))
439 return;
440
441 if (!strstr(boot_args, "root=")) {
442 get_partition_unique_uuid(ANDROID_PARTITION_SYSTEM,
443 guid_buf, UUID_SIZE);
444 strcat(root_partuuid, guid_buf);
445 env_update("bootargs", root_partuuid);
446 }
447 }
448
ab_update_root_partition(void)449 void ab_update_root_partition(void)
450 {
451 char *boot_args = env_get("bootargs");
452 char root_part_dev[64] = {0};
453 disk_partition_t part_info;
454 struct blk_desc *dev_desc;
455 const char *part_type;
456 int part_num;
457
458 dev_desc = rockchip_get_bootdev();
459 if (!dev_desc)
460 return;
461
462 if (ab_is_support_dynamic_partition(dev_desc))
463 return;
464
465 /* Get 'system' partition device number. */
466 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_SYSTEM, &part_info);
467 if (part_num < 0) {
468 printf("%s: Failed to get partition '%s'.\n", __func__, ANDROID_PARTITION_SYSTEM);
469 return;
470 }
471
472 /* Get partition type. */
473 part_type = part_get_type(dev_desc);
474 if (!part_type)
475 return;
476
477 /* Judge the partition device type. */
478 switch (dev_desc->if_type) {
479 case IF_TYPE_MMC:
480 case IF_TYPE_SCSI: /* scsi 0: UFS */
481 if (strstr(part_type, "ENV"))
482 snprintf(root_part_dev, 64, "root=/dev/mmcblk0p%d", part_num);
483 else if (strstr(part_type, "EFI"))
484 ab_update_root_uuid();
485 break;
486 case IF_TYPE_SPINAND:
487 if (strstr(part_type, "ENV"))
488 /* TODO */
489 printf("%s: TODO: ENV partition for 'IF_TYPE_SPINAND'.\n", __func__);
490 else if (strstr(part_type, "EFI"))
491 ab_update_root_uuid();
492 break;
493 case IF_TYPE_MTD:
494 if (dev_desc->devnum == BLK_MTD_NAND || dev_desc->devnum == BLK_MTD_SPI_NAND) {
495 if (strstr(boot_args, "rootfstype=squashfs") || strstr(boot_args, "rootfstype=erofs"))
496 snprintf(root_part_dev, 64, "ubi.mtd=%d root=/dev/ubiblock0_0", part_num - 1);
497 else if (strstr(boot_args, "rootfstype=ubifs"))
498 snprintf(root_part_dev, 64, "ubi.mtd=%d root=ubi0:system", part_num - 1);
499 } else if (dev_desc->devnum == BLK_MTD_SPI_NOR) {
500 snprintf(root_part_dev, 64, "root=/dev/mtdblock%d", part_num - 1);
501 }
502 break;
503 default:
504 ab_update_root_uuid();
505 printf("Unknown part type, set default 'root=' with UUID.\n");
506 return;
507 }
508
509 env_update("bootargs", root_part_dev);
510 }
511
ab_get_slot_suffix(char * slot_suffix)512 int ab_get_slot_suffix(char *slot_suffix)
513 {
514 /* TODO: get from pre-loader or misc partition */
515 if (rk_avb_get_current_slot(slot_suffix)) {
516 printf("rk_avb_get_current_slot() failed\n");
517 return -1;
518 }
519
520 if (slot_suffix[0] != '_') {
521 #ifndef CONFIG_ANDROID_AVB
522 printf("###There is no bootable slot, bring up lastboot!###\n");
523 if (rk_get_lastboot() == 1)
524 memcpy(slot_suffix, "_b", 2);
525 else if (rk_get_lastboot() == 0)
526 memcpy(slot_suffix, "_a", 2);
527 else
528 #endif
529 return -1;
530 }
531
532 return 0;
533 }
534
ab_decrease_tries(void)535 int ab_decrease_tries(void)
536 {
537 AvbABData ab_data_orig;
538 AvbABData ab_data;
539 char slot_suffix[3] = {0};
540 AvbOps *ops;
541 size_t slot_index = 0;
542
543 if (ab_get_slot_suffix(slot_suffix))
544 return -1;
545
546 if (!strncmp(slot_suffix, "_a", 2))
547 slot_index = 0;
548 else if (!strncmp(slot_suffix, "_b", 2))
549 slot_index = 1;
550 else
551 slot_index = 0;
552
553 ops = avb_ops_user_new();
554 if (!ops) {
555 printf("avb_ops_user_new() failed!\n");
556 return -1;
557 }
558
559 if (load_metadata(ops->ab_ops, &ab_data, &ab_data_orig)) {
560 printf("Can not load metadata\n");
561 return -1;
562 }
563
564 /* ... and decrement tries remaining, if applicable. */
565 if (!ab_data.slots[slot_index].successful_boot &&
566 ab_data.slots[slot_index].tries_remaining > 0)
567 ab_data.slots[slot_index].tries_remaining -= 1;
568
569 if (save_metadata_if_changed(ops->ab_ops, &ab_data, &ab_data_orig)) {
570 printf("Can not save metadata\n");
571 return -1;
572 }
573
574 return 0;
575 }
576
577 /*
578 * In android A/B system, there is no recovery partition,
579 * but in the linux system, we need the recovery to update system.
580 * This function is used to find firmware in recovery partition
581 * when enable CONFIG_ANDROID_AB.
582 */
ab_can_find_recovery_part(void)583 bool ab_can_find_recovery_part(void)
584 {
585 disk_partition_t part_info;
586 struct blk_desc *dev_desc;
587 int part_num;
588
589 dev_desc = rockchip_get_bootdev();
590 if (!dev_desc) {
591 printf("%s: Could not find device\n", __func__);
592 return false;
593 }
594
595 part_num = part_get_info_by_name(dev_desc, ANDROID_PARTITION_RECOVERY,
596 &part_info);
597 if (part_num < 0)
598 return false;
599 else
600 return true;
601 }
602