blob: ae6492d817d1e3db1acfb376d043c88820603ce9 [file] [log] [blame]
Xindong Xu495e9682023-02-24 04:50:07 +00001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <env.h>
9#include <malloc.h>
10#include <asm/byteorder.h>
11#include <config.h>
12#include <asm/amlogic/arch/io.h>
13#include <amlogic/partition_table.h>
14#include <amlogic/libavb/libavb.h>
15#include <version.h>
16#include <amlogic/storage.h>
17#include <fastboot.h>
18#include <u-boot/sha1.h>
19#include <asm/amlogic/arch/efuse.h>
20#include <amlogic/emmc_partitions.h>
Xindong Xue5d4d172023-04-10 10:30:25 +080021#if (IS_ENABLED(CONFIG_UNIFY_BOOTLOADER))
Xindong Xu495e9682023-02-24 04:50:07 +000022#include "cmd_bootctl_wrapper.h"
23#endif
24#include "cmd_bootctl_utils.h"
25#include <amlogic/store_wrapper.h>
26
27#if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE)
28extern efuse_obj_field_t efuse_field;
29#endif//#ifdef CONFIG_EFUSE_OBJ_API
30
31#ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK
32
33// Spaces used by misc partition are as below:
34// 0 - 2K For bootloader_message
35// 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used
36// as bootloader_message_ab struct)
37// 16K - 32K Used by uncrypt and recovery to store wipe_package for A/B devices
38// 32K - 64K System space, used for miscellanious AOSP features. See below.
39// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
40// are not configurable without changing all of them.
41#define BOOTLOADER_MESSAGE_OFFSET_IN_MISC 0
42#define VENDOR_SPACE_OFFSET_IN_MISC 2 * 1024
43#define WIPE_PACKAGE_OFFSET_IN_MISC 16 * 1024
44#define SYSTEM_SPACE_OFFSET_IN_MISC 32 * 1024
45#define SYSTEM_SPACE_SIZE_IN_MISC 32 * 1024
46
47
48#define AB_METADATA_MISC_PARTITION_OFFSET 2048
49
50#define MISCBUF_SIZE 2080
51
52/* Bootloader Message (2-KiB)
53 *
54 * This structure describes the content of a block in flash
55 * that is used for recovery and the bootloader to talk to
56 * each other.
57 *
58 * The command field is updated by linux when it wants to
59 * reboot into recovery or to update radio or bootloader firmware.
60 * It is also updated by the bootloader when firmware update
61 * is complete (to boot into recovery for any final cleanup)
62 *
63 * The status field was used by the bootloader after the completion
64 * of an "update-radio" or "update-hboot" command, which has been
65 * deprecated since Froyo.
66 *
67 * The recovery field is only written by linux and used
68 * for the system to send a message to recovery or the
69 * other way around.
70 *
71 * The stage field is written by packages which restart themselves
72 * multiple times, so that the UI can reflect which invocation of the
73 * package it is. If the value is of the format "#/#" (eg, "1/3"),
74 * the UI will add a simple indicator of that status.
75 *
76 * We used to have slot_suffix field for A/B boot control metadata in
77 * this struct, which gets unintentionally cleared by recovery or
78 * uncrypt. Move it into struct bootloader_message_ab to avoid the
79 * issue.
80 */
81struct bootloader_message {
82 char command[32];
83 char status[32];
84 char recovery[768];
85
86 // The 'recovery' field used to be 1024 bytes. It has only ever
87 // been used to store the recovery command line, so 768 bytes
88 // should be plenty. We carve off the last 256 bytes to store the
89 // stage string (for multistage packages) and possible future
90 // expansion.
91 char stage[32];
92
93 // The 'reserved' field used to be 224 bytes when it was initially
94 // carved off from the 1024-byte recovery field. Bump it up to
95 // 1184-byte so that the entire bootloader_message struct rounds up
96 // to 2048-byte.
97 char reserved[1184];
98};
99
100/**
101 * The A/B-specific bootloader message structure (4-KiB).
102 *
103 * We separate A/B boot control metadata from the regular bootloader
104 * message struct and keep it here. Everything that's A/B-specific
105 * stays after struct bootloader_message, which should be managed by
106 * the A/B-bootloader or boot control HAL.
107 *
108 * The slot_suffix field is used for A/B implementations where the
109 * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
110 * commandline parameter. This is used by fs_mgr to mount /system and
111 * other partitions with the slotselect flag set in fstab. A/B
112 * implementations are free to use all 32 bytes and may store private
113 * data past the first NUL-byte in this field. It is encouraged, but
114 * not mandatory, to use 'struct bootloader_control' described below.
115 *
116 * The update_channel field is used to store the Omaha update channel
117 * if update_engine is compiled with Omaha support.
118 */
119struct bootloader_message_ab {
120 struct bootloader_message message;
121 char slot_suffix[32];
122 char update_channel[128];
123
124 // Round up the entire struct to 4096-byte.
125 char reserved[1888];
126};
127
128#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
129#define BOOT_CTRL_VERSION 1
130
131typedef struct slot_metadata {
132 // Slot priority with 15 meaning highest priority, 1 lowest
133 // priority and 0 the slot is unbootable.
134 uint8_t priority : 4;
135 // Number of times left attempting to boot this slot.
136 uint8_t tries_remaining : 3;
137 // 1 if this slot has booted successfully, 0 otherwise.
138 uint8_t successful_boot : 1;
139 // 1 if this slot is corrupted from a dm-verity corruption, 0
140 // otherwise.
141 uint8_t verity_corrupted : 1;
142 // Reserved for further use.
143 uint8_t reserved : 7;
144} slot_metadata;
145
146/* Bootloader Control AB
147 *
148 * This struct can be used to manage A/B metadata. It is designed to
149 * be put in the 'slot_suffix' field of the 'bootloader_message'
150 * structure described above. It is encouraged to use the
151 * 'bootloader_control' structure to store the A/B metadata, but not
152 * mandatory.
153 */
154typedef struct bootloader_control {
155 // NUL terminated active slot suffix.
156 char slot_suffix[4];
157 // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
158 uint32_t magic;
159 // Version of struct being used (see BOOT_CTRL_VERSION).
160 uint8_t version;
161 // Number of slots being managed.
162 uint8_t nb_slot : 3;
163 // Number of times left attempting to boot recovery.
164 uint8_t recovery_tries_remaining : 3;
165 // Status of any pending snapshot merge of dynamic partitions.
166 uint8_t merge_status : 3;
167 // Ensure 4-bytes alignment for slot_info field.
168 uint8_t roll_flag;
169 // Per-slot information. Up to 4 slots.
170 struct slot_metadata slot_info[4];
171 // Reserved for further use.
172 uint8_t reserved1[8];
173 // CRC32 of all 28 bytes preceding this field (little endian
174 // format).
175 uint32_t crc32_le;
176}bootloader_control;
177
178#define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
179#define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
180
181unsigned int kDefaultBootAttempts = 7;
182
183/* Magic for the A/B struct when serialized. */
184#define AVB_AB_MAGIC "\0AB0"
185#define AVB_AB_MAGIC_LEN 4
186
187/* Versioning for the on-disk A/B metadata - keep in sync with avbtool. */
188#define AVB_AB_MAJOR_VERSION 1
189#define AVB_AB_MINOR_VERSION 0
190
191/* Size of AvbABData struct. */
192#define AVB_AB_DATA_SIZE 32
193
194/* Maximum values for slot data */
195#define AVB_AB_MAX_PRIORITY 15
196#define AVB_AB_MAX_TRIES_REMAINING 7
197
198/* Struct used for recording per-slot metadata.
199 *
200 * When serialized, data is stored in network byte-order.
201 */
202typedef struct AvbABSlotData {
203 /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY,
204 * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY
205 * being the highest. The special value 0 is used to indicate the
206 * slot is unbootable.
207 */
208 uint8_t priority;
209
210 /* Number of times left attempting to boot this slot ranging from 0
211 * to AVB_AB_MAX_TRIES_REMAINING.
212 */
213 uint8_t tries_remaining;
214
215 /* Non-zero if this slot has booted successfully, 0 otherwise. */
216 uint8_t successful_boot;
217
218 /* Reserved for future use. */
219 uint8_t reserved[1];
220} AvbABSlotData;
221
222/* Struct used for recording A/B metadata.
223 *
224 * When serialized, data is stored in network byte-order.
225 */
226typedef struct AvbABData {
227 /* Magic number used for identification - see AVB_AB_MAGIC. */
228 uint8_t magic[AVB_AB_MAGIC_LEN];
229
230 /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */
231 uint8_t version_major;
232 uint8_t version_minor;
233
234 /* Padding to ensure |slots| field start eight bytes in. */
235 uint8_t reserved1[2];
236
237 /* Per-slot metadata. */
238 AvbABSlotData slots[2];
239
240 /* Reserved for future use. */
241 uint8_t reserved2[12];
242
243 /* CRC32 of all 28 bytes preceding this field. */
244 uint32_t crc32;
245}AvbABData;
246
247#ifdef CONFIG_UNIFY_BOOTLOADER
248bootctl_func_handles vab_cmd_bootctrl_handles = {0};
249#endif
250
251static bool boot_info_validate(bootloader_control *info)
252{
253 if (info->magic != BOOT_CTRL_MAGIC) {
254 printf("Magic 0x%x is incorrect.\n", info->magic);
255 return false;
256 }
257 return true;
258}
259
260bool boot_info_validate_normalAB(AvbABData* info)
261{
262 if (memcmp(info->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
263 printf("Magic %s is incorrect.\n", info->magic);
264 return false;
265 }
266 if (info->version_major > AVB_AB_MAJOR_VERSION) {
267 printf("No support for given major version.\n");
268 return false;
269 }
270 return true;
271}
272
273
274void boot_info_reset(bootloader_control* boot_ctrl)
275{
276 int slot;
277
278 memset(boot_ctrl, '\0', sizeof(bootloader_control));
279 memcpy(boot_ctrl->slot_suffix, "_a", 2);
280 boot_ctrl->magic = BOOT_CTRL_MAGIC;
281 boot_ctrl->version = BOOT_CTRL_VERSION;
282 boot_ctrl->nb_slot = 2;
283 boot_ctrl->roll_flag = 0;
284
285 for (slot = 0; slot < 4; ++slot) {
286 slot_metadata entry = {};
287
288 if (slot < boot_ctrl->nb_slot) {
289 entry.priority = 7;
290 entry.tries_remaining = kDefaultBootAttempts;
291 entry.successful_boot = 0;
292 } else {
293 entry.priority = 0; // Unbootable
294 entry.tries_remaining = 0;
295 entry.successful_boot = 0;
296 }
297
298 boot_ctrl->slot_info[slot] = entry;
299 }
300 boot_ctrl->slot_info[0].successful_boot = 1;
301 boot_ctrl->recovery_tries_remaining = 0;
302}
303
304static void dump_boot_info(bootloader_control *boot_ctrl)
305{
306#if 0
307 int slot;
308
309 printf("boot_ctrl->slot_suffix = %s\n", boot_ctrl->slot_suffix);
310 printf("boot_ctrl->magic = 0x%x\n", boot_ctrl->magic);
311 printf("boot_ctrl->version = %d\n", boot_ctrl->version);
312 printf("boot_ctrl->nb_slot = %d\n", boot_ctrl->nb_slot);
313 for (slot = 0; slot < 4; ++slot) {
314 printf("boot_ctrl->slot_info[%d].priority = %d\n",
315 slot, boot_ctrl->slot_info[slot].priority);
316 printf("boot_ctrl->slot_info[%d].tries_remaining = %d\n",
317 slot, boot_ctrl->slot_info[slot].tries_remaining);
318 printf("boot_ctrl->slot_info[%d].successful_boot = %d\n",
319 slot, boot_ctrl->slot_info[slot].successful_boot);
320 }
321 printf("boot_ctrl->recovery_tries_remaining = %d\n",
322 boot_ctrl->recovery_tries_remaining);
323#endif
324}
325
326static bool slot_is_bootable(slot_metadata* slot) {
327 return slot->tries_remaining != 0;
328}
329
330static int get_active_slot(bootloader_control *info)
331{
332 if (info->slot_info[0].priority > info->slot_info[1].priority) {
333 return 0;
334 } else if (info->slot_info[0].priority == info->slot_info[1].priority) {
335 if (info->slot_info[0].successful_boot == 1)
336 return 0;
337 else
338 return 1;
339 } else {
340 return 1;
341 }
342}
343
344static bool slot_is_bootable_normalAB(AvbABSlotData* slot) {
345 return slot->priority > 0 &&
346 (slot->successful_boot || (slot->tries_remaining > 0));
347}
348
349int get_active_slot_normalAB(AvbABData* info) {
350 if (info->slots[0].priority > info->slots[1].priority)
351 return 0;
352 else
353 return 1;
354}
355
356static uint32_t vab_crc32(const uint8_t *buf, size_t size)
357{
358 static uint32_t crc_table[256];
359 uint32_t ret = -1;
360
361 // Compute the CRC-32 table only once.
362 if (!crc_table[1]) {
363 for (uint32_t i = 0; i < 256; ++i) {
364 uint32_t crc = i;
365
366 for (uint32_t j = 0; j < 8; ++j) {
367 uint32_t mask = -(crc & 1);
368
369 crc = (crc >> 1) ^ (0xEDB88320 & mask);
370 }
371 crc_table[i] = crc;
372 }
373 }
374
375 for (size_t i = 0; i < size; ++i)
376 ret = (ret >> 8) ^ crc_table[(ret ^ buf[i]) & 0xFF];
377
378 return ~ret;
379}
380
381static int boot_info_set_active_slot(bootloader_control *bootctrl, int slot)
382{
383 int i;
384 // Set every other slot with a lower priority than the new "active" slot.
385 const unsigned int kActivePriority = 15;
386 const unsigned int kActiveTries = 6;
387
388 for (i = 0; i < bootctrl->nb_slot; ++i) {
389 if (i != slot) {
390 //bootctrl->slot_info[i].priority -= 1;
391 if (bootctrl->slot_info[i].priority >= kActivePriority)
392 bootctrl->slot_info[i].priority = kActivePriority - 1;
393 }
394 printf("bootctrl->slot_info[%d].priority = %d\n", i,
395 bootctrl->slot_info[i].priority);
396 }
397
398 // Note that setting a slot as active doesn't change the successful bit.
399 // The successful bit will only be changed by setSlotAsUnbootable().
400 bootctrl->slot_info[slot].priority = kActivePriority;
401 bootctrl->slot_info[slot].tries_remaining = kActiveTries;
402
403 printf("bootctrl->slot_info[%d].priority = %d\n", slot,
404 bootctrl->slot_info[slot].priority);
405 printf("bootctrl->slot_info[%d].tries_remaining = %d\n",
406 slot, bootctrl->slot_info[slot].tries_remaining);
407
408 // Setting the current slot as active is a way to revert the operation that
409 // set *another* slot as active at the end of an updater. This is commonly
410 // used to cancel the pending update. We should only reset the verity_corrpted
411 // bit when attempting a new slot, otherwise the verity bit on the current
412 // slot would be flip.
413 if (slot != get_active_slot(bootctrl))
414 bootctrl->slot_info[slot].verity_corrupted = 0;
415
416 dump_boot_info(bootctrl);
417
418 return 0;
419}
420
421static bool boot_info_load(bootloader_control *out_info, char *miscbuf)
422{
423 memcpy(out_info, miscbuf + AB_METADATA_MISC_PARTITION_OFFSET, sizeof(bootloader_control));
424 dump_boot_info(out_info);
425 return true;
426}
427
428bool boot_info_load_normalAB(AvbABData *out_info, char *miscbuf)
429{
430 memcpy(out_info, miscbuf + AB_METADATA_MISC_PARTITION_OFFSET, AVB_AB_DATA_SIZE);
431 return true;
432}
433
434static bool boot_info_save(bootloader_control *info, char *miscbuf)
435{
436 char *partition = "misc";
437 int ret = 0;
438
439 printf("save boot-info\n");
440 info->crc32_le = vab_crc32((const uint8_t *)info,
441 sizeof(bootloader_control) - sizeof(uint32_t));
442
443 memcpy(miscbuf + AB_METADATA_MISC_PARTITION_OFFSET, info, sizeof(bootloader_control));
444 dump_boot_info(info);
Xindong Xue5d4d172023-04-10 10:30:25 +0800445
446#ifdef CONFIG_AML_MTD
447 enum boot_type_e device_boot_flag = store_get_type();
448
449 if (device_boot_flag == BOOT_NAND_NFTL || device_boot_flag == BOOT_NAND_MTD ||
450 device_boot_flag == BOOT_SNAND) {
451 int ret = 0;
452
453 ret = run_command("store erase misc 0 0x4000", 0);
454 if (ret != 0) {
455 printf("erase partition misc failed!\n");
456 return false;
457 }
Xindong Xu495e9682023-02-24 04:50:07 +0000458 }
Xindong Xue5d4d172023-04-10 10:30:25 +0800459#endif
460
Xindong Xu495e9682023-02-24 04:50:07 +0000461 ret = store_logic_write((const char *)partition, 0, MISCBUF_SIZE, (unsigned char *)miscbuf);
462 if (ret) {
463 printf("store logic write failed at %s\n", partition);
464 return false;
465 }
466 return true;
467}
468
469static int is_BootSame(int srcindex, int dstindex)
470{
471 int iRet = 0;
472 int ret = -1;
473 unsigned char *buffer_src = NULL;
474 unsigned char *buffer_dest = NULL;
475 const int SHA1SUMLEN = 20;
476 u8 gensum0[SHA1SUMLEN * 2];
477 u8 *gensum1 = gensum0 + SHA1SUMLEN;
478 int capacity_boot = 0;
479
480#ifdef CONFIG_MMC_MESON_GX
481 struct mmc *mmc = NULL;
482
483 if (store_get_type() == BOOT_EMMC)
484 mmc = find_mmc_device(1);
485
486 if (mmc)
487 capacity_boot = mmc->capacity_boot;
488#endif
489
490 printf("is_BootSame_capacity_boot: %x\n", capacity_boot);
491
492 buffer_src = (unsigned char *)malloc(capacity_boot);
493 if (!buffer_src) {
494 printf("ERROR! fail to allocate memory ...\n");
495 goto exit;
496 }
497 memset(buffer_src, 0, capacity_boot);
498
499 iRet = store_boot_read("bootloader", srcindex, 0, buffer_src);
500 if (iRet) {
501 printf("Fail read bootloader %d\n", srcindex);
502 goto exit;
503 }
504 sha1_csum(buffer_src, capacity_boot, gensum0);
505
506 buffer_dest = buffer_src;
507 memset(buffer_dest, 0, capacity_boot);
508 iRet = store_boot_read("bootloader", dstindex, 0, buffer_dest);
509 if (iRet) {
510 printf("Fail read bootloader %d\n", dstindex);
511 goto exit;
512 }
513 sha1_csum(buffer_dest, capacity_boot, gensum1);
514
515 ret = memcmp(gensum0, gensum1, SHA1SUMLEN);
516 printf("bootloader %d & %d %s same\n", srcindex, dstindex, ret ? "NOT" : "DO");
517
518exit:
519 if (buffer_src) {
520 free(buffer_src);
521 buffer_src = NULL;
522 }
523 return ret;
524}
525
526static int write_bootloader(int copy, int dstindex)
527{
528 int iRet = 0;
529 int ret = -1;
530 unsigned char *buffer = NULL;
531 int capacity_boot = 0;
532
533#ifdef CONFIG_MMC_MESON_GX
534 struct mmc *mmc = NULL;
535
536 if (store_get_type() == BOOT_EMMC)
537 mmc = find_mmc_device(1);
538#endif
539
540 if (mmc)
541 capacity_boot = mmc->capacity_boot;
542
543 printf("write_bootloader_capacity_boot: %x\n", capacity_boot);
544
545 buffer = (unsigned char *)malloc(capacity_boot);
546 if (!buffer) {
547 printf("ERROR! fail to allocate memory ...\n");
548 goto exit;
549 }
550 memset(buffer, 0, capacity_boot);
551 printf("copy from boot%d to boot%d\n", copy, dstindex);
552 iRet = store_boot_read("bootloader", copy, 0, buffer);
553 if (iRet) {
554 printf("Fail read bootloader from rsv with sz\n");
555 goto exit;
556 }
557 iRet = store_boot_write("bootloader", dstindex, 0, buffer);
558 if (iRet) {
559 printf("Failed to write bootloader\n");
560 goto exit;
561 } else {
562 ret = 0;
563 }
564
565exit:
566 if (buffer) {
567 free(buffer);
568 buffer = NULL;
569 }
570 return ret;
571}
572
573static int do_GetValidSlot(
574 cmd_tbl_t *cmdtp,
575 int flag,
576 int argc,
577 char * const argv[])
578{
579 char miscbuf[MISCBUF_SIZE] = {0};
580 bootloader_control boot_ctrl;
581 AvbABData info;
582 int slot;
583 int AB_mode = 0;
584 bool bootable_a, bootable_b;
585 bool nocs_mode = false;
586
587 if (argc != 1)
588 return cmd_usage(cmdtp);
589
590 boot_info_open_partition(miscbuf);
591 boot_info_load(&boot_ctrl, miscbuf);
592
593 if (!boot_info_validate(&boot_ctrl)) {
594 printf("boot-info virtual ab is invalid. Try normal ab.\n");
595 boot_info_load_normalAB(&info, miscbuf);
596 if (!boot_info_validate_normalAB(&info)) {
597 printf("boot-info is invalid. Resetting.\n");
598 boot_info_reset(&boot_ctrl);
599 boot_info_save(&boot_ctrl, miscbuf);
600 } else {
601 printf("update from normal ab to virtual ab\n");
602 AB_mode = 1;
603 }
604 }
605
606 if (AB_mode == 1) {
607 slot = get_active_slot_normalAB(&info);
608 printf("active slot = %d\n", slot);
609 bootable_a = slot_is_bootable_normalAB(&info.slots[0]);
610 bootable_b = slot_is_bootable_normalAB(&info.slots[1]);
611 boot_info_reset(&boot_ctrl);
612 boot_ctrl.slot_info[0].successful_boot = info.slots[0].successful_boot;
613 boot_ctrl.slot_info[1].successful_boot = info.slots[1].successful_boot;
614 boot_info_set_active_slot(&boot_ctrl, slot);
615 boot_info_save(&boot_ctrl, miscbuf);
616 slot = get_active_slot(&boot_ctrl);
617 } else {
618 slot = get_active_slot(&boot_ctrl);
619 printf("active slot = %d\n", slot);
620 bootable_a = slot_is_bootable(&boot_ctrl.slot_info[0]);
621 bootable_b = slot_is_bootable(&boot_ctrl.slot_info[1]);
622 }
623
624 if (dynamic_partition)
625 env_set("partition_mode", "dynamic");
626 else
627 env_set("partition_mode", "normal");
628
629 if (gpt_partition)
630 env_set("gpt_mode", "true");
631 else
632 env_set("gpt_mode", "false");
633
634 if (vendor_boot_partition) {
635 env_set("vendor_boot_mode", "true");
636 printf("set vendor_boot_mode true\n");
637 } else {
638 env_set("vendor_boot_mode", "false");
639 printf("set vendor_boot_mode false\n");
640 }
641
642 if (slot == 0) {
643 if (bootable_a) {
644 if (has_boot_slot == 1) {
645 env_set("active_slot", "_a");
646 env_set("boot_part", "boot_a");
647 env_set("recovery_part", "recovery_a");
648 env_set("slot-suffixes", "0");
649 } else {
650 env_set("active_slot", "normal");
651 env_set("boot_part", "boot");
652 env_set("recovery_part", "recovery");
653 env_set("slot-suffixes", "-1");
654 }
655 return 0;
656 } else if (bootable_b) {
657 printf("slot a is unbootable, back to b\n");
658 boot_ctrl.roll_flag = 1;
659 boot_info_save(&boot_ctrl, miscbuf);
660 run_command("set_active_slot b", 0);
661 env_set("update_env", "1");
662 env_set("reboot_status", "reboot_next");
663
664#if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE)
665 run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0);
666 if (*efuse_field.data == 1)
667 nocs_mode = true;
668#endif//#ifdef CONFIG_EFUSE_OBJ_API
669 if (gpt_partition || nocs_mode) {
670 printf("gpt or nocs mode\n");
671 write_bootloader(2, 1);
672 env_set("expect_index", "1");
673 } else {
674 printf("normal mode\n");
675 write_bootloader(2, 0);
676 env_set("expect_index", "0");
677 }
678 run_command("saveenv", 0);
679 run_command("reset", 0);
680 } else {
681 run_command("run init_display; run storeargs; run update;", 0);
682 }
683 }
684
685 if (slot == 1) {
686 if (bootable_b) {
687 if (has_boot_slot == 1) {
688 env_set("active_slot", "_b");
689 env_set("boot_part", "boot_b");
690 env_set("recovery_part", "recovery_b");
691 env_set("slot-suffixes", "1");
692 } else {
693 env_set("active_slot", "normal");
694 env_set("boot_part", "boot");
695 env_set("recovery_part", "recovery");
696 env_set("slot-suffixes", "-1");
697 }
698 return 0;
699 } else if (bootable_a) {
700 printf("slot b is unbootable, back to a\n");
701 boot_ctrl.roll_flag = 1;
702 boot_info_save(&boot_ctrl, miscbuf);
703 run_command("set_active_slot a", 0);
704 env_set("update_env", "1");
705 env_set("reboot_status", "reboot_next");
706
707#if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE)
708 run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0);
709 if (*efuse_field.data == 1)
710 nocs_mode = true;
711#endif//#ifdef CONFIG_EFUSE_OBJ_API
712 if (gpt_partition || nocs_mode) {
713 printf("gpt or nocs mode\n");
714 write_bootloader(2, 1);
715 env_set("expect_index", "1");
716 } else {
717 printf("normal mode\n");
718 write_bootloader(1, 0);
719 env_set("expect_index", "0");
720 }
721 run_command("saveenv", 0);
722 run_command("reset", 0);
723 } else {
724 run_command("run init_display; run storeargs; run update;", 0);
725 }
726 }
727
728 return 0;
729}
730
731static int do_SetActiveSlot(
732 cmd_tbl_t *cmdtp,
733 int flag,
734 int argc,
735 char * const argv[])
736{
737 char miscbuf[MISCBUF_SIZE] = {0};
738 bootloader_control info;
739
740 if (argc != 2)
741 return cmd_usage(cmdtp);
742
743 if (has_boot_slot == 0) {
744 printf("device is not ab mode\n");
745 return -1;
746 }
747
748 boot_info_open_partition(miscbuf);
749 boot_info_load(&info, miscbuf);
750
751 if (!boot_info_validate(&info)) {
752 printf("boot-info is invalid. Resetting.\n");
753 boot_info_reset(&info);
754 boot_info_save(&info, miscbuf);
755 }
756
757 if (strcmp(argv[1], "a") == 0) {
758 env_set("active_slot", "_a");
759 env_set("slot-suffixes", "0");
760 env_set("boot_part", "boot_a");
761 env_set("recovery_part", "recovery_a");
762 printf("set active slot a\n");
763 boot_info_set_active_slot(&info, 0);
764 } else if (strcmp(argv[1], "b") == 0) {
765 env_set("active_slot", "_b");
766 env_set("slot-suffixes", "1");
767 env_set("boot_part", "boot_b");
768 env_set("recovery_part", "recovery_b");
769 printf("set active slot b\n");
770 boot_info_set_active_slot(&info, 1);
771 } else {
772 printf("error input slot\n");
773 return -1;
774 }
775
776 boot_info_save(&info, miscbuf);
777
778 printf("info.roll_flag = %d\n", info.roll_flag);
779
780 if (!gpt_partition && info.roll_flag == 1) {
781 printf("if null gpt, write dtb back when rollback\n");
782 if (run_command("imgread dtb ${boot_part} ${dtb_mem_addr}", 0)) {
783 printf("Fail in load dtb\n");
784 } else {
785 printf("write dtb back\n");
786 run_command("emmc dtb_write ${dtb_mem_addr} 0", 0);
787 }
788 }
789
790 return 0;
791}
792
793static int do_SetRollFlag
794(cmd_tbl_t *cmdtp,
795 int flag,
796 int argc,
797 char * const argv[])
798{
799 char miscbuf[MISCBUF_SIZE] = {0};
800 bootloader_control info;
801
802 if (argc != 2)
803 return cmd_usage(cmdtp);
804
805 if (has_boot_slot == 0) {
806 printf("device is not ab mode\n");
807 return -1;
808 }
809
810 boot_info_open_partition(miscbuf);
811 boot_info_load(&info, miscbuf);
812
813 if (!boot_info_validate(&info)) {
814 printf("boot-info is invalid. Resetting.\n");
815 return 0;
816 }
817
818 if (strcmp(argv[1], "1") == 0)
819 info.roll_flag = 1;
820 else
821 info.roll_flag = 0;
822
823 boot_info_save(&info, miscbuf);
824
825 printf("set info.roll_flag = %d\n", info.roll_flag);
826
827 return 0;
828}
829
830static int do_SetUpdateTries(
831 cmd_tbl_t *cmdtp,
832 int flag,
833 int argc,
834 char * const argv[])
835{
836 char miscbuf[MISCBUF_SIZE] = {0};
837 bootloader_control boot_ctrl;
838 bool bootable_a, bootable_b;
839 int slot;
840 int ret = -1;
841 bool nocs_mode = false;
Xindong Xue5d4d172023-04-10 10:30:25 +0800842 int update_flag = 0;
Xindong Xu495e9682023-02-24 04:50:07 +0000843
844 if (has_boot_slot == 0) {
845 printf("device is not ab mode\n");
846 return -1;
847 }
848
849 boot_info_open_partition(miscbuf);
850 boot_info_load(&boot_ctrl, miscbuf);
851
852 if (!boot_info_validate(&boot_ctrl)) {
853 printf("boot-info is invalid. Resetting\n");
854 boot_info_reset(&boot_ctrl);
855 boot_info_save(&boot_ctrl, miscbuf);
856 }
857
858 slot = get_active_slot(&boot_ctrl);
859 bootable_a = slot_is_bootable(&boot_ctrl.slot_info[0]);
860 bootable_b = slot_is_bootable(&boot_ctrl.slot_info[1]);
861
862 if (slot == 0) {
863 if (bootable_a) {
Xindong Xue5d4d172023-04-10 10:30:25 +0800864 if (boot_ctrl.slot_info[0].successful_boot == 0) {
Xindong Xu495e9682023-02-24 04:50:07 +0000865 boot_ctrl.slot_info[0].tries_remaining -= 1;
Xindong Xue5d4d172023-04-10 10:30:25 +0800866 update_flag = 1;
867 }
Xindong Xu495e9682023-02-24 04:50:07 +0000868 }
869 }
870
871 if (slot == 1) {
872 if (bootable_b) {
Xindong Xue5d4d172023-04-10 10:30:25 +0800873 if (boot_ctrl.slot_info[1].successful_boot == 0) {
Xindong Xu495e9682023-02-24 04:50:07 +0000874 boot_ctrl.slot_info[1].tries_remaining -= 1;
Xindong Xue5d4d172023-04-10 10:30:25 +0800875 update_flag = 1;
876 }
Xindong Xu495e9682023-02-24 04:50:07 +0000877 }
878 }
879
Xindong Xue5d4d172023-04-10 10:30:25 +0800880 if (update_flag == 1)
881 boot_info_save(&boot_ctrl, miscbuf);
Xindong Xu495e9682023-02-24 04:50:07 +0000882
883 printf("do_SetUpdateTries boot_ctrl.roll_flag = %d\n", boot_ctrl.roll_flag);
884 if (boot_ctrl.roll_flag == 1) {
885 env_set("rollback_flag", "1");
886 }
887
888#if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE)
889 run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0);
890 if (*efuse_field.data == 1)
891 nocs_mode = true;
892#endif//#ifdef CONFIG_EFUSE_OBJ_API
893
894 if (boot_ctrl.slot_info[slot].successful_boot == 1) {
895 if (gpt_partition || nocs_mode) {
896 char *bootloaderindex = NULL;
897
898 printf("current slot %d is successful_boot\n", slot);
899 bootloaderindex = env_get("forUpgrade_bootloaderIndex");
900 printf("bootloaderindex: %s\n", bootloaderindex);
901 /*if boot from boot1, means boot0 is bab, don't need to copyback*/
902 if (bootloaderindex && strcmp(bootloaderindex, "2")) {
903 printf("check if boot0 = boot1\n");
904 ret = is_BootSame(1, 2);
905 if (ret) {
906 printf("boot0 doesn't = boot1, write boot0 to boot1\n");
907 write_bootloader(1, 2);
908 printf("after write boot0 to boot1\n");
909 }
910 }
911 }
912 }
913 return 0;
914}
915
916static int do_CopySlot(
917 cmd_tbl_t *cmdtp,
918 int flag,
919 int argc,
920 char * const argv[])
921{
922 char miscbuf[MISCBUF_SIZE] = {0};
923 bootloader_control boot_ctrl;
924 int copy = -1;
925 int dest = -1;
926
927 boot_info_open_partition(miscbuf);
928 boot_info_load(&boot_ctrl, miscbuf);
929
930 if (!boot_info_validate(&boot_ctrl)) {
931 printf("boot-info is invalid. Resetting\n");
932 boot_info_reset(&boot_ctrl);
933 boot_info_save(&boot_ctrl, miscbuf);
934 }
935
936 if (strcmp(argv[1], "1") == 0)
937 copy = 1;
938 else if (strcmp(argv[1], "2") == 0)
939 copy = 2;
940 else if (strcmp(argv[1], "0") == 0)
941 copy = 0;
942
943 if (strcmp(argv[2], "1") == 0)
944 dest = 1;
945 else if (strcmp(argv[2], "2") == 0)
946 dest = 2;
947 else if (strcmp(argv[2], "0") == 0)
948 dest = 0;
949
950 if (copy == 1) {
951 if (boot_ctrl.slot_info[0].successful_boot == 1)
952 write_bootloader(copy, dest);
953 } else if (copy == 2) {
954 if (boot_ctrl.slot_info[1].successful_boot == 1) {
955 write_bootloader(copy, dest);
956 } else {
957 env_set("update_env", "1");
958 env_set("reboot_status", "reboot_next");
959 env_set("expect_index", "2");
960 run_command("saveenv", 0);
961 }
962 }
963
964 return 0;
965}
966
967static int do_GetSystemMode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
968{
969#ifdef CONFIG_SYSTEM_AS_ROOT
970 env_set("system_mode", "1");
971#else
972 env_set("system_mode", "0");
973#endif
974
975 return 0;
976}
977
978static int do_GetAvbMode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
979{
980#ifdef CONFIG_AVB2
981 env_set("avb2", "1");
982#else
983 env_set("avb2", "0");
984#endif
985
986 return 0;
987}
988
Xindong Xue5d4d172023-04-10 10:30:25 +0800989static int do_UpdateDt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Xindong Xu495e9682023-02-24 04:50:07 +0000990{
991 char *update_dt = env_get("update_dt");
992 char *part_changed = env_get("part_changed");
993
994 printf("update_dt %s, part_changed: %s\n", update_dt, part_changed);
995 if (update_dt && (!strcmp(update_dt, "1"))) {
996 printf("write dtb\n");
997 run_command("imgread dtb ${boot_part} ${dtb_mem_addr}", 0);
998 run_command("emmc dtb_write ${dtb_mem_addr} 0", 0);
999
1000 env_set("update_dt", "0");
1001 run_command("saveenv", 0);
1002
1003 if (part_changed && (!strcmp(part_changed, "1"))) {
1004 env_set("part_changed", "0");
1005 run_command("saveenv", 0);
1006
1007 run_command("reset", 0);
1008 }
1009 }
1010 return 0;
1011}
1012
1013#endif /* CONFIG_BOOTLOADER_CONTROL_BLOCK */
1014
1015#ifdef CONFIG_UNIFY_BOOTLOADER
1016bootctl_func_handles *get_bootctl_cmd_func_vab(void)
1017{
1018 vab_cmd_bootctrl_handles.do_GetValidSlot_func = do_GetValidSlot;
1019 vab_cmd_bootctrl_handles.do_SetActiveSlot_func = do_SetActiveSlot;
1020 vab_cmd_bootctrl_handles.do_SetRollFlag_func = do_SetRollFlag;
1021 vab_cmd_bootctrl_handles.do_CopySlot_func = do_CopySlot;
1022 vab_cmd_bootctrl_handles.do_SetUpdateTries_func = do_SetUpdateTries;
1023 vab_cmd_bootctrl_handles.do_GetSystemMode_func = do_GetSystemMode;
1024 vab_cmd_bootctrl_handles.do_GetAvbMode_func = do_GetAvbMode;
Xindong Xue5d4d172023-04-10 10:30:25 +08001025 vab_cmd_bootctrl_handles.do_UpdateDt_func = do_UpdateDt;
Xindong Xu495e9682023-02-24 04:50:07 +00001026
1027 return &vab_cmd_bootctrl_handles;
1028}
1029
1030#else
1031
1032U_BOOT_CMD(
1033 get_valid_slot, 2, 0, do_GetValidSlot,
1034 "get_valid_slot",
1035 "\nThis command will choose valid slot to boot up which saved in misc\n"
1036 "partition by mark to decide whether execute command!\n"
1037 "So you can execute command: get_valid_slot"
1038);
1039
1040U_BOOT_CMD(
1041 set_active_slot, 2, 1, do_SetActiveSlot,
1042 "set_active_slot",
1043 "\nThis command will set active slot\n"
1044 "So you can execute command: set_active_slot a"
1045);
1046
1047U_BOOT_CMD(
1048 set_roll_flag, 2, 1, do_SetRollFlag,
1049 "set_roll_flag",
1050 "\nThis command will set active slot\n"
1051 "So you can execute command: set_active_slot a"
1052);
1053
1054U_BOOT_CMD
1055(copy_slot_bootable, 3, 1, do_CopySlot,
1056 "copy_slot_bootable",
1057 "\nThis command will set active slot\n"
1058 "So you can execute command: copy_slot_bootable 2 1"
1059);
1060
1061U_BOOT_CMD(
1062 update_tries, 2, 0, do_SetUpdateTries,
1063 "update_tries",
1064 "\nThis command will change tries_remaining in misc\n"
1065 "So you can execute command: update_tries"
1066);
1067
1068U_BOOT_CMD(
1069 get_system_as_root_mode, 1, 0, do_GetSystemMode,
1070 "get_system_as_root_mode",
1071 "\nThis command will get system_as_root_mode\n"
1072 "So you can execute command: get_system_as_root_mode"
1073);
1074
1075U_BOOT_CMD(
1076 get_avb_mode, 1, 0, do_GetAvbMode,
1077 "get_avb_mode",
1078 "\nThis command will get avb mode\n"
1079 "So you can execute command: get_avb_mode"
1080);
1081U_BOOT_CMD
1082(update_dt, 1, 0, do_UpdateDt,
1083 "update_dt",
1084 "\nThis command will update dt\n"
1085 "So you can execute command: update_dt"
1086);
1087#endif
Mingyen Hung6e468002023-01-04 23:43:04 -08001088
1089int set_successful_boot(void) {
1090 char miscbuf[MISCBUF_SIZE] = {0};
1091 AvbABData info;
1092 int slot_num = 0;
1093 bootloader_control boot_ctrl;
1094 bool bootable = 0;
1095 int AB_mode = 0;
1096
1097 boot_info_open_partition(miscbuf);
1098 boot_info_load(&boot_ctrl, miscbuf);
1099
1100 if (!boot_info_validate(&boot_ctrl)) {
1101 printf("boot-info virtual ab is invalid. Try normal ab.\n");
1102 boot_info_load_normalAB(&info, miscbuf);
1103 if (!boot_info_validate_normalAB(&info)) {
1104 printf("boot-info is invalid.\n");
1105 /*printf("boot-info is invalid. Resetting.\n");
1106 boot_info_reset(&boot_ctrl);
1107 boot_info_save(&boot_ctrl, miscbuf);*/
1108 } else {
1109 printf("update from normal ab to virtual ab\n");
1110 AB_mode = 1;
1111 }
1112 }
1113
1114 if (AB_mode == 1) {
1115 slot_num = get_active_slot_normalAB(&info);
1116 printf("active slot = %d\n", slot_num);
1117 bootable = slot_is_bootable_normalAB(&info.slots[slot_num]);
1118 //bootable_b = slot_is_bootable_normalAB(&info.slots[1]);
1119 /*boot_info_reset(&boot_ctrl);
1120 boot_ctrl.slot_info[0].successful_boot = info.slots[0].successful_boot;
1121 boot_ctrl.slot_info[1].successful_boot = info.slots[1].successful_boot;
1122 boot_info_set_active_slot(&boot_ctrl, slot);
1123 boot_info_save(&boot_ctrl, miscbuf);
1124 slot = get_active_slot(&boot_ctrl);*/
1125 } else {
1126 slot_num = get_active_slot(&boot_ctrl);
1127 printf("active slot = %d\n", slot_num);
1128 bootable = slot_is_bootable(&boot_ctrl.slot_info[slot_num]);
1129 //bootable_b = slot_is_bootable(&boot_ctrl.slot_info[1]);
1130 }
1131
1132 if (bootable) {
1133 printf("slots[%d] is bootable\n", slot_num);
1134 return 0;
1135 }
1136
1137 return -1;
1138}
1139