MA-17541-1 Support virtual A/B update
authorJi Luo <ji.luo@nxp.com>
Wed, 22 Jul 2020 11:03:32 +0000 (19:03 +0800)
committerJi Luo <ji.luo@nxp.com>
Thu, 13 May 2021 01:49:18 +0000 (09:49 +0800)
A 'misc_virtual_ab_message' struct will be stored at the 32kB offset
in misc partition, which will be used to record the virtual A/B update
status.

Bootloader should take care of this status, some operations must be
restricted. This commit will:
    1. Restrict erase/flash operations to "misc", "userdata" or
       "metadata" partitions if the merge status are "SNAPSHOTTED" or
       "MERGING".
    2. Restrict slot switch if the merge status is "MERGING".
    3. Output a warning in slot switch if the merge status is "SNAPSHOTTED".
    4. Set the merge status as "CANCELLED" if image flash happen.

Test: 1. fastboot erase/flash "userdata", "misc", "metadata" after virtual
        A/B update
      2. slot switch after virtual A/B update

Signed-off-by: Ji Luo <ji.luo@nxp.com>
Change-Id: I33f0041c5e76913d3970d943cad52353e0ac5f2d
(cherry picked from commit 30df087bfc5e31413473f85dfefaa7176bc394a8)
(cherry picked from commit 7fd03bcc8f1fc094362c11d71cf740ac9b5724c1)

drivers/fastboot/fb_fsl/Makefile
drivers/fastboot/fb_fsl/fb_fsl_command.c
drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.c [new file with mode: 0644]
drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.h [new file with mode: 0644]
include/android_bootloader_message.h
lib/Kconfig

index 61db7ed..6a88aee 100644 (file)
@@ -10,4 +10,5 @@ ifndef CONFIG_SPL_BUILD
 obj-y += fb_fsl_dev.o fb_fsl_boot.o fb_fsl_command.o fb_fsl_common.o fb_fsl_getvar.o fb_fsl_partitions.o
 obj-$(CONFIG_FASTBOOT_LOCK) += fastboot_lock_unlock.o
 obj-$(CONFIG_BCB_SUPPORT) += command.o bcb.o
+obj-$(CONFIG_VIRTUAL_AB_SUPPORT) += fb_fsl_virtual_ab.o
 endif
index c5f6b9f..6580e6e 100644 (file)
@@ -49,6 +49,7 @@
 #endif
 
 #include "fb_fsl_common.h"
+#include "fb_fsl_virtual_ab.h"
 
 #define EP_BUFFER_SIZE                 4096
 
@@ -409,6 +410,14 @@ static FbLockState do_fastboot_unlock(bool force)
                        }
                }
 #endif
+
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+               if (virtual_ab_update_is_merging() || virtual_ab_update_is_snapshoted()) {
+                       printf("Can not erase userdata while a snapshot update is in progress!\n");
+                       return FASTBOOT_LOCK_ERROR;
+               }
+#endif
+
                wipe_all_userdata();
                status = fastboot_set_lock_stat(FASTBOOT_UNLOCK);
                if (status < 0)
@@ -430,6 +439,13 @@ static FbLockState do_fastboot_lock(void)
                return FASTBOOT_LOCK;
        }
 
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+               if (virtual_ab_update_is_merging() || virtual_ab_update_is_snapshoted()) {
+                       printf("Can not erase userdata while a snapshot update is in progress!\n");
+                       return FASTBOOT_LOCK_ERROR;
+               }
+#endif
+
        wipe_all_userdata();
        status = fastboot_set_lock_stat(FASTBOOT_LOCK);
        if (status < 0)
@@ -734,6 +750,20 @@ static void set_active_avb(char *cmd, char *response)
                return;
        }
 
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+       if (virtual_ab_update_is_merging()) {
+               printf("Can not switch slot while snapshot merge is in progress!\n");
+               fastboot_fail("Snapshot merge is in progress!", response);
+               return;
+       }
+
+       /* Only output a warning when the image is snapshoted. */
+       if (virtual_ab_update_is_snapshoted())
+               printf("Warning: changing the active slot with a snapshot applied may cancel the update!\n");
+       else
+               printf("Warning: Virtual A/B is enabled, switch slot may make the system fail to boot. \n");
+#endif
+
        slot = slotidx_from_suffix(cmd);
 
        if (slot < 0) {
@@ -778,9 +808,23 @@ static void flash(char *cmd, char *response)
        }
 #endif
 
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+       if (partition_is_protected_during_merge(cmd)) {
+               printf("Can not flash partition %s while a snapshot update is in progress!\n", cmd);
+               fastboot_fail("Snapshot update is in progress", response);
+               return;
+       }
+#endif
+
        fastboot_process_flash(cmd, fastboot_buf_addr,
                fastboot_bytes_received, response);
 
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+       /* Cancel virtual AB update after image flash */
+       if (virtual_ab_update_is_merging() || virtual_ab_update_is_snapshoted())
+               virtual_ab_cancel_update();
+#endif
+
 #if defined(CONFIG_FASTBOOT_LOCK)
        if (strncmp(cmd, "gpt", 3) == 0) {
                int gpt_valid = 0;
@@ -820,6 +864,15 @@ static void erase(char *cmd, char *response)
                return;
        }
 #endif
+
+#ifdef CONFIG_VIRTUAL_AB_SUPPORT
+       if (partition_is_protected_during_merge(cmd)) {
+               printf("Can not erase partition %s while a snapshot update is in progress!", cmd);
+               fastboot_fail("Snapshot update is in progress", response);
+               return;
+       }
+#endif
+
        fastboot_process_erase(cmd, response);
 }
 #endif
diff --git a/drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.c b/drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.c
new file mode 100644 (file)
index 0000000..09e54f5
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <part.h>
+#include "android_bootloader_message.h"
+#include "../lib/avb/fsl/utils.h"
+#include "fb_fsl_virtual_ab.h"
+#include "fsl_avb.h"
+#include "fb_fsl.h"
+
+static int read_virtual_ab_message(misc_virtual_ab_message *message)
+{
+       size_t num_bytes;
+
+       if (fsl_read_from_partition_multi(NULL, FASTBOOT_PARTITION_MISC,
+                                       SYSTEM_SPACE_SIZE_IN_MISC,
+                                       sizeof(misc_virtual_ab_message),
+                                       (void *)message, &num_bytes) || (num_bytes != sizeof(misc_virtual_ab_message))) {
+               printf("Error reading virtual AB message from misc!\n");
+               return -1;
+       }
+
+       if ((message->magic != MISC_VIRTUAL_AB_MAGIC_HEADER) ||
+               (message->version != MISC_VIRTUAL_AB_MESSAGE_VERSION)) {
+               printf("Invalid virtual AB status, resetting...");
+               message->version = MISC_VIRTUAL_AB_MESSAGE_VERSION;
+               message->magic = MISC_VIRTUAL_AB_MAGIC_HEADER;
+               message->merge_status = VIRTUAL_AB_NONE;
+               message->source_slot = 0;
+               if (fsl_write_to_partition(NULL, FASTBOOT_PARTITION_MISC,
+                                               SYSTEM_SPACE_SIZE_IN_MISC,
+                                               sizeof(misc_virtual_ab_message),
+                                               (void *)message)) {
+                       printf("Error writing virtual AB message to misc!\n");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* Flash or erase shall be prohibited to "misc", "userdata" and "metadata" partitions
+ * when the virtual AB status is VIRTUAL_AB_MERGING or VIRTUAL_AB_SNAPSHOTTED.
+ * */
+bool partition_is_protected_during_merge(char *part)
+{
+       if ((!strncmp(part, "misc", sizeof("misc")) ||
+               !strncmp(part, "userdata", sizeof("userdata")) ||
+               !strncmp(part, "metadata", sizeof("metadata"))) &&
+               (virtual_ab_update_is_merging() || virtual_ab_update_is_snapshoted()))
+               return true;
+       else
+               return false;
+}
+
+bool virtual_ab_update_is_merging(void)
+{
+       misc_virtual_ab_message message;
+       read_virtual_ab_message(&message);
+       if (message.merge_status == VIRTUAL_AB_MERGING)
+               return true;
+       else
+               return false;
+}
+
+bool virtual_ab_update_is_snapshoted(void)
+{
+       misc_virtual_ab_message message;
+
+       read_virtual_ab_message(&message);
+       if (message.merge_status == VIRTUAL_AB_SNAPSHOTTED)
+               return true;
+       else
+               return false;
+}
+
+int virtual_ab_cancel_update(void)
+{
+       misc_virtual_ab_message message;
+
+       read_virtual_ab_message(&message);
+       message.merge_status = VIRTUAL_AB_CANCELLED;
+
+       if (fsl_write_to_partition(NULL, FASTBOOT_PARTITION_MISC,
+                                       SYSTEM_SPACE_SIZE_IN_MISC,
+                                       sizeof(misc_virtual_ab_message),
+                                       (void *)&message)) {
+               printf("Error writing virtual AB message to misc!\n");
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.h b/drivers/fastboot/fb_fsl/fb_fsl_virtual_ab.h
new file mode 100644 (file)
index 0000000..75ceb55
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+typedef enum {
+       VIRTUAL_AB_NONE = 0,
+       VIRTUAL_AB_UNKNOWN,
+       VIRTUAL_AB_SNAPSHOTTED,
+       VIRTUAL_AB_MERGING,
+       VIRTUAL_AB_CANCELLED,
+} Virtual_AB_Status;
+
+bool partition_is_protected_during_merge(char *part);
+bool virtual_ab_update_is_merging(void);
+bool virtual_ab_update_is_snapshoted(void);
+int virtual_ab_cancel_update(void);
index 579a492..0ba9068 100644 (file)
 // 2K  - 16K    Used by Vendor's bootloader (the 2K - 4K range may be optionally used
 //              as bootloader_message_ab struct)
 // 16K - 64K    Used by uncrypt and recovery to store wipe_package for A/B devices
+// 32K - 64K    System space, used for miscellanious AOSP features. See below.
 // Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
 // are not configurable without changing all of them.
 static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
 static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
+static const size_t SYSTEM_SPACE_SIZE_IN_MISC = 32 * 1024;
 
 /* Bootloader Message (2-KiB)
  *
@@ -204,6 +206,17 @@ static_assert(sizeof(struct bootloader_control) ==
 #endif
 #endif /* __UBOOT__ */
 
+typedef struct misc_virtual_ab_message {
+  uint8_t version;
+  uint32_t magic;
+  uint8_t merge_status;  // IBootControl 1.1, MergeStatus enum.
+  uint8_t source_slot;   // Slot number when merge_status was written.
+  uint8_t reserved[57];
+} __attribute__((packed)) misc_virtual_ab_message;
+
+#define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
+#define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
+
 #ifndef __UBOOT__
 #ifdef __cplusplus
 
index c34fa5c..5cf6a9f 100644 (file)
@@ -374,6 +374,9 @@ config TRUSTY_UNLOCK_PERMISSION
 config VENDOR_BOOT_SUPPORT
        bool "Support vendor boot load"
 
+config VIRTUAL_AB_SUPPORT
+       bool "Support virtual AB update"
+
 endmenu
 
 menu "Hashing Support"