[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:
Luo Ji 2018-06-08 10:31:11 +08:00 committed by Ji Luo
parent 4cfd7437ac
commit dbcf1e3cc0
16 changed files with 599 additions and 81 deletions

View File

@ -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,12 @@ 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)
@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -193,8 +193,8 @@ 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.
@ -205,7 +205,8 @@ void fsl_set_key_version(AvbAtxOps* atx_ops,
/* 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,
@ -220,6 +221,15 @@ AvbABFlowResult avb_single_flow(AvbABOps* ab_ops,
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);

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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 */

View File

@ -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 ?
// 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)
@ -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;
}

View File

@ -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

View File

@ -1,4 +1,6 @@
ccflags-y += -DAVB_COMPILATION
ifndef CONFIG_SPL_BUILD
obj-y += avb_descriptor.o \
avb_kernel_cmdline_descriptor.o \
avb_sha512.o \
@ -7,7 +9,6 @@ obj-y += avb_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 \
@ -15,3 +16,6 @@ obj-y += avb_descriptor.o \
avb_sha256.o \
avb_util.o \
avb_cmdline.o
endif
obj-y += avb_crc32.o