[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>
This commit is contained in:
parent
4cfd7437ac
commit
dbcf1e3cc0
|
|
@ -4,6 +4,8 @@
|
||||||
*
|
*
|
||||||
* Aneesh V <aneesh@ti.com>
|
* Aneesh V <aneesh@ti.com>
|
||||||
*
|
*
|
||||||
|
* Copyright 2018 NXP
|
||||||
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
*/
|
*/
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
@ -18,7 +20,7 @@
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
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)
|
ulong sector, struct image_header *header)
|
||||||
{
|
{
|
||||||
u32 image_size_sectors;
|
u32 image_size_sectors;
|
||||||
|
|
@ -44,7 +46,7 @@ static int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc,
|
||||||
return 0;
|
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)
|
ulong count, void *buf)
|
||||||
{
|
{
|
||||||
struct mmc *mmc = load->dev;
|
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);
|
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
|
static __maybe_unused
|
||||||
int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
|
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 -
|
struct image_header *header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
|
||||||
sizeof(struct image_header));
|
sizeof(struct image_header));
|
||||||
|
|
@ -98,6 +106,8 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_DUAL_BOOTLOADER */
|
||||||
|
|
||||||
static int spl_mmc_get_device_index(u32 boot_device)
|
static int spl_mmc_get_device_index(u32 boot_device)
|
||||||
{
|
{
|
||||||
switch (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
|
* 1 and 2 match up to boot0 / boot1 and 7 is user data
|
||||||
* which is the first physical partition (0).
|
* 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;
|
part = (mmc->part_config >> 3) & PART_ACCESS_MASK;
|
||||||
|
|
||||||
if (part == 7)
|
if (part == 7)
|
||||||
part = 0;
|
part = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (CONFIG_IS_ENABLED(MMC_TINY))
|
if (CONFIG_IS_ENABLED(MMC_TINY))
|
||||||
err = mmc_switch_part(mmc, part);
|
err = mmc_switch_part(mmc, part);
|
||||||
|
|
@ -361,8 +376,13 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
|
||||||
return err;
|
return err;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
|
#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,
|
err = mmc_load_image_raw_sector(spl_image, mmc,
|
||||||
spl_mmc_get_uboot_raw_sector(mmc));
|
spl_mmc_get_uboot_raw_sector(mmc));
|
||||||
|
#endif
|
||||||
if (!err)
|
if (!err)
|
||||||
return err;
|
return err;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,4 @@ CONFIG_USB_XHCI_IMX8M=y
|
||||||
CONFIG_USB_XHCI_DWC3=y
|
CONFIG_USB_XHCI_DWC3=y
|
||||||
CONFIG_USB_DWC3=y
|
CONFIG_USB_DWC3=y
|
||||||
CONFIG_USB_DWC3_GADGET=y
|
CONFIG_USB_DWC3_GADGET=y
|
||||||
|
CONFIG_SPL_LIBDISK_SUPPORT=y
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,9 @@ CONFIG_DM_THERMAL=y
|
||||||
CONFIG_FIT=y
|
CONFIG_FIT=y
|
||||||
CONFIG_SPL_FIT=y
|
CONFIG_SPL_FIT=y
|
||||||
CONFIG_SPL_LOAD_FIT=y
|
CONFIG_SPL_LOAD_FIT=y
|
||||||
|
CONFIG_SPL_MMC_SUPPORT=y
|
||||||
|
CONFIG_SPL_MMC_WRITE=y
|
||||||
CONFIG_USB=y
|
CONFIG_USB=y
|
||||||
CONFIG_DM_USB=y
|
CONFIG_DM_USB=y
|
||||||
CONFIG_ANDROID_BOOT_IMAGE=y
|
CONFIG_ANDROID_BOOT_IMAGE=y
|
||||||
|
CONFIG_SPL_LIBDISK_SUPPORT=y
|
||||||
|
|
|
||||||
|
|
@ -280,8 +280,10 @@ void part_print_efi(struct blk_desc *dev_desc)
|
||||||
printf("\tguid:\t%s\n", uuid);
|
printf("\tguid:\t%s\n", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
|
||||||
/* Remember to free pte */
|
/* Remember to free pte */
|
||||||
free(gpt_pte);
|
free(gpt_pte);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,7 +318,9 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
|
||||||
!is_pte_valid(&gpt_pte[part - 1])) {
|
!is_pte_valid(&gpt_pte[part - 1])) {
|
||||||
debug("%s: *** ERROR: Invalid partition number %d ***\n",
|
debug("%s: *** ERROR: Invalid partition number %d ***\n",
|
||||||
__func__, part);
|
__func__, part);
|
||||||
|
#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
|
||||||
free(gpt_pte);
|
free(gpt_pte);
|
||||||
|
#endif
|
||||||
return -1;
|
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__,
|
debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__,
|
||||||
info->start, info->size, info->name);
|
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);
|
free(gpt_pte);
|
||||||
|
#endif
|
||||||
return 0;
|
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 (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);
|
free(*pgpt_pte);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're done, all's well */
|
/* We're done, all's well */
|
||||||
return 1;
|
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),
|
(u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
|
||||||
(ulong)count);
|
(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 (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,
|
pte = memalign(ARCH_DMA_MINALIGN,
|
||||||
PAD_TO_BLOCKSIZE(count, dev_desc));
|
PAD_TO_BLOCKSIZE(count, dev_desc));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0 || pte == NULL) {
|
if (count == 0 || pte == NULL) {
|
||||||
|
|
@ -1087,13 +1113,14 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
|
||||||
__func__, (ulong)count);
|
__func__, (ulong)count);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read GPT Entries from device */
|
/* Read GPT Entries from device */
|
||||||
blk = le64_to_cpu(pgpt_head->partition_entry_lba);
|
blk = le64_to_cpu(pgpt_head->partition_entry_lba);
|
||||||
blk_cnt = BLOCK_CNT(count, dev_desc);
|
blk_cnt = BLOCK_CNT(count, dev_desc);
|
||||||
if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
|
if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
|
||||||
printf("*** ERROR: Can't read GPT Entries ***\n");
|
printf("*** ERROR: Can't read GPT Entries ***\n");
|
||||||
|
#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
|
||||||
free(pte);
|
free(pte);
|
||||||
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return pte;
|
return pte;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
|
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
|
||||||
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
|
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
|
||||||
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x6000 /* 24 KB */
|
#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_ICACHE_OFF
|
||||||
#define CONFIG_SYS_DCACHE_OFF
|
#define CONFIG_SYS_DCACHE_OFF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,11 @@
|
||||||
#define CONFIG_SPL_LIBGENERIC_SUPPORT
|
#define CONFIG_SPL_LIBGENERIC_SUPPORT
|
||||||
#define CONFIG_SPL_SERIAL_SUPPORT
|
#define CONFIG_SPL_SERIAL_SUPPORT
|
||||||
#define CONFIG_SPL_GPIO_SUPPORT
|
#define CONFIG_SPL_GPIO_SUPPORT
|
||||||
#define CONFIG_SPL_MMC_SUPPORT
|
|
||||||
#define CONFIG_SPL_BSS_START_ADDR 0x00180000
|
#define CONFIG_SPL_BSS_START_ADDR 0x00180000
|
||||||
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
|
#define CONFIG_SPL_BSS_MAX_SIZE 0x2000 /* 8 KB */
|
||||||
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
|
#define CONFIG_SYS_SPL_MALLOC_START 0x00182000
|
||||||
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x2000 /* 8 KB */
|
#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_ICACHE_OFF
|
||||||
#define CONFIG_SYS_DCACHE_OFF
|
#define CONFIG_SYS_DCACHE_OFF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ AvbIOResult fsl_read_from_partition(AvbOps* ops, const char* partition,
|
||||||
/* multi block read version
|
/* multi block read version
|
||||||
* */
|
* */
|
||||||
AvbIOResult fsl_read_from_partition_multi(AvbOps* ops, const char* partition,
|
AvbIOResult fsl_read_from_partition_multi(AvbOps* ops, const char* partition,
|
||||||
int64_t offset, size_t num_bytes,
|
int64_t offset, size_t num_bytes,
|
||||||
void* buffer, size_t* out_num_read);
|
void* buffer, size_t* out_num_read);
|
||||||
|
|
||||||
/* Writes |num_bytes| from |bffer| at offset |offset| to partition
|
/* Writes |num_bytes| from |bffer| at offset |offset| to partition
|
||||||
* with name |partition| (NUL-terminated UTF-8 string). If |offset|
|
* 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.
|
* true if trusted or false if untrusted.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_validate_vbmeta_public_key_rpmb(AvbOps* ops,
|
AvbIOResult fsl_validate_vbmeta_public_key_rpmb(AvbOps* ops,
|
||||||
const uint8_t* public_key_data,
|
const uint8_t* public_key_data,
|
||||||
size_t public_key_length,
|
size_t public_key_length,
|
||||||
const uint8_t* public_key_metadata,
|
const uint8_t* public_key_metadata,
|
||||||
size_t public_key_metadata_length,
|
size_t public_key_metadata_length,
|
||||||
bool* out_is_trusted);
|
bool* out_is_trusted);
|
||||||
|
|
||||||
/* Gets the rollback index corresponding to the slot given by
|
/* Gets the rollback index corresponding to the slot given by
|
||||||
* |rollback_index_slot|. The value is returned in
|
* |rollback_index_slot|. The value is returned in
|
||||||
|
|
@ -103,7 +103,7 @@ AvbIOResult fsl_validate_vbmeta_public_key_rpmb(AvbOps* ops,
|
||||||
* this number.
|
* this number.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_read_rollback_index_rpmb(AvbOps* ops, size_t rollback_index_slot,
|
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
|
/* Sets the rollback index corresponding to the slot given by
|
||||||
* |rollback_index_slot| to |rollback_index|. Returns
|
* |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.
|
* this number.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_write_rollback_index_rpmb(AvbOps* ops, size_t rollback_index_slot,
|
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
|
/* Gets whether the device is unlocked. The value is returned in
|
||||||
* |out_is_unlocked| (true if unlocked, false otherwise). Returns
|
* |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.
|
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
|
AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
|
||||||
const char* partition,
|
const char* partition,
|
||||||
char* guid_buf,
|
char* guid_buf,
|
||||||
size_t guid_buf_size);
|
size_t guid_buf_size);
|
||||||
|
|
||||||
/* Gets the size of a partition with the name in |partition|
|
/* Gets the size of a partition with the name in |partition|
|
||||||
* (NUL-terminated UTF-8 string). Returns the value in
|
* (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.
|
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_get_size_of_partition(AvbOps* ops,
|
AvbIOResult fsl_get_size_of_partition(AvbOps* ops,
|
||||||
const char* partition,
|
const char* partition,
|
||||||
uint64_t* out_size_num_bytes);
|
uint64_t* out_size_num_bytes);
|
||||||
/* check if the fastboot getvar cmd is for query [avb] bootctl's slot var
|
/* check if the fastboot getvar cmd is for query [avb] bootctl's slot var
|
||||||
* cmd is the fastboot getvar's cmd in
|
* cmd is the fastboot getvar's cmd in
|
||||||
* return true if it is a bootctl related cmd, false if it's not.
|
* 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
|
* permanently read-only location (e.g. fuses) when a device is LOCKED. On
|
||||||
* success, returned AVB_IO_RESULT_OK and populates |hash|.
|
* success, returned AVB_IO_RESULT_OK and populates |hash|.
|
||||||
*/
|
*/
|
||||||
AvbIOResult fsl_read_permanent_attributes_hash(
|
AvbIOResult fsl_read_permanent_attributes_hash(AvbAtxOps* atx_ops,
|
||||||
AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]);
|
uint8_t hash[AVB_SHA256_DIGEST_SIZE]);
|
||||||
|
|
||||||
/* Provides the key version of a key used during verification. This may be
|
/* Provides the key version of a key used during verification. This may be
|
||||||
* useful for managing the minimum key version.
|
* useful for managing the minimum key version.
|
||||||
*/
|
*/
|
||||||
void fsl_set_key_version(AvbAtxOps* atx_ops,
|
void fsl_set_key_version(AvbAtxOps* atx_ops,
|
||||||
size_t rollback_index_location,
|
size_t rollback_index_location,
|
||||||
uint64_t key_version);
|
uint64_t key_version);
|
||||||
|
|
||||||
/* This is the fast version of avb_ab_flow(), this function will
|
/* 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
|
* 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,
|
AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
|
||||||
const char* const* requested_partitions,
|
const char* const* requested_partitions,
|
||||||
AvbSlotVerifyFlags flags,
|
AvbSlotVerifyFlags flags,
|
||||||
AvbHashtreeErrorMode hashtree_error_mode,
|
AvbHashtreeErrorMode hashtree_error_mode,
|
||||||
AvbSlotVerifyData** out_data);
|
AvbSlotVerifyData** out_data);
|
||||||
|
|
||||||
/* This is for legacy i.mx6/7 which don't enable A/B but want to
|
/* This is for legacy i.mx6/7 which don't enable A/B but want to
|
||||||
* verify boot/recovery with AVB */
|
* verify boot/recovery with AVB */
|
||||||
AvbABFlowResult avb_single_flow(AvbABOps* ab_ops,
|
AvbABFlowResult avb_single_flow(AvbABOps* ab_ops,
|
||||||
const char* const* requested_partitions,
|
const char* const* requested_partitions,
|
||||||
AvbSlotVerifyFlags flags,
|
AvbSlotVerifyFlags flags,
|
||||||
AvbHashtreeErrorMode hashtree_error_mode,
|
AvbHashtreeErrorMode hashtree_error_mode,
|
||||||
AvbSlotVerifyData** out_data);
|
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 */
|
/* Program ATX perm_attr into RPMB partition */
|
||||||
int avb_atx_fuse_perm_attr(uint8_t *staged_buffer, uint32_t size);
|
int avb_atx_fuse_perm_attr(uint8_t *staged_buffer, uint32_t size);
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,8 @@ static inline int blk_get_device_part_str(const char *ifname,
|
||||||
#ifdef CONFIG_SPL_BUILD
|
#ifdef CONFIG_SPL_BUILD
|
||||||
# define part_print_ptr(x) NULL
|
# define part_print_ptr(x) NULL
|
||||||
# if defined(CONFIG_SPL_EXT_SUPPORT) || defined(CONFIG_SPL_FAT_SUPPORT) || \
|
# 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
|
# define part_get_info_ptr(x) x
|
||||||
# else
|
# else
|
||||||
# define part_get_info_ptr(x) NULL
|
# define part_get_info_ptr(x) NULL
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,11 @@ config RBTREE
|
||||||
config BITREVERSE
|
config BITREVERSE
|
||||||
bool "Bit reverse library from Linux"
|
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
|
source lib/dhry/Kconfig
|
||||||
|
|
||||||
menu "Security support"
|
menu "Security support"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
|
||||||
obj-$(CONFIG_ARCH_AT91) += at91/
|
obj-$(CONFIG_ARCH_AT91) += at91/
|
||||||
obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/
|
obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/
|
||||||
obj-$(CONFIG_AES) += aes.o
|
obj-$(CONFIG_AES) += aes.o
|
||||||
obj-$(CONFIG_AVB_SUPPORT) += avb/
|
|
||||||
obj-y += charset.o
|
obj-y += charset.o
|
||||||
obj-$(CONFIG_USB_TTY) += circbuf.o
|
obj-$(CONFIG_USB_TTY) += circbuf.o
|
||||||
obj-y += crc7.o
|
obj-y += crc7.o
|
||||||
|
|
@ -50,6 +49,7 @@ endif
|
||||||
obj-$(CONFIG_RSA) += rsa/
|
obj-$(CONFIG_RSA) += rsa/
|
||||||
obj-$(CONFIG_SHA1) += sha1.o
|
obj-$(CONFIG_SHA1) += sha1.o
|
||||||
obj-$(CONFIG_SHA256) += sha256.o
|
obj-$(CONFIG_SHA256) += sha256.o
|
||||||
|
obj-$(CONFIG_AVB_SUPPORT) += avb/
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
|
obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
|
||||||
obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
|
obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ subdir-ccflags-y += -I./lib/avb \
|
||||||
-Wno-unused-parameter \
|
-Wno-unused-parameter \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-std=gnu99
|
-std=gnu99
|
||||||
obj-y += libavb/
|
|
||||||
|
ifndef CONFIG_SPL_BUILD
|
||||||
obj-y += libavb_ab/
|
obj-y += libavb_ab/
|
||||||
obj-$(CONFIG_AVB_ATX) += libavb_atx/
|
obj-$(CONFIG_AVB_ATX) += libavb_atx/
|
||||||
|
endif
|
||||||
|
obj-y += libavb/
|
||||||
obj-y += fsl/
|
obj-y += fsl/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
ccflags-y += -Werror
|
ccflags-y += -Werror
|
||||||
|
|
||||||
|
ifndef CONFIG_SPL_BUILD
|
||||||
obj-y += fsl_avb.o
|
obj-y += fsl_avb.o
|
||||||
obj-y += fsl_avbkey.o
|
obj-y += fsl_avbkey.o
|
||||||
obj-y += fsl_bootctl.o
|
obj-y += fsl_bootctl.o
|
||||||
obj-y += fsl_avb_ab_flow.o
|
|
||||||
obj-y += fsl_avb_sysdeps_uboot.o
|
obj-y += fsl_avb_sysdeps_uboot.o
|
||||||
|
endif
|
||||||
|
|
||||||
obj-y += utils.o
|
obj-y += utils.o
|
||||||
|
obj-y += fsl_avb_ab_flow.o
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,19 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <fsl_avb.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"};
|
static const char* slot_suffixes[2] = {"_a", "_b"};
|
||||||
|
|
||||||
/* This is a copy of slot_set_unbootable() form
|
/* 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->priority = 0;
|
||||||
slot->tries_remaining = 0;
|
slot->tries_remaining = 0;
|
||||||
slot->successful_boot = 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
|
/* Ensure all unbootable and/or illegal states are marked as the
|
||||||
* canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
|
* canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
|
||||||
* and successful_boot=0. This is a copy of fsl_slot_normalize from
|
* and successful_boot=0. This is a copy of slot_normalize from
|
||||||
* lib/avb/libavb_ab/avb_ab_flow.c.
|
* 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->priority > 0) {
|
||||||
if ((slot->tries_remaining == 0) && (!slot->successful_boot)) {
|
if ((slot->tries_remaining == 0) && (!slot->successful_boot)) {
|
||||||
/* We've exhausted all tries -> unbootable. */
|
/* 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
|
/* This is a copy of slot_is_bootable() from
|
||||||
* AVB_IO_RESULT_OK on success, error code otherwise. This is a
|
* externel/avb/libavb_ab/avb_ab_flow.c.
|
||||||
* copy of save_metadata_if_changed form lib/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,
|
static AvbIOResult fsl_save_metadata_if_changed(AvbABOps* ab_ops,
|
||||||
AvbABData* ab_data,
|
AvbABData* ab_data,
|
||||||
|
|
@ -52,14 +328,6 @@ static AvbIOResult fsl_save_metadata_if_changed(AvbABOps* ab_ops,
|
||||||
return AVB_IO_RESULT_OK;
|
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
|
/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
|
||||||
* success, error code otherwise. This is a copy of load_metadata()
|
* success, error code otherwise. This is a copy of load_metadata()
|
||||||
* from /lib/avb/libavb_ab/avb_ab_flow.c.
|
* from /lib/avb/libavb_ab/avb_ab_flow.c.
|
||||||
|
|
@ -396,3 +664,5 @@ out:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_DUAL_BOOTLOADER && CONFIG_SPL_BUILD */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||||
+ * Copyright 2017 NXP
|
+ * Copyright 2018 NXP
|
||||||
+ *
|
+ *
|
||||||
+ * SPDX-License-Identifier: GPL-2.0+
|
+ * SPDX-License-Identifier: GPL-2.0+
|
||||||
+ */
|
+ */
|
||||||
|
|
@ -10,9 +10,13 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "utils.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,
|
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;
|
long off;
|
||||||
if (margin == NULL)
|
if (margin == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -22,21 +26,27 @@ int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
|
||||||
|
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
margin->blk_start = (offset + 1) / (uint64_t)blksz + part_end;
|
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 (offset + num_bytes - 1 >= 0) {
|
||||||
if (!allow_partial)
|
if (!allow_partial)
|
||||||
return -1;
|
return -1;
|
||||||
margin->blk_end = part_end;
|
margin->blk_end = part_end;
|
||||||
margin->end = blksz - 1;
|
margin->end = blksz - 1;
|
||||||
} else {
|
} else {
|
||||||
margin->blk_end = (num_bytes + offset) / (uint64_t)blksz + part_end; // which blk the last byte is in
|
// which blk the last byte is in
|
||||||
margin->end = (off = (num_bytes + offset - 1) % (uint64_t)blksz) == 0 ?
|
margin->blk_end = (num_bytes + offset) /
|
||||||
0 : blksz + off; // last byte
|
(uint64_t)blksz + part_end;
|
||||||
|
margin->end = (off = (num_bytes + offset - 1) %
|
||||||
|
(uint64_t)blksz) == 0 ?
|
||||||
|
0 : blksz + off; // last byte
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
margin->blk_start = offset / (uint64_t)blksz + part_start;
|
margin->blk_start = offset / (uint64_t)blksz + part_start;
|
||||||
margin->start = offset % (uint64_t)blksz;
|
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;
|
margin->end = (offset + num_bytes - 1) % (uint64_t)blksz;
|
||||||
if (margin->blk_end > part_end) {
|
if (margin->blk_end > part_end) {
|
||||||
if (!allow_partial)
|
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",
|
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)
|
if (margin->blk_start > part_end || margin->blk_start < part_start)
|
||||||
return -1;
|
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);
|
VDEBUG("bm=%ld\n", margin->multi);
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||||
* Copyright 2017 NXP
|
* Copyright 2018 NXP
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
*/
|
*/
|
||||||
|
|
@ -26,6 +26,17 @@ struct margin_pos {
|
||||||
typedef struct margin_pos margin_pos_t;
|
typedef struct margin_pos margin_pos_t;
|
||||||
|
|
||||||
int get_margin_pos(uint64_t part_start, uint64_t part_end, unsigned long blksz,
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,21 @@
|
||||||
ccflags-y += -DAVB_COMPILATION
|
ccflags-y += -DAVB_COMPILATION
|
||||||
|
|
||||||
|
ifndef CONFIG_SPL_BUILD
|
||||||
obj-y += avb_descriptor.o \
|
obj-y += avb_descriptor.o \
|
||||||
avb_kernel_cmdline_descriptor.o \
|
avb_kernel_cmdline_descriptor.o \
|
||||||
avb_sha512.o \
|
avb_sha512.o \
|
||||||
avb_vbmeta_image.o \
|
avb_vbmeta_image.o \
|
||||||
avb_chain_partition_descriptor.o \
|
avb_chain_partition_descriptor.o \
|
||||||
avb_footer.o \
|
avb_footer.o \
|
||||||
avb_property_descriptor.o \
|
avb_property_descriptor.o \
|
||||||
avb_slot_verify.o \
|
avb_slot_verify.o \
|
||||||
avb_crc32.o \
|
avb_hash_descriptor.o \
|
||||||
avb_hash_descriptor.o \
|
avb_rsa.o \
|
||||||
avb_rsa.o \
|
avb_crypto.o \
|
||||||
avb_crypto.o \
|
avb_hashtree_descriptor.o \
|
||||||
avb_hashtree_descriptor.o \
|
avb_sha256.o \
|
||||||
avb_sha256.o \
|
avb_util.o \
|
||||||
avb_util.o \
|
avb_cmdline.o
|
||||||
avb_cmdline.o
|
endif
|
||||||
|
|
||||||
|
obj-y += avb_crc32.o
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue