summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Ji <ji.luo@nxp.com>2018-06-08 10:31:11 +0800
committerJi Luo <ji.luo@nxp.com>2018-08-20 21:31:28 +0800
commitdbcf1e3cc079d2f1b3df6c4c9ec3a34d0c05eb4c (patch)
tree65685970179ebf242d0a49e14fbd4108d85beda9
parent4cfd7437ac44f7bf64650e1f95628624d7eb79b2 (diff)
[iot] Support dual bootloader in SPL
Move the A/B slot check to SPL, the A/B slot switch workflow is just like what we have in libavb_ab. Test: A/B select works fine on imx8m. Change-Id: Ie3d827a9be0298b491bf2bc8d48833597fd70e90 Signed-off-by: Luo Ji <ji.luo@nxp.com>
-rw-r--r--common/spl/spl_mmc.c26
-rw-r--r--configs/imx8mq_evk_androidthings_defconfig1
-rw-r--r--configs/imx8mq_phanbell_androidthings_defconfig3
-rw-r--r--disk/part_efi.c35
-rw-r--r--include/configs/imx8mq_evk.h1
-rw-r--r--include/configs/imx8mq_phanbell.h2
-rw-r--r--include/fsl_avb.h64
-rw-r--r--include/part.h3
-rw-r--r--lib/Kconfig5
-rw-r--r--lib/Makefile2
-rw-r--r--lib/avb/Makefile5
-rw-r--r--lib/avb/fsl/Makefile6
-rw-r--r--lib/avb/fsl/fsl_avb_ab_flow.c302
-rw-r--r--lib/avb/fsl/utils.c176
-rw-r--r--lib/avb/fsl/utils.h15
-rw-r--r--lib/avb/libavb/Makefile34
16 files changed, 599 insertions, 81 deletions
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 4b9be0dc4d..150886c1a8 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -4,6 +4,8 @@
*
* Aneesh V <aneesh@ti.com>
*
+ * Copyright 2018 NXP
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@@ -18,7 +20,7 @@
DECLARE_GLOBAL_DATA_PTR;
-static int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc,
+int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc,
ulong sector, struct image_header *header)
{
u32 image_size_sectors;
@@ -44,7 +46,7 @@ static int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc,
return 0;
}
-static ulong h_spl_load_read(struct spl_load_info *load, ulong sector,
+ulong h_spl_load_read(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
{
struct mmc *mmc = load->dev;
@@ -52,9 +54,15 @@ static ulong h_spl_load_read(struct spl_load_info *load, ulong sector,
return blk_dread(mmc_get_blk_desc(mmc), sector, count, buf);
}
+#ifdef CONFIG_DUAL_BOOTLOADER
+/* Pre-declaration of mmc_load_image_raw_sector_dual_uboot().
+ */
+extern int mmc_load_image_raw_sector_dual_uboot(struct spl_image_info *spl_image,
+ struct mmc *mmc);
+#else
static __maybe_unused
int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
- struct mmc *mmc, unsigned long sector)
+ struct mmc *mmc, unsigned long sector)
{
struct image_header *header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
sizeof(struct image_header));
@@ -98,6 +106,8 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
return 0;
}
+#endif /* CONFIG_DUAL_BOOTLOADER */
+
static int spl_mmc_get_device_index(u32 boot_device)
{
switch (boot_device) {
@@ -329,10 +339,15 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
* 1 and 2 match up to boot0 / boot1 and 7 is user data
* which is the first physical partition (0).
*/
+#ifdef CONFIG_DUAL_BOOTLOADER
+ /* Bootloader is stored in eMMC user partition for dual bootloader */
+ part = 0;
+#else
part = (mmc->part_config >> 3) & PART_ACCESS_MASK;
if (part == 7)
part = 0;
+#endif
if (CONFIG_IS_ENABLED(MMC_TINY))
err = mmc_switch_part(mmc, part);
@@ -361,8 +376,13 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
return err;
#endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+#ifdef CONFIG_DUAL_BOOTLOADER
+ err = mmc_load_image_raw_sector_dual_uboot(spl_image,
+ mmc);
+#else
err = mmc_load_image_raw_sector(spl_image, mmc,
spl_mmc_get_uboot_raw_sector(mmc));
+#endif
if (!err)
return err;
#endif
diff --git a/configs/imx8mq_evk_androidthings_defconfig b/configs/imx8mq_evk_androidthings_defconfig
index 85077f125d..8eaacb05b5 100644
--- a/configs/imx8mq_evk_androidthings_defconfig
+++ b/configs/imx8mq_evk_androidthings_defconfig
@@ -68,3 +68,4 @@ CONFIG_USB_XHCI_IMX8M=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_GADGET=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
diff --git a/configs/imx8mq_phanbell_androidthings_defconfig b/configs/imx8mq_phanbell_androidthings_defconfig
index a83c41abf3..b22267d83c 100644
--- a/configs/imx8mq_phanbell_androidthings_defconfig
+++ b/configs/imx8mq_phanbell_androidthings_defconfig
@@ -42,6 +42,9 @@ CONFIG_DM_THERMAL=y
CONFIG_FIT=y
CONFIG_SPL_FIT=y
CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_MMC_WRITE=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_ANDROID_BOOT_IMAGE=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
diff --git a/disk/part_efi.c b/disk/part_efi.c
index ee9d64703d..b778106449 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -280,8 +280,10 @@ void part_print_efi(struct blk_desc *dev_desc)
printf("\tguid:\t%s\n", uuid);
}
+#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
/* Remember to free pte */
free(gpt_pte);
+#endif
return;
}
@@ -316,7 +318,9 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
!is_pte_valid(&gpt_pte[part - 1])) {
debug("%s: *** ERROR: Invalid partition number %d ***\n",
__func__, part);
+#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
free(gpt_pte);
+#endif
return -1;
}
@@ -343,8 +347,14 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__,
info->start, info->size, info->name);
- /* Remember to free pte */
+#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
+ /* Heap memory is very limited in SPL, if the dual bootloader is
+ * enabled, just load pte to dram instead of oc-ram. In such case,
+ * this part of memory shouldn't be freed. But in common routine,
+ * don't forget to free the memory after use.
+ */
free(gpt_pte);
+#endif
return 0;
}
@@ -1039,10 +1049,17 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
}
if (validate_gpt_entries(pgpt_head, *pgpt_pte)) {
+
+#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
+ /* Heap memory is very limited in SPL, if the dual bootloader is
+ * enabled, just load pte to dram instead of oc-ram. In such case,
+ * this part of memory shouldn't be freed. But in common routine,
+ * don't forget to free the memory after use.
+ */
free(*pgpt_pte);
+#endif
return 0;
}
-
/* We're done, all's well */
return 1;
}
@@ -1076,10 +1093,19 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
(u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
(ulong)count);
- /* Allocate memory for PTE, remember to FREE */
+ /* Allocate memory for PTE.
+ * Heap memory is very limited in SPL, if the dual bootloader is
+ * enabled, just load pte to dram instead of oc-ram. In such case,
+ * this part of memory shouldn't be freed. But in common routine,
+ * don't forget to free the memory after use.
+ */
if (count != 0) {
+#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD)
+ pte = (gpt_entry *)CONFIG_SYS_SPL_PTE_RAM_BASE;
+#else
pte = memalign(ARCH_DMA_MINALIGN,
PAD_TO_BLOCKSIZE(count, dev_desc));
+#endif
}
if (count == 0 || pte == NULL) {
@@ -1087,13 +1113,14 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
__func__, (ulong)count);
return NULL;
}
-
/* Read GPT Entries from device */
blk = le64_to_cpu(pgpt_head->partition_entry_lba);
blk_cnt = BLOCK_CNT(count, dev_desc);
if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
printf("*** ERROR: Can't read GPT Entries ***\n");
+#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
free(pte);
+#endif
return NULL;
}
return pte;
diff --git a/include/configs/imx8mq_evk.h b/include/configs/imx8mq_evk.h
index 0b9c01685e..0adfbef852 100644
--- a/include/configs/imx8mq_evk.h
+++ b/include/configs/imx8mq_evk.h
@@ -39,6 +39,7 @@
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x6000 /* 24 KB */
+#define CONFIG_SYS_SPL_PTE_RAM_BASE 0x41580000
#define CONFIG_SYS_ICACHE_OFF
#define CONFIG_SYS_DCACHE_OFF
diff --git a/include/configs/imx8mq_phanbell.h b/include/configs/imx8mq_phanbell.h
index 12f4cc65eb..87c864a95f 100644
--- a/include/configs/imx8mq_phanbell.h
+++ b/include/configs/imx8mq_phanbell.h
@@ -34,11 +34,11 @@
#define CONFIG_SPL_LIBGENERIC_SUPPORT
#define CONFIG_SPL_SERIAL_SUPPORT
#define CONFIG_SPL_GPIO_SUPPORT
-#define CONFIG_SPL_MMC_SUPPORT
#define CONFIG_SPL_BSS_START_ADDR 0x00180000
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x2000 /* 8 KB */
+#define CONFIG_SYS_SPL_PTE_RAM_BASE 0x41580000
#define CONFIG_SYS_ICACHE_OFF
#define CONFIG_SYS_DCACHE_OFF
diff --git a/include/fsl_avb.h b/include/fsl_avb.h
index ae290a9f48..b480e9d62a 100644
--- a/include/fsl_avb.h
+++ b/include/fsl_avb.h
@@ -33,8 +33,8 @@ AvbIOResult fsl_read_from_partition(AvbOps* ops, const char* partition,
/* multi block read version
* */
AvbIOResult fsl_read_from_partition_multi(AvbOps* ops, const char* partition,
- int64_t offset, size_t num_bytes,
- void* buffer, size_t* out_num_read);
+ int64_t offset, size_t num_bytes,
+ void* buffer, size_t* out_num_read);
/* Writes |num_bytes| from |bffer| at offset |offset| to partition
* with name |partition| (NUL-terminated UTF-8 string). If |offset|
@@ -87,11 +87,11 @@ AvbIOResult fsl_write_ab_metadata(AvbABOps* ab_ops, const struct AvbABData* data
* true if trusted or false if untrusted.
*/
AvbIOResult fsl_validate_vbmeta_public_key_rpmb(AvbOps* ops,
- const uint8_t* public_key_data,
- size_t public_key_length,
- const uint8_t* public_key_metadata,
- size_t public_key_metadata_length,
- bool* out_is_trusted);
+ const uint8_t* public_key_data,
+ size_t public_key_length,
+ const uint8_t* public_key_metadata,
+ size_t public_key_metadata_length,
+ bool* out_is_trusted);
/* Gets the rollback index corresponding to the slot given by
* |rollback_index_slot|. The value is returned in
@@ -103,7 +103,7 @@ AvbIOResult fsl_validate_vbmeta_public_key_rpmb(AvbOps* ops,
* this number.
*/
AvbIOResult fsl_read_rollback_index_rpmb(AvbOps* ops, size_t rollback_index_slot,
- uint64_t* out_rollback_index);
+ uint64_t* out_rollback_index);
/* Sets the rollback index corresponding to the slot given by
* |rollback_index_slot| to |rollback_index|. Returns
@@ -115,7 +115,7 @@ AvbIOResult fsl_read_rollback_index_rpmb(AvbOps* ops, size_t rollback_index_slot
* this number.
*/
AvbIOResult fsl_write_rollback_index_rpmb(AvbOps* ops, size_t rollback_index_slot,
- uint64_t rollback_index);
+ uint64_t rollback_index);
/* Gets whether the device is unlocked. The value is returned in
* |out_is_unlocked| (true if unlocked, false otherwise). Returns
@@ -135,9 +135,9 @@ AvbIOResult fsl_read_is_device_unlocked(AvbOps* ops, bool* out_is_unlocked);
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
*/
AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
- const char* partition,
- char* guid_buf,
- size_t guid_buf_size);
+ const char* partition,
+ char* guid_buf,
+ size_t guid_buf_size);
/* Gets the size of a partition with the name in |partition|
* (NUL-terminated UTF-8 string). Returns the value in
@@ -145,8 +145,8 @@ AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
*/
AvbIOResult fsl_get_size_of_partition(AvbOps* ops,
- const char* partition,
- uint64_t* out_size_num_bytes);
+ const char* partition,
+ uint64_t* out_size_num_bytes);
/* check if the fastboot getvar cmd is for query [avb] bootctl's slot var
* cmd is the fastboot getvar's cmd in
* return true if it is a bootctl related cmd, false if it's not.
@@ -193,32 +193,42 @@ AvbIOResult fsl_read_permanent_attributes(
* permanently read-only location (e.g. fuses) when a device is LOCKED. On
* success, returned AVB_IO_RESULT_OK and populates |hash|.
*/
-AvbIOResult fsl_read_permanent_attributes_hash(
- AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]);
+AvbIOResult fsl_read_permanent_attributes_hash(AvbAtxOps* atx_ops,
+ uint8_t hash[AVB_SHA256_DIGEST_SIZE]);
/* Provides the key version of a key used during verification. This may be
* useful for managing the minimum key version.
*/
void fsl_set_key_version(AvbAtxOps* atx_ops,
- size_t rollback_index_location,
- uint64_t key_version);
+ size_t rollback_index_location,
+ uint64_t key_version);
/* This is the fast version of avb_ab_flow(), this function will
* not check another slot if one slot can pass the verify (or verify
- * fail is acceptable). */
+ * fail is acceptable).
+ */
AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
- const char* const* requested_partitions,
- AvbSlotVerifyFlags flags,
- AvbHashtreeErrorMode hashtree_error_mode,
- AvbSlotVerifyData** out_data);
+ const char* const* requested_partitions,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data);
/* This is for legacy i.mx6/7 which don't enable A/B but want to
* verify boot/recovery with AVB */
AvbABFlowResult avb_single_flow(AvbABOps* ab_ops,
- const char* const* requested_partitions,
- AvbSlotVerifyFlags flags,
- AvbHashtreeErrorMode hashtree_error_mode,
- AvbSlotVerifyData** out_data);
+ const char* const* requested_partitions,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data);
+
+/* Avb verify flow for dual bootloader, only the slot chosen by SPL will
+ * be verified.
+ */
+AvbABFlowResult avb_flow_dual_uboot(AvbABOps* ab_ops,
+ const char* const* requested_partitions,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data);
/* Program ATX perm_attr into RPMB partition */
int avb_atx_fuse_perm_attr(uint8_t *staged_buffer, uint32_t size);
diff --git a/include/part.h b/include/part.h
index 5678dab3f5..b39800b1f3 100644
--- a/include/part.h
+++ b/include/part.h
@@ -250,7 +250,8 @@ static inline int blk_get_device_part_str(const char *ifname,
#ifdef CONFIG_SPL_BUILD
# define part_print_ptr(x) NULL
# if defined(CONFIG_SPL_EXT_SUPPORT) || defined(CONFIG_SPL_FAT_SUPPORT) || \
- defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION)
+ defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) || \
+ defined(CONFIG_DUAL_BOOTLOADER)
# define part_get_info_ptr(x) x
# else
# define part_get_info_ptr(x) NULL
diff --git a/lib/Kconfig b/lib/Kconfig
index 400e9d79b7..309d2abb2f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -122,6 +122,11 @@ config RBTREE
config BITREVERSE
bool "Bit reverse library from Linux"
+config DUAL_BOOTLOADER
+ bool "Enable dual bootloader support"
+ help
+ Enable A/B bootloader select in SPL.
+
source lib/dhry/Kconfig
menu "Security support"
diff --git a/lib/Makefile b/lib/Makefile
index 8038041193..3685d75766 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
obj-$(CONFIG_ARCH_AT91) += at91/
obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/
obj-$(CONFIG_AES) += aes.o
-obj-$(CONFIG_AVB_SUPPORT) += avb/
obj-y += charset.o
obj-$(CONFIG_USB_TTY) += circbuf.o
obj-y += crc7.o
@@ -50,6 +49,7 @@ endif
obj-$(CONFIG_RSA) += rsa/
obj-$(CONFIG_SHA1) += sha1.o
obj-$(CONFIG_SHA256) += sha256.o
+obj-$(CONFIG_AVB_SUPPORT) += avb/
obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
diff --git a/lib/avb/Makefile b/lib/avb/Makefile
index bb96ad14da..6d9bc7ed4f 100644
--- a/lib/avb/Makefile
+++ b/lib/avb/Makefile
@@ -10,7 +10,10 @@ subdir-ccflags-y += -I./lib/avb \
-Wno-unused-parameter \
-ffunction-sections \
-std=gnu99
-obj-y += libavb/
+
+ifndef CONFIG_SPL_BUILD
obj-y += libavb_ab/
obj-$(CONFIG_AVB_ATX) += libavb_atx/
+endif
+obj-y += libavb/
obj-y += fsl/
diff --git a/lib/avb/fsl/Makefile b/lib/avb/fsl/Makefile
index 990d62fe26..be3d904e33 100644
--- a/lib/avb/fsl/Makefile
+++ b/lib/avb/fsl/Makefile
@@ -1,7 +1,11 @@
ccflags-y += -Werror
+
+ifndef CONFIG_SPL_BUILD
obj-y += fsl_avb.o
obj-y += fsl_avbkey.o
obj-y += fsl_bootctl.o
-obj-y += fsl_avb_ab_flow.o
obj-y += fsl_avb_sysdeps_uboot.o
+endif
+
obj-y += utils.o
+obj-y += fsl_avb_ab_flow.o
diff --git a/lib/avb/fsl/fsl_avb_ab_flow.c b/lib/avb/fsl/fsl_avb_ab_flow.c
index d82525670e..5d91711ca4 100644
--- a/lib/avb/fsl/fsl_avb_ab_flow.c
+++ b/lib/avb/fsl/fsl_avb_ab_flow.c
@@ -4,13 +4,19 @@
#include <common.h>
#include <fsl_avb.h>
+#include <mmc.h>
+#include <spl.h>
+#include <part.h>
+#include <image.h>
+#include "utils.h"
+#if defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
static const char* slot_suffixes[2] = {"_a", "_b"};
/* This is a copy of slot_set_unbootable() form
- * lib/avb/libavb_ab/avb_ab_flow.c.
+ * external/avb/libavb_ab/avb_ab_flow.c.
*/
-static void fsl_slot_set_unbootable(AvbABSlotData* slot) {
+void fsl_slot_set_unbootable(AvbABSlotData* slot) {
slot->priority = 0;
slot->tries_remaining = 0;
slot->successful_boot = 0;
@@ -18,10 +24,10 @@ static void fsl_slot_set_unbootable(AvbABSlotData* slot) {
/* Ensure all unbootable and/or illegal states are marked as the
* canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
- * and successful_boot=0. This is a copy of fsl_slot_normalize from
- * lib/avb/libavb_ab/avb_ab_flow.c.
+ * and successful_boot=0. This is a copy of slot_normalize from
+ * external/avb/libavb_ab/avb_ab_flow.c.
*/
-static void fsl_slot_normalize(AvbABSlotData* slot) {
+void fsl_slot_normalize(AvbABSlotData* slot) {
if (slot->priority > 0) {
if ((slot->tries_remaining == 0) && (!slot->successful_boot)) {
/* We've exhausted all tries -> unbootable. */
@@ -38,9 +44,279 @@ static void fsl_slot_normalize(AvbABSlotData* slot) {
}
}
-/* Writes A/B metadata to disk only if it has changed - returns
- * AVB_IO_RESULT_OK on success, error code otherwise. This is a
- * copy of save_metadata_if_changed form lib/avb/libavb_ab/avb_ab_flow.c.
+/* This is a copy of slot_is_bootable() from
+ * externel/avb/libavb_ab/avb_ab_flow.c.
+ */
+bool fsl_slot_is_bootable(AvbABSlotData* slot) {
+ return (slot->priority > 0) &&
+ (slot->successful_boot || (slot->tries_remaining > 0));
+}
+#endif /* CONFIG_DUAL_BOOTLOADER || !CONFIG_SPL_BUILD */
+
+#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD)
+
+#define FSL_AB_METADATA_MISC_PARTITION_OFFSET 2048
+#define PARTITION_NAME_LEN 13
+#define PARTITION_MISC "misc"
+#define PARTITION_BOOTLOADER "bootloader"
+
+/* Pre-declaration of h_spl_load_read(), see detail implementation in
+ * common/spl/spl_mmc.c.
+ */
+ulong h_spl_load_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf);
+
+void fsl_avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
+ AvbABData* dest) {
+ memcpy(dest, src, sizeof(AvbABData));
+ dest->crc32 = cpu_to_be32(
+ avb_crc32((const uint8_t*)dest,
+ sizeof(AvbABData) - sizeof(uint32_t)));
+}
+
+void fsl_avb_ab_data_init(AvbABData* data) {
+ memset(data, '\0', sizeof(AvbABData));
+ memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
+ data->version_major = AVB_AB_MAJOR_VERSION;
+ data->version_minor = AVB_AB_MINOR_VERSION;
+ data->slots[0].priority = AVB_AB_MAX_PRIORITY;
+ data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+ data->slots[0].successful_boot = 0;
+ data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
+ data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+ data->slots[1].successful_boot = 0;
+}
+
+bool fsl_avb_ab_data_verify_and_byteswap(const AvbABData* src,
+ AvbABData* dest) {
+ /* Ensure magic is correct. */
+ if (memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
+ printf("Magic is incorrect.\n");
+ return false;
+ }
+
+ memcpy(dest, src, sizeof(AvbABData));
+ dest->crc32 = be32_to_cpu(dest->crc32);
+
+ /* Ensure we don't attempt to access any fields if the major version
+ * is not supported.
+ */
+ if (dest->version_major > AVB_AB_MAJOR_VERSION) {
+ printf("No support for given major version.\n");
+ return false;
+ }
+
+ /* Fail if CRC32 doesn't match. */
+ if (dest->crc32 !=
+ avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
+ printf("CRC32 does not match.\n");
+ return false;
+ }
+
+ return true;
+}
+
+/* Writes A/B metadata to disk only if it has changed.
+ */
+int fsl_save_metadata_if_changed_dual_uboot(struct blk_desc *dev_desc,
+ AvbABData* ab_data,
+ AvbABData* ab_data_orig) {
+ AvbABData serialized;
+ size_t num_bytes;
+ disk_partition_t info;
+
+ /* Save metadata if changed. */
+ if (memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
+ /* Get misc partition info */
+ if (part_get_info_by_name(dev_desc, PARTITION_MISC, &info) == -1) {
+ printf("Can't get partition info of partition: misc\n");
+ return -1;
+ }
+
+ /* Writing A/B metadata to disk. */
+ fsl_avb_ab_data_update_crc_and_byteswap(ab_data, &serialized);
+ if (write_to_partition_in_bytes(dev_desc, &info,
+ FSL_AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ (void *)&serialized, &num_bytes) ||
+ (num_bytes != sizeof(AvbABData))) {
+ printf("Error--write metadata fail!\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Load metadate from misc partition.
+ */
+int fsl_load_metadata_dual_uboot(struct blk_desc *dev_desc,
+ AvbABData* ab_data,
+ AvbABData* ab_data_orig) {
+ disk_partition_t info;
+ AvbABData serialized;
+ size_t num_bytes;
+
+ if (part_get_info_by_name(dev_desc, PARTITION_MISC, &info) == -1) {
+ printf("Can't get partition info of partition: misc\n");
+ return -1;
+ } else {
+ read_from_partition_in_bytes(
+ dev_desc, &info, FSL_AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ (void *)ab_data, &num_bytes );
+ if (num_bytes != sizeof(AvbABData)) {
+ printf("Error--read metadata fail!\n");
+ return -1;
+ } else {
+ if (!fsl_avb_ab_data_verify_and_byteswap(ab_data, &serialized)) {
+ printf("Error validating A/B metadata from disk.\n");
+ printf("Resetting and writing new A/B metadata to disk.\n");
+ fsl_avb_ab_data_init(ab_data);
+ fsl_avb_ab_data_update_crc_and_byteswap(ab_data, &serialized);
+ num_bytes = 0;
+ if (write_to_partition_in_bytes(
+ dev_desc, &info,
+ FSL_AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ (void *)&serialized, &num_bytes) ||
+ (num_bytes != sizeof(AvbABData))) {
+ printf("Error--write metadata fail!\n");
+ return -1;
+ } else
+ return 0;
+ } else {
+ memcpy(ab_data_orig, ab_data, sizeof(AvbABData));
+ /* Ensure data is normalized, e.g. illegal states will be marked as
+ * unbootable and all unbootable states are represented with
+ * (priority=0, tries_remaining=0, successful_boot=0).
+ */
+ fsl_slot_normalize(&ab_data->slots[0]);
+ fsl_slot_normalize(&ab_data->slots[1]);
+ return 0;
+ }
+ }
+ }
+}
+
+int mmc_load_image_raw_sector_dual_uboot(
+ struct spl_image_info *spl_image, struct mmc *mmc)
+{
+ unsigned long count;
+ disk_partition_t info;
+ int ret = 0, n = 0;
+ char partition_name[PARTITION_NAME_LEN];
+ struct blk_desc *dev_desc;
+ struct image_header *header;
+ AvbABData ab_data, ab_data_orig;
+ size_t slot_index_to_boot, target_slot;
+
+ /* Check if gpt is valid */
+ dev_desc = mmc_get_blk_desc(mmc);
+ if (dev_desc) {
+ if (part_get_info(dev_desc, 1, &info)) {
+ printf("GPT is invalid, please flash correct GPT!\n");
+ ret = -EIO;
+ goto end;
+ }
+ } else {
+ printf("Get block desc fail!\n");
+ ret = -EIO;
+ goto end;
+ }
+
+ /* Load AB metadata from misc partition */
+ if (fsl_load_metadata_dual_uboot(dev_desc, &ab_data,
+ &ab_data_orig)) {
+ ret = -1;
+ goto end;
+ }
+
+ slot_index_to_boot = 2; // Means not 0 or 1
+ target_slot =
+ (ab_data.slots[1].priority > ab_data.slots[0].priority) ? 1 : 0;
+
+ for (n = 0; n < 2; n++) {
+ if (!fsl_slot_is_bootable(&ab_data.slots[target_slot])) {
+ target_slot = (target_slot == 1 ? 0 : 1);
+ continue;
+ }
+ /* Choose slot to load. */
+ snprintf(partition_name, PARTITION_NAME_LEN,
+ PARTITION_BOOTLOADER"%s",
+ slot_suffixes[target_slot]);
+
+ /* Read part info from gpt */
+ if (part_get_info_by_name(dev_desc, partition_name, &info) == -1) {
+ printf("Can't get partition info of partition bootloader%s\n",
+ slot_suffixes[target_slot]);
+ } else {
+ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+ sizeof(struct image_header));
+
+ /* read image header to find the image size & load address */
+ count = blk_dread(dev_desc, info.start, 1, header);
+ if (count == 0) {
+ ret = -EIO;
+ goto end;
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.dev = mmc;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = mmc->read_bl_len;
+ load.read = h_spl_load_read;
+ ret = spl_load_simple_fit(spl_image, &load,
+ info.start, header);
+ } else {
+ ret = -1;
+ }
+ }
+
+ /* Set current slot to unbootable if load/verify fail. */
+ if (ret != 0) {
+ printf("Load or verify bootloader%s fail, setting unbootable..\n",
+ slot_suffixes[target_slot]);
+ fsl_slot_set_unbootable(&ab_data.slots[target_slot]);
+ /* Switch to another slot. */
+ target_slot = (target_slot == 1 ? 0 : 1);
+ } else {
+ slot_index_to_boot = target_slot;
+ n = 2;
+ }
+ }
+
+ if (slot_index_to_boot == 2) {
+ /* No bootable slots! */
+ printf("No bootable slots found.\n");
+ ret = -1;
+ goto end;
+ } else if (!ab_data.slots[slot_index_to_boot].successful_boot &&
+ (ab_data.slots[slot_index_to_boot].tries_remaining > 0)) {
+ ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
+ }
+ printf("Booting from bootloader%s...\n", slot_suffixes[slot_index_to_boot]);
+
+end:
+ /* Save metadata if changed. */
+ if (fsl_save_metadata_if_changed_dual_uboot(dev_desc, &ab_data, &ab_data_orig)) {
+ ret = -1;
+ }
+
+ if (ret)
+ return -1;
+ else
+ return 0;
+}
+
+/* For normal build */
+#elif !defined(CONFIG_SPL_BUILD)
+
+/* Writes A/B metadata to disk only if it has been changed.
*/
static AvbIOResult fsl_save_metadata_if_changed(AvbABOps* ab_ops,
AvbABData* ab_data,
@@ -52,14 +328,6 @@ static AvbIOResult fsl_save_metadata_if_changed(AvbABOps* ab_ops,
return AVB_IO_RESULT_OK;
}
-/* This is a copy of slot_is_bootable() from
- * lib/avb/libavb_ab/avb_ab_flow.c.
- */
-static bool fsl_slot_is_bootable(AvbABSlotData* slot) {
- return (slot->priority > 0) &&
- (slot->successful_boot || (slot->tries_remaining > 0));
-}
-
/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
* success, error code otherwise. This is a copy of load_metadata()
* from /lib/avb/libavb_ab/avb_ab_flow.c.
@@ -396,3 +664,5 @@ out:
return ret;
}
+
+#endif /* CONFIG_DUAL_BOOTLOADER && CONFIG_SPL_BUILD */
diff --git a/lib/avb/fsl/utils.c b/lib/avb/fsl/utils.c
index 6416fa971e..d3b4254b55 100644
--- a/lib/avb/fsl/utils.c
+++ b/lib/avb/fsl/utils.c
@@ -1,6 +1,6 @@
/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
-+ * Copyright 2017 NXP
++ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
@@ -10,9 +10,13 @@
#include "debug.h"
#include "utils.h"
-/* get margin_pos struct from offset [to the partition start/end] and num_bytes to read/write */
+/*
+ * get margin_pos struct from offset [to the partition start/end] and
+ * num_bytes to read/write
+ */
int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
- margin_pos_t *margin, int64_t offset, size_t num_bytes, bool allow_partial) {
+ margin_pos_t *margin, int64_t offset, size_t num_bytes,
+ bool allow_partial) {
long off;
if (margin == NULL)
return -1;
@@ -22,21 +26,27 @@ int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
if (offset < 0) {
margin->blk_start = (offset + 1) / (uint64_t)blksz + part_end;
- margin->start = (off = offset % (uint64_t)blksz) == 0 ? 0 : blksz + off; // offset == -1 means the last byte?, or start need -1
+ // offset == -1 means the last byte?, or start need -1
+ margin->start = (off = offset % (uint64_t)blksz) == 0 ?
+ 0 : blksz + off;
if (offset + num_bytes - 1 >= 0) {
if (!allow_partial)
return -1;
margin->blk_end = part_end;
margin->end = blksz - 1;
} else {
- margin->blk_end = (num_bytes + offset) / (uint64_t)blksz + part_end; // which blk the last byte is in
- margin->end = (off = (num_bytes + offset - 1) % (uint64_t)blksz) == 0 ?
- 0 : blksz + off; // last byte
+ // which blk the last byte is in
+ margin->blk_end = (num_bytes + offset) /
+ (uint64_t)blksz + part_end;
+ margin->end = (off = (num_bytes + offset - 1) %
+ (uint64_t)blksz) == 0 ?
+ 0 : blksz + off; // last byte
}
} else {
margin->blk_start = offset / (uint64_t)blksz + part_start;
margin->start = offset % (uint64_t)blksz;
- margin->blk_end = (offset + num_bytes - 1) / (uint64_t)blksz + part_start ;
+ margin->blk_end = ((offset + num_bytes - 1) / (uint64_t)blksz) +
+ part_start ;
margin->end = (offset + num_bytes - 1) % (uint64_t)blksz;
if (margin->blk_end > part_end) {
if (!allow_partial)
@@ -46,7 +56,7 @@ int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
}
}
VDEBUG("bs=%ld, be=%ld, s=%ld, e=%ld\n",
- margin->blk_start, margin->blk_end, margin->start, margin->end);
+ margin->blk_start, margin->blk_end, margin->start, margin->end);
if (margin->blk_start > part_end || margin->blk_start < part_start)
return -1;
@@ -56,3 +66,151 @@ int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
VDEBUG("bm=%ld\n", margin->multi);
return 0;
}
+
+int read_from_partition_in_bytes(struct blk_desc *fs_dev_desc,
+ disk_partition_t *info, int64_t offset,
+ size_t num_bytes, void* buffer,
+ size_t* out_num_read)
+{
+ unsigned char *bdata;
+ unsigned char *out_buf = (unsigned char *)buffer;
+ unsigned char *dst, *dst64 = NULL;
+ unsigned long blksz;
+ unsigned long s, cnt;
+ size_t num_read = 0;
+ lbaint_t part_start, part_end, bs, be, bm, blk_num;
+ margin_pos_t margin;
+ int ret;
+
+ if(buffer == NULL || out_num_read == NULL) {
+ printf("NULL pointer error!\n");
+ return -1;
+ }
+
+ blksz = fs_dev_desc->blksz;
+ part_start = info->start;
+ part_end = info->start + info->size - 1;
+
+ if (get_margin_pos((uint64_t)part_start, (uint64_t)part_end, blksz,
+ &margin, offset, num_bytes, true))
+ return -1;
+
+ bs = (lbaint_t)margin.blk_start;
+ be = (lbaint_t)margin.blk_end;
+ s = margin.start;
+ bm = margin.multi;
+
+ /* alloc a blksz mem */
+ bdata = (unsigned char *)memalign(ALIGN_BYTES, blksz);
+ if (bdata == NULL) {
+ printf("Failed to allocate memory!\n");
+ return -1;
+ }
+
+ /* support multi blk read */
+ while (bs <= be) {
+ if (!s && bm > 1) {
+ dst = out_buf;
+ /* for mmc blk read alignment */
+ dst64 = PTR_ALIGN(out_buf, 64);
+ if (dst64 != dst) {
+ dst = dst64;
+ bm--;
+ }
+ blk_num = bm;
+ cnt = bm * blksz;
+ bm = 0; /* no more multi blk */
+ } else {
+ blk_num = 1;
+ cnt = blksz - s;
+ if (num_read + cnt > num_bytes)
+ cnt = num_bytes - num_read;
+ dst = bdata;
+ }
+ if (!blk_dread(fs_dev_desc, bs, blk_num, dst)) {
+ ret = -1;
+ goto fail;
+ }
+
+ if (dst == bdata)
+ memcpy(out_buf, bdata + s, cnt);
+ else if (dst == dst64)
+ memcpy(out_buf, dst, cnt); /* internal copy */
+
+ s = 0;
+ bs += blk_num;
+ num_read += cnt;
+ out_buf += cnt;
+ }
+ *out_num_read = num_read;
+ ret = 0;
+
+fail:
+ free(bdata);
+ return ret;
+}
+
+int write_to_partition_in_bytes(struct blk_desc *fs_dev_desc,
+ disk_partition_t *info, int64_t offset,
+ size_t num_bytes,
+ void* buffer, size_t *out_num_write)
+{
+ unsigned char *bdata;
+ unsigned char *in_buf = (unsigned char *)buffer;
+ unsigned long blksz;
+ unsigned long s, cnt;
+ size_t num_write = 0;
+ lbaint_t part_start, part_end, bs;
+ margin_pos_t margin;
+ int ret;
+
+ if(buffer == NULL || out_num_write == NULL) {
+ printf("NULL pointer error!\n");
+ return -1;
+ }
+
+ blksz = fs_dev_desc->blksz;
+ part_start = info->start;
+ part_end = info->start + info->size - 1;
+
+ if(get_margin_pos((uint64_t)part_start, (uint64_t)part_end, blksz,
+ &margin, offset, num_bytes, false))
+ return -1;
+
+ bs = (lbaint_t)margin.blk_start;
+ s = margin.start;
+
+ // alloc a blksz mem
+ bdata = (unsigned char *)memalign(ALIGN_BYTES, blksz);
+ if (bdata == NULL)
+ return -1;
+
+ while (num_write < num_bytes) {
+ memset(bdata, 0, blksz);
+ cnt = blksz - s;
+ if (num_write + cnt > num_bytes)
+ cnt = num_bytes - num_write;
+ if (!s || cnt != blksz) { //read blk first
+ if (!blk_dread(fs_dev_desc, bs, 1,
+ bdata)) {
+ ret = -1;
+ goto fail;
+ }
+ }
+ memcpy(bdata + s, in_buf, cnt); //change data
+ if (!blk_dwrite(fs_dev_desc, bs, 1, bdata)) {
+ ret = -1;
+ goto fail;
+ }
+ bs++;
+ num_write += cnt;
+ in_buf += cnt;
+ s = 0;
+ }
+ *out_num_write = num_write;
+ ret = 0;
+
+fail:
+ free(bdata);
+ return ret;
+}
diff --git a/lib/avb/fsl/utils.h b/lib/avb/fsl/utils.h
index 8100e77be4..698aec0dc3 100644
--- a/lib/avb/fsl/utils.h
+++ b/lib/avb/fsl/utils.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright 2017 NXP
+ * Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -26,6 +26,17 @@ struct margin_pos {
typedef struct margin_pos margin_pos_t;
int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
- margin_pos_t *margin, int64_t offset, size_t num_bytes, bool allow_partial);
+ margin_pos_t *margin, int64_t offset, size_t num_bytes,
+ bool allow_partial);
+
+int read_from_partition_in_bytes(struct blk_desc *fs_dev_desc,
+ disk_partition_t *info,
+ int64_t offset, size_t num_bytes,
+ void* buffer, size_t* out_num_read);
+
+int write_to_partition_in_bytes(struct blk_desc *fs_dev_desc,
+ disk_partition_t *info, int64_t offset,
+ size_t num_bytes, void* buffer,
+ size_t *out_num_write);
#endif
diff --git a/lib/avb/libavb/Makefile b/lib/avb/libavb/Makefile
index f09c0d4bc6..7d4ae8e88f 100644
--- a/lib/avb/libavb/Makefile
+++ b/lib/avb/libavb/Makefile
@@ -1,17 +1,21 @@
ccflags-y += -DAVB_COMPILATION
+
+ifndef CONFIG_SPL_BUILD
obj-y += avb_descriptor.o \
- avb_kernel_cmdline_descriptor.o \
- avb_sha512.o \
- avb_vbmeta_image.o \
- avb_chain_partition_descriptor.o \
- avb_footer.o \
- avb_property_descriptor.o \
- avb_slot_verify.o \
- avb_crc32.o \
- avb_hash_descriptor.o \
- avb_rsa.o \
- avb_crypto.o \
- avb_hashtree_descriptor.o \
- avb_sha256.o \
- avb_util.o \
- avb_cmdline.o
+ avb_kernel_cmdline_descriptor.o \
+ avb_sha512.o \
+ avb_vbmeta_image.o \
+ avb_chain_partition_descriptor.o \
+ avb_footer.o \
+ avb_property_descriptor.o \
+ avb_slot_verify.o \
+ avb_hash_descriptor.o \
+ avb_rsa.o \
+ avb_crypto.o \
+ avb_hashtree_descriptor.o \
+ avb_sha256.o \
+ avb_util.o \
+ avb_cmdline.o
+endif
+
+obj-y += avb_crc32.o