diff options
author | Luo Ji <ji.luo@nxp.com> | 2018-06-08 10:31:11 +0800 |
---|---|---|
committer | Luo Ji <ji.luo@nxp.com> | 2018-07-06 15:48:48 +0800 |
commit | 315674c6100bc2f97cd9f7e82031dee2e0e2f621 (patch) | |
tree | ebfb38d49949c7d0e2ab5ce7754575d841787e59 | |
parent | a789184b56157c289fee55ed65c56f5ac993ded3 (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.c | 25 | ||||
-rw-r--r-- | configs/mx8mq_evk_androidthings_defconfig | 1 | ||||
-rw-r--r-- | configs/mx8mq_phanbell_androidthings_defconfig | 1 | ||||
-rw-r--r-- | disk/part_efi.c | 35 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 4 | ||||
-rw-r--r-- | drivers/mmc/mmc_private.h | 6 | ||||
-rw-r--r-- | include/configs/imx8mq_evk.h | 1 | ||||
-rw-r--r-- | include/configs/imx8mq_phanbell.h | 1 | ||||
-rw-r--r-- | include/fsl_avb.h | 64 | ||||
-rw-r--r-- | include/part.h | 3 | ||||
-rw-r--r-- | lib/Kconfig | 5 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/avb/Makefile | 5 | ||||
-rw-r--r-- | lib/avb/fsl/Makefile | 6 | ||||
-rw-r--r-- | lib/avb/fsl/fsl_avb_ab_flow.c | 302 | ||||
-rw-r--r-- | lib/avb/fsl/utils.c | 176 | ||||
-rw-r--r-- | lib/avb/fsl/utils.h | 15 | ||||
-rw-r--r-- | lib/avb/libavb/Makefile | 34 |
18 files changed, 606 insertions, 80 deletions
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 18c1b59b22..92fcf575db 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,6 +54,13 @@ 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 int mmc_load_image_raw_sector(struct spl_image_info *spl_image, struct mmc *mmc, unsigned long sector) { @@ -96,6 +105,8 @@ end: return 0; } +#endif /* CONFIG_DUAL_BOOTLOADER */ + int spl_mmc_get_device_index(u32 boot_device) { switch (boot_device) { @@ -309,10 +320,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); @@ -341,8 +357,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, CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); +#endif if (!err) return err; #endif diff --git a/configs/mx8mq_evk_androidthings_defconfig b/configs/mx8mq_evk_androidthings_defconfig index 2928928b16..6020605fa7 100644 --- a/configs/mx8mq_evk_androidthings_defconfig +++ b/configs/mx8mq_evk_androidthings_defconfig @@ -39,3 +39,4 @@ CONFIG_SPL_FIT=y CONFIG_SPL_LOAD_FIT=y CONFIG_CMD_FASTBOOT=y CONFIG_ANDROID_BOOT_IMAGE=y +CONFIG_SPL_LIBDISK_SUPPORT=y diff --git a/configs/mx8mq_phanbell_androidthings_defconfig b/configs/mx8mq_phanbell_androidthings_defconfig index 3d0bfce5e3..32a4282c90 100644 --- a/configs/mx8mq_phanbell_androidthings_defconfig +++ b/configs/mx8mq_phanbell_androidthings_defconfig @@ -39,3 +39,4 @@ CONFIG_SPL_LOAD_FIT=y CONFIG_FASTBOOT=y CONFIG_CMD_FASTBOOT=y CONFIG_ANDROID_BOOT_IMAGE=y +CONFIG_SPL_LIBDISK_SUPPORT=y diff --git a/disk/part_efi.c b/disk/part_efi.c index 8bc6f39f4d..788860fcc7 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -246,8 +246,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; } @@ -282,7 +284,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; } @@ -309,8 +313,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; } @@ -916,10 +926,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; } @@ -953,10 +970,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) { @@ -964,13 +990,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/drivers/mmc/Makefile b/drivers/mmc/Makefile index 8e922db3f1..eaea8c3de8 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -44,7 +44,11 @@ obj-$(CONFIG_SH_SDHI) += sh_sdhi.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o +ifdef CONFIG_DUAL_BOOTLOADER +obj-y += mmc_write.o +else obj-$(CONFIG_SPL_SAVEENV) += mmc_write.o +endif else obj-$(CONFIG_GENERIC_MMC) += mmc_write.o endif diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index 03bf24d5fe..6fb680d3e5 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -56,7 +56,7 @@ static inline ulong mmc_bwrite(struct udevice *dev, lbaint_t start, { return 0; } -#else +#elif !defined(CONFIG_DUAL_BOOTLOADER) static inline unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) { @@ -68,6 +68,10 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, { return 0; } +#else /* CONFIG_DUAL_BOOTLOADER && !CONFIG_BLK*/ +ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, + const void *src); +ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt); #endif #endif /* CONFIG_SPL_BUILD */ diff --git a/include/configs/imx8mq_evk.h b/include/configs/imx8mq_evk.h index 617fabb5a9..d1617134dc 100644 --- a/include/configs/imx8mq_evk.h +++ b/include/configs/imx8mq_evk.h @@ -40,6 +40,7 @@ #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/configs/imx8mq_phanbell.h b/include/configs/imx8mq_phanbell.h index ed54133df9..a422973db1 100644 --- a/include/configs/imx8mq_phanbell.h +++ b/include/configs/imx8mq_phanbell.h @@ -41,6 +41,7 @@ #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 c459dfe665..30e9c1000f 100644 --- a/include/part.h +++ b/include/part.h @@ -213,7 +213,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 1295a9b12a..657f792c81 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -55,6 +55,11 @@ config LIB_RAND config AVB_ATX bool "Enable AVB_ATX support" +config DUAL_BOOTLOADER + bool "Enable dual bootloader support" + help + Enable A/B bootloader select in SPL. + source lib/dhry/Kconfig source lib/rsa/Kconfig diff --git a/lib/Makefile b/lib/Makefile index 2927591c80..ca1c5236d0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ obj-$(CONFIG_FIT) += libfdt/ obj-$(CONFIG_CMD_DHRYSTONE) += dhry/ -obj-$(CONFIG_AVB_SUPPORT) += avb/ obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/ obj-$(CONFIG_AES) += aes.o obj-$(CONFIG_USB_TTY) += circbuf.o @@ -48,6 +47,7 @@ endif obj-$(CONFIG_$(SPL_)RSA) += rsa/ obj-$(CONFIG_$(SPL_)SHA1) += sha1.o obj-$(CONFIG_$(SPL_)SHA256) += sha256.o +obj-$(CONFIG_AVB_SUPPORT) += avb/ obj-$(CONFIG_SPL_SAVEENV) += qsort.o obj-$(CONFIG_$(SPL_)OF_LIBFDT) += libfdt/ 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..e1bb3fb08d 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)) { + 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)) { + 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)) { + 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..1cfe9df295 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 (!fs_dev_desc->block_read(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 (!fs_dev_desc->block_read(fs_dev_desc, bs, 1, + bdata)) { + ret = -1; + goto fail; + } + } + memcpy(bdata + s, in_buf, cnt); //change data + if (!fs_dev_desc->block_write(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 |