]> git.sur5r.net Git - u-boot/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-sh
authorTom Rini <trini@konsulko.com>
Thu, 21 Jun 2018 13:02:35 +0000 (09:02 -0400)
committerTom Rini <trini@konsulko.com>
Thu, 21 Jun 2018 13:02:35 +0000 (09:02 -0400)
115 files changed:
.gitignore
MAINTAINERS
Makefile
arch/arc/dts/.gitignore [deleted file]
arch/arm/cpu/armv8/fsl-layerscape/mp.c
arch/arm/cpu/armv8/zynqmp/mp.c
arch/arm/dts/.gitignore [deleted file]
arch/arm/dts/dragonboard410c-uboot.dtsi
arch/arm/include/asm/arch-meson/clock.h [new file with mode: 0644]
arch/arm/include/asm/arch-meson/gx.h
arch/arm/lib/image.c
arch/arm/lib/vectors.S
arch/arm/mach-davinci/include/mach/gpio.h
arch/arm/mach-imx/mx6/mp.c
arch/arm/mach-meson/Kconfig
arch/arm/mach-meson/eth.c
arch/arm/mach-omap2/omap3/clock.c
arch/arm/mach-sunxi/board.c
arch/m68k/include/asm/processor.h
arch/microblaze/dts/.gitignore [deleted file]
arch/mips/dts/.gitignore [deleted file]
arch/nios2/dts/.gitignore [deleted file]
arch/powerpc/cpu/mpc85xx/mp.c
arch/powerpc/cpu/mpc86xx/mp.c
arch/sandbox/dts/.gitignore [deleted file]
arch/x86/dts/.gitignore [deleted file]
board/amlogic/libretech-cc/libretech-cc.c
board/amlogic/odroid-c2/odroid-c2.c
board/davinci/da8xxevm/da850evm.c
board/synopsys/emdk/README [new file with mode: 0644]
cmd/Kconfig
cmd/Makefile
cmd/avb.c [new file with mode: 0644]
cmd/booti.c
cmd/iotrace.c
cmd/mmc.c
common/Makefile
common/avb_verify.c [new file with mode: 0644]
common/bootm.c
common/console.c
common/iotrace.c
common/log.c
configs/da850evm_defconfig
configs/khadas-vim_defconfig
configs/libretech-cc_defconfig
configs/odroid-c2_defconfig
configs/p212_defconfig
doc/README.avb2 [new file with mode: 0644]
drivers/adc/meson-saradc.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/clk/Makefile
drivers/clk/clk_meson.c [new file with mode: 0644]
drivers/clk/clk_meson.h [new file with mode: 0644]
drivers/gpio/da8xx_gpio.c
drivers/gpio/omap_gpio.c
drivers/i2c/meson_i2c.c
drivers/misc/swap_case.c
drivers/mtd/spi/sandbox.c
dts/.gitignore [deleted file]
fs/btrfs/btrfs.h
fs/btrfs/super.c
include/avb_verify.h [new file with mode: 0644]
include/blk.h
include/common.h
include/configs/UCP1020.h
include/configs/da850evm.h
include/configs/dragonboard410c.h
include/configs/meson-gx-common.h
include/configs/vme8349.h
include/environment/ti/boot.h
include/image.h
include/iotrace.h
include/log.h
lib/Kconfig
lib/Makefile
lib/libavb/Makefile [new file with mode: 0644]
lib/libavb/avb_chain_partition_descriptor.c [new file with mode: 0644]
lib/libavb/avb_chain_partition_descriptor.h [new file with mode: 0644]
lib/libavb/avb_cmdline.c [new file with mode: 0644]
lib/libavb/avb_cmdline.h [new file with mode: 0644]
lib/libavb/avb_crypto.c [new file with mode: 0644]
lib/libavb/avb_crypto.h [new file with mode: 0644]
lib/libavb/avb_descriptor.c [new file with mode: 0644]
lib/libavb/avb_descriptor.h [new file with mode: 0644]
lib/libavb/avb_footer.c [new file with mode: 0644]
lib/libavb/avb_footer.h [new file with mode: 0644]
lib/libavb/avb_hash_descriptor.c [new file with mode: 0644]
lib/libavb/avb_hash_descriptor.h [new file with mode: 0644]
lib/libavb/avb_hashtree_descriptor.c [new file with mode: 0644]
lib/libavb/avb_hashtree_descriptor.h [new file with mode: 0644]
lib/libavb/avb_kernel_cmdline_descriptor.c [new file with mode: 0644]
lib/libavb/avb_kernel_cmdline_descriptor.h [new file with mode: 0644]
lib/libavb/avb_ops.h [new file with mode: 0644]
lib/libavb/avb_property_descriptor.c [new file with mode: 0644]
lib/libavb/avb_property_descriptor.h [new file with mode: 0644]
lib/libavb/avb_rsa.c [new file with mode: 0644]
lib/libavb/avb_rsa.h [new file with mode: 0644]
lib/libavb/avb_sha.h [new file with mode: 0644]
lib/libavb/avb_sha256.c [new file with mode: 0644]
lib/libavb/avb_sha512.c [new file with mode: 0644]
lib/libavb/avb_slot_verify.c [new file with mode: 0644]
lib/libavb/avb_slot_verify.h [new file with mode: 0644]
lib/libavb/avb_sysdeps.h [new file with mode: 0644]
lib/libavb/avb_sysdeps_posix.c [new file with mode: 0644]
lib/libavb/avb_util.c [new file with mode: 0644]
lib/libavb/avb_util.h [new file with mode: 0644]
lib/libavb/avb_vbmeta_image.c [new file with mode: 0644]
lib/libavb/avb_vbmeta_image.h [new file with mode: 0644]
lib/libavb/avb_version.c [new file with mode: 0644]
lib/libavb/avb_version.h [new file with mode: 0644]
lib/libavb/libavb.h [new file with mode: 0644]
lib/rsa/rsa-sign.c
test/py/tests/test_avb.py [new file with mode: 0644]
tools/fdtgrep.c

index 9110eda6468fb70c6472b13aa086981a8855ed43..6bb0adefa7b2ca100ce56fe7381465e1cd18abd4 100644 (file)
@@ -3,29 +3,31 @@
 # subdirectories here. Add them in the ".gitignore" file
 # in that subdirectory instead.
 #
-# Normal rules
+# Normal rules (sorted alphabetically)
 #
 .*
-*.o
-*.o.*
 *.a
-*.s
-*.su
-*.mod.c
+*.bin
+*.cfgtmp
+*.dtb
+*.dtb.S
+*.elf
+*.exe
+*.gcda
+*.gcno
 *.i
 *.lex.c
 *.lst
+*.mod.c
+*.o
+*.o.*
 *.order
-*.elf
-*.swp
-*.bin
 *.patch
-*.cfgtmp
+*.s
+*.su
+*.swp
 *.tab.[ch]
 
-# host programs on Cygwin
-*.exe
-
 # Build tree
 /build-*
 
@@ -86,7 +88,3 @@ GTAGS
 *.orig
 *~
 \#*#
-
-# gcc code coverage files
-*.gcda
-*.gcno
index 642c448093859fd9cce3974933b019996419eaff..b2c9717cb7647ad26d06d57b5d01e17c39c2ed1c 100644 (file)
@@ -184,7 +184,7 @@ F:  arch/arm/mach-s5pc1xx/
 F:     arch/arm/cpu/armv7/s5p-common/
 
 ARM SNAPDRAGON
-M:     Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+M:     Ramon Fried <ramon.fried@gmail.com>
 S:     Maintained
 F:     arch/arm/mach-snapdragon/
 
index 6a190e7a894b7de0ca45ffc84eabb69a1d1919ed..399c5a5b549d7d13a324b3f0c618e34eb2f6f5e7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 VERSION = 2018
 PATCHLEVEL = 07
 SUBLEVEL =
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME =
 
 # *DOCUMENTATION*
@@ -263,8 +263,9 @@ HOSTCXXFLAGS = -O2
 # Some Linux distributions (including RHEL7, SLES13, Debian 8) still
 # have older compilers as their default, so we make it explicit for
 # these that our host tools are GNU11 (i.e. C11 w/ GNU extensions).
+CSTD_FLAG := -std=gnu11
 ifeq ($(HOSTOS),linux)
-HOSTCFLAGS += --std=gnu11
+HOSTCFLAGS += $(CSTD_FLAG)
 endif
 
 ifeq ($(HOSTOS),cygwin)
@@ -370,7 +371,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__
 
 KBUILD_CFLAGS   := -Wall -Wstrict-prototypes \
                   -Wno-format-security \
-                  -fno-builtin -ffreestanding
+                  -fno-builtin -ffreestanding $(CSTD_FLAG)
 KBUILD_CFLAGS  += -fshort-wchar
 KBUILD_AFLAGS   := -D__ASSEMBLY__
 
diff --git a/arch/arc/dts/.gitignore b/arch/arc/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
index dd89d0a83f89cdbdde7a2adf38aa80a95dc0ae75..7627fd13e7d87995c2d19ae2ed4a6c38a279b439 100644 (file)
@@ -191,14 +191,14 @@ int is_core_online(u64 cpu_id)
        return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
 }
 
-int cpu_reset(int nr)
+int cpu_reset(u32 nr)
 {
        puts("Feature is not implemented.\n");
 
        return 0;
 }
 
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        puts("Feature is not implemented.\n");
 
@@ -231,7 +231,7 @@ static int core_to_pos(int nr)
        return i;
 }
 
-int cpu_status(int nr)
+int cpu_status(u32 nr)
 {
        u64 *table;
        int pos;
@@ -257,7 +257,7 @@ int cpu_status(int nr)
        return 0;
 }
 
-int cpu_release(int nr, int argc, char * const argv[])
+int cpu_release(u32 nr, int argc, char * const argv[])
 {
        u64 boot_addr;
        u64 *table = (u64 *)get_spin_tbl_addr();
index 7e270a7dc23253c1d68546edafd5cfb1e0f9ee17..2a71870ae7bccd81dbbe3b3a1db5db063a3379db 100644 (file)
@@ -45,7 +45,7 @@ int is_core_valid(unsigned int core)
        return 0;
 }
 
-int cpu_reset(int nr)
+int cpu_reset(u32 nr)
 {
        puts("Feature is not implemented.\n");
        return 0;
@@ -131,7 +131,7 @@ static void enable_clock_r5(void)
        udelay(0x500);
 }
 
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
                u32 val = readl(&crfapb_base->rst_fpd_apu);
@@ -144,7 +144,7 @@ int cpu_disable(int nr)
        return 0;
 }
 
-int cpu_status(int nr)
+int cpu_status(u32 nr)
 {
        if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
                u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
@@ -220,7 +220,7 @@ void initialize_tcm(bool mode)
        }
 }
 
-int cpu_release(int nr, int argc, char * const argv[])
+int cpu_release(u32 nr, int argc, char * const argv[])
 {
        if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
                u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
diff --git a/arch/arm/dts/.gitignore b/arch/arm/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
index b968f5eb683318185315ffc2040d1bca3eed5b97..3a1ea13ee52347567f0aaa98480d112aeb89ef83 100644 (file)
@@ -6,10 +6,6 @@
  */
 
 / {
-       config {
-               u-boot,mmc-env-partition = "boot";
-       };
-
        soc {
                u-boot,dm-pre-reloc;
 
                        };
                };
 
-       qcom,gcc@1800000 {
-               u-boot,dm-pre-reloc;
-       };
+               qcom,gcc@1800000 {
+                       u-boot,dm-pre-reloc;
+               };
 
-       serial@78b0000 {
-               u-boot,dm-pre-reloc;
+               serial@78b0000 {
+                       u-boot,dm-pre-reloc;
+                       };
                };
-       };
 };
 
 
diff --git a/arch/arm/include/asm/arch-meson/clock.h b/arch/arm/include/asm/arch-meson/clock.h
new file mode 100644 (file)
index 0000000..c0ff00f
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2016 - AmLogic, Inc.
+ * Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
+ */
+#ifndef _ARCH_MESON_CLOCK_H_
+#define _ARCH_MESON_CLOCK_H_
+
+/*
+ * Clock controller register offsets
+ *
+ * Register offsets from the data sheet are listed in comment blocks below.
+ * Those offsets must be multiplied by 4 before adding them to the base address
+ * to get the right value
+ */
+#define SCR                            0x2C /* 0x0b offset in data sheet */
+#define TIMEOUT_VALUE                  0x3c /* 0x0f offset in data sheet */
+
+#define HHI_GP0_PLL_CNTL               0x40 /* 0x10 offset in data sheet */
+#define HHI_GP0_PLL_CNTL2              0x44 /* 0x11 offset in data sheet */
+#define HHI_GP0_PLL_CNTL3              0x48 /* 0x12 offset in data sheet */
+#define HHI_GP0_PLL_CNTL4              0x4c /* 0x13 offset in data sheet */
+#define        HHI_GP0_PLL_CNTL5               0x50 /* 0x14 offset in data sheet */
+#define        HHI_GP0_PLL_CNTL1               0x58 /* 0x16 offset in data sheet */
+
+#define        HHI_XTAL_DIVN_CNTL              0xbc /* 0x2f offset in data sheet */
+#define        HHI_TIMER90K                    0xec /* 0x3b offset in data sheet */
+
+#define        HHI_MEM_PD_REG0                 0x100 /* 0x40 offset in data sheet */
+#define        HHI_MEM_PD_REG1                 0x104 /* 0x41 offset in data sheet */
+#define        HHI_VPU_MEM_PD_REG1             0x108 /* 0x42 offset in data sheet */
+#define        HHI_VIID_CLK_DIV                0x128 /* 0x4a offset in data sheet */
+#define        HHI_VIID_CLK_CNTL               0x12c /* 0x4b offset in data sheet */
+
+#define HHI_GCLK_MPEG0                 0x140 /* 0x50 offset in data sheet */
+#define HHI_GCLK_MPEG1                 0x144 /* 0x51 offset in data sheet */
+#define HHI_GCLK_MPEG2                 0x148 /* 0x52 offset in data sheet */
+#define HHI_GCLK_OTHER                 0x150 /* 0x54 offset in data sheet */
+#define HHI_GCLK_AO                    0x154 /* 0x55 offset in data sheet */
+#define HHI_SYS_OSCIN_CNTL             0x158 /* 0x56 offset in data sheet */
+#define HHI_SYS_CPU_CLK_CNTL1          0x15c /* 0x57 offset in data sheet */
+#define HHI_SYS_CPU_RESET_CNTL         0x160 /* 0x58 offset in data sheet */
+#define HHI_VID_CLK_DIV                        0x164 /* 0x59 offset in data sheet */
+
+#define HHI_MPEG_CLK_CNTL              0x174 /* 0x5d offset in data sheet */
+#define HHI_AUD_CLK_CNTL               0x178 /* 0x5e offset in data sheet */
+#define HHI_VID_CLK_CNTL               0x17c /* 0x5f offset in data sheet */
+#define HHI_AUD_CLK_CNTL2              0x190 /* 0x64 offset in data sheet */
+#define HHI_VID_CLK_CNTL2              0x194 /* 0x65 offset in data sheet */
+#define HHI_SYS_CPU_CLK_CNTL0          0x19c /* 0x67 offset in data sheet */
+#define HHI_VID_PLL_CLK_DIV            0x1a0 /* 0x68 offset in data sheet */
+#define HHI_AUD_CLK_CNTL3              0x1a4 /* 0x69 offset in data sheet */
+#define HHI_MALI_CLK_CNTL              0x1b0 /* 0x6c offset in data sheet */
+#define HHI_VPU_CLK_CNTL               0x1bC /* 0x6f offset in data sheet */
+
+#define HHI_HDMI_CLK_CNTL              0x1CC /* 0x73 offset in data sheet */
+#define HHI_VDEC_CLK_CNTL              0x1E0 /* 0x78 offset in data sheet */
+#define HHI_VDEC2_CLK_CNTL             0x1E4 /* 0x79 offset in data sheet */
+#define HHI_VDEC3_CLK_CNTL             0x1E8 /* 0x7a offset in data sheet */
+#define HHI_VDEC4_CLK_CNTL             0x1EC /* 0x7b offset in data sheet */
+#define HHI_HDCP22_CLK_CNTL            0x1F0 /* 0x7c offset in data sheet */
+#define HHI_VAPBCLK_CNTL               0x1F4 /* 0x7d offset in data sheet */
+
+#define HHI_VPU_CLKB_CNTL              0x20C /* 0x83 offset in data sheet */
+#define HHI_USB_CLK_CNTL               0x220 /* 0x88 offset in data sheet */
+#define HHI_32K_CLK_CNTL               0x224 /* 0x89 offset in data sheet */
+#define HHI_GEN_CLK_CNTL               0x228 /* 0x8a offset in data sheet */
+#define HHI_GEN_CLK_CNTL               0x228 /* 0x8a offset in data sheet */
+
+#define HHI_PCM_CLK_CNTL               0x258 /* 0x96 offset in data sheet */
+#define HHI_NAND_CLK_CNTL              0x25C /* 0x97 offset in data sheet */
+#define HHI_SD_EMMC_CLK_CNTL           0x264 /* 0x99 offset in data sheet */
+
+#define HHI_MPLL_CNTL                  0x280 /* 0xa0 offset in data sheet */
+#define HHI_MPLL_CNTL2                 0x284 /* 0xa1 offset in data sheet */
+#define HHI_MPLL_CNTL3                 0x288 /* 0xa2 offset in data sheet */
+#define HHI_MPLL_CNTL4                 0x28C /* 0xa3 offset in data sheet */
+#define HHI_MPLL_CNTL5                 0x290 /* 0xa4 offset in data sheet */
+#define HHI_MPLL_CNTL6                 0x294 /* 0xa5 offset in data sheet */
+#define HHI_MPLL_CNTL7                 0x298 /* 0xa6 offset in data sheet */
+#define HHI_MPLL_CNTL8                 0x29C /* 0xa7 offset in data sheet */
+#define HHI_MPLL_CNTL9                 0x2A0 /* 0xa8 offset in data sheet */
+#define HHI_MPLL_CNTL10                        0x2A4 /* 0xa9 offset in data sheet */
+
+#define HHI_MPLL3_CNTL0                        0x2E0 /* 0xb8 offset in data sheet */
+#define HHI_MPLL3_CNTL1                        0x2E4 /* 0xb9 offset in data sheet */
+#define HHI_VDAC_CNTL0                 0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1                 0x2F8 /* 0xbe offset in data sheet */
+
+#define HHI_SYS_PLL_CNTL               0x300 /* 0xc0 offset in data sheet */
+#define HHI_SYS_PLL_CNTL2              0x304 /* 0xc1 offset in data sheet */
+#define HHI_SYS_PLL_CNTL3              0x308 /* 0xc2 offset in data sheet */
+#define HHI_SYS_PLL_CNTL4              0x30c /* 0xc3 offset in data sheet */
+#define HHI_SYS_PLL_CNTL5              0x310 /* 0xc4 offset in data sheet */
+#define HHI_DPLL_TOP_I                 0x318 /* 0xc6 offset in data sheet */
+#define HHI_DPLL_TOP2_I                        0x31C /* 0xc7 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL              0x320 /* 0xc8 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL2             0x324 /* 0xc9 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL3             0x328 /* 0xca offset in data sheet */
+#define HHI_HDMI_PLL_CNTL4             0x32C /* 0xcb offset in data sheet */
+#define HHI_HDMI_PLL_CNTL5             0x330 /* 0xcc offset in data sheet */
+#define HHI_HDMI_PLL_CNTL6             0x334 /* 0xcd offset in data sheet */
+#define HHI_HDMI_PLL_CNTL_I            0x338 /* 0xce offset in data sheet */
+#define HHI_HDMI_PLL_CNTL7             0x33C /* 0xcf offset in data sheet */
+
+#define HHI_HDMI_PHY_CNTL0             0x3A0 /* 0xe8 offset in data sheet */
+#define HHI_HDMI_PHY_CNTL1             0x3A4 /* 0xe9 offset in data sheet */
+#define HHI_HDMI_PHY_CNTL2             0x3A8 /* 0xea offset in data sheet */
+#define HHI_HDMI_PHY_CNTL3             0x3AC /* 0xeb offset in data sheet */
+
+#define HHI_VID_LOCK_CLK_CNTL          0x3C8 /* 0xf2 offset in data sheet */
+#define HHI_BT656_CLK_CNTL             0x3D4 /* 0xf5 offset in data sheet */
+#define HHI_SAR_CLK_CNTL               0x3D8 /* 0xf6 offset in data sheet */
+
+ulong meson_measure_clk_rate(unsigned int clk);
+
+#endif
index 03fb6b03de8e8b28af0791ee6ab6096422395bd5..4bc9475d35e77e4cc867f9abb262247172ead77b 100644 (file)
 /* Ethernet memory power domain */
 #define GX_MEM_PD_REG_0_ETH_MASK       (BIT(2) | BIT(3))
 
-/* Clock gates */
-#define GX_GCLK_MPEG_0 GX_HIU_ADDR(0x50)
-#define GX_GCLK_MPEG_1 GX_HIU_ADDR(0x51)
-#define GX_GCLK_MPEG_2 GX_HIU_ADDR(0x52)
-#define GX_GCLK_MPEG_OTHER     GX_HIU_ADDR(0x53)
-#define GX_GCLK_MPEG_AO        GX_HIU_ADDR(0x54)
-
-#define GX_GCLK_MPEG_0_I2C   BIT(9)
-#define GX_GCLK_MPEG_1_ETH     BIT(3)
-
 #endif /* __GX_H__ */
index 1a04e2b875615313c745d437a15872044ce64fe0..699bf44e702f7a7084997406203fd7d2aaaf87fa 100644 (file)
@@ -26,7 +26,8 @@ struct Image_header {
        uint32_t        res5;
 };
 
-int booti_setup(ulong image, ulong *relocated_addr, ulong *size)
+int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
+               bool force_reloc)
 {
        struct Image_header *ih;
        uint64_t dst;
@@ -63,7 +64,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size)
         * images->ep.  Otherwise, relocate the image to the base of RAM
         * since memory below it is not accessible via the linear mapping.
         */
-       if (le64_to_cpu(ih->flags) & BIT(3))
+       if (!force_reloc && (le64_to_cpu(ih->flags) & BIT(3)))
                dst = image - text_offset;
        else
                dst = gd->bd->bi_dram[0].start;
index 79afc27e84716f58b8de111de940353385fe72ff..d629cb1dc2d2f40dc02c99ae243dd9482de4eb8d 100644 (file)
@@ -133,7 +133,7 @@ not_used:
 irq:
 fiq:
 1:
-       bl      1b                      /* hang and never return */
+       b       1b                      /* hang and never return */
 
 #else  /* !CONFIG_SPL_BUILD */
 
index f1d4d9e9e04fba280f91fa01da5be29ed2b6775f..d4b25c3d60ef2e4e164d3ceb1c9900bbad3f1894 100644 (file)
@@ -39,7 +39,7 @@ struct davinci_gpio_bank {
        unsigned int irq_num;
        unsigned int irq_mask;
        unsigned long *in_use;
-       unsigned long base;
+       struct davinci_gpio *base;
 };
 
 #define davinci_gpio_bank01 ((struct davinci_gpio *)DAVINCI_GPIO_BANK01)
@@ -48,7 +48,9 @@ struct davinci_gpio_bank {
 #define davinci_gpio_bank67 ((struct davinci_gpio *)DAVINCI_GPIO_BANK67)
 #define davinci_gpio_bank8 ((struct davinci_gpio *)DAVINCI_GPIO_BANK8)
 
+#ifndef CONFIG_DM_GPIO
 #define gpio_status()          gpio_info()
+#endif
 #define GPIO_NAME_SIZE         20
 #if defined(CONFIG_SOC_DM644X)
 /* GPIO0 to GPIO53, omit the V3.3 volts one */
@@ -63,4 +65,14 @@ struct davinci_gpio_bank {
 
 void gpio_info(void);
 
+#ifdef CONFIG_DM_GPIO
+
+/* Information about a GPIO bank */
+struct davinci_gpio_platdata {
+       int bank_index;
+       ulong base;     /* address of registers in physical memory */
+       const char *port_name;
+};
+#endif
+
 #endif
index c3806dca3ad03db998209819651c80d1a53f8e43..eda168d8671115f1da535d79393398006fd85e49 100644 (file)
@@ -29,20 +29,20 @@ static uint32_t cpu_ctrl_mask[MAX_CPUS] = {
        SRC_SCR_CORE_3_ENABLE_MASK
 };
 
-int cpu_reset(int nr)
+int cpu_reset(u32 nr)
 {
        /* Software reset of the CPU N */
        src->scr |= cpu_reset_mask[nr];
        return 0;
 }
 
-int cpu_status(int nr)
+int cpu_status(u32 nr)
 {
        printf("core %d => %d\n", nr, !!(src->scr & cpu_ctrl_mask[nr]));
        return 0;
 }
 
-int cpu_release(int nr, int argc, char *const argv[])
+int cpu_release(u32 nr, int argc, char *const argv[])
 {
        uint32_t boot_addr;
 
@@ -78,7 +78,7 @@ int is_core_valid(unsigned int core)
        return 1;
 }
 
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        /* Disable the CPU N */
        src->scr &= ~cpu_ctrl_mask[nr];
index 0350787daa79f3de397b19f6d4b14db22c070d3e..9a06ccc8610e38f3f6dca7b9e187879d9445499e 100644 (file)
@@ -3,6 +3,7 @@ if ARCH_MESON
 config MESON_GXBB
        bool "Support Meson GXBaby"
        select ARM64
+       select CLK
        select DM
        select DM_SERIAL
        help
@@ -12,6 +13,7 @@ config MESON_GXBB
 config MESON_GXL
        bool "Support Meson GXL"
        select ARM64
+       select CLK
        select DM
        select DM_SERIAL
        help
index 061f19a0e31c4407ed99e666226b67759b12cec2..8b28bc853111cb16dea9554b857a276824b2a33e 100644 (file)
@@ -48,7 +48,6 @@ void meson_gx_eth_init(phy_interface_t mode, unsigned int flags)
                return;
        }
 
-       /* Enable power and clock gate */
-       setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH);
+       /* Enable power gate */
        clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK);
 }
index b9d92c62b1b87017c3335109b10c2bc29273630a..9a03bfa9d3bbbb19616edbd40d6d94e9f7666efb 100644 (file)
@@ -750,23 +750,23 @@ void per_clocks_enable(void)
        setbits_le32(&prcm_base->iclken_per, 0x00000800);
 #endif
 
-#ifdef CONFIG_OMAP3_GPIO_2
+#if (CONFIG_IS_ENABLED(OMAP3_GPIO_2) || CONFIG_IS_ENABLED(CMD_GPIO))
        setbits_le32(&prcm_base->fclken_per, 0x00002000);
        setbits_le32(&prcm_base->iclken_per, 0x00002000);
 #endif
-#ifdef CONFIG_OMAP3_GPIO_3
+#if (CONFIG_IS_ENABLED(OMAP3_GPIO_3) || CONFIG_IS_ENABLED(CMD_GPIO))
        setbits_le32(&prcm_base->fclken_per, 0x00004000);
        setbits_le32(&prcm_base->iclken_per, 0x00004000);
 #endif
-#ifdef CONFIG_OMAP3_GPIO_4
+#if (CONFIG_IS_ENABLED(OMAP3_GPIO_4) || CONFIG_IS_ENABLED(CMD_GPIO))
        setbits_le32(&prcm_base->fclken_per, 0x00008000);
        setbits_le32(&prcm_base->iclken_per, 0x00008000);
 #endif
-#ifdef CONFIG_OMAP3_GPIO_5
+#if (CONFIG_IS_ENABLED(OMAP3_GPIO_5) || CONFIG_IS_ENABLED(CMD_GPIO))
        setbits_le32(&prcm_base->fclken_per, 0x00010000);
        setbits_le32(&prcm_base->iclken_per, 0x00010000);
 #endif
-#ifdef CONFIG_OMAP3_GPIO_6
+#if (CONFIG_IS_ENABLED(OMAP3_GPIO_6) || CONFIG_IS_ENABLED(CMD_GPIO))
        setbits_le32(&prcm_base->fclken_per, 0x00020000);
        setbits_le32(&prcm_base->iclken_per, 0x00020000);
 #endif
index 7ac8360c0117a824fc17c606f3e5f563fd6a585a..58fef05bd737b57bdcc27b90087bfe1fb4421ab6 100644 (file)
@@ -207,9 +207,6 @@ void s_init(void)
        eth_init_board();
 }
 
-#ifdef CONFIG_SPL_BUILD
-#endif
-
 /* The sunxi internal brom will try to loader external bootloader
  * from mmc0, nand flash, mmc2.
  */
index 3fafa6ff1a8d3151e5fe437fbdbf3c8cc96881ea..4af69190b7371362170949ebacab88aeef6b0d33 100644 (file)
@@ -11,8 +11,4 @@ n:
 /* Macros for setting and retrieving special purpose registers */
 #define setvbr(v)      asm volatile("movec %0,%%VBR" : : "r" (v))
 
-#ifndef __ASSEMBLY__
-
-#endif /* ifndef ASSEMBLY*/
-
 #endif /* __ASM_M68K_PROCESSOR_H */
diff --git a/arch/microblaze/dts/.gitignore b/arch/microblaze/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
diff --git a/arch/mips/dts/.gitignore b/arch/mips/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
diff --git a/arch/nios2/dts/.gitignore b/arch/nios2/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
index 42501ca3cec5cd4a0ac03152c09b82e451eb9369..b0aa72ed6e0213a28db99b4feae0d0322be892e4 100644 (file)
@@ -42,7 +42,7 @@ int hold_cores_in_reset(int verbose)
        return 0;
 }
 
-int cpu_reset(int nr)
+int cpu_reset(u32 nr)
 {
        volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
        out_be32(&pic->pir, 1 << nr);
@@ -53,7 +53,7 @@ int cpu_reset(int nr)
        return 0;
 }
 
-int cpu_status(int nr)
+int cpu_status(u32 nr)
 {
        u32 *table, id = get_my_id();
 
@@ -79,7 +79,7 @@ int cpu_status(int nr)
 }
 
 #ifdef CONFIG_FSL_CORENET
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
@@ -95,7 +95,7 @@ int is_core_disabled(int nr) {
        return (coredisrl & (1 << nr));
 }
 #else
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
@@ -137,7 +137,7 @@ static u8 boot_entry_map[4] = {
        BOOT_ENTRY_R3_LOWER,
 };
 
-int cpu_release(int nr, int argc, char * const argv[])
+int cpu_release(u32 nr, int argc, char * const argv[])
 {
        u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;
        u64 boot_addr;
index 97bd160df8a5f5ce3a9e77e3666f6366061cb9c9..ce300eac5b0e858cf1d8340016389449d3e70568 100644 (file)
@@ -13,7 +13,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int cpu_reset(int nr)
+int cpu_reset(u32 nr)
 {
        /* dummy function so common/cmd_mp.c will build
         * should be implemented in the future, when cpu_release()
@@ -23,13 +23,13 @@ int cpu_reset(int nr)
        return 1;
 }
 
-int cpu_status(int nr)
+int cpu_status(u32 nr)
 {
        /* dummy function so common/cmd_mp.c will build */
        return 0;
 }
 
-int cpu_disable(int nr)
+int cpu_disable(u32 nr)
 {
        volatile immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
        volatile ccsr_gur_t *gur = &immap->im_gur;
@@ -66,7 +66,7 @@ int is_core_disabled(int nr) {
        return 0;
 }
 
-int cpu_release(int nr, int argc, char * const argv[])
+int cpu_release(u32 nr, int argc, char * const argv[])
 {
        /* dummy function so common/cmd_mp.c will build
         * should be implemented in the future */
diff --git a/arch/sandbox/dts/.gitignore b/arch/sandbox/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
diff --git a/arch/x86/dts/.gitignore b/arch/x86/dts/.gitignore
deleted file mode 100644 (file)
index b60ed20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.dtb
index e89bf773cc7ee5f278d57bcdb3f2652e09c1ea32..ccab1272c5915d1469afe9e224151315442cb4d0 100644 (file)
@@ -32,10 +32,6 @@ int misc_init_r(void)
        meson_gx_eth_init(PHY_INTERFACE_MODE_RMII,
                          MESON_GXL_USE_INTERNAL_RMII_PHY);
 
-       /* Enable power and clock gate */
-       setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH);
-       clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK);
-
        if (!eth_env_get_enetaddr("ethaddr", mac_addr)) {
                len = meson_sm_read_efuse(EFUSE_MAC_OFFSET,
                                          mac_addr, EFUSE_MAC_SIZE);
index 1b7fd8199bb8e32068a16fbbbfbaff7b1ff4b98d..c47b9ce9cb77ac066c9cf4ed17200d365b70cbf7 100644 (file)
@@ -30,9 +30,6 @@ int misc_init_r(void)
 
        meson_gx_eth_init(PHY_INTERFACE_MODE_RGMII, 0);
 
-       /* Enable power and clock gate */
-       setbits_le32(GX_GCLK_MPEG_0, GX_GCLK_MPEG_0_I2C);
-
        /* Reset PHY on GPIOZ_14 */
        clrbits_le32(GX_GPIO_EN(3), BIT(14));
        clrbits_le32(GX_GPIO_OUT(3), BIT(14));
index c565ba7831cfc04d301b39468e3c3148222885f1..5583b45792c88d0511ec9720d9b8c309bbe6bf81 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <environment.h>
 #include <i2c.h>
 #include <net.h>
@@ -24,6 +25,7 @@
 #include <linux/errno.h>
 #include <hwconfig.h>
 #include <asm/mach-types.h>
+#include <asm/gpio.h>
 
 #ifdef CONFIG_MMC_DAVINCI
 #include <mmc.h>
diff --git a/board/synopsys/emdk/README b/board/synopsys/emdk/README
new file mode 100644 (file)
index 0000000..706b547
--- /dev/null
@@ -0,0 +1,82 @@
+================================================================================
+Useful notes on bulding and using of U-Boot on ARC EM Development Kit (AKA EMDK)
+================================================================================
+
+   BOARD OVERVIEW
+
+   The DesignWare ARC EM Development Kit is FPGA-bases platform for rapid
+   software development on the ARC EM family of processors.
+
+   Since this board is based on FPGA it's possible to load and use different
+   versions of ARC EM CPUs. U-Boot is built to be run on the simplest
+   possible configuration which means the same one binary will work on more
+   advanced configurations as well.
+
+   The board has the following features useful for U-Boot:
+    * On-board 2-channel FTDI TTL-to-USB converter
+      - The first channel is used for serial debug port (which makes it possible
+        to use a serial connection on pretty much any host machine be it
+        Windows, Linux or Mac).
+        On Linux machine typucally FTDI serial port would be /dev/ttyUSB0.
+        There's no HW flow-control and baud-rate is 115200.
+
+      - The second channel is used for built-in Digilent USB JTAG probe.
+        That means no extra hardware is required to access ARC core from a
+        debugger on development host. Both proprietary MetaWare debugger and
+        open source OpenOCD + GDB client are supported.
+
+      - Also with help of this FTDI chip it is possible to reset entire
+        board with help of a special `rff-ftdi-reset` utility, see:
+        https://github.com/foss-for-synopsys-dwc-arc-processors/rff-ftdi-reset
+
+    * Micro SD-card slot
+      - U-Boot expects to see the very first partition on the card formatted as
+        FAT file-system and uses it for keeping its environment in `uboot.env`
+        file. Note uboot.env is not just a text file but it is auto-generated
+        file created by U-Boot on invocation of `saveenv` command.
+        It contains a checksum which makes this saved environment invalid in
+        case of maual modification.
+
+      - There might be more useful files on that first FAT partition like
+        user applications, data files etc.
+
+    * 256 KiB of "ROM"
+      - This so-called "ROM" is a part of FPGA image and even though it
+        might be unlocked for writes its initial content will be restored
+        on the next power-on.
+
+
+   BUILDING U-BOOT
+
+   1. Configure U-Boot:
+      ------------------------->8----------------------
+      make emdk_defconfig
+      ------------------------->8----------------------
+
+   2. To build Elf file (for example to be used with host debugger via JTAG
+      connection to the target board):
+      ------------------------->8----------------------
+      make mdbtrick
+      ------------------------->8----------------------
+
+      This will produce `u-boot` Elf file.
+
+   3. To build binary image to be put in "ROM":
+      ------------------------->8----------------------
+      make u-boot.bin
+      ------------------------->8----------------------
+
+
+   EXECUTING U-BOOT
+
+   1. The EMDK board is supposed to auto-start U-Boot image stored in ROM on
+      power-on. For that make sure VCCIO DIP-switches are all in "off" state.
+
+   2. Though it is possible to load U-Boot as a simple Elf file via JTAG right
+      in "ROM" and start it from the debugger. One important note here we first
+      need to enable writes into "ROM" by writing 1 to 0xf0001000.
+
+      2.1. In case of proprietary MetaWare debugger run:
+      ------------------------->8----------------------
+      mdb -dll=opxdarc.so -OK -preloadexec="eval *(int*)0xf0001000=0" u-boot
+      ------------------------->8----------------------
index 1eb55e52508eb5350dae2fdbc203bd77670f0f51..45c83359add828a60dd8e6f69f9b4abb39a2e44d 100644 (file)
@@ -1754,6 +1754,22 @@ config CMD_TRACE
          for analsys (e.g. using bootchart). See doc/README.trace for full
          details.
 
+config CMD_AVB
+       bool "avb - Android Verified Boot 2.0 operations"
+       depends on LIBAVB
+       default n
+       help
+         Enables a "avb" command to perform verification of partitions using
+         Android Verified Boot 2.0 functionality. It includes such subcommands:
+           avb init - initialize avb2 subsystem
+           avb read_rb - read rollback index
+           avb write_rb - write rollback index
+           avb is_unlocked - check device lock state
+           avb get_uuid - read and print uuid of a partition
+           avb read_part - read data from partition
+           avb read_part_hex - read data from partition and output to stdout
+           avb write_part - write data to partition
+           avb verify - run full verification chain
 endmenu
 
 config CMD_UBI
index e0088df33bd1be1763870102682d2fc920a0173c..13cf7bf6c205d43a42214f4d44bde4205c661386 100644 (file)
@@ -155,6 +155,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
 
 obj-$(CONFIG_CMD_BLOB) += blob.o
 
+# Android Verified Boot 2.0
+obj-$(CONFIG_CMD_AVB) += avb.o
+
 obj-$(CONFIG_X86) += x86/
 endif # !CONFIG_SPL_BUILD
 
diff --git a/cmd/avb.c b/cmd/avb.c
new file mode 100644 (file)
index 0000000..f045a0c
--- /dev/null
+++ b/cmd/avb.c
@@ -0,0 +1,372 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <command.h>
+#include <image.h>
+#include <malloc.h>
+#include <mmc.h>
+
+#define AVB_BOOTARGS   "avb_bootargs"
+static struct AvbOps *avb_ops;
+
+static const char * const requested_partitions[] = {"boot",
+                                            "system",
+                                            "vendor",
+                                            NULL};
+
+int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       unsigned long mmc_dev;
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       mmc_dev = simple_strtoul(argv[1], NULL, 16);
+
+       if (avb_ops)
+               avb_ops_free(avb_ops);
+
+       avb_ops = avb_ops_alloc(mmc_dev);
+       if (avb_ops)
+               return CMD_RET_SUCCESS;
+
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       const char *part;
+       s64 offset;
+       size_t bytes, bytes_read = 0;
+       void *buffer;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
+               return CMD_RET_USAGE;
+       }
+
+       if (argc != 5)
+               return CMD_RET_USAGE;
+
+       part = argv[1];
+       offset = simple_strtoul(argv[2], NULL, 16);
+       bytes = simple_strtoul(argv[3], NULL, 16);
+       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
+
+       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
+                                        buffer, &bytes_read) ==
+                                        AVB_IO_RESULT_OK) {
+               printf("Read %zu bytes\n", bytes_read);
+               return CMD_RET_SUCCESS;
+       }
+
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc,
+                        char *const argv[])
+{
+       const char *part;
+       s64 offset;
+       size_t bytes, bytes_read = 0;
+       char *buffer;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
+               return CMD_RET_USAGE;
+       }
+
+       if (argc != 4)
+               return CMD_RET_USAGE;
+
+       part = argv[1];
+       offset = simple_strtoul(argv[2], NULL, 16);
+       bytes = simple_strtoul(argv[3], NULL, 16);
+
+       buffer = malloc(bytes);
+       if (!buffer) {
+               printf("Failed to tlb_allocate buffer for data\n");
+               return CMD_RET_FAILURE;
+       }
+       memset(buffer, 0, bytes);
+
+       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer,
+                                        &bytes_read) == AVB_IO_RESULT_OK) {
+               printf("Requested %zu, read %zu bytes\n", bytes, bytes_read);
+               printf("Data: ");
+               for (int i = 0; i < bytes_read; i++)
+                       printf("%02X", buffer[i]);
+
+               printf("\n");
+
+               free(buffer);
+               return CMD_RET_SUCCESS;
+       }
+
+       free(buffer);
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       const char *part;
+       s64 offset;
+       size_t bytes;
+       void *buffer;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 5)
+               return CMD_RET_USAGE;
+
+       part = argv[1];
+       offset = simple_strtoul(argv[2], NULL, 16);
+       bytes = simple_strtoul(argv[3], NULL, 16);
+       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
+
+       if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) ==
+           AVB_IO_RESULT_OK) {
+               printf("Wrote %zu bytes\n", bytes);
+               return CMD_RET_SUCCESS;
+       }
+
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       size_t index;
+       u64 rb_idx;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       index = (size_t)simple_strtoul(argv[1], NULL, 16);
+
+       if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) ==
+           AVB_IO_RESULT_OK) {
+               printf("Rollback index: %llu\n", rb_idx);
+               return CMD_RET_SUCCESS;
+       }
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       size_t index;
+       u64 rb_idx;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 3)
+               return CMD_RET_USAGE;
+
+       index = (size_t)simple_strtoul(argv[1], NULL, 16);
+       rb_idx = simple_strtoul(argv[2], NULL, 16);
+
+       if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) ==
+           AVB_IO_RESULT_OK)
+               return CMD_RET_SUCCESS;
+
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag,
+                   int argc, char * const argv[])
+{
+       const char *part;
+       char buffer[UUID_STR_LEN + 1];
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       part = argv[1];
+
+       if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer,
+                                                  UUID_STR_LEN + 1) ==
+                                                  AVB_IO_RESULT_OK) {
+               printf("'%s' UUID: %s\n", part, buffer);
+               return CMD_RET_SUCCESS;
+       }
+
+       return CMD_RET_FAILURE;
+}
+
+int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
+                      int argc, char *const argv[])
+{
+       AvbSlotVerifyResult slot_result;
+       AvbSlotVerifyData *out_data;
+       char *cmdline;
+       char *extra_args;
+
+       bool unlocked = false;
+       int res = CMD_RET_FAILURE;
+
+       if (!avb_ops) {
+               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 1)
+               return CMD_RET_USAGE;
+
+       printf("## Android Verified Boot 2.0 version %s\n",
+              avb_version_string());
+
+       if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) !=
+           AVB_IO_RESULT_OK) {
+               printf("Can't determine device lock state.\n");
+               return CMD_RET_FAILURE;
+       }
+
+       slot_result =
+               avb_slot_verify(avb_ops,
+                               requested_partitions,
+                               "",
+                               unlocked,
+                               AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+                               &out_data);
+
+       switch (slot_result) {
+       case AVB_SLOT_VERIFY_RESULT_OK:
+               /* Until we don't have support of changing unlock states, we
+                * assume that we are by default in locked state.
+                * So in this case we can boot only when verification is
+                * successful; we also supply in cmdline GREEN boot state
+                */
+               printf("Verification passed successfully\n");
+
+               /* export additional bootargs to AVB_BOOTARGS env var */
+
+               extra_args = avb_set_state(avb_ops, AVB_GREEN);
+               if (extra_args)
+                       cmdline = append_cmd_line(out_data->cmdline,
+                                                 extra_args);
+               else
+                       cmdline = out_data->cmdline;
+
+               env_set(AVB_BOOTARGS, cmdline);
+
+               res = CMD_RET_SUCCESS;
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+               printf("Verification failed\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+               printf("I/O error occurred during verification\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+               printf("OOM error occurred during verification\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+               printf("Corrupted dm-verity metadata detected\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+               printf("Unsupported version avbtool was used\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+               printf("Checking rollback index failed\n");
+               break;
+       case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+               printf("Public key was rejected\n");
+               break;
+       default:
+               printf("Unknown error occurred\n");
+       }
+
+       return res;
+}
+
+int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag,
+                      int argc, char * const argv[])
+{
+       bool unlock;
+
+       if (!avb_ops) {
+               printf("AVB not initialized, run 'avb init' first\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc != 1) {
+               printf("--%s(-1)\n", __func__);
+               return CMD_RET_USAGE;
+       }
+
+       if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) ==
+           AVB_IO_RESULT_OK) {
+               printf("Unlocked = %d\n", unlock);
+               return CMD_RET_SUCCESS;
+       }
+
+       return CMD_RET_FAILURE;
+}
+
+static cmd_tbl_t cmd_avb[] = {
+       U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""),
+       U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""),
+       U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""),
+       U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""),
+       U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""),
+       U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""),
+       U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""),
+       U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""),
+       U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""),
+};
+
+static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       cmd_tbl_t *cp;
+
+       cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
+
+       argc--;
+       argv++;
+
+       if (!cp || argc > cp->maxargs)
+               return CMD_RET_USAGE;
+
+       if (flag == CMD_FLAG_REPEAT)
+               return CMD_RET_FAILURE;
+
+       return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+       avb, 29, 0, do_avb,
+       "Provides commands for testing Android Verified Boot 2.0 functionality",
+       "init <dev> - initialize avb2 for <dev>\n"
+       "avb read_rb <num> - read rollback index at location <num>\n"
+       "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
+       "avb is_unlocked - returns unlock status of the device\n"
+       "avb get_uuid <partname> - read and print uuid of partition <part>\n"
+       "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n"
+       "    partition <partname> to buffer <addr>\n"
+       "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n"
+       "    partition <partname> and print to stdout\n"
+       "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n"
+       "    <partname> by <offset> using data from <addr>\n"
+       "avb verify - run verification process using hash data\n"
+       "    from vbmeta structure\n"
+       );
index 45fbb99b680a9a5c3e230e6145cec5d42e15faf0..04353b68eccc0d73d62c44128016da883fd9a5c5 100644 (file)
@@ -37,7 +37,7 @@ static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc,
                debug("*  kernel: cmdline image address = 0x%08lx\n", ld);
        }
 
-       ret = booti_setup(ld, &relocated_addr, &image_size);
+       ret = booti_setup(ld, &relocated_addr, &image_size, false);
        if (ret != 0)
                return 1;
 
index 601b8c8e32acd308517df820d9e479072a0fa4eb..fa6c68b19825a3f7c934712f3b173bae60e04a7c 100644 (file)
@@ -9,12 +9,13 @@
 
 static void do_print_stats(void)
 {
-       ulong start, size, offset, count;
+       ulong start, size, needed_size, offset, count;
 
        printf("iotrace is %sabled\n", iotrace_get_enabled() ? "en" : "dis");
-       iotrace_get_buffer(&start, &size, &offset, &count);
+       iotrace_get_buffer(&start, &size, &needed_size, &offset, &count);
        printf("Start:  %08lx\n", start);
-       printf("Size:   %08lx\n", size);
+       printf("Actual Size:   %08lx\n", size);
+       printf("Needed Size:   %08lx\n", needed_size);
        iotrace_get_region(&start, &size);
        printf("Region: %08lx\n", start);
        printf("Size:   %08lx\n", size);
@@ -24,6 +25,36 @@ static void do_print_stats(void)
        printf("CRC32:  %08lx\n", (ulong)iotrace_get_checksum());
 }
 
+static void do_print_trace(void)
+{
+       ulong start, size, needed_size, offset, count;
+
+       struct iotrace_record *cur_record;
+
+       iotrace_get_buffer(&start, &size, &needed_size, &offset, &count);
+
+       if (!start || !size || !count)
+               return;
+
+       printf("Timestamp  Value          Address\n");
+
+       cur_record = (struct iotrace_record *)start;
+       for (int i = 0; i < count; i++) {
+               if (cur_record->flags & IOT_WRITE)
+                       printf("%08llu: 0x%08lx --> 0x%08llx\n",
+                              cur_record->timestamp,
+                                       cur_record->value,
+                                       (unsigned long long)cur_record->addr);
+               else
+                       printf("%08llu: 0x%08lx <-- 0x%08llx\n",
+                              cur_record->timestamp,
+                                       cur_record->value,
+                                       (unsigned long long)cur_record->addr);
+
+               cur_record++;
+       }
+}
+
 static int do_set_buffer(int argc, char * const argv[])
 {
        ulong addr = 0, size = 0;
@@ -76,6 +107,9 @@ int do_iotrace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        case 's':
                do_print_stats();
                break;
+       case 'd':
+               do_print_trace();
+               break;
        default:
                return CMD_RET_USAGE;
        }
@@ -90,5 +124,6 @@ U_BOOT_CMD(
        "iotrace buffer <address> <size>      - set iotrace buffer\n"
        "iotrace limit <address> <size>       - set iotrace region limit\n"
        "iotrace pause                        - pause tracing\n"
-       "iotrace resume                       - resume tracing"
+       "iotrace resume                       - resume tracing\n"
+       "iotrace dump                         - dump iotrace buffer"
 );
index c2ee2d9c0af1d9e77d4339621a2173411e92d07a..3920a1836a594903116841f809676f34ff022061 100644 (file)
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -935,6 +935,7 @@ U_BOOT_CMD(
        "mmc part - lists available partition on current mmc device\n"
        "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
        "mmc list - lists available devices\n"
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
        "mmc hwpartition [args...] - does hardware partitioning\n"
        "  arguments (sizes in 512-byte blocks):\n"
        "    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n"
@@ -942,6 +943,7 @@ U_BOOT_CMD(
        "    [check|set|complete] - mode, complete set partitioning completed\n"
        "  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
        "  Power cycling is required to initialize partitions after set to complete.\n"
+#endif
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
        "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
        " - Set the BOOT_BUS_WIDTH field of the specified device\n"
index b3da72ebb2c94ee3ca23a104cb8d79a1be51f5eb..66584f8f48be554a2afe662433d8e05503724982 100644 (file)
@@ -120,3 +120,5 @@ obj-$(CONFIG_$(SPL_)LOG) += log.o
 obj-$(CONFIG_$(SPL_)LOG_CONSOLE) += log_console.o
 obj-y += s_record.o
 obj-y += xyzModem.o
+
+obj-$(CONFIG_LIBAVB) += avb_verify.o
diff --git a/common/avb_verify.c b/common/avb_verify.c
new file mode 100644 (file)
index 0000000..f9a00f8
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <fastboot.h>
+#include <image.h>
+#include <malloc.h>
+#include <part.h>
+
+const unsigned char avb_root_pub[1032] = {
+       0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4,
+       0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2,
+       0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e,
+       0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94,
+       0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53,
+       0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88,
+       0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf,
+       0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad,
+       0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3,
+       0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7,
+       0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4,
+       0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a,
+       0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93,
+       0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb,
+       0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47,
+       0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c,
+       0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b,
+       0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45,
+       0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7,
+       0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd,
+       0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27,
+       0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f,
+       0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7,
+       0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a,
+       0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9,
+       0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3,
+       0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1,
+       0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0,
+       0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d,
+       0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16,
+       0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59,
+       0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a,
+       0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81,
+       0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf,
+       0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c,
+       0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2,
+       0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80,
+       0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf,
+       0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2,
+       0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89,
+       0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe,
+       0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb,
+       0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed,
+       0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd,
+       0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a,
+       0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5,
+       0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37,
+       0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91,
+       0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6,
+       0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a,
+       0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95,
+       0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb,
+       0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7,
+       0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4,
+       0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e,
+       0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc,
+       0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64,
+       0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6,
+       0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74,
+       0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f,
+       0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12,
+       0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2,
+       0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87,
+       0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89,
+       0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5,
+       0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3,
+       0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6,
+       0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6,
+       0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25,
+       0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe,
+       0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1,
+       0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15,
+       0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4,
+       0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2,
+       0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81,
+       0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86,
+       0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2,
+       0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7,
+       0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec,
+       0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c,
+       0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b,
+       0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6,
+       0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16,
+       0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34,
+       0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5,
+       0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48,
+       0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f,
+       0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c,
+       0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc,
+       0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68,
+       0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2,
+       0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb,
+       0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7,
+       0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac,
+       0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25,
+       0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1,
+       0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea,
+       0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1,
+       0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda,
+       0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13,
+       0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5,
+       0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77,
+       0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac,
+       0xd8, 0x7e,
+};
+
+/**
+ * ============================================================================
+ * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
+ * ============================================================================
+ */
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
+{
+       struct AvbOpsData *data;
+       char *cmdline = NULL;
+
+       if (!ops)
+               return NULL;
+
+       data = (struct AvbOpsData *)ops->user_data;
+       if (!data)
+               return NULL;
+
+       data->boot_state = boot_state;
+       switch (boot_state) {
+       case AVB_GREEN:
+               cmdline = "androidboot.verifiedbootstate=green";
+               break;
+       case AVB_YELLOW:
+               cmdline = "androidboot.verifiedbootstate=yellow";
+               break;
+       case AVB_ORANGE:
+               cmdline = "androidboot.verifiedbootstate=orange";
+       case AVB_RED:
+               break;
+       }
+
+       return cmdline;
+}
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
+{
+       char *cmd_line;
+
+       if (!cmdline_new)
+               return cmdline_orig;
+
+       if (cmdline_orig)
+               cmd_line = cmdline_orig;
+       else
+               cmd_line = " ";
+
+       cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
+
+       return cmd_line;
+}
+
+static int avb_find_dm_args(char **args, char *str)
+{
+       int i;
+
+       if (!str)
+               return -1;
+
+       for (i = 0; i < AVB_MAX_ARGS, args[i]; ++i) {
+               if (strstr(args[i], str))
+                       return i;
+       }
+
+       return -1;
+}
+
+static char *avb_set_enforce_option(const char *cmdline, const char *option)
+{
+       char *cmdarg[AVB_MAX_ARGS];
+       char *newargs = NULL;
+       int i = 0;
+       int total_args;
+
+       memset(cmdarg, 0, sizeof(cmdarg));
+       cmdarg[i++] = strtok((char *)cmdline, " ");
+
+       do {
+               cmdarg[i] = strtok(NULL, " ");
+               if (!cmdarg[i])
+                       break;
+
+               if (++i >= AVB_MAX_ARGS) {
+                       printf("%s: Can't handle more then %d args\n",
+                              __func__, i);
+                       return NULL;
+               }
+       } while (true);
+
+       total_args = i;
+       i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
+       if (i >= 0) {
+               cmdarg[i] = (char *)option;
+       } else {
+               i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
+               if (i < 0) {
+                       printf("%s: No verity options found\n", __func__);
+                       return NULL;
+               }
+
+               cmdarg[i] = (char *)option;
+       }
+
+       for (i = 0; i <= total_args; i++)
+               newargs = append_cmd_line(newargs, cmdarg[i]);
+
+       return newargs;
+}
+
+char *avb_set_ignore_corruption(const char *cmdline)
+{
+       char *newargs = NULL;
+
+       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
+       if (newargs)
+               newargs = append_cmd_line(newargs,
+                                         "androidboot.veritymode=eio");
+
+       return newargs;
+}
+
+char *avb_set_enforce_verity(const char *cmdline)
+{
+       char *newargs;
+
+       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
+       if (newargs)
+               newargs = append_cmd_line(newargs,
+                                         "androidboot.veritymode=enforcing");
+       return newargs;
+}
+
+/**
+ * ============================================================================
+ * IO(mmc) auxiliary functions
+ * ============================================================================
+ */
+static unsigned long mmc_read_and_flush(struct mmc_part *part,
+                                       lbaint_t start,
+                                       lbaint_t sectors,
+                                       void *buffer)
+{
+       unsigned long blks;
+       void *tmp_buf;
+       size_t buf_size;
+       bool unaligned = is_buf_unaligned(buffer);
+
+       if (start < part->info.start) {
+               printf("%s: partition start out of bounds\n", __func__);
+               return 0;
+       }
+       if ((start + sectors) > (part->info.start + part->info.size)) {
+               sectors = part->info.start + part->info.size - start;
+               printf("%s: read sector aligned to partition bounds (%ld)\n",
+                      __func__, sectors);
+       }
+
+       /*
+        * Reading fails on unaligned buffers, so we have to
+        * use aligned temporary buffer and then copy to destination
+        */
+
+       if (unaligned) {
+               printf("Handling unaligned read buffer..\n");
+               tmp_buf = get_sector_buf();
+               buf_size = get_sector_buf_size();
+               if (sectors > buf_size / part->info.blksz)
+                       sectors = buf_size / part->info.blksz;
+       } else {
+               tmp_buf = buffer;
+       }
+
+       blks = part->mmc->block_dev.block_read(part->mmc_blk,
+                               start, sectors, tmp_buf);
+       /* flush cache after read */
+       flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
+
+       if (unaligned)
+               memcpy(buffer, tmp_buf, sectors * part->info.blksz);
+
+       return blks;
+}
+
+static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
+                              lbaint_t sectors, void *buffer)
+{
+       void *tmp_buf;
+       size_t buf_size;
+       bool unaligned = is_buf_unaligned(buffer);
+
+       if (start < part->info.start) {
+               printf("%s: partition start out of bounds\n", __func__);
+               return 0;
+       }
+       if ((start + sectors) > (part->info.start + part->info.size)) {
+               sectors = part->info.start + part->info.size - start;
+               printf("%s: sector aligned to partition bounds (%ld)\n",
+                      __func__, sectors);
+       }
+       if (unaligned) {
+               tmp_buf = get_sector_buf();
+               buf_size = get_sector_buf_size();
+               printf("Handling unaligned wrire buffer..\n");
+               if (sectors > buf_size / part->info.blksz)
+                       sectors = buf_size / part->info.blksz;
+
+               memcpy(tmp_buf, buffer, sectors * part->info.blksz);
+       } else {
+               tmp_buf = buffer;
+       }
+
+       return part->mmc->block_dev.block_write(part->mmc_blk,
+                               start, sectors, tmp_buf);
+}
+
+static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
+{
+       int ret;
+       u8 dev_num;
+       int part_num = 0;
+       struct mmc_part *part;
+       struct blk_desc *mmc_blk;
+
+       part = malloc(sizeof(struct mmc_part));
+       if (!part)
+               return NULL;
+
+       dev_num = get_boot_device(ops);
+       part->mmc = find_mmc_device(dev_num);
+       if (!part->mmc) {
+               printf("No MMC device at slot %x\n", dev_num);
+               return NULL;
+       }
+
+       if (mmc_init(part->mmc)) {
+               printf("MMC initialization failed\n");
+               return NULL;
+       }
+
+       ret = mmc_switch_part(part->mmc, part_num);
+       if (ret)
+               return NULL;
+
+       mmc_blk = mmc_get_blk_desc(part->mmc);
+       if (!mmc_blk) {
+               printf("Error - failed to obtain block descriptor\n");
+               return NULL;
+       }
+
+       ret = part_get_info_by_name(mmc_blk, partition, &part->info);
+       if (!ret) {
+               printf("Can't find partition '%s'\n", partition);
+               return NULL;
+       }
+
+       part->dev_num = dev_num;
+       part->mmc_blk = mmc_blk;
+
+       return part;
+}
+
+static AvbIOResult mmc_byte_io(AvbOps *ops,
+                              const char *partition,
+                              s64 offset,
+                              size_t num_bytes,
+                              void *buffer,
+                              size_t *out_num_read,
+                              enum mmc_io_type io_type)
+{
+       ulong ret;
+       struct mmc_part *part;
+       u64 start_offset, start_sector, sectors, residue;
+       u8 *tmp_buf;
+       size_t io_cnt = 0;
+
+       if (!partition || !buffer || io_type > IO_WRITE)
+               return AVB_IO_RESULT_ERROR_IO;
+
+       part = get_partition(ops, partition);
+       if (!part)
+               return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+       start_offset = calc_offset(part, offset);
+       while (num_bytes) {
+               start_sector = start_offset / part->info.blksz;
+               sectors = num_bytes / part->info.blksz;
+               /* handle non block-aligned reads */
+               if (start_offset % part->info.blksz ||
+                   num_bytes < part->info.blksz) {
+                       tmp_buf = get_sector_buf();
+                       if (start_offset % part->info.blksz) {
+                               residue = part->info.blksz -
+                                       (start_offset % part->info.blksz);
+                               if (residue > num_bytes)
+                                       residue = num_bytes;
+                       } else {
+                               residue = num_bytes;
+                       }
+
+                       if (io_type == IO_READ) {
+                               ret = mmc_read_and_flush(part,
+                                                        part->info.start +
+                                                        start_sector,
+                                                        1, tmp_buf);
+
+                               if (ret != 1) {
+                                       printf("%s: read error (%ld, %lld)\n",
+                                              __func__, ret, start_sector);
+                                       return AVB_IO_RESULT_ERROR_IO;
+                               }
+                               /*
+                                * if this is not aligned at sector start,
+                                * we have to adjust the tmp buffer
+                                */
+                               tmp_buf += (start_offset % part->info.blksz);
+                               memcpy(buffer, (void *)tmp_buf, residue);
+                       } else {
+                               ret = mmc_read_and_flush(part,
+                                                        part->info.start +
+                                                        start_sector,
+                                                        1, tmp_buf);
+
+                               if (ret != 1) {
+                                       printf("%s: read error (%ld, %lld)\n",
+                                              __func__, ret, start_sector);
+                                       return AVB_IO_RESULT_ERROR_IO;
+                               }
+                               memcpy((void *)tmp_buf +
+                                       start_offset % part->info.blksz,
+                                       buffer, residue);
+
+                               ret = mmc_write(part, part->info.start +
+                                               start_sector, 1, tmp_buf);
+                               if (ret != 1) {
+                                       printf("%s: write error (%ld, %lld)\n",
+                                              __func__, ret, start_sector);
+                                       return AVB_IO_RESULT_ERROR_IO;
+                               }
+                       }
+
+                       io_cnt += residue;
+                       buffer += residue;
+                       start_offset += residue;
+                       num_bytes -= residue;
+                       continue;
+               }
+
+               if (sectors) {
+                       if (io_type == IO_READ) {
+                               ret = mmc_read_and_flush(part,
+                                                        part->info.start +
+                                                        start_sector,
+                                                        sectors, buffer);
+                       } else {
+                               ret = mmc_write(part,
+                                               part->info.start +
+                                               start_sector,
+                                               sectors, buffer);
+                       }
+
+                       if (!ret) {
+                               printf("%s: sector read error\n", __func__);
+                               return AVB_IO_RESULT_ERROR_IO;
+                       }
+
+                       io_cnt += ret * part->info.blksz;
+                       buffer += ret * part->info.blksz;
+                       start_offset += ret * part->info.blksz;
+                       num_bytes -= ret * part->info.blksz;
+               }
+       }
+
+       /* Set counter for read operation */
+       if (io_type == IO_READ && out_num_read)
+               *out_num_read = io_cnt;
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB 2.0 operations
+ * ============================================================================
+ */
+
+/**
+ * read_from_partition() - reads @num_bytes from  @offset from partition
+ * identified by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition_name: partition name, NUL-terminated UTF-8 string
+ * @offset: offset from the beginning of partition
+ * @num_bytes: amount of bytes to read
+ * @buffer: destination buffer to store data
+ * @out_num_read:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ *      AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o
+ *            subsystem
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with
+ *      the given name
+ */
+static AvbIOResult read_from_partition(AvbOps *ops,
+                                      const char *partition_name,
+                                      s64 offset_from_partition,
+                                      size_t num_bytes,
+                                      void *buffer,
+                                      size_t *out_num_read)
+{
+       return mmc_byte_io(ops, partition_name, offset_from_partition,
+                          num_bytes, buffer, out_num_read, IO_READ);
+}
+
+/**
+ * write_to_partition() - writes N bytes to a partition identified by a string
+ * name
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @partition_name: partition name
+ * @offset_from_partition: offset from the beginning of partition
+ * @num_bytes: amount of bytes to write
+ * @buf: data to write
+ * @out_num_read:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ *      AVB_IO_RESULT_ERROR_IO, if input/output error occurred
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in
+ *            @partition_name was not found
+ */
+static AvbIOResult write_to_partition(AvbOps *ops,
+                                     const char *partition_name,
+                                     s64 offset_from_partition,
+                                     size_t num_bytes,
+                                     const void *buffer)
+{
+       return mmc_byte_io(ops, partition_name, offset_from_partition,
+                          num_bytes, (void *)buffer, NULL, IO_WRITE);
+}
+
+/**
+ * validate_vmbeta_public_key() - checks if the given public key used to sign
+ * the vbmeta partition is trusted
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @public_key_data: public key for verifying vbmeta partition signature
+ * @public_key_length: length of public key
+ * @public_key_metadata:
+ * @public_key_metadata_length:
+ * @out_key_is_trusted:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ */
+static AvbIOResult validate_vbmeta_public_key(AvbOps *ops,
+                                             const u8 *public_key_data,
+                                             size_t public_key_length,
+                                             const u8
+                                             *public_key_metadata,
+                                             size_t
+                                             public_key_metadata_length,
+                                             bool *out_key_is_trusted)
+{
+       if (!public_key_length || !public_key_data || !out_key_is_trusted)
+               return AVB_IO_RESULT_ERROR_IO;
+
+       *out_key_is_trusted = false;
+       if (public_key_length != sizeof(avb_root_pub))
+               return AVB_IO_RESULT_ERROR_IO;
+
+       if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0)
+               *out_key_is_trusted = true;
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_rollback_index() - gets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @out_rollback_index: used to write a retrieved rollback index.
+ *
+ * @return
+ *       AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult read_rollback_index(AvbOps *ops,
+                                      size_t rollback_index_slot,
+                                      u64 *out_rollback_index)
+{
+       /* For now we always return 0 as the stored rollback index. */
+       printf("%s not supported yet\n", __func__);
+
+       if (out_rollback_index)
+               *out_rollback_index = 0;
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * write_rollback_index() - sets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @rollback_index: rollback index to write.
+ *
+ * @return
+ *       AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult write_rollback_index(AvbOps *ops,
+                                       size_t rollback_index_slot,
+                                       u64 rollback_index)
+{
+       /* For now this is a no-op. */
+       printf("%s not supported yet\n", __func__);
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_is_device_unlocked() - gets whether the device is unlocked
+ *
+ * @ops: contains AVB ops handlers
+ * @out_is_unlocked: device unlock state is stored here, true if unlocked,
+ *       false otherwise
+ *
+ * @return:
+ *       AVB_IO_RESULT_OK: state is retrieved successfully
+ *       AVB_IO_RESULT_ERROR_IO: an error occurred
+ */
+static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
+{
+       /* For now we always return that the device is unlocked. */
+
+       printf("%s not supported yet\n", __func__);
+
+       *out_is_unlocked = true;
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * get_unique_guid_for_partition() - gets the GUID for a partition identified
+ * by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition: partition name (NUL-terminated UTF-8 string)
+ * @guid_buf: buf, used to copy in GUID string. Example of value:
+ *      527c1c6d-6361-4593-8842-3c78fcd39219
+ * @guid_buf_size: @guid_buf buffer size
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, on success (GUID found)
+ *      AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was
+ *             provided
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
+ */
+static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
+                                                const char *partition,
+                                                char *guid_buf,
+                                                size_t guid_buf_size)
+{
+       struct mmc_part *part;
+       size_t uuid_size;
+
+       part = get_partition(ops, partition);
+       if (!part)
+               return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+       uuid_size = sizeof(part->info.uuid);
+       if (uuid_size > guid_buf_size)
+               return AVB_IO_RESULT_ERROR_IO;
+
+       memcpy(guid_buf, part->info.uuid, uuid_size);
+       guid_buf[uuid_size - 1] = 0;
+
+       return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB2.0 AvbOps alloc/initialisation/free
+ * ============================================================================
+ */
+AvbOps *avb_ops_alloc(int boot_device)
+{
+       struct AvbOpsData *ops_data;
+
+       ops_data = avb_calloc(sizeof(struct AvbOpsData));
+       if (!ops_data)
+               return NULL;
+
+       ops_data->ops.user_data = ops_data;
+
+       ops_data->ops.read_from_partition = read_from_partition;
+       ops_data->ops.write_to_partition = write_to_partition;
+       ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
+       ops_data->ops.read_rollback_index = read_rollback_index;
+       ops_data->ops.write_rollback_index = write_rollback_index;
+       ops_data->ops.read_is_device_unlocked = read_is_device_unlocked;
+       ops_data->ops.get_unique_guid_for_partition =
+               get_unique_guid_for_partition;
+
+       ops_data->mmc_dev = boot_device;
+
+       return &ops_data->ops;
+}
+
+void avb_ops_free(AvbOps *ops)
+{
+       struct AvbOpsData *ops_data;
+
+       if (ops)
+               return;
+
+       ops_data = ops->user_data;
+
+       if (ops_data)
+               avb_free(ops_data);
+}
index e789f6818aa30d043fea4526bef9806b535bf679..e517d9f118a8e2bd8c9623725a712a638d9b540d 100644 (file)
@@ -202,8 +202,23 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
        }
 
        if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
-               images.os.load = images.os.image_start;
-               images.ep += images.os.load;
+               if (CONFIG_IS_ENABLED(CMD_BOOTI) &&
+                   images.os.arch == IH_ARCH_ARM64) {
+                       ulong image_addr;
+                       ulong image_size;
+
+                       ret = booti_setup(images.os.image_start, &image_addr,
+                                         &image_size, true);
+                       if (ret != 0)
+                               return 1;
+
+                       images.os.type = IH_TYPE_KERNEL;
+                       images.os.load = image_addr;
+                       images.ep = image_addr;
+               } else {
+                       images.os.load = images.os.image_start;
+                       images.ep += images.os.image_start;
+               }
        }
 
        images.os.start = map_to_sysmem(os_hdr);
index 2688af56e1582ad2f2330477010c112533eeb279..2ba33dc5740240092e04883c5393f6b731ad51ad 100644 (file)
@@ -502,8 +502,10 @@ void putc(const char c)
                return;
        }
 #endif
+       if (!gd)
+               return;
 #ifdef CONFIG_CONSOLE_RECORD
-       if (gd && (gd->flags & GD_FLG_RECORD) && gd->console_out.start)
+       if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start)
                membuff_putbyte(&gd->console_out, c);
 #endif
 #ifdef CONFIG_SILENT_CONSOLE
@@ -541,8 +543,10 @@ void puts(const char *s)
                return;
        }
 #endif
+       if (!gd)
+               return;
 #ifdef CONFIG_CONSOLE_RECORD
-       if (gd && (gd->flags & GD_FLG_RECORD) && gd->console_out.start)
+       if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start)
                membuff_put(&gd->console_out, s, strlen(s));
 #endif
 #ifdef CONFIG_SILENT_CONSOLE
index 2f03a6082e893f0c2493c16c749a17e21442c692..49bee3c92a094903c24213e83a7387549b583cdd 100644 (file)
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Support up to the machine word length for now */
-typedef ulong iovalue_t;
-
-enum iotrace_flags {
-       IOT_8 = 0,
-       IOT_16,
-       IOT_32,
-
-       IOT_READ = 0 << 3,
-       IOT_WRITE = 1 << 3,
-};
-
-/**
- * struct iotrace_record - Holds a single I/O trace record
- *
- * @flags: I/O access type
- * @timestamp: Timestamp of access
- * @addr: Address of access
- * @value: Value written or read
- */
-struct iotrace_record {
-       enum iotrace_flags flags;
-       u64 timestamp;
-       phys_addr_t addr;
-       iovalue_t value;
-};
-
 /**
  * struct iotrace - current trace status and checksum
  *
  * @start:     Start address of iotrace buffer
- * @size:      Size of iotrace buffer in bytes
+ * @size:      Actual size of iotrace buffer in bytes
+ * @needed_size: Needed of iotrace buffer in bytes
  * @offset:    Current write offset into iotrace buffer
  * @region_start: Address of IO region to trace
  * @region_size: Size of region to trace. if 0 will trace all address space
@@ -52,6 +26,7 @@ struct iotrace_record {
 static struct iotrace {
        ulong start;
        ulong size;
+       ulong needed_size;
        ulong offset;
        ulong region_start;
        ulong region_size;
@@ -82,7 +57,12 @@ static void add_record(int flags, const void *ptr, ulong value)
                rec = (struct iotrace_record *)map_sysmem(
                                        iotrace.start + iotrace.offset,
                                        sizeof(value));
+       } else {
+               WARN_ONCE(1, "WARNING: iotrace buffer exhausted, please check needed length using \"iotrace stats\"\n");
+               iotrace.needed_size += sizeof(struct iotrace_record);
+               return;
        }
+
        rec->timestamp = timer_get_us();
        rec->flags = flags;
        rec->addr = map_to_sysmem(ptr);
@@ -92,6 +72,7 @@ static void add_record(int flags, const void *ptr, ulong value)
        iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec,
                              sizeof(*rec));
 
+       iotrace.needed_size += sizeof(struct iotrace_record);
        iotrace.offset += sizeof(struct iotrace_record);
 }
 
@@ -189,10 +170,11 @@ void iotrace_set_buffer(ulong start, ulong size)
        iotrace.crc32 = 0;
 }
 
-void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count)
+void iotrace_get_buffer(ulong *start, ulong *size, ulong *needed_size, ulong *offset, ulong *count)
 {
        *start = iotrace.start;
        *size = iotrace.size;
+       *needed_size = iotrace.needed_size;
        *offset = iotrace.offset;
        *count = iotrace.offset / sizeof(struct iotrace_record);
 }
index 3b5588ebe7ad4e36c3e278438fc62fee01f567dc..59869cd29dabba5375e5897f96a0f46a53f29ebb 100644 (file)
@@ -38,12 +38,16 @@ static const char *log_level_name[LOGL_COUNT] = {
 
 const char *log_get_cat_name(enum log_category_t cat)
 {
-       if (cat > LOGC_COUNT)
-               return "invalid";
+       const char *name;
+
+       if (cat < 0 || cat >= LOGC_COUNT)
+               return "<invalid>";
        if (cat >= LOGC_NONE)
                return log_cat_name[cat - LOGC_NONE];
 
-       return uclass_get_name((enum uclass_id)cat);
+       name = uclass_get_name((enum uclass_id)cat);
+
+       return name ? name : "<missing>";
 }
 
 enum log_category_t log_get_cat_by_name(const char *name)
index bb1368b9adf715ee91cc50c75b5135ce354d1358..6a2b7ae670dd9b2fc3b70dd399804bc2c5e08bc2 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_SYS_PROMPT="U-Boot > "
 CONFIG_CRC32_VERIFY=y
 # CONFIG_CMD_EEPROM is not set
 # CONFIG_CMD_FLASH is not set
-# CONFIG_CMD_GPIO is not set
 # CONFIG_CMD_GPT is not set
 # CONFIG_CMD_PART is not set
 # CONFIG_CMD_SETEXPR is not set
@@ -37,6 +36,7 @@ CONFIG_CMD_DIAG=y
 CONFIG_OF_CONTROL=y
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_DM=y
+CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_DM_SPI_FLASH=y
index 49a653f0424b1c82fdc1af510bd0a80185e2c4ec..1eb13df4b48539a04eb351f0266a53974b593e49 100644 (file)
@@ -16,10 +16,15 @@ CONFIG_OF_BOARD_SETUP=y
 CONFIG_CMD_GPIO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_REGULATOR=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_GPIO=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_RESET=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_MESON_GX=y
 CONFIG_PHY_ADDR_ENABLE=y
@@ -34,3 +39,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y
 CONFIG_DEBUG_UART_SKIP_INIT=y
 CONFIG_MESON_SERIAL=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_STORAGE=y
+CONFIG_PHY=y
+CONFIG_MESON_GXL_USB_PHY=y
index 7ba2fa1fe2da29d33dfeafaddb1218a1adee906e..d4f2f58c8a7e25e2b0d50abb31e8fe0291893fbe 100644 (file)
@@ -13,13 +13,21 @@ CONFIG_OF_BOARD_SETUP=y
 # CONFIG_DISPLAY_BOARDINFO is not set
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_IMI is not set
+CONFIG_CMD_ADC=y
 CONFIG_CMD_GPIO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_REGULATOR=y
+CONFIG_ADC=y
+CONFIG_SARADC_MESON=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_GPIO=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_RESET=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_MESON_GX=y
 CONFIG_PHY_ADDR_ENABLE=y
@@ -34,3 +42,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y
 CONFIG_DEBUG_UART_SKIP_INIT=y
 CONFIG_MESON_SERIAL=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_STORAGE=y
+CONFIG_PHY=y
+CONFIG_MESON_GXL_USB_PHY=y
index ecc8d03e318f593c2c145d79a1d0c3af07cd0bd9..9be69adcac9e32901b252c921f31cc635b03071a 100644 (file)
@@ -18,11 +18,15 @@ CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_MMC=y
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_REGULATOR=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MESON=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_RESET=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_MESON_GX=y
 CONFIG_DM_ETH=y
index 344c04aa8d58c13c2cee4dfd564766facbd82153..f9b282e2daaea12f729e50c409b8f94fe7846f01 100644 (file)
@@ -16,10 +16,15 @@ CONFIG_OF_BOARD_SETUP=y
 CONFIG_CMD_GPIO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_REGULATOR=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_GPIO=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_RESET=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_MESON_GX=y
 CONFIG_PHY_ADDR_ENABLE=y
@@ -34,3 +39,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y
 CONFIG_DEBUG_UART_SKIP_INIT=y
 CONFIG_MESON_SERIAL=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_STORAGE=y
+CONFIG_PHY=y
+CONFIG_MESON_GXL_USB_PHY=y
diff --git a/doc/README.avb2 b/doc/README.avb2
new file mode 100644 (file)
index 0000000..67784b5
--- /dev/null
@@ -0,0 +1,97 @@
+Android Verified Boot 2.0
+
+This file contains information about the current support of Android Verified
+Boot 2.0 in U-boot
+
+1. OVERVIEW
+---------------------------------
+Verified Boot establishes a chain of trust from the bootloader to system images
+* Provides integrity checking for:
+  - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
+    partition is done and the hash is compared with the one stored in
+    the VBMeta image
+  - system/vendor partitions: verifying root hash of dm-verity hashtrees.
+* Provides capabilities for rollback protection.
+
+Integrity of the bootloader (U-boot BLOB and environment) is out of scope.
+
+For additional details check:
+https://android.googlesource.com/platform/external/avb/+/master/README.md
+
+
+2. AVB 2.0 U-BOOT SHELL COMMANDS
+-----------------------------------
+Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
+different testing purposes:
+
+avb init <dev> - initialize avb 2.0 for <dev>
+avb verify - run verification process using hash data from vbmeta structure
+avb read_rb <num> - read rollback index at location <num>
+avb write_rb <num> <rb> - write rollback index <rb> to <num>
+avb is_unlocked - returns unlock status of the device
+avb get_uuid <partname> - read and print uuid of partition <partname>
+avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
+partition <partname> to buffer <addr>
+avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
+<partname> by <offset> using data from <addr>
+
+
+3. PARTITIONS TAMPERING (EXAMPLE)
+-----------------------------------
+Boot or system/vendor (dm-verity metadata section) is tampered:
+=> avb init 1
+=> avb verify
+avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
+descriptor.
+Slot verification result: ERROR_IO
+
+Vbmeta partition is tampered:
+=> avb init 1
+=> avb verify
+avb_vbmeta_image.c:206: ERROR: Hash does not match!
+avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
+HASH_MISMATCH
+Slot verification result: ERROR_IO
+
+
+4. ENABLE ON YOUR BOARD
+-----------------------------------
+The following options must be enabled:
+CONFIG_LIBAVB=y
+CONFIG_CMD_AVB=y
+
+
+Then add `avb verify` invocation to your android boot sequence of commands,
+e.g.:
+
+=> avb_verify=avb init $mmcdev; avb verify;
+=> if run avb_verify; then                       \
+        echo AVB verification OK. Continue boot; \
+        set bootargs $bootargs $avb_bootargs;    \
+   else                                          \
+        echo AVB verification failed;            \
+        exit;                                    \
+   fi;                                           \
+
+=> emmc_android_boot=                                   \
+       echo Trying to boot Android from eMMC ...;       \
+       ...                                              \
+       run avb_verify;                                  \
+       mmc read ${fdtaddr} ${fdt_start} ${fdt_size};    \
+       mmc read ${loadaddr} ${boot_start} ${boot_size}; \
+       bootm $loadaddr $loadaddr $fdtaddr;              \
+
+
+To switch on automatic generation of vbmeta partition in AOSP build, add these
+lines to device configuration mk file:
+
+BOARD_AVB_ENABLE := true
+BOARD_AVB_ALGORITHM := SHA512_RSA4096
+BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
+
+After flashing U-boot don't forget to update environment and write new
+partition table:
+=> env default -f -a
+=> setenv partitions $partitions_android
+=> env save
+=> gpt write mmc 1 $partitions_android
index bcab76d0509bc8bb1d7d53085e579e1cc9b74591..f7c919d3b0a47506eeb45eb1b2467d2e0fab4f6a 100644 (file)
@@ -654,7 +654,7 @@ static int meson_saradc_probe(struct udevice *dev)
        struct meson_saradc_priv *priv = dev_get_priv(dev);
        int ret;
 
-       ret = regmap_init_mem(dev, &priv->regmap);
+       ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
        if (ret)
                return ret;
 
index 0792373cfc48b0960098c06743ab75f7210fb5bd..f9502b36bacd56f52b3796969d03aeac3ccdd6cc 100644 (file)
@@ -37,6 +37,13 @@ config BLOCK_CACHE
          it will prevent repeated reads from directory structures and other
          filesystem data structures.
 
+config SPL_BLOCK_CACHE
+       bool "Use block device cache in SPL"
+       depends on SPL_BLK
+       default n
+       help
+         This option enables the disk-block cache in SPL
+
 config IDE
        bool "Support IDE controllers"
        select HAVE_BLOCK_DEVICE
index 5fcafb193ee98523fbe738710100b9a1824f6a6a..0e80ce94058fef014763e7cfbb2aec1c7ff15825 100644 (file)
@@ -11,4 +11,4 @@ endif
 
 obj-$(CONFIG_IDE) += ide.o
 obj-$(CONFIG_SANDBOX) += sandbox.o
-obj-$(CONFIG_BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_$(SPL_)BLOCK_CACHE) += blkcache.o
index 58139b13a89b3daf9ecbafc2128d89ee4afa5ee3..426c67db9b49227d2520f7c1f238e99ccb240cf8 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o clk_fixed_rate.o
 
 obj-y += tegra/
 obj-$(CONFIG_ARCH_ASPEED) += aspeed/
+obj-$(CONFIG_ARCH_MESON) += clk_meson.o
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_CLK_AT91) += at91/
 obj-$(CONFIG_CLK_MVEBU) += mvebu/
diff --git a/drivers/clk/clk_meson.c b/drivers/clk/clk_meson.c
new file mode 100644 (file)
index 0000000..3850128
--- /dev/null
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
+ * (C) Copyright 2018 - BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <dt-bindings/clock/gxbb-clkc.h>
+#include "clk_meson.h"
+
+#define XTAL_RATE 24000000
+
+struct meson_clk {
+       void __iomem *addr;
+};
+
+static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
+
+struct meson_gate gates[] = {
+       /* Everything Else (EE) domain gates */
+       MESON_GATE(CLKID_DDR, HHI_GCLK_MPEG0, 0),
+       MESON_GATE(CLKID_DOS, HHI_GCLK_MPEG0, 1),
+       MESON_GATE(CLKID_ISA, HHI_GCLK_MPEG0, 5),
+       MESON_GATE(CLKID_PL301, HHI_GCLK_MPEG0, 6),
+       MESON_GATE(CLKID_PERIPHS, HHI_GCLK_MPEG0, 7),
+       MESON_GATE(CLKID_SPICC, HHI_GCLK_MPEG0, 8),
+       MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9),
+       MESON_GATE(CLKID_SAR_ADC, HHI_GCLK_MPEG0, 10),
+       MESON_GATE(CLKID_SMART_CARD, HHI_GCLK_MPEG0, 11),
+       MESON_GATE(CLKID_RNG0, HHI_GCLK_MPEG0, 12),
+       MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13),
+       MESON_GATE(CLKID_SDHC, HHI_GCLK_MPEG0, 14),
+       MESON_GATE(CLKID_STREAM, HHI_GCLK_MPEG0, 15),
+       MESON_GATE(CLKID_ASYNC_FIFO, HHI_GCLK_MPEG0, 16),
+       MESON_GATE(CLKID_SDIO, HHI_GCLK_MPEG0, 17),
+       MESON_GATE(CLKID_ABUF, HHI_GCLK_MPEG0, 18),
+       MESON_GATE(CLKID_HIU_IFACE, HHI_GCLK_MPEG0, 19),
+       MESON_GATE(CLKID_ASSIST_MISC, HHI_GCLK_MPEG0, 23),
+       MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 24),
+       MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25),
+       MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26),
+       MESON_GATE(CLKID_SPI, HHI_GCLK_MPEG0, 30),
+
+       MESON_GATE(CLKID_I2S_SPDIF, HHI_GCLK_MPEG1, 2),
+       MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3),
+       MESON_GATE(CLKID_DEMUX, HHI_GCLK_MPEG1, 4),
+       MESON_GATE(CLKID_AIU_GLUE, HHI_GCLK_MPEG1, 6),
+       MESON_GATE(CLKID_IEC958, HHI_GCLK_MPEG1, 7),
+       MESON_GATE(CLKID_I2S_OUT, HHI_GCLK_MPEG1, 8),
+       MESON_GATE(CLKID_AMCLK, HHI_GCLK_MPEG1, 9),
+       MESON_GATE(CLKID_AIFIFO2, HHI_GCLK_MPEG1, 10),
+       MESON_GATE(CLKID_MIXER, HHI_GCLK_MPEG1, 11),
+       MESON_GATE(CLKID_MIXER_IFACE, HHI_GCLK_MPEG1, 12),
+       MESON_GATE(CLKID_ADC, HHI_GCLK_MPEG1, 13),
+       MESON_GATE(CLKID_BLKMV, HHI_GCLK_MPEG1, 14),
+       MESON_GATE(CLKID_AIU, HHI_GCLK_MPEG1, 15),
+       MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16),
+       MESON_GATE(CLKID_G2D, HHI_GCLK_MPEG1, 20),
+       MESON_GATE(CLKID_USB0, HHI_GCLK_MPEG1, 21),
+       MESON_GATE(CLKID_USB1, HHI_GCLK_MPEG1, 22),
+       MESON_GATE(CLKID_RESET, HHI_GCLK_MPEG1, 23),
+       MESON_GATE(CLKID_NAND, HHI_GCLK_MPEG1, 24),
+       MESON_GATE(CLKID_DOS_PARSER, HHI_GCLK_MPEG1, 25),
+       MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 26),
+       MESON_GATE(CLKID_VDIN1, HHI_GCLK_MPEG1, 28),
+       MESON_GATE(CLKID_AHB_ARB0, HHI_GCLK_MPEG1, 29),
+       MESON_GATE(CLKID_EFUSE, HHI_GCLK_MPEG1, 30),
+       MESON_GATE(CLKID_BOOT_ROM, HHI_GCLK_MPEG1, 31),
+
+       MESON_GATE(CLKID_AHB_DATA_BUS, HHI_GCLK_MPEG2, 1),
+       MESON_GATE(CLKID_AHB_CTRL_BUS, HHI_GCLK_MPEG2, 2),
+       MESON_GATE(CLKID_HDMI_INTR_SYNC, HHI_GCLK_MPEG2, 3),
+       MESON_GATE(CLKID_HDMI_PCLK, HHI_GCLK_MPEG2, 4),
+       MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8),
+       MESON_GATE(CLKID_USB0_DDR_BRIDGE, HHI_GCLK_MPEG2, 9),
+       MESON_GATE(CLKID_MMC_PCLK, HHI_GCLK_MPEG2, 11),
+       MESON_GATE(CLKID_DVIN, HHI_GCLK_MPEG2, 12),
+       MESON_GATE(CLKID_UART2, HHI_GCLK_MPEG2, 15),
+       MESON_GATE(CLKID_SANA, HHI_GCLK_MPEG2, 22),
+       MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25),
+       MESON_GATE(CLKID_SEC_AHB_AHB3_BRIDGE, HHI_GCLK_MPEG2, 26),
+       MESON_GATE(CLKID_CLK81_A53, HHI_GCLK_MPEG2, 29),
+
+       MESON_GATE(CLKID_VCLK2_VENCI0, HHI_GCLK_OTHER, 1),
+       MESON_GATE(CLKID_VCLK2_VENCI1, HHI_GCLK_OTHER, 2),
+       MESON_GATE(CLKID_VCLK2_VENCP0, HHI_GCLK_OTHER, 3),
+       MESON_GATE(CLKID_VCLK2_VENCP1, HHI_GCLK_OTHER, 4),
+       MESON_GATE(CLKID_GCLK_VENCI_INT0, HHI_GCLK_OTHER, 8),
+       MESON_GATE(CLKID_DAC_CLK, HHI_GCLK_OTHER, 10),
+       MESON_GATE(CLKID_AOCLK_GATE, HHI_GCLK_OTHER, 14),
+       MESON_GATE(CLKID_IEC958_GATE, HHI_GCLK_OTHER, 16),
+       MESON_GATE(CLKID_ENC480P, HHI_GCLK_OTHER, 20),
+       MESON_GATE(CLKID_RNG1, HHI_GCLK_OTHER, 21),
+       MESON_GATE(CLKID_GCLK_VENCI_INT1, HHI_GCLK_OTHER, 22),
+       MESON_GATE(CLKID_VCLK2_VENCLMCC, HHI_GCLK_OTHER, 24),
+       MESON_GATE(CLKID_VCLK2_VENCL, HHI_GCLK_OTHER, 25),
+       MESON_GATE(CLKID_VCLK_OTHER, HHI_GCLK_OTHER, 26),
+       MESON_GATE(CLKID_EDP, HHI_GCLK_OTHER, 31),
+
+       /* Always On (AO) domain gates */
+       MESON_GATE(CLKID_AO_MEDIA_CPU, HHI_GCLK_AO, 0),
+       MESON_GATE(CLKID_AO_AHB_SRAM, HHI_GCLK_AO, 1),
+       MESON_GATE(CLKID_AO_AHB_BUS, HHI_GCLK_AO, 2),
+       MESON_GATE(CLKID_AO_IFACE, HHI_GCLK_AO, 3),
+       MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4),
+
+       /* PLL Gates */
+       /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */
+       MESON_GATE(CLKID_FCLK_DIV3, HHI_MPLL_CNTL6, 28),
+       MESON_GATE(CLKID_FCLK_DIV4, HHI_MPLL_CNTL6, 29),
+       MESON_GATE(CLKID_FCLK_DIV5, HHI_MPLL_CNTL6, 30),
+       MESON_GATE(CLKID_FCLK_DIV7, HHI_MPLL_CNTL6, 31),
+       MESON_GATE(CLKID_MPLL0, HHI_MPLL_CNTL7, 14),
+       MESON_GATE(CLKID_MPLL1, HHI_MPLL_CNTL8, 14),
+       MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14),
+       /* CLKID_CLK81 is critical for the system */
+
+       /* Peripheral Gates */
+       MESON_GATE(CLKID_SAR_ADC_CLK, HHI_SAR_CLK_CNTL, 8),
+       MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7),
+       MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23),
+       MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7),
+};
+
+static int meson_set_gate(struct clk *clk, bool on)
+{
+       struct meson_clk *priv = dev_get_priv(clk->dev);
+       struct meson_gate *gate;
+
+       if (clk->id >= ARRAY_SIZE(gates))
+               return -ENOENT;
+
+       gate = &gates[clk->id];
+
+       if (gate->reg == 0)
+               return 0;
+
+       clrsetbits_le32(priv->addr + gate->reg,
+                       BIT(gate->bit), on ? BIT(gate->bit) : 0);
+       return 0;
+}
+
+static int meson_clk_enable(struct clk *clk)
+{
+       return meson_set_gate(clk, true);
+}
+
+static int meson_clk_disable(struct clk *clk)
+{
+       return meson_set_gate(clk, false);
+}
+
+static unsigned long meson_clk81_get_rate(struct clk *clk)
+{
+       struct meson_clk *priv = dev_get_priv(clk->dev);
+       unsigned long parent_rate;
+       u32 reg;
+       int parents[] = {
+               -1,
+               -1,
+               CLKID_FCLK_DIV7,
+               CLKID_MPLL1,
+               CLKID_MPLL2,
+               CLKID_FCLK_DIV4,
+               CLKID_FCLK_DIV3,
+               CLKID_FCLK_DIV5
+       };
+
+       /* mux */
+       reg = readl(priv->addr + HHI_MPEG_CLK_CNTL);
+       reg = (reg >> 12) & 7;
+
+       switch (reg) {
+       case 0:
+               parent_rate = XTAL_RATE;
+               break;
+       case 1:
+               return -ENOENT;
+       default:
+               parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]);
+       }
+
+       /* divider */
+       reg = readl(priv->addr + HHI_MPEG_CLK_CNTL);
+       reg = reg & ((1 << 7) - 1);
+
+       return parent_rate / reg;
+}
+
+static long mpll_rate_from_params(unsigned long parent_rate,
+                                 unsigned long sdm,
+                                 unsigned long n2)
+{
+       unsigned long divisor = (SDM_DEN * n2) + sdm;
+
+       if (n2 < N2_MIN)
+               return -EINVAL;
+
+       return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
+}
+
+static struct parm meson_mpll0_parm[3] = {
+       {HHI_MPLL_CNTL7, 0, 14}, /* psdm */
+       {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */
+};
+
+static struct parm meson_mpll1_parm[3] = {
+       {HHI_MPLL_CNTL8, 0, 14}, /* psdm */
+       {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */
+};
+
+static struct parm meson_mpll2_parm[3] = {
+       {HHI_MPLL_CNTL9, 0, 14}, /* psdm */
+       {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */
+};
+
+/*
+ * MultiPhase Locked Loops are outputs from a PLL with additional frequency
+ * scaling capabilities. MPLL rates are calculated as:
+ *
+ * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
+ */
+static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id)
+{
+       struct meson_clk *priv = dev_get_priv(clk->dev);
+       struct parm *psdm, *pn2;
+       unsigned long reg, sdm, n2;
+       unsigned long parent_rate;
+
+       switch (id) {
+       case CLKID_MPLL0:
+               psdm = &meson_mpll0_parm[0];
+               pn2 = &meson_mpll0_parm[1];
+               break;
+       case CLKID_MPLL1:
+               psdm = &meson_mpll1_parm[0];
+               pn2 = &meson_mpll1_parm[1];
+               break;
+       case CLKID_MPLL2:
+               psdm = &meson_mpll2_parm[0];
+               pn2 = &meson_mpll2_parm[1];
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL);
+       if (IS_ERR_VALUE(parent_rate))
+               return parent_rate;
+
+       reg = readl(priv->addr + psdm->reg_off);
+       sdm = PARM_GET(psdm->width, psdm->shift, reg);
+
+       reg = readl(priv->addr + pn2->reg_off);
+       n2 = PARM_GET(pn2->width, pn2->shift, reg);
+
+       return mpll_rate_from_params(parent_rate, sdm, n2);
+}
+
+static struct parm meson_fixed_pll_parm[3] = {
+       {HHI_MPLL_CNTL, 0, 9}, /* pm */
+       {HHI_MPLL_CNTL, 9, 5}, /* pn */
+       {HHI_MPLL_CNTL, 16, 2}, /* pod */
+};
+
+static struct parm meson_sys_pll_parm[3] = {
+       {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */
+       {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */
+       {HHI_SYS_PLL_CNTL, 10, 2}, /* pod */
+};
+
+static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
+{
+       struct meson_clk *priv = dev_get_priv(clk->dev);
+       struct parm *pm, *pn, *pod;
+       unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
+       u16 n, m, od;
+       u32 reg;
+
+       switch (id) {
+       case CLKID_FIXED_PLL:
+               pm = &meson_fixed_pll_parm[0];
+               pn = &meson_fixed_pll_parm[1];
+               pod = &meson_fixed_pll_parm[2];
+               break;
+       case CLKID_SYS_PLL:
+               pm = &meson_sys_pll_parm[0];
+               pn = &meson_sys_pll_parm[1];
+               pod = &meson_sys_pll_parm[2];
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       reg = readl(priv->addr + pn->reg_off);
+       n = PARM_GET(pn->width, pn->shift, reg);
+
+       reg = readl(priv->addr + pm->reg_off);
+       m = PARM_GET(pm->width, pm->shift, reg);
+
+       reg = readl(priv->addr + pod->reg_off);
+       od = PARM_GET(pod->width, pod->shift, reg);
+
+       return ((parent_rate_mhz * m / n) >> od) * 1000000;
+}
+
+static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
+{
+       ulong rate;
+
+       switch (id) {
+       case CLKID_FIXED_PLL:
+       case CLKID_SYS_PLL:
+               rate = meson_pll_get_rate(clk, id);
+               break;
+       case CLKID_FCLK_DIV2:
+               rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2;
+               break;
+       case CLKID_FCLK_DIV3:
+               rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3;
+               break;
+       case CLKID_FCLK_DIV4:
+               rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4;
+               break;
+       case CLKID_FCLK_DIV5:
+               rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5;
+               break;
+       case CLKID_FCLK_DIV7:
+               rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7;
+               break;
+       case CLKID_MPLL0:
+       case CLKID_MPLL1:
+       case CLKID_MPLL2:
+               rate = meson_mpll_get_rate(clk, id);
+               break;
+       case CLKID_CLK81:
+               rate = meson_clk81_get_rate(clk);
+               break;
+       default:
+               if (gates[id].reg != 0) {
+                       /* a clock gate */
+                       rate = meson_clk81_get_rate(clk);
+                       break;
+               }
+               return -ENOENT;
+       }
+
+       printf("clock %lu has rate %lu\n", id, rate);
+       return rate;
+}
+
+static ulong meson_clk_get_rate(struct clk *clk)
+{
+       return meson_clk_get_rate_by_id(clk, clk->id);
+}
+
+static int meson_clk_probe(struct udevice *dev)
+{
+       struct meson_clk *priv = dev_get_priv(dev);
+
+       priv->addr = dev_read_addr_ptr(dev);
+
+       debug("meson-clk: probed at addr %p\n", priv->addr);
+
+       return 0;
+}
+
+static struct clk_ops meson_clk_ops = {
+       .disable        = meson_clk_disable,
+       .enable         = meson_clk_enable,
+       .get_rate       = meson_clk_get_rate,
+};
+
+static const struct udevice_id meson_clk_ids[] = {
+       { .compatible = "amlogic,gxbb-clkc" },
+       { .compatible = "amlogic,gxl-clkc" },
+       { }
+};
+
+U_BOOT_DRIVER(meson_clk) = {
+       .name           = "meson_clk",
+       .id             = UCLASS_CLK,
+       .of_match       = meson_clk_ids,
+       .priv_auto_alloc_size = sizeof(struct meson_clk),
+       .ops            = &meson_clk_ops,
+       .probe          = meson_clk_probe,
+};
diff --git a/drivers/clk/clk_meson.h b/drivers/clk/clk_meson.h
new file mode 100644 (file)
index 0000000..7adc55a
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
+ * (C) Copyright 2018 - BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef CLK_MESON_H
+#define CLK_MESON_H
+
+/* Gate Structure */
+
+struct meson_gate {
+       unsigned int reg;
+       unsigned int bit;
+};
+
+#define MESON_GATE(id, _reg, _bit)             \
+       [id] = {                                \
+               .reg = (_reg),                  \
+               .bit = (_bit),                  \
+       }
+
+/* PLL Parameters */
+
+struct parm {
+       u16 reg_off;
+       u8 shift;
+       u8 width;
+};
+
+#define PMASK(width)                    GENMASK(width - 1, 0)
+#define SETPMASK(width, shift)          GENMASK(shift + width - 1, shift)
+#define CLRPMASK(width, shift)          (~SETPMASK(width, shift))
+
+#define PARM_GET(width, shift, reg)                                     \
+       (((reg) & SETPMASK(width, shift)) >> (shift))
+#define PARM_SET(width, shift, reg, val)                                \
+       (((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
+
+/* MPLL Parameters */
+
+#define SDM_DEN 16384
+#define N2_MIN  4
+#define N2_MAX  511
+
+#endif
index e410f5f9dfe6cd03bbfb534ef100ee9a27d77b70..1a1d37ae2a42068b0935e69886b9bea25afbc4ff 100644 (file)
@@ -7,11 +7,14 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/davinci_misc.h>
 
+#ifndef CONFIG_DM_GPIO
 static struct gpio_registry {
        int is_registered;
        char name[GPIO_NAME_SIZE];
@@ -303,7 +306,7 @@ static const struct pinmux_config gpio_pinmux[] = {
 #define davinci_configure_pin_mux(a, b)
 #endif /* CONFIG_SOC_DA8XX */
 
-int gpio_request(unsigned gpio, const char *label)
+int gpio_request(unsigned int gpio, const char *label)
 {
        if (gpio >= MAX_NUM_GPIOS)
                return -1;
@@ -320,7 +323,7 @@ int gpio_request(unsigned gpio, const char *label)
        return 0;
 }
 
-int gpio_free(unsigned gpio)
+int gpio_free(unsigned int gpio)
 {
        if (gpio >= MAX_NUM_GPIOS)
                return -1;
@@ -333,42 +336,30 @@ int gpio_free(unsigned gpio)
        /* Do not configure as input or change pin mux here */
        return 0;
 }
+#endif
 
-int gpio_direction_input(unsigned gpio)
+static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio, int value)
 {
-       struct davinci_gpio *bank;
-
-       bank = GPIO_BANK(gpio);
-       setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
+       clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
+       gpio_set_value(gpio, value);
        return 0;
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int _gpio_direction_input(struct davinci_gpio *bank, unsigned int gpio)
 {
-       struct davinci_gpio *bank;
-
-       bank = GPIO_BANK(gpio);
-       clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
-       gpio_set_value(gpio, value);
+       setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
        return 0;
 }
 
-int gpio_get_value(unsigned gpio)
+static int _gpio_get_value(struct davinci_gpio *bank, unsigned int gpio)
 {
-       struct davinci_gpio *bank;
        unsigned int ip;
-
-       bank = GPIO_BANK(gpio);
        ip = in_le32(&bank->in_data) & (1U << GPIO_BIT(gpio));
        return ip ? 1 : 0;
 }
 
-int gpio_set_value(unsigned gpio, int value)
+static int _gpio_set_value(struct davinci_gpio *bank, unsigned int gpio, int value)
 {
-       struct davinci_gpio *bank;
-
-       bank = GPIO_BANK(gpio);
-
        if (value)
                bank->set_data = 1U << GPIO_BIT(gpio);
        else
@@ -377,14 +368,21 @@ int gpio_set_value(unsigned gpio, int value)
        return 0;
 }
 
+static int _gpio_get_dir(struct davinci_gpio *bank, unsigned int gpio)
+{
+       return in_le32(&bank->dir) & (1U << GPIO_BIT(gpio));
+}
+
+#ifndef CONFIG_DM_GPIO
+
 void gpio_info(void)
 {
-       unsigned gpio, dir, val;
+       unsigned int gpio, dir, val;
        struct davinci_gpio *bank;
 
        for (gpio = 0; gpio < MAX_NUM_GPIOS; ++gpio) {
                bank = GPIO_BANK(gpio);
-               dir = in_le32(&bank->dir) & (1U << GPIO_BIT(gpio));
+               dir = _gpio_get_dir(bank, gpio);
                val = gpio_get_value(gpio);
 
                printf("% 4d: %s: %d [%c] %s\n",
@@ -393,3 +391,150 @@ void gpio_info(void)
                        gpio_registry[gpio].name);
        }
 }
+
+int gpio_direction_input(unsigned int gpio)
+{
+       struct davinci_gpio *bank;
+
+       bank = GPIO_BANK(gpio);
+       return _gpio_direction_input(bank, gpio);
+}
+
+int gpio_direction_output(unsigned int gpio, int value)
+{
+       struct davinci_gpio *bank;
+
+       bank = GPIO_BANK(gpio);
+       return _gpio_direction_output(bank, gpio, value);
+}
+
+int gpio_get_value(unsigned int gpio)
+{
+       struct davinci_gpio *bank;
+
+       bank = GPIO_BANK(gpio);
+       return _gpio_get_value(bank, gpio);
+}
+
+int gpio_set_value(unsigned int gpio, int value)
+{
+       struct davinci_gpio *bank;
+
+       bank = GPIO_BANK(gpio);
+       return _gpio_set_value(bank, gpio, value);
+}
+
+#else /* CONFIG_DM_GPIO */
+
+static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset)
+{
+       struct davinci_gpio_bank *bank = dev_get_priv(dev);
+
+       /* The device tree is not broken into banks but the infrastructure is
+        * expecting it this way, so we'll first include the 0x10 offset, then
+        * calculate the bank manually based on the offset.
+        */
+
+       return ((struct davinci_gpio *)bank->base) + 0x10 + (offset >> 5);
+}
+
+static int davinci_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+       struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+       _gpio_direction_input(base, offset);
+       return 0;
+}
+
+static int davinci_gpio_direction_output(struct udevice *dev, unsigned int offset,
+                                        int value)
+{
+       struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+       _gpio_direction_output(base, offset, value);
+       return 0;
+}
+
+static int davinci_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+       struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+       return _gpio_get_value(base, offset);
+}
+
+static int davinci_gpio_set_value(struct udevice *dev, unsigned int offset,
+                                 int value)
+{
+       struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+       _gpio_set_value(base, offset, value);
+
+       return 0;
+}
+
+static int davinci_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+       unsigned int dir;
+       struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+       dir = _gpio_get_dir(base, offset);
+
+       if (dir)
+               return GPIOF_INPUT;
+
+       return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops gpio_davinci_ops = {
+       .direction_input        = davinci_gpio_direction_input,
+       .direction_output       = davinci_gpio_direction_output,
+       .get_value              = davinci_gpio_get_value,
+       .set_value              = davinci_gpio_set_value,
+       .get_function           = davinci_gpio_get_function,
+};
+
+static int davinci_gpio_probe(struct udevice *dev)
+{
+       struct davinci_gpio_bank *bank = dev_get_priv(dev);
+       struct davinci_gpio_platdata *plat = dev_get_platdata(dev);
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       const void *fdt = gd->fdt_blob;
+       int node = dev_of_offset(dev);
+
+       uc_priv->bank_name = plat->port_name;
+       uc_priv->gpio_count = fdtdec_get_int(fdt, node, "ti,ngpio", -1);
+       bank->base = (struct davinci_gpio *)plat->base;
+       return 0;
+}
+
+static const struct udevice_id davinci_gpio_ids[] = {
+       { .compatible = "ti,dm6441-gpio" },
+       { }
+};
+
+static int davinci_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+       struct davinci_gpio_platdata *plat = dev_get_platdata(dev);
+       fdt_addr_t addr;
+
+       addr = devfdt_get_addr(dev);
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       plat->base = addr;
+       return 0;
+}
+
+U_BOOT_DRIVER(gpio_davinci) = {
+       .name   = "gpio_davinci",
+       .id     = UCLASS_GPIO,
+       .ops    = &gpio_davinci_ops,
+       .ofdata_to_platdata = of_match_ptr(davinci_gpio_ofdata_to_platdata),
+       .of_match = davinci_gpio_ids,
+       .bind   = dm_scan_fdt_dev,
+       .platdata_auto_alloc_size = sizeof(struct davinci_gpio_platdata),
+       .probe  = davinci_gpio_probe,
+       .priv_auto_alloc_size = sizeof(struct davinci_gpio_bank),
+};
+
+#endif
index d128f942a0681da211648e2cb55caa9f3ef16320..79a975ce71b7ef5de446d61ef0cec79daa247e9c 100644 (file)
@@ -288,11 +288,17 @@ static int omap_gpio_probe(struct udevice *dev)
        struct gpio_bank *bank = dev_get_priv(dev);
        struct omap_gpio_platdata *plat = dev_get_platdata(dev);
        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       int banknum;
+       char name[18], *str;
 
-       uc_priv->bank_name = plat->port_name;
+       banknum = plat->bank_index;
+       sprintf(name, "GPIO%d_", banknum + 1);
+       str = strdup(name);
+       if (!str)
+               return -ENOMEM;
+       uc_priv->bank_name = str;
        uc_priv->gpio_count = GPIO_PER_BANK;
        bank->base = (void *)plat->base;
-
        return 0;
 }
 
index 8c9318d4f150864d138b33108dc74ec189ec6da9..7d06d95cf38876092b982e3e4422eff2b446ee4f 100644 (file)
@@ -3,8 +3,8 @@
  * (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com>
  */
 #include <common.h>
-#include <asm/arch/i2c.h>
 #include <asm/io.h>
+#include <clk.h>
 #include <dm.h>
 #include <i2c.h>
 
@@ -42,6 +42,7 @@ struct i2c_regs {
 };
 
 struct meson_i2c {
+       struct clk clk;
        struct i2c_regs *regs;
        struct i2c_msg *msg;    /* Current I2C message */
        bool last;              /* Whether the message is the last */
@@ -221,9 +222,13 @@ static int meson_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
 static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 {
        struct meson_i2c *i2c = dev_get_priv(bus);
-       unsigned int clk_rate = MESON_I2C_CLK_RATE;
+       ulong clk_rate;
        unsigned int div;
 
+       clk_rate = clk_get_rate(&i2c->clk);
+       if (IS_ERR_VALUE(clk_rate))
+               return -EINVAL;
+
        div = DIV_ROUND_UP(clk_rate, speed * 4);
 
        /* clock divider has 12 bits */
@@ -238,7 +243,7 @@ static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
        clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
                        (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
 
-       debug("meson i2c: set clk %u, src %u, div %u\n", speed, clk_rate, div);
+       debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div);
 
        return 0;
 }
@@ -246,6 +251,15 @@ static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 static int meson_i2c_probe(struct udevice *bus)
 {
        struct meson_i2c *i2c = dev_get_priv(bus);
+       int ret;
+
+       ret = clk_get_by_index(bus, 0, &i2c->clk);
+       if (ret < 0)
+               return ret;
+
+       ret = clk_enable(&i2c->clk);
+       if (ret)
+               return ret;
 
        i2c->regs = dev_read_addr_ptr(bus);
        clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
index 56cd0700fa45a1d044ddf6aa6dff2dee9960a02f..b777404c0977d5e9be61bbe91ed8597f898eca74 100644 (file)
@@ -21,7 +21,7 @@
  */
 struct swap_case_platdata {
        u16 command;
-       u32 bar[2];
+       u32 bar[6];
 };
 
 #define offset_to_barnum(offset)       \
index 7893efee12aa519086670e95048ff4b44763738a..f23c0e13e0c87124682dee147e530dad737a56c7 100644 (file)
@@ -567,16 +567,17 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
        strncpy(name, spec, sizeof(name) - 6);
        name[sizeof(name) - 6] = '\0';
        strcat(name, "-emul");
-       str = strdup(name);
-       if (!str)
-               return -ENOMEM;
        drv = lists_driver_lookup_name("sandbox_sf_emul");
        if (!drv) {
                puts("Cannot find sandbox_sf_emul driver\n");
                return -ENOENT;
        }
+       str = strdup(name);
+       if (!str)
+               return -ENOMEM;
        ret = device_bind(bus, drv, str, NULL, of_offset, &emul);
        if (ret) {
+               free(str);
                printf("Cannot create emul device for spec '%s' (err=%d)\n",
                       spec, ret);
                return ret;
diff --git a/dts/.gitignore b/dts/.gitignore
deleted file mode 100644 (file)
index 1b37180..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.dtb
-*.dtb.S
index 27d78837c54105aaddc0361f633abd16eb39c30e..986d078679784bd3e143c834e96ebba8ad15a930 100644 (file)
@@ -13,7 +13,6 @@
 
 struct btrfs_info {
        struct btrfs_super_block sb;
-       struct btrfs_root_backup *root_backup;
 
        struct btrfs_root tree_root;
        struct btrfs_root fs_root;
index ad6641f3148eb75673dc852094375e4e1084dd2d..e680caa56a4d0a8063072ca60acf9780a325a558 100644 (file)
 
 #define BTRFS_SUPER_INFO_SIZE  4096
 
-static int btrfs_newest_root_backup(struct btrfs_super_block *sb)
+/*
+ * checks if a valid root backup is present.
+ * considers the case when all root backups empty valid.
+ * returns -1 in case of invalid root backup and 0 for valid.
+ */
+static int btrfs_check_super_roots(struct btrfs_super_block *sb)
 {
        struct btrfs_root_backup *root_backup;
        int i, newest = -1;
+       int num_empty = 0;
 
        for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; ++i) {
                root_backup = sb->super_roots + i;
+
+               if (root_backup->tree_root == 0 && root_backup->tree_root_gen == 0)
+                       num_empty++;
+
                if (root_backup->tree_root_gen == sb->generation)
                        newest = i;
        }
 
-       return newest;
+       if (num_empty == BTRFS_NUM_BACKUP_ROOTS) {
+               return 0;
+       } else if (newest >= 0) {
+               return 0;
+       }
+
+       return -1;
 }
 
 static inline int is_power_of_2(u64 x)
@@ -166,7 +182,7 @@ int btrfs_read_superblock(void)
        char raw_sb[BTRFS_SUPER_INFO_SIZE];
        struct btrfs_super_block *sb = (struct btrfs_super_block *) raw_sb;
        u64 dev_total_bytes;
-       int i, root_backup_idx;
+       int i;
 
        dev_total_bytes = (u64) btrfs_part_info->size * btrfs_part_info->blksz;
 
@@ -211,17 +227,15 @@ int btrfs_read_superblock(void)
                return -1;
        }
 
-       root_backup_idx = btrfs_newest_root_backup(&btrfs_info.sb);
-       if (root_backup_idx < 0) {
+       if (btrfs_check_super_roots(&btrfs_info.sb)) {
                printf("%s: No valid root_backup found!\n", __func__);
                return -1;
        }
-       btrfs_info.root_backup = btrfs_info.sb.super_roots + root_backup_idx;
 
-       if (btrfs_info.root_backup->num_devices != 1) {
+       if (btrfs_info.sb.num_devices != 1) {
                printf("%s: Unsupported number of devices (%lli). This driver "
                       "only supports filesystem on one device.\n", __func__,
-                      btrfs_info.root_backup->num_devices);
+                      btrfs_info.sb.num_devices);
                return -1;
        }
 
diff --git a/include/avb_verify.h b/include/avb_verify.h
new file mode 100644 (file)
index 0000000..eaa60f5
--- /dev/null
@@ -0,0 +1,96 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef        _AVB_VERIFY_H
+#define _AVB_VERIFY_H
+
+#include <../lib/libavb/libavb.h>
+#include <mmc.h>
+
+#define AVB_MAX_ARGS                   1024
+#define VERITY_TABLE_OPT_RESTART       "restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING       "ignore_corruption"
+#define ALLOWED_BUF_ALIGN              8
+
+enum avb_boot_state {
+       AVB_GREEN,
+       AVB_YELLOW,
+       AVB_ORANGE,
+       AVB_RED,
+};
+
+struct AvbOpsData {
+       struct AvbOps ops;
+       int mmc_dev;
+       enum avb_boot_state boot_state;
+};
+
+struct mmc_part {
+       int dev_num;
+       struct mmc *mmc;
+       struct blk_desc *mmc_blk;
+       disk_partition_t info;
+};
+
+enum mmc_io_type {
+       IO_READ,
+       IO_WRITE
+};
+
+AvbOps *avb_ops_alloc(int boot_device);
+void avb_ops_free(AvbOps *ops);
+
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
+char *avb_set_enforce_verity(const char *cmdline);
+char *avb_set_ignore_corruption(const char *cmdline);
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
+
+/**
+ * ============================================================================
+ * I/O helper inline functions
+ * ============================================================================
+ */
+static inline uint64_t calc_offset(struct mmc_part *part, int64_t offset)
+{
+       u64 part_size = part->info.size * part->info.blksz;
+
+       if (offset < 0)
+               return part_size + offset;
+
+       return offset;
+}
+
+static inline size_t get_sector_buf_size(void)
+{
+       return (size_t)CONFIG_FASTBOOT_BUF_SIZE;
+}
+
+static inline void *get_sector_buf(void)
+{
+       return (void *)CONFIG_FASTBOOT_BUF_ADDR;
+}
+
+static inline bool is_buf_unaligned(void *buffer)
+{
+       return (bool)((uintptr_t)buffer % ALLOWED_BUF_ALIGN);
+}
+
+static inline int get_boot_device(AvbOps *ops)
+{
+       struct AvbOpsData *data;
+
+       if (ops) {
+               data = ops->user_data;
+               if (data)
+                       return data->mmc_dev;
+       }
+
+       return -1;
+}
+
+#endif /* _AVB_VERIFY_H */
index fc0c239e4680b49ebd619d4784d76e8c66952ee4..86f6d5057f23e7155a6ead3248d426baef94d171 100644 (file)
@@ -111,7 +111,7 @@ struct blk_desc {
 #define PAD_TO_BLOCKSIZE(size, blk_desc) \
        (PAD_SIZE(size, blk_desc->blksz))
 
-#ifdef CONFIG_BLOCK_CACHE
+#if CONFIG_IS_ENABLED(BLOCK_CACHE)
 /**
  * blkcache_read() - attempt to read a set of blocks from cache
  *
index 60c79137e212c0eb6f22a7f6ef4305d6b8583275..940161f1758b77cfa31984ed3b65bd28b208b47d 100644 (file)
@@ -536,10 +536,10 @@ void show_activity(int arg);
 
 /* Multicore arch functions */
 #ifdef CONFIG_MP
-int cpu_status(int nr);
-int cpu_reset(int nr);
-int cpu_disable(int nr);
-int cpu_release(int nr, int argc, char * const argv[]);
+int cpu_status(u32 nr);
+int cpu_reset(u32 nr);
+int cpu_disable(u32 nr);
+int cpu_release(u32 nr, int argc, char * const argv[]);
 #endif
 
 #else  /* __ASSEMBLY__ */
index 6231a1e4ae6c471a20d986f2a6d564b541f3878d..b5ff5d3fe1817bc63bc9aebe97cfe49c808677ba 100644 (file)
@@ -70,8 +70,6 @@
 #define CONFIG_NETMASK         255.255.255.0
 #define CONFIG_ETHPRIME                "eTSEC1"
 
-#ifndef CONFIG_SPI_FLASH
-#endif
 #define CONFIG_SYS_REDUNDAND_ENVIRONMENT
 
 #define CONFIG_SYS_L2_SIZE     (256 << 10)
index d2cd4403119dadc50f956df975d1502381053f50..ebfdd1c7a3728abd54a86650fefb072da2846db2 100644 (file)
@@ -40,7 +40,6 @@
 
 #ifdef CONFIG_DIRECT_NOR_BOOT
 #define CONFIG_ARCH_CPU_INIT
-#define CONFIG_DA8XX_GPIO
 #define CONFIG_SYS_DV_NOR_BOOT_CFG     (0x11)
 #endif
 
 #define CONFIG_MTD_PARTITIONS          /* required for UBI partition support */
 #endif
 
+#define CONFIG_DA8XX_GPIO
 /*
  * U-Boot general configuration
  */
index 86fa735470c743027806400bada46487cc1a2e3e..46a7179f1bed023b5b1a306678627b073bdebd28 100644 (file)
@@ -94,6 +94,7 @@ REFLASH(dragonboard/u-boot.img, 8)\
 
 #define CONFIG_ENV_SIZE                        0x2000
 #define CONFIG_SYS_MMC_ENV_DEV         0       /* mmc0 = emmc, mmc1 = sd */
+#define CONFIG_SYS_MMC_ENV_PART 2 /* Set env partition to BOOT2 partition */
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN          (CONFIG_ENV_SIZE + SZ_8M)
index 6e61b704a3caa8d8b0db816175aaa38e57e981bb..7435f3475ea8120cda119aa128b33a1c81cc6a39 100644 (file)
 #define GICD_BASE                      0xc4301000
 #define GICC_BASE                      0xc4302000
 
+#ifdef CONFIG_CMD_USB
+#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0)
+#else
+#define BOOT_TARGET_DEVICES_USB(func)
+#endif
+
 #define BOOT_TARGET_DEVICES(func) \
        func(MMC, mmc, 0) \
        func(MMC, mmc, 1) \
        func(MMC, mmc, 2) \
+       BOOT_TARGET_DEVICES_USB(func) \
        func(PXE, pxe, na) \
        func(DHCP, dhcp, na)
 
index 0d8ae0b099b63457d76086241887a92184f1feda..2456475f27ca7a44651f5bd4604a1aa360d2f9a8 100644 (file)
 #undef PCI_ONE_PCI1
 #endif
 
-#ifndef VME_CADDY2
-#endif
-
 #undef CONFIG_EEPRO100
 #undef CONFIG_TULIP
 
index a43b211df5e3867e49cd42d2cad5b7cf79fa0f43..2893cd4287a03727159b56733caa5ddf318a8d34 100644 (file)
 #define CONSOLEDEV "ttyO2"
 #endif
 
+#define VBMETA_PART_SIZE               (64 * 1024)
+
+#if defined(CONFIG_LIBAVB)
+#define VBMETA_PART \
+       "name=vbmeta,size=" __stringify(VBMETA_PART_SIZE) \
+       ",uuid=${uuid_gpt_vbmeta};"
+#else
+#define VBMETA_PART                    ""
+#endif
+
 #ifndef PARTS_DEFAULT
 /* Define the default GPT table for eMMC */
 #define PARTS_DEFAULT \
        "name=cache,size=256M,uuid=${uuid_gpt_cache};" \
        "name=ipu1,size=1M,uuid=${uuid_gpt_ipu1};" \
        "name=ipu2,size=1M,uuid=${uuid_gpt_ipu2};" \
+       VBMETA_PART \
        "name=userdata,size=-,uuid=${uuid_gpt_userdata}"
 #endif /* PARTS_DEFAULT */
 
+#if defined(CONFIG_CMD_AVB)
+#define AVB_VERIFY_CHECK "if run avb_verify; then " \
+                               "echo AVB verification OK.;" \
+                               "set bootargs $bootargs $avb_bootargs;" \
+                       "else " \
+                               "echo AVB verification failed.;" \
+                       "exit; fi;"
+#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify;\0"
+#else
+#define AVB_VERIFY_CHECK ""
+#define AVB_VERIFY_CMD ""
+#endif
+
 #define DEFAULT_COMMON_BOOT_TI_ARGS \
        "console=" CONSOLEDEV ",115200n8\0" \
        "fdtfile=undefined\0" \
@@ -48,6 +72,7 @@
        "bootfile=zImage\0" \
        "usbtty=cdc_acm\0" \
        "vram=16M\0" \
+       AVB_VERIFY_CMD \
        "partitions=" PARTS_DEFAULT "\0" \
        "optargs=\0" \
        "dofastboot=0\0" \
@@ -66,6 +91,7 @@
                "setenv machid fe6; " \
                "mmc dev $mmcdev; " \
                "mmc rescan; " \
+               AVB_VERIFY_CHECK \
                "part start mmc ${mmcdev} environment fdt_start; " \
                "part size mmc ${mmcdev} environment fdt_size; " \
                "part start mmc ${mmcdev} boot boot_start; " \
index 95d5934344cffb5add1ddbc546126690b7a1689c..420b8ff5761a1bd267fa6d95e77077ae8fe6048e 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "compiler.h"
 #include <asm/byteorder.h>
+#include <stdbool.h>
 
 /* Define this to avoid #ifdefs later on */
 struct lmb;
@@ -881,9 +882,11 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
  * @image: Address of image
  * @start: Returns start address of image
  * @size : Returns size image
+ * @force_reloc: Ignore image->ep field, always place image to RAM start
  * @return 0 if OK, 1 if the image was not recognised
  */
-int booti_setup(ulong image, ulong *relocated_addr, ulong *size);
+int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
+               bool force_reloc);
 
 /*******************************************************************/
 /* New uImage format specific code (prefixed with fit_) */
index 1efb117343ab0481c7040c9d35c2a046db154325..be1d2753e195632fbf6daace82a2ad2165532257 100644 (file)
@@ -6,8 +6,36 @@
 #ifndef __IOTRACE_H
 #define __IOTRACE_H
 
+//#include <common.h>
 #include <linux/types.h>
 
+/* Support up to the machine word length for now */
+typedef ulong iovalue_t;
+
+enum iotrace_flags {
+       IOT_8 = 0,
+       IOT_16,
+       IOT_32,
+
+       IOT_READ = 0 << 3,
+       IOT_WRITE = 1 << 3,
+};
+
+/**
+ * struct iotrace_record - Holds a single I/O trace record
+ *
+ * @flags: I/O access type
+ * @timestamp: Timestamp of access
+ * @addr: Address of access
+ * @value: Value written or read
+ */
+struct iotrace_record {
+       enum iotrace_flags flags;
+       u64 timestamp;
+       phys_addr_t addr;
+       iovalue_t value;
+};
+
 /*
  * This file is designed to be included in arch/<arch>/include/asm/io.h.
  * It redirects all IO access through a tracing/checksumming feature for
@@ -118,11 +146,12 @@ void iotrace_set_buffer(ulong start, ulong size);
  * iotrace_get_buffer() - Get buffer information
  *
  * @start: Returns start address of buffer
- * @size: Returns size of buffer in bytes
+ * @size: Returns actual size of buffer in bytes
+ * @needed_size: Returns needed size of buffer in bytes
  * @offset: Returns the byte offset where the next output trace record will
  * @count: Returns the number of trace records recorded
  * be written (or would be if the buffer was large enough)
  */
-void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count);
+void iotrace_get_buffer(ulong *start, ulong *size, ulong *needed_size, ulong *offset, ulong *count);
 
 #endif /* __IOTRACE_H */
index a3edd25546a0505f4a5abf5b8863da7c1116a367..3e99d6e62b69db48976cc7d3f8f09ae6104f5314 100644 (file)
@@ -274,7 +274,8 @@ struct log_filter {
  * log_get_cat_name() - Get the name of a category
  *
  * @cat: Category to look up
- * @return category name (which may be a uclass driver name)
+ * @return category name (which may be a uclass driver name) if found, or
+ *      "<invalid>" if invalid, or "<missing>" if not found
  */
 const char *log_get_cat_name(enum log_category_t cat);
 
index dd54516f302146ec945b7aa4a2b2a253ef8f7357..a77bf1c688affc9f72ebd10ed0df1c2d4f9672dc 100644 (file)
@@ -187,6 +187,20 @@ config TPM
 
 endmenu
 
+menu "Android Verified Boot"
+
+config LIBAVB
+       bool "Android Verified Boot 2.0 support"
+       depends on ANDROID_BOOT_IMAGE
+       default n
+       help
+         This enables support of Android Verified Boot 2.0 which can be used
+         to assure the end user of the integrity of the software running on a
+         device. Introduces such features as boot chain of trust, rollback
+         protection etc.
+
+endmenu
+
 menu "Hashing Support"
 
 config SHA1
index 427d3591599cadcc2ccbc8ae80fe8a80169031fb..5f583aed37d94c9a7cd54ef89a62795358fa6c99 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
 obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
 obj-$(CONFIG_$(SPL_)LZO) += lzo/
 
+obj-$(CONFIG_LIBAVB) += libavb/
 
 obj-$(CONFIG_$(SPL_TPL_)SAVEENV) += qsort.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
diff --git a/lib/libavb/Makefile b/lib/libavb/Makefile
new file mode 100644 (file)
index 0000000..b983fe7
--- /dev/null
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2017 Linaro Limited
+
+obj-$(CONFIG_LIBAVB) += avb_chain_partition_descriptor.o avb_cmdline.o
+obj-$(CONFIG_LIBAVB) += avb_crypto.o avb_footer.o avb_hashtree_descriptor.o
+obj-$(CONFIG_LIBAVB) += avb_property_descriptor.o avb_sha256.o
+obj-$(CONFIG_LIBAVB) += avb_slot_verify.o avb_util.o avb_version.o
+obj-$(CONFIG_LIBAVB) += avb_descriptor.o avb_hash_descriptor.o
+obj-$(CONFIG_LIBAVB) += avb_kernel_cmdline_descriptor.o avb_rsa.o avb_sha512.o
+obj-$(CONFIG_LIBAVB) += avb_sysdeps_posix.o avb_vbmeta_image.o
+
+ccflags-y = -DAVB_COMPILATION
diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c
new file mode 100644 (file)
index 0000000..e299306
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_chain_partition_descriptor.h"
+#include "avb_util.h"
+
+bool avb_chain_partition_descriptor_validate_and_byteswap(
+    const AvbChainPartitionDescriptor* src, AvbChainPartitionDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbChainPartitionDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) {
+    avb_error("Invalid tag for chain partition descriptor.\n");
+    return false;
+  }
+
+  dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->public_key_len = avb_be32toh(dest->public_key_len);
+
+  if (dest->rollback_index_location < 1) {
+    avb_error("Invalid rollback index location value.\n");
+    return false;
+  }
+
+  /* Check that partition_name and public_key are fully contained. */
+  expected_size = sizeof(AvbChainPartitionDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->public_key_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_chain_partition_descriptor.h b/lib/libavb/avb_chain_partition_descriptor.h
new file mode 100644 (file)
index 0000000..80e2271
--- /dev/null
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_CHAIN_PARTITION_DESCRIPTOR_H_
+#define AVB_CHAIN_PARTITION_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor containing a pointer to signed integrity data stored
+ * on another partition. The descriptor contains the partition name in
+ * question (without the A/B suffix), the public key used to sign the
+ * integrity data, and rollback index location to use for rollback
+ * protection.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded) and |public_key_len| bytes of the
+ * public key.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ */
+typedef struct AvbChainPartitionDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t rollback_index_location;
+  uint32_t partition_name_len;
+  uint32_t public_key_len;
+  uint8_t reserved[64];
+} AVB_ATTR_PACKED AvbChainPartitionDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_chain_partition_descriptor_validate_and_byteswap(
+    const AvbChainPartitionDescriptor* src,
+    AvbChainPartitionDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_CHAIN_PARTITION_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
new file mode 100644 (file)
index 0000000..91a6615
--- /dev/null
@@ -0,0 +1,421 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_cmdline.h"
+#include "avb_sha.h"
+#include "avb_util.h"
+#include "avb_version.h"
+
+#define NUM_GUIDS 3
+
+/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
+ * values. Returns NULL on OOM, otherwise the cmdline with values
+ * replaced.
+ */
+char* avb_sub_cmdline(AvbOps* ops,
+                      const char* cmdline,
+                      const char* ab_suffix,
+                      bool using_boot_for_vbmeta,
+                      const AvbCmdlineSubstList* additional_substitutions) {
+  const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
+  const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
+                                        "$(ANDROID_BOOT_PARTUUID)",
+                                        "$(ANDROID_VBMETA_PARTUUID)"};
+  char* ret = NULL;
+  AvbIOResult io_ret;
+  size_t n;
+
+  /* Special-case for when the top-level vbmeta struct is in the boot
+   * partition.
+   */
+  if (using_boot_for_vbmeta) {
+    part_name_str[2] = "boot";
+  }
+
+  /* Replace unique partition GUIDs */
+  for (n = 0; n < NUM_GUIDS; n++) {
+    char part_name[AVB_PART_NAME_MAX_SIZE];
+    char guid_buf[37];
+
+    if (!avb_str_concat(part_name,
+                        sizeof part_name,
+                        part_name_str[n],
+                        avb_strlen(part_name_str[n]),
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      goto fail;
+    }
+
+    io_ret = ops->get_unique_guid_for_partition(
+        ops, part_name, guid_buf, sizeof guid_buf);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      goto fail;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error getting unique GUID for partition.\n");
+      goto fail;
+    }
+
+    if (ret == NULL) {
+      ret = avb_replace(cmdline, replace_str[n], guid_buf);
+    } else {
+      char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
+      avb_free(ret);
+      ret = new_ret;
+    }
+    if (ret == NULL) {
+      goto fail;
+    }
+  }
+
+  avb_assert(ret != NULL);
+
+  /* Replace any additional substitutions. */
+  if (additional_substitutions != NULL) {
+    for (n = 0; n < additional_substitutions->size; ++n) {
+      char* new_ret = avb_replace(ret,
+                                  additional_substitutions->tokens[n],
+                                  additional_substitutions->values[n]);
+      avb_free(ret);
+      ret = new_ret;
+      if (ret == NULL) {
+        goto fail;
+      }
+    }
+  }
+
+  return ret;
+
+fail:
+  if (ret != NULL) {
+    avb_free(ret);
+  }
+  return NULL;
+}
+
+static int cmdline_append_option(AvbSlotVerifyData* slot_data,
+                                 const char* key,
+                                 const char* value) {
+  size_t offset, key_len, value_len;
+  char* new_cmdline;
+
+  key_len = avb_strlen(key);
+  value_len = avb_strlen(value);
+
+  offset = 0;
+  if (slot_data->cmdline != NULL) {
+    offset = avb_strlen(slot_data->cmdline);
+    if (offset > 0) {
+      offset += 1;
+    }
+  }
+
+  new_cmdline = avb_calloc(offset + key_len + value_len + 2);
+  if (new_cmdline == NULL) {
+    return 0;
+  }
+  if (offset > 0) {
+    avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
+    new_cmdline[offset - 1] = ' ';
+  }
+  avb_memcpy(new_cmdline + offset, key, key_len);
+  new_cmdline[offset + key_len] = '=';
+  avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
+  if (slot_data->cmdline != NULL) {
+    avb_free(slot_data->cmdline);
+  }
+  slot_data->cmdline = new_cmdline;
+
+  return 1;
+}
+
+#define AVB_MAX_DIGITS_UINT64 32
+
+/* Writes |value| to |digits| in base 10 followed by a NUL byte.
+ * Returns number of characters written excluding the NUL byte.
+ */
+static size_t uint64_to_base10(uint64_t value,
+                               char digits[AVB_MAX_DIGITS_UINT64]) {
+  char rev_digits[AVB_MAX_DIGITS_UINT64];
+  size_t n, num_digits;
+
+  for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
+    rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
+    if (value == 0) {
+      break;
+    }
+  }
+
+  for (n = 0; n < num_digits; n++) {
+    digits[n] = rev_digits[num_digits - 1 - n];
+  }
+  digits[n] = '\0';
+  return n;
+}
+
+static int cmdline_append_version(AvbSlotVerifyData* slot_data,
+                                  const char* key,
+                                  uint64_t major_version,
+                                  uint64_t minor_version) {
+  char major_digits[AVB_MAX_DIGITS_UINT64];
+  char minor_digits[AVB_MAX_DIGITS_UINT64];
+  char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
+  size_t num_major_digits, num_minor_digits;
+
+  num_major_digits = uint64_to_base10(major_version, major_digits);
+  num_minor_digits = uint64_to_base10(minor_version, minor_digits);
+  avb_memcpy(combined, major_digits, num_major_digits);
+  combined[num_major_digits] = '.';
+  avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
+  combined[num_major_digits + 1 + num_minor_digits] = '\0';
+
+  return cmdline_append_option(slot_data, key, combined);
+}
+
+static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
+                                        const char* key,
+                                        uint64_t value) {
+  char digits[AVB_MAX_DIGITS_UINT64];
+  uint64_to_base10(value, digits);
+  return cmdline_append_option(slot_data, key, digits);
+}
+
+static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
+                              const char* key,
+                              const uint8_t* data,
+                              size_t data_len) {
+  int ret;
+  char* hex_data = avb_bin2hex(data, data_len);
+  if (hex_data == NULL) {
+    return 0;
+  }
+  ret = cmdline_append_option(slot_data, key, hex_data);
+  avb_free(hex_data);
+  return ret;
+}
+
+AvbSlotVerifyResult avb_append_options(
+    AvbOps* ops,
+    AvbSlotVerifyData* slot_data,
+    AvbVBMetaImageHeader* toplevel_vbmeta,
+    AvbAlgorithmType algorithm_type,
+    AvbHashtreeErrorMode hashtree_error_mode) {
+  AvbSlotVerifyResult ret;
+  const char* verity_mode;
+  bool is_device_unlocked;
+  AvbIOResult io_ret;
+
+  /* Add androidboot.vbmeta.device option. */
+  if (!cmdline_append_option(slot_data,
+                             "androidboot.vbmeta.device",
+                             "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  /* Add androidboot.vbmeta.avb_version option. */
+  if (!cmdline_append_version(slot_data,
+                              "androidboot.vbmeta.avb_version",
+                              AVB_VERSION_MAJOR,
+                              AVB_VERSION_MINOR)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  /* Set androidboot.avb.device_state to "locked" or "unlocked". */
+  io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting device state.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+  if (!cmdline_append_option(slot_data,
+                             "androidboot.vbmeta.device_state",
+                             is_device_unlocked ? "unlocked" : "locked")) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
+   * function as is used to sign vbmeta.
+   */
+  switch (algorithm_type) {
+    /* Explicit fallthrough. */
+    case AVB_ALGORITHM_TYPE_NONE:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
+      size_t n, total_size = 0;
+      uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
+      avb_slot_verify_data_calculate_vbmeta_digest(
+          slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
+      for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+        total_size += slot_data->vbmeta_images[n].vbmeta_size;
+      }
+      if (!cmdline_append_option(
+              slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
+          !cmdline_append_uint64_base10(
+              slot_data, "androidboot.vbmeta.size", total_size) ||
+          !cmdline_append_hex(slot_data,
+                              "androidboot.vbmeta.digest",
+                              vbmeta_digest,
+                              AVB_SHA256_DIGEST_SIZE)) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      }
+    } break;
+    /* Explicit fallthrough. */
+    case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
+      size_t n, total_size = 0;
+      uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
+      avb_slot_verify_data_calculate_vbmeta_digest(
+          slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
+      for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+        total_size += slot_data->vbmeta_images[n].vbmeta_size;
+      }
+      if (!cmdline_append_option(
+              slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
+          !cmdline_append_uint64_base10(
+              slot_data, "androidboot.vbmeta.size", total_size) ||
+          !cmdline_append_hex(slot_data,
+                              "androidboot.vbmeta.digest",
+                              vbmeta_digest,
+                              AVB_SHA512_DIGEST_SIZE)) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      }
+    } break;
+    case _AVB_ALGORITHM_NUM_TYPES:
+      avb_assert_not_reached();
+      break;
+  }
+
+  /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
+  if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+    verity_mode = "disabled";
+  } else {
+    const char* dm_verity_mode;
+    char* new_ret;
+
+    switch (hashtree_error_mode) {
+      case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
+        if (!cmdline_append_option(
+                slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto out;
+        }
+        verity_mode = "enforcing";
+        dm_verity_mode = "restart_on_corruption";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_RESTART:
+        verity_mode = "enforcing";
+        dm_verity_mode = "restart_on_corruption";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_EIO:
+        verity_mode = "eio";
+        /* For now there's no option to specify the EIO mode. So
+         * just use 'ignore_zero_blocks' since that's already set
+         * and dm-verity-target.c supports specifying this multiple
+         * times.
+         */
+        dm_verity_mode = "ignore_zero_blocks";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_LOGGING:
+        verity_mode = "logging";
+        dm_verity_mode = "ignore_corruption";
+        break;
+    }
+    new_ret = avb_replace(
+        slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
+    avb_free(slot_data->cmdline);
+    slot_data->cmdline = new_ret;
+    if (slot_data->cmdline == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+  }
+  if (!cmdline_append_option(
+          slot_data, "androidboot.veritymode", verity_mode)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+  return ret;
+}
+
+AvbCmdlineSubstList* avb_new_cmdline_subst_list() {
+  return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList));
+}
+
+void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) {
+  size_t i;
+  for (i = 0; i < cmdline_subst->size; ++i) {
+    avb_free(cmdline_subst->tokens[i]);
+    avb_free(cmdline_subst->values[i]);
+  }
+  cmdline_subst->size = 0;
+  avb_free(cmdline_subst);
+}
+
+AvbSlotVerifyResult avb_add_root_digest_substitution(
+    const char* part_name,
+    const uint8_t* digest,
+    size_t digest_size,
+    AvbCmdlineSubstList* out_cmdline_subst) {
+  const char* kDigestSubPrefix = "$(AVB_";
+  const char* kDigestSubSuffix = "_ROOT_DIGEST)";
+  size_t part_name_len = avb_strlen(part_name);
+  size_t list_index = out_cmdline_subst->size;
+
+  avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE);
+  avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE);
+  if (part_name_len >= AVB_PART_NAME_MAX_SIZE ||
+      digest_size > AVB_SHA512_DIGEST_SIZE) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  }
+
+  if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) {
+    /* The list is full. Currently dynamic growth of this list is not supported.
+     */
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  }
+
+  /* Construct the token to replace in the command line based on the partition
+   * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'.
+   */
+  out_cmdline_subst->tokens[list_index] =
+      avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL);
+  if (out_cmdline_subst->tokens[list_index] == NULL) {
+    goto fail;
+  }
+  avb_uppercase(out_cmdline_subst->tokens[list_index]);
+
+  /* The digest value is hex encoded when inserted in the command line. */
+  out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size);
+  if (out_cmdline_subst->values[list_index] == NULL) {
+    goto fail;
+  }
+
+  out_cmdline_subst->size++;
+  return AVB_SLOT_VERIFY_RESULT_OK;
+
+fail:
+  if (out_cmdline_subst->tokens[list_index]) {
+    avb_free(out_cmdline_subst->tokens[list_index]);
+  }
+  if (out_cmdline_subst->values[list_index]) {
+    avb_free(out_cmdline_subst->values[list_index]);
+  }
+  return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+}
diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
new file mode 100644 (file)
index 0000000..9af3a99
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#ifdef AVB_INSIDE_LIBAVB_H
+#error "You can't include avb_sha.h in the public header libavb.h."
+#endif
+
+#ifndef AVB_COMPILATION
+#error "Never include this file, it may only be used from internal avb code."
+#endif
+
+#ifndef AVB_CMDLINE_H_
+#define AVB_CMDLINE_H_
+
+#include "avb_ops.h"
+#include "avb_slot_verify.h"
+
+/* Maximum allow length (in bytes) of a partition name, including
+ * ab_suffix.
+ */
+#define AVB_PART_NAME_MAX_SIZE 32
+
+#define AVB_MAX_NUM_CMDLINE_SUBST 10
+
+/* Holds information about command-line substitutions. */
+typedef struct AvbCmdlineSubstList {
+  size_t size;
+  char* tokens[AVB_MAX_NUM_CMDLINE_SUBST];
+  char* values[AVB_MAX_NUM_CMDLINE_SUBST];
+} AvbCmdlineSubstList;
+
+/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
+ * values. Returns NULL on OOM, otherwise the cmdline with values
+ * replaced.
+ */
+char* avb_sub_cmdline(AvbOps* ops,
+                      const char* cmdline,
+                      const char* ab_suffix,
+                      bool using_boot_for_vbmeta,
+                      const AvbCmdlineSubstList* additional_substitutions);
+
+AvbSlotVerifyResult avb_append_options(
+    AvbOps* ops,
+    AvbSlotVerifyData* slot_data,
+    AvbVBMetaImageHeader* toplevel_vbmeta,
+    AvbAlgorithmType algorithm_type,
+    AvbHashtreeErrorMode hashtree_error_mode);
+
+/* Allocates and initializes a new command line substitution list. Free with
+ * |avb_free_cmdline_subst_list|.
+ */
+AvbCmdlineSubstList* avb_new_cmdline_subst_list(void);
+
+/* Use this instead of |avb_free| to deallocate a AvbCmdlineSubstList. */
+void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst);
+
+/* Adds a hashtree root digest to be substituted in $(AVB_*_ROOT_DIGEST)
+ * variables. The partition name differentiates the variable. For example, if
+ * |part_name| is "foo" then $(AVB_FOO_ROOT_DIGEST) will be substituted with the
+ * hex encoding of the digest. The substitution will be added to
+ * |out_cmdline_subst|. Returns AVB_SLOT_VERIFY_RESULT_OK on success.
+ */
+AvbSlotVerifyResult avb_add_root_digest_substitution(
+    const char* part_name,
+    const uint8_t* digest,
+    size_t digest_size,
+    AvbCmdlineSubstList* out_cmdline_subst);
+
+#endif
diff --git a/lib/libavb/avb_crypto.c b/lib/libavb/avb_crypto.c
new file mode 100644 (file)
index 0000000..f1836d5
--- /dev/null
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_crypto.h"
+#include "avb_rsa.h"
+#include "avb_sha.h"
+#include "avb_util.h"
+
+/* NOTE: The PKC1-v1.5 padding is a blob of binary DER of ASN.1 and is
+ * obtained from section 5.2.2 of RFC 4880.
+ */
+
+static const uint8_t
+    padding_RSA2048_SHA256[AVB_RSA2048_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+        0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA4096_SHA256[AVB_RSA4096_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA8192_SHA256[AVB_RSA8192_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+        0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA2048_SHA512[AVB_RSA2048_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
+
+static const uint8_t
+    padding_RSA4096_SHA512[AVB_RSA4096_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30,
+        0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+        0x05, 0x00, 0x04, 0x40};
+
+static const uint8_t
+    padding_RSA8192_SHA512[AVB_RSA8192_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
+
+static AvbAlgorithmData algorithm_data[_AVB_ALGORITHM_NUM_TYPES] = {
+    /* AVB_ALGORITHM_TYPE_NONE */
+    {.padding = NULL, .padding_len = 0, .hash_len = 0},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA2048 */
+    {.padding = padding_RSA2048_SHA256,
+     .padding_len = sizeof(padding_RSA2048_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA4096 */
+    {.padding = padding_RSA4096_SHA256,
+     .padding_len = sizeof(padding_RSA4096_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA8192 */
+    {.padding = padding_RSA8192_SHA256,
+     .padding_len = sizeof(padding_RSA8192_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA2048 */
+    {.padding = padding_RSA2048_SHA512,
+     .padding_len = sizeof(padding_RSA2048_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA4096 */
+    {.padding = padding_RSA4096_SHA512,
+     .padding_len = sizeof(padding_RSA4096_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA8192 */
+    {.padding = padding_RSA8192_SHA512,
+     .padding_len = sizeof(padding_RSA8192_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+};
+
+const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm) {
+  if ((size_t)algorithm < _AVB_ALGORITHM_NUM_TYPES) {
+    return &algorithm_data[algorithm];
+  }
+  return NULL;
+}
+
+bool avb_rsa_public_key_header_validate_and_byteswap(
+    const AvbRSAPublicKeyHeader* src, AvbRSAPublicKeyHeader* dest) {
+  avb_memcpy(dest, src, sizeof(AvbRSAPublicKeyHeader));
+
+  dest->key_num_bits = avb_be32toh(dest->key_num_bits);
+  dest->n0inv = avb_be32toh(dest->n0inv);
+
+  return true;
+}
diff --git a/lib/libavb/avb_crypto.h b/lib/libavb/avb_crypto.h
new file mode 100644 (file)
index 0000000..d8f649b
--- /dev/null
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_CRYPTO_H_
+#define AVB_CRYPTO_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Size of a RSA-2048 signature. */
+#define AVB_RSA2048_NUM_BYTES 256
+
+/* Size of a RSA-4096 signature. */
+#define AVB_RSA4096_NUM_BYTES 512
+
+/* Size of a RSA-8192 signature. */
+#define AVB_RSA8192_NUM_BYTES 1024
+
+/* Size in bytes of a SHA-1 digest. */
+#define AVB_SHA1_DIGEST_SIZE 20
+
+/* Size in bytes of a SHA-256 digest. */
+#define AVB_SHA256_DIGEST_SIZE 32
+
+/* Size in bytes of a SHA-512 digest. */
+#define AVB_SHA512_DIGEST_SIZE 64
+
+/* Possible digest types supported by libavb routines. */
+typedef enum {
+  AVB_DIGEST_TYPE_SHA256,
+  AVB_DIGEST_TYPE_SHA512,
+} AvbDigestType;
+
+/* Algorithms that can be used in the vbmeta image for
+ * verification. An algorithm consists of a hash type and a signature
+ * type.
+ *
+ * The data used to calculate the hash is the three blocks mentioned
+ * in the documentation for |AvbVBMetaImageHeader| except for the data
+ * in the "Authentication data" block.
+ *
+ * For signatures with RSA keys, PKCS v1.5 padding is used. The public
+ * key data is stored in the auxiliary data block, see
+ * |AvbRSAPublicKeyHeader| for the serialization format.
+ *
+ * Each algorithm type is described below:
+ *
+ * AVB_ALGORITHM_TYPE_NONE: There is no hash, no signature of the
+ * data, and no public key. The data cannot be verified. The fields
+ * |hash_size|, |signature_size|, and |public_key_size| must be zero.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA2048: The hash function used is
+ * SHA-256, resulting in 32 bytes of hash digest data. This hash is
+ * signed with a 2048-bit RSA key. The field |hash_size| must be 32,
+ * |signature_size| must be 256, and the public key data must have
+ * |key_num_bits| set to 2048.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA4096: Like above, but only with
+ * a 4096-bit RSA key and |signature_size| set to 512.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA8192: Like above, but only with
+ * a 8192-bit RSA key and |signature_size| set to 1024.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA2048: The hash function used is
+ * SHA-512, resulting in 64 bytes of hash digest data. This hash is
+ * signed with a 2048-bit RSA key. The field |hash_size| must be 64,
+ * |signature_size| must be 256, and the public key data must have
+ * |key_num_bits| set to 2048.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA4096: Like above, but only with
+ * a 4096-bit RSA key and |signature_size| set to 512.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA8192: Like above, but only with
+ * a 8192-bit RSA key and |signature_size| set to 1024.
+ */
+typedef enum {
+  AVB_ALGORITHM_TYPE_NONE,
+  AVB_ALGORITHM_TYPE_SHA256_RSA2048,
+  AVB_ALGORITHM_TYPE_SHA256_RSA4096,
+  AVB_ALGORITHM_TYPE_SHA256_RSA8192,
+  AVB_ALGORITHM_TYPE_SHA512_RSA2048,
+  AVB_ALGORITHM_TYPE_SHA512_RSA4096,
+  AVB_ALGORITHM_TYPE_SHA512_RSA8192,
+  _AVB_ALGORITHM_NUM_TYPES
+} AvbAlgorithmType;
+
+/* Holds algorithm-specific data. The |padding| is needed by avb_rsa_verify. */
+typedef struct {
+  const uint8_t* padding;
+  size_t padding_len;
+  size_t hash_len;
+} AvbAlgorithmData;
+
+/* Provides algorithm-specific data for a given |algorithm|. Returns NULL if
+ * |algorithm| is invalid.
+ */
+const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* The header for a serialized RSA public key.
+ *
+ * The size of the key is given by |key_num_bits|, for example 2048
+ * for a RSA-2048 key. By definition, a RSA public key is the pair (n,
+ * e) where |n| is the modulus (which can be represented in
+ * |key_num_bits| bits) and |e| is the public exponent. The exponent
+ * is not stored since it's assumed to always be 65537.
+ *
+ * To optimize verification, the key block includes two precomputed
+ * values, |n0inv| (fits in 32 bits) and |rr| and can always be
+ * represented in |key_num_bits|.
+
+ * The value |n0inv| is the value -1/n[0] (mod 2^32). The value |rr|
+ * is (2^key_num_bits)^2 (mod n).
+ *
+ * Following this header is |key_num_bits| bits of |n|, then
+ * |key_num_bits| bits of |rr|. Both values are stored with most
+ * significant bit first. Each serialized number takes up
+ * |key_num_bits|/8 bytes.
+ *
+ * All fields in this struct are stored in network byte order when
+ * serialized.  To generate a copy with fields swapped to native byte
+ * order, use the function avb_rsa_public_key_header_validate_and_byteswap().
+ *
+ * The avb_rsa_verify() function expects a key in this serialized
+ * format.
+ *
+ * The 'avbtool extract_public_key' command can be used to generate a
+ * serialized RSA public key.
+ */
+typedef struct AvbRSAPublicKeyHeader {
+  uint32_t key_num_bits;
+  uint32_t n0inv;
+} AVB_ATTR_PACKED AvbRSAPublicKeyHeader;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ */
+bool avb_rsa_public_key_header_validate_and_byteswap(
+    const AvbRSAPublicKeyHeader* src,
+    AvbRSAPublicKeyHeader* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_CRYPTO_H_ */
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
new file mode 100644 (file)
index 0000000..fb0b305
--- /dev/null
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_descriptor.h"
+#include "avb_util.h"
+#include "avb_vbmeta_image.h"
+
+bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src,
+                                          AvbDescriptor* dest) {
+  dest->tag = avb_be64toh(src->tag);
+  dest->num_bytes_following = avb_be64toh(src->num_bytes_following);
+
+  if ((dest->num_bytes_following & 0x07) != 0) {
+    avb_error("Descriptor size is not divisible by 8.\n");
+    return false;
+  }
+  return true;
+}
+
+bool avb_descriptor_foreach(const uint8_t* image_data,
+                            size_t image_size,
+                            AvbDescriptorForeachFunc foreach_func,
+                            void* user_data) {
+  const AvbVBMetaImageHeader* header = NULL;
+  bool ret = false;
+  const uint8_t* image_end;
+  const uint8_t* desc_start;
+  const uint8_t* desc_end;
+  const uint8_t* p;
+
+  if (image_data == NULL) {
+    avb_error("image_data is NULL\n.");
+    goto out;
+  }
+
+  if (foreach_func == NULL) {
+    avb_error("foreach_func is NULL\n.");
+    goto out;
+  }
+
+  if (image_size < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+
+  /* Ensure magic is correct. */
+  if (avb_memcmp(image_data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    goto out;
+  }
+
+  /* Careful, not byteswapped - also ensure it's aligned properly. */
+  avb_assert_aligned(image_data);
+  header = (const AvbVBMetaImageHeader*)image_data;
+  image_end = image_data + image_size;
+
+  desc_start = image_data + sizeof(AvbVBMetaImageHeader) +
+               avb_be64toh(header->authentication_data_block_size) +
+               avb_be64toh(header->descriptors_offset);
+
+  desc_end = desc_start + avb_be64toh(header->descriptors_size);
+
+  if (desc_start < image_data || desc_start > image_end ||
+      desc_end < image_data || desc_end > image_end || desc_end < desc_start) {
+    avb_error("Descriptors not inside passed-in data.\n");
+    goto out;
+  }
+
+  for (p = desc_start; p < desc_end;) {
+    const AvbDescriptor* dh = (const AvbDescriptor*)p;
+    avb_assert_aligned(dh);
+    uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
+    uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
+
+    if ((nb_total & 7) != 0) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
+
+    if (nb_total + p < desc_start || nb_total + p > desc_end) {
+      avb_error("Invalid data in descriptors array.\n");
+      goto out;
+    }
+
+    if (foreach_func(dh, user_data) == 0) {
+      goto out;
+    }
+
+    p += nb_total;
+  }
+
+  ret = true;
+
+out:
+  return ret;
+}
+
+static bool count_descriptors(const AvbDescriptor* descriptor,
+                              void* user_data) {
+  size_t* num_descriptors = user_data;
+  *num_descriptors += 1;
+  return true;
+}
+
+typedef struct {
+  size_t descriptor_number;
+  const AvbDescriptor** descriptors;
+} SetDescriptorData;
+
+static bool set_descriptors(const AvbDescriptor* descriptor, void* user_data) {
+  SetDescriptorData* data = user_data;
+  data->descriptors[data->descriptor_number++] = descriptor;
+  return true;
+}
+
+const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data,
+                                             size_t image_size,
+                                             size_t* out_num_descriptors) {
+  size_t num_descriptors = 0;
+  SetDescriptorData data;
+
+  avb_descriptor_foreach(
+      image_data, image_size, count_descriptors, &num_descriptors);
+
+  data.descriptor_number = 0;
+  data.descriptors =
+      avb_calloc(sizeof(const AvbDescriptor*) * (num_descriptors + 1));
+  if (data.descriptors == NULL) {
+    return NULL;
+  }
+  avb_descriptor_foreach(image_data, image_size, set_descriptors, &data);
+  avb_assert(data.descriptor_number == num_descriptors);
+
+  if (out_num_descriptors != NULL) {
+    *out_num_descriptors = num_descriptors;
+  }
+
+  return data.descriptors;
+}
diff --git a/lib/libavb/avb_descriptor.h b/lib/libavb/avb_descriptor.h
new file mode 100644 (file)
index 0000000..d4f42ac
--- /dev/null
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_DESCRIPTOR_H_
+#define AVB_DESCRIPTOR_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Well-known descriptor tags.
+ *
+ * AVB_DESCRIPTOR_TAG_PROPERTY: see |AvbPropertyDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_HASHTREE: see |AvbHashtreeDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_HASH: see |AvbHashDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: see |AvbKernelCmdlineDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: see |AvbChainPartitionDescriptor| struct.
+ */
+typedef enum {
+  AVB_DESCRIPTOR_TAG_PROPERTY,
+  AVB_DESCRIPTOR_TAG_HASHTREE,
+  AVB_DESCRIPTOR_TAG_HASH,
+  AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
+  AVB_DESCRIPTOR_TAG_CHAIN_PARTITION,
+} AvbDescriptorTag;
+
+/* The header for a serialized descriptor.
+ *
+ * A descriptor always have two fields, a |tag| (denoting its type,
+ * see the |AvbDescriptorTag| enumeration) and the size of the bytes
+ * following, |num_bytes_following|.
+ *
+ * For padding, |num_bytes_following| is always a multiple of 8.
+ */
+typedef struct AvbDescriptor {
+  uint64_t tag;
+  uint64_t num_bytes_following;
+} AVB_ATTR_PACKED AvbDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_descriptor_validate_and_byteswap(
+    const AvbDescriptor* src, AvbDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Signature for callback function used in avb_descriptor_foreach().
+ * The passed in descriptor is given by |descriptor| and the
+ * |user_data| passed to avb_descriptor_foreach() function is in
+ * |user_data|. Return true to continue iterating, false to stop
+ * iterating.
+ *
+ * Note that |descriptor| points into the image passed to
+ * avb_descriptor_foreach() - all fields need to be byteswapped!
+ */
+typedef bool AvbDescriptorForeachFunc(const AvbDescriptor* descriptor,
+                                      void* user_data);
+
+/* Convenience function to iterate over all descriptors in an vbmeta
+ * image.
+ *
+ * The function given by |foreach_func| will be called for each
+ * descriptor. The given function should return true to continue
+ * iterating, false to stop.
+ *
+ * The |user_data| parameter will be passed to |foreach_func|.
+ *
+ * Returns false if the iteration was short-circuited, that is if
+ * an invocation of |foreach_func| returned false.
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a known
+ * good public key. Additionally, |image_data| must be word-aligned.
+ */
+bool avb_descriptor_foreach(const uint8_t* image_data,
+                            size_t image_size,
+                            AvbDescriptorForeachFunc foreach_func,
+                            void* user_data);
+
+/* Gets all descriptors in a vbmeta image.
+ *
+ * The return value is a NULL-pointer terminated array of
+ * AvbDescriptor pointers. Free with avb_free() when you are done with
+ * it. If |out_num_descriptors| is non-NULL, the number of descriptors
+ * will be returned there.
+ *
+ * Note that each AvbDescriptor pointer in the array points into
+ * |image_data| - all fields need to be byteswapped!
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a known
+ * good public key. Additionally, |image_data| must be word-aligned.
+ */
+const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data,
+                                             size_t image_size,
+                                             size_t* out_num_descriptors)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_footer.c b/lib/libavb/avb_footer.c
new file mode 100644 (file)
index 0000000..697a715
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_footer.h"
+#include "avb_util.h"
+
+bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest) {
+  avb_memcpy(dest, src, sizeof(AvbFooter));
+
+  dest->version_major = avb_be32toh(dest->version_major);
+  dest->version_minor = avb_be32toh(dest->version_minor);
+
+  dest->original_image_size = avb_be64toh(dest->original_image_size);
+  dest->vbmeta_offset = avb_be64toh(dest->vbmeta_offset);
+  dest->vbmeta_size = avb_be64toh(dest->vbmeta_size);
+
+  /* Check that magic is correct. */
+  if (avb_safe_memcmp(dest->magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) !=
+      0) {
+    avb_error("Footer magic is incorrect.\n");
+    return false;
+  }
+
+  /* Ensure we don't attempt to access any fields if the footer major
+   * version is not supported.
+   */
+  if (dest->version_major > AVB_FOOTER_VERSION_MAJOR) {
+    avb_error("No support for footer version.\n");
+    return false;
+  }
+
+  return true;
+}
diff --git a/lib/libavb/avb_footer.h b/lib/libavb/avb_footer.h
new file mode 100644 (file)
index 0000000..62a6e65
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_FOOTER_H_
+#define AVB_FOOTER_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Magic for the footer. */
+#define AVB_FOOTER_MAGIC "AVBf"
+#define AVB_FOOTER_MAGIC_LEN 4
+
+/* Size of the footer. */
+#define AVB_FOOTER_SIZE 64
+
+/* The current footer version used - keep in sync with avbtool. */
+#define AVB_FOOTER_VERSION_MAJOR 1
+#define AVB_FOOTER_VERSION_MINOR 0
+
+/* The struct used as a footer used on partitions, used to find the
+ * AvbVBMetaImageHeader struct. This struct is always stored at the
+ * end of a partition.
+ */
+typedef struct AvbFooter {
+  /*   0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */
+  uint8_t magic[AVB_FOOTER_MAGIC_LEN];
+  /*   4: The major version of the footer struct. */
+  uint32_t version_major;
+  /*   8: The minor version of the footer struct. */
+  uint32_t version_minor;
+
+  /*  12: The original size of the image on the partition. */
+  uint64_t original_image_size;
+
+  /*  20: The offset of the |AvbVBMetaImageHeader| struct. */
+  uint64_t vbmeta_offset;
+
+  /*  28: The size of the vbmeta block (header + auth + aux blocks). */
+  uint64_t vbmeta_size;
+
+  /*  36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This
+   * must be set to zeroes.
+   */
+  uint8_t reserved[28];
+} AVB_ATTR_PACKED AvbFooter;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ */
+bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_FOOTER_H_ */
diff --git a/lib/libavb/avb_hash_descriptor.c b/lib/libavb/avb_hash_descriptor.c
new file mode 100644 (file)
index 0000000..cd1438e
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_hash_descriptor.h"
+#include "avb_util.h"
+
+bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src,
+                                               AvbHashDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbHashDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASH) {
+    avb_error("Invalid tag for hash descriptor.\n");
+    return false;
+  }
+
+  dest->image_size = avb_be64toh(dest->image_size);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->salt_len = avb_be32toh(dest->salt_len);
+  dest->digest_len = avb_be32toh(dest->digest_len);
+  dest->flags = avb_be32toh(dest->flags);
+
+  /* Check that partition_name, salt, and digest are fully contained. */
+  expected_size = sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->salt_len) ||
+      !avb_safe_add_to(&expected_size, dest->digest_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_hash_descriptor.h b/lib/libavb/avb_hash_descriptor.h
new file mode 100644 (file)
index 0000000..bede97f
--- /dev/null
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_HASH_DESCRIPTOR_H_
+#define AVB_HASH_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flags for hash descriptors.
+ *
+ * AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
+ *   partition logic to this partition. This is intentionally a negative boolean
+ *   because A/B should be both the default and most used in practice.
+ */
+typedef enum {
+  AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+} AvbHashDescriptorFlags;
+
+/* A descriptor containing information about hash for an image.
+ *
+ * This descriptor is typically used for boot partitions to verify the
+ * entire kernel+initramfs image before executing it.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then
+ * |digest_len| bytes of the digest.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ *
+ * Changes in v1.1:
+ *   - flags field is added which supports AVB_HASH_DESCRIPTOR_FLAGS_USE_AB
+ *   - digest_len may be zero, which indicates the use of a persistent digest
+ */
+typedef struct AvbHashDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint64_t image_size;
+  uint8_t hash_algorithm[32];
+  uint32_t partition_name_len;
+  uint32_t salt_len;
+  uint32_t digest_len;
+  uint32_t flags;
+  uint8_t reserved[60];
+} AVB_ATTR_PACKED AvbHashDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src,
+                                               AvbHashDescriptor* dest)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_HASH_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_hashtree_descriptor.c b/lib/libavb/avb_hashtree_descriptor.c
new file mode 100644 (file)
index 0000000..2a61b35
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_hashtree_descriptor.h"
+#include "avb_util.h"
+
+bool avb_hashtree_descriptor_validate_and_byteswap(
+    const AvbHashtreeDescriptor* src, AvbHashtreeDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbHashtreeDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASHTREE) {
+    avb_error("Invalid tag for hashtree descriptor.\n");
+    return false;
+  }
+
+  dest->dm_verity_version = avb_be32toh(dest->dm_verity_version);
+  dest->image_size = avb_be64toh(dest->image_size);
+  dest->tree_offset = avb_be64toh(dest->tree_offset);
+  dest->tree_size = avb_be64toh(dest->tree_size);
+  dest->data_block_size = avb_be32toh(dest->data_block_size);
+  dest->hash_block_size = avb_be32toh(dest->hash_block_size);
+  dest->fec_num_roots = avb_be32toh(dest->fec_num_roots);
+  dest->fec_offset = avb_be64toh(dest->fec_offset);
+  dest->fec_size = avb_be64toh(dest->fec_size);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->salt_len = avb_be32toh(dest->salt_len);
+  dest->root_digest_len = avb_be32toh(dest->root_digest_len);
+  dest->flags = avb_be32toh(dest->flags);
+
+  /* Check that partition_name, salt, and root_digest are fully contained. */
+  expected_size = sizeof(AvbHashtreeDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->salt_len) ||
+      !avb_safe_add_to(&expected_size, dest->root_digest_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_hashtree_descriptor.h b/lib/libavb/avb_hashtree_descriptor.h
new file mode 100644 (file)
index 0000000..d7f3eb5
--- /dev/null
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_HASHTREE_DESCRIPTOR_H_
+#define AVB_HASHTREE_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flags for hashtree descriptors.
+ *
+ * AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
+ *   partition logic to this partition. This is intentionally a negative boolean
+ *   because A/B should be both the default and most used in practice.
+ */
+typedef enum {
+  AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+} AvbHashtreeDescriptorFlags;
+
+/* A descriptor containing information about a dm-verity hashtree.
+ *
+ * Hash-trees are used to verify large partitions typically containing
+ * file systems. See
+ * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more
+ * information about dm-verity.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then
+ * |root_digest_len| bytes of the root digest.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ *
+ * Changes in v1.1:
+ *   - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB
+ *   - digest_len may be zero, which indicates the use of a persistent digest
+ */
+typedef struct AvbHashtreeDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t dm_verity_version;
+  uint64_t image_size;
+  uint64_t tree_offset;
+  uint64_t tree_size;
+  uint32_t data_block_size;
+  uint32_t hash_block_size;
+  uint32_t fec_num_roots;
+  uint64_t fec_offset;
+  uint64_t fec_size;
+  uint8_t hash_algorithm[32];
+  uint32_t partition_name_len;
+  uint32_t salt_len;
+  uint32_t root_digest_len;
+  uint32_t flags;
+  uint8_t reserved[60];
+} AVB_ATTR_PACKED AvbHashtreeDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_hashtree_descriptor_validate_and_byteswap(
+    const AvbHashtreeDescriptor* src,
+    AvbHashtreeDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_HASHTREE_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_kernel_cmdline_descriptor.c b/lib/libavb/avb_kernel_cmdline_descriptor.c
new file mode 100644 (file)
index 0000000..fa3fe45
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_kernel_cmdline_descriptor.h"
+#include "avb_util.h"
+
+bool avb_kernel_cmdline_descriptor_validate_and_byteswap(
+    const AvbKernelCmdlineDescriptor* src, AvbKernelCmdlineDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbKernelCmdlineDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) {
+    avb_error("Invalid tag for kernel cmdline descriptor.\n");
+    return false;
+  }
+
+  dest->flags = avb_be32toh(dest->flags);
+  dest->kernel_cmdline_length = avb_be32toh(dest->kernel_cmdline_length);
+
+  /* Check that kernel_cmdline is fully contained. */
+  expected_size = sizeof(AvbKernelCmdlineDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->kernel_cmdline_length)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+
+  return true;
+}
diff --git a/lib/libavb/avb_kernel_cmdline_descriptor.h b/lib/libavb/avb_kernel_cmdline_descriptor.h
new file mode 100644 (file)
index 0000000..246fbda
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_KERNEL_CMDLINE_DESCRIPTOR_H_
+#define AVB_KERNEL_CMDLINE_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flags for kernel command-line descriptors.
+ *
+ * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED: The
+ * cmdline will only be applied if hashtree verification is not
+ * disabled (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED).
+ *
+ * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED: The cmdline
+ * will only be applied if hashtree verification is disabled
+ * (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED).
+ */
+typedef enum {
+  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0),
+  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1)
+} AvbKernelCmdlineFlags;
+
+/* A descriptor containing information to be appended to the kernel
+ * command-line.
+ *
+ * The |flags| field contains flags from the AvbKernelCmdlineFlags
+ * enumeration.
+ *
+ * Following this struct are |kernel_cmdline_len| bytes with the
+ * kernel command-line (UTF-8 encoded).
+ */
+typedef struct AvbKernelCmdlineDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t flags;
+  uint32_t kernel_cmdline_length;
+} AVB_ATTR_PACKED AvbKernelCmdlineDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_kernel_cmdline_descriptor_validate_and_byteswap(
+    const AvbKernelCmdlineDescriptor* src,
+    AvbKernelCmdlineDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_KERNEL_CMDLINE_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h
new file mode 100644 (file)
index 0000000..8bbdc7c
--- /dev/null
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_OPS_H_
+#define AVB_OPS_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Well-known names of named persistent values. */
+#define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest."
+
+/* Return codes used for I/O operations.
+ *
+ * AVB_IO_RESULT_OK is returned if the requested operation was
+ * successful.
+ *
+ * AVB_IO_RESULT_ERROR_IO is returned if the underlying hardware (disk
+ * or other subsystem) encountered an I/O error.
+ *
+ * AVB_IO_RESULT_ERROR_OOM is returned if unable to allocate memory.
+ *
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is returned if the requested
+ * partition does not exist.
+ *
+ * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION is returned if the
+ * range of bytes requested to be read or written is outside the range
+ * of the partition.
+ *
+ * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE is returned if a named persistent value
+ * does not exist.
+ *
+ * AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE is returned if a named persistent
+ * value size is not supported or does not match the expected size.
+ *
+ * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned if a buffer is too small
+ * for the requested operation.
+ */
+typedef enum {
+  AVB_IO_RESULT_OK,
+  AVB_IO_RESULT_ERROR_OOM,
+  AVB_IO_RESULT_ERROR_IO,
+  AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION,
+  AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION,
+  AVB_IO_RESULT_ERROR_NO_SUCH_VALUE,
+  AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE,
+  AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE,
+} AvbIOResult;
+
+struct AvbOps;
+typedef struct AvbOps AvbOps;
+
+/* Forward-declaration of operations in libavb_ab. */
+struct AvbABOps;
+
+/* Forward-declaration of operations in libavb_atx. */
+struct AvbAtxOps;
+
+/* High-level operations/functions/methods that are platform
+ * dependent.
+ *
+ * Operations may be added in the future so when implementing it
+ * always make sure to zero out sizeof(AvbOps) bytes of the struct to
+ * ensure that unimplemented operations are set to NULL.
+ */
+struct AvbOps {
+  /* This pointer can be used by the application/bootloader using
+   * libavb and is typically used in each operation to get a pointer
+   * to platform-specific resources. It cannot be used by libraries.
+   */
+  void* user_data;
+
+  /* If libavb_ab is used, this should point to the
+   * AvbABOps. Otherwise it must be set to NULL.
+   */
+  struct AvbABOps* ab_ops;
+
+  /* If libavb_atx is used, this should point to the
+   * AvbAtxOps. Otherwise it must be set to NULL.
+   */
+  struct AvbAtxOps* atx_ops;
+
+  /* Reads |num_bytes| from offset |offset| from partition with name
+   * |partition| (NUL-terminated UTF-8 string). If |offset| is
+   * negative, its absolute value should be interpreted as the number
+   * of bytes from the end of the partition.
+   *
+   * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if
+   * there is no partition with the given name,
+   * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested
+   * |offset| is outside the partition, and AVB_IO_RESULT_ERROR_IO if
+   * there was an I/O error from the underlying I/O subsystem.  If the
+   * operation succeeds as requested AVB_IO_RESULT_OK is returned and
+   * the data is available in |buffer|.
+   *
+   * The only time partial I/O may occur is if reading beyond the end
+   * of the partition. In this case the value returned in
+   * |out_num_read| may be smaller than |num_bytes|.
+   */
+  AvbIOResult (*read_from_partition)(AvbOps* ops,
+                                     const char* partition,
+                                     int64_t offset,
+                                     size_t num_bytes,
+                                     void* buffer,
+                                     size_t* out_num_read);
+
+  /* Gets the starting pointer of a partition that is pre-loaded in memory, and
+   * save it to |out_pointer|. The preloaded partition is expected to be
+   * |num_bytes|, where the actual preloaded byte count is returned in
+   * |out_num_bytes_preloaded|. |out_num_bytes_preloaded| must be no larger than
+   * |num_bytes|.
+   *
+   * This provides an alternative way to access a partition that is preloaded
+   * into memory without a full memory copy. When this function pointer is not
+   * set (has value NULL), or when the |out_pointer| is set to NULL as a result,
+   * |read_from_partition| will be used as the fallback. This function is mainly
+   * used for accessing the entire partition content to calculate its hash.
+   *
+   * Preloaded partition data must outlive the lifespan of the
+   * |AvbSlotVerifyData| structure that |avb_slot_verify| outputs.
+   */
+  AvbIOResult (*get_preloaded_partition)(AvbOps* ops,
+                                         const char* partition,
+                                         size_t num_bytes,
+                                         uint8_t** out_pointer,
+                                         size_t* out_num_bytes_preloaded);
+
+  /* Writes |num_bytes| from |bffer| at offset |offset| to partition
+   * with name |partition| (NUL-terminated UTF-8 string). If |offset|
+   * is negative, its absolute value should be interpreted as the
+   * number of bytes from the end of the partition.
+   *
+   * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if
+   * there is no partition with the given name,
+   * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested
+   * byterange goes outside the partition, and AVB_IO_RESULT_ERROR_IO
+   * if there was an I/O error from the underlying I/O subsystem.  If
+   * the operation succeeds as requested AVB_IO_RESULT_OK is
+   * returned.
+   *
+   * This function never does any partial I/O, it either transfers all
+   * of the requested bytes or returns an error.
+   */
+  AvbIOResult (*write_to_partition)(AvbOps* ops,
+                                    const char* partition,
+                                    int64_t offset,
+                                    size_t num_bytes,
+                                    const void* buffer);
+
+  /* Checks if the given public key used to sign the 'vbmeta'
+   * partition is trusted. Boot loaders typically compare this with
+   * embedded key material generated with 'avbtool
+   * extract_public_key'.
+   *
+   * The public key is in the array pointed to by |public_key_data|
+   * and is of |public_key_length| bytes.
+   *
+   * If there is no public key metadata (set with the avbtool option
+   * --public_key_metadata) then |public_key_metadata| will be set to
+   * NULL. Otherwise this field points to the data which is
+   * |public_key_metadata_length| bytes long.
+   *
+   * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
+   * true if trusted or false if untrusted.
+   */
+  AvbIOResult (*validate_vbmeta_public_key)(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);
+
+  /* Gets the rollback index corresponding to the location given by
+   * |rollback_index_location|. The value is returned in
+   * |out_rollback_index|. Returns AVB_IO_RESULT_OK if the rollback
+   * index was retrieved, otherwise an error code.
+   *
+   * A device may have a limited amount of rollback index locations (say,
+   * one or four) so may error out if |rollback_index_location| exceeds
+   * this number.
+   */
+  AvbIOResult (*read_rollback_index)(AvbOps* ops,
+                                     size_t rollback_index_location,
+                                     uint64_t* out_rollback_index);
+
+  /* Sets the rollback index corresponding to the location given by
+   * |rollback_index_location| to |rollback_index|. Returns
+   * AVB_IO_RESULT_OK if the rollback index was set, otherwise an
+   * error code.
+   *
+   * A device may have a limited amount of rollback index locations (say,
+   * one or four) so may error out if |rollback_index_location| exceeds
+   * this number.
+   */
+  AvbIOResult (*write_rollback_index)(AvbOps* ops,
+                                      size_t rollback_index_location,
+                                      uint64_t rollback_index);
+
+  /* Gets whether the device is unlocked. The value is returned in
+   * |out_is_unlocked| (true if unlocked, false otherwise). Returns
+   * AVB_IO_RESULT_OK if the state was retrieved, otherwise an error
+   * code.
+   */
+  AvbIOResult (*read_is_device_unlocked)(AvbOps* ops, bool* out_is_unlocked);
+
+  /* Gets the unique partition GUID for a partition with name in
+   * |partition| (NUL-terminated UTF-8 string). The GUID is copied as
+   * a string into |guid_buf| of size |guid_buf_size| and will be NUL
+   * terminated. The string must be lower-case and properly
+   * hyphenated. For example:
+   *
+   *  527c1c6d-6361-4593-8842-3c78fcd39219
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*get_unique_guid_for_partition)(AvbOps* ops,
+                                               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
+   * |out_size_num_bytes|.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*get_size_of_partition)(AvbOps* ops,
+                                       const char* partition,
+                                       uint64_t* out_size_num_bytes);
+
+  /* Reads a persistent value corresponding to the given |name|. The value is
+   * returned in |out_buffer| which must point to |buffer_size| bytes. On
+   * success |out_num_bytes_read| contains the number of bytes read into
+   * |out_buffer|. If AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned,
+   * |out_num_bytes_read| contains the number of bytes that would have been read
+   * which can be used to allocate a buffer.
+   *
+   * The |buffer_size| may be zero and the |out_buffer| may be NULL, but if
+   * |out_buffer| is NULL then |buffer_size| *must* be zero.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   *
+   * If the value does not exist, is not supported, or is not populated, returns
+   * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the
+   * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE.
+   *
+   * This operation is currently only used to support persistent digests. If a
+   * device does not use persistent digests this function pointer can be set to
+   * NULL.
+   */
+  AvbIOResult (*read_persistent_value)(AvbOps* ops,
+                                       const char* name,
+                                       size_t buffer_size,
+                                       uint8_t* out_buffer,
+                                       size_t* out_num_bytes_read);
+
+  /* Writes a persistent value corresponding to the given |name|. The value is
+   * supplied in |value| which must point to |value_size| bytes. Any existing
+   * value with the same name is overwritten. If |value_size| is zero, future
+   * calls to |read_persistent_value| will return
+   * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   *
+   * If the value |name| is not supported, returns
+   * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported,
+   * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE.
+   *
+   * This operation is currently only used to support persistent digests. If a
+   * device does not use persistent digests this function pointer can be set to
+   * NULL.
+   */
+  AvbIOResult (*write_persistent_value)(AvbOps* ops,
+                                        const char* name,
+                                        size_t value_size,
+                                        const uint8_t* value);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_OPS_H_ */
diff --git a/lib/libavb/avb_property_descriptor.c b/lib/libavb/avb_property_descriptor.c
new file mode 100644 (file)
index 0000000..589c963
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_property_descriptor.h"
+#include "avb_util.h"
+
+bool avb_property_descriptor_validate_and_byteswap(
+    const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
+    avb_error("Invalid tag for property descriptor.\n");
+    return false;
+  }
+
+  dest->key_num_bytes = avb_be64toh(dest->key_num_bytes);
+  dest->value_num_bytes = avb_be64toh(dest->value_num_bytes);
+
+  /* Check that key and value are fully contained. */
+  expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2;
+  if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) ||
+      !avb_safe_add_to(&expected_size, dest->value_num_bytes)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+
+  return true;
+}
+
+typedef struct {
+  const char* key;
+  size_t key_size;
+  const char* ret_value;
+  size_t ret_value_size;
+} PropertyIteratorData;
+
+static bool property_lookup_desc_foreach(const AvbDescriptor* header,
+                                         void* user_data) {
+  PropertyIteratorData* data = (PropertyIteratorData*)user_data;
+  AvbPropertyDescriptor prop_desc;
+  const uint8_t* p;
+  bool ret = true;
+
+  if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
+    goto out;
+  }
+
+  if (!avb_property_descriptor_validate_and_byteswap(
+          (const AvbPropertyDescriptor*)header, &prop_desc)) {
+    goto out;
+  }
+
+  p = (const uint8_t*)header;
+  if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) {
+    avb_error("No terminating NUL byte in key.\n");
+    goto out;
+  }
+
+  if (data->key_size == prop_desc.key_num_bytes) {
+    if (avb_memcmp(p + sizeof(AvbPropertyDescriptor),
+                   data->key,
+                   data->key_size) == 0) {
+      data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) +
+                                      prop_desc.key_num_bytes + 1);
+      data->ret_value_size = prop_desc.value_num_bytes;
+      /* Stop iterating. */
+      ret = false;
+      goto out;
+    }
+  }
+
+out:
+  return ret;
+}
+
+const char* avb_property_lookup(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                size_t* out_value_size) {
+  PropertyIteratorData data;
+
+  if (key_size == 0) {
+    key_size = avb_strlen(key);
+  }
+
+  data.key = key;
+  data.key_size = key_size;
+
+  if (avb_descriptor_foreach(
+          image_data, image_size, property_lookup_desc_foreach, &data) == 0) {
+    if (out_value_size != NULL) {
+      *out_value_size = data.ret_value_size;
+    }
+    return data.ret_value;
+  }
+
+  if (out_value_size != NULL) {
+    *out_value_size = 0;
+  }
+  return NULL;
+}
+
+bool avb_property_lookup_uint64(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                uint64_t* out_value) {
+  const char* value;
+  bool ret = false;
+  uint64_t parsed_val;
+  int base;
+  int n;
+
+  value = avb_property_lookup(image_data, image_size, key, key_size, NULL);
+  if (value == NULL) {
+    goto out;
+  }
+
+  base = 10;
+  if (avb_memcmp(value, "0x", 2) == 0) {
+    base = 16;
+    value += 2;
+  }
+
+  parsed_val = 0;
+  for (n = 0; value[n] != '\0'; n++) {
+    int c = value[n];
+    int digit;
+
+    parsed_val *= base;
+
+    if (c >= '0' && c <= '9') {
+      digit = c - '0';
+    } else if (base == 16 && c >= 'a' && c <= 'f') {
+      digit = c - 'a' + 10;
+    } else if (base == 16 && c >= 'A' && c <= 'F') {
+      digit = c - 'A' + 10;
+    } else {
+      avb_error("Invalid digit.\n");
+      goto out;
+    }
+
+    parsed_val += digit;
+  }
+
+  ret = true;
+  if (out_value != NULL) {
+    *out_value = parsed_val;
+  }
+
+out:
+  return ret;
+}
diff --git a/lib/libavb/avb_property_descriptor.h b/lib/libavb/avb_property_descriptor.h
new file mode 100644 (file)
index 0000000..917c58f
--- /dev/null
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_PROPERTY_DESCRIPTOR_H_
+#define AVB_PROPERTY_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor for properties (free-form key/value pairs).
+ *
+ * Following this struct are |key_num_bytes| bytes of key data,
+ * followed by a NUL byte, then |value_num_bytes| bytes of value data,
+ * followed by a NUL byte and then enough padding to make the combined
+ * size a multiple of 8.
+ */
+typedef struct AvbPropertyDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint64_t key_num_bytes;
+  uint64_t value_num_bytes;
+} AVB_ATTR_PACKED AvbPropertyDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_property_descriptor_validate_and_byteswap(
+    const AvbPropertyDescriptor* src,
+    AvbPropertyDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Convenience function for looking up the value for a property with
+ * name |key| in a vbmeta image. If |key_size| is 0, |key| must be
+ * NUL-terminated.
+ *
+ * The |image_data| parameter must be a pointer to a vbmeta image of
+ * size |image_size|.
+ *
+ * This function returns a pointer to the value inside the passed-in
+ * image or NULL if not found. Note that the value is always
+ * guaranteed to be followed by a NUL byte.
+ *
+ * If the value was found and |out_value_size| is not NULL, the size
+ * of the value is returned there.
+ *
+ * This function is O(n) in number of descriptors so if you need to
+ * look up a lot of values, you may want to build a more efficient
+ * lookup-table by manually walking all descriptors using
+ * avb_descriptor_foreach().
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a
+ * known good public key.
+ */
+const char* avb_property_lookup(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                size_t* out_value_size)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Like avb_property_lookup() but parses the intial portions of the
+ * value as an unsigned 64-bit integer. Both decimal and hexadecimal
+ * representations (e.g. "0x2a") are supported. Returns false on
+ * failure and true on success. On success, the parsed value is
+ * returned in |out_value|.
+ */
+bool avb_property_lookup_uint64(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                uint64_t* out_value)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_PROPERTY_DESCRIPTOR_H_ */
diff --git a/lib/libavb/avb_rsa.c b/lib/libavb/avb_rsa.c
new file mode 100644 (file)
index 0000000..bbf1562
--- /dev/null
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT OR BSD-3-Clause
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+/* Implementation of RSA signature verification which uses a pre-processed
+ * key for computation. The code extends libmincrypt RSA verification code to
+ * support multiple RSA key lengths and hash digest algorithms.
+ */
+
+#include "avb_rsa.h"
+#include "avb_sha.h"
+#include "avb_util.h"
+#include "avb_vbmeta_image.h"
+
+typedef struct IAvbKey {
+  unsigned int len; /* Length of n[] in number of uint32_t */
+  uint32_t n0inv;   /* -1 / n[0] mod 2^32 */
+  uint32_t* n;      /* modulus as array (host-byte order) */
+  uint32_t* rr;     /* R^2 as array (host-byte order) */
+} IAvbKey;
+
+static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) {
+  AvbRSAPublicKeyHeader h;
+  IAvbKey* key = NULL;
+  size_t expected_length;
+  unsigned int i;
+  const uint8_t* n;
+  const uint8_t* rr;
+
+  if (!avb_rsa_public_key_header_validate_and_byteswap(
+          (const AvbRSAPublicKeyHeader*)data, &h)) {
+    avb_error("Invalid key.\n");
+    goto fail;
+  }
+
+  if (!(h.key_num_bits == 2048 || h.key_num_bits == 4096 ||
+        h.key_num_bits == 8192)) {
+    avb_error("Unexpected key length.\n");
+    goto fail;
+  }
+
+  expected_length = sizeof(AvbRSAPublicKeyHeader) + 2 * h.key_num_bits / 8;
+  if (length != expected_length) {
+    avb_error("Key does not match expected length.\n");
+    goto fail;
+  }
+
+  n = data + sizeof(AvbRSAPublicKeyHeader);
+  rr = data + sizeof(AvbRSAPublicKeyHeader) + h.key_num_bits / 8;
+
+  /* Store n and rr following the key header so we only have to do one
+   * allocation.
+   */
+  key = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 2 * h.key_num_bits / 8));
+  if (key == NULL) {
+    goto fail;
+  }
+
+  key->len = h.key_num_bits / 32;
+  key->n0inv = h.n0inv;
+  key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(IAvbKey) bytes. */
+  key->rr = key->n + key->len;
+
+  /* Crypto-code below (modpowF4() and friends) expects the key in
+   * little-endian format (rather than the format we're storing the
+   * key in), so convert it.
+   */
+  for (i = 0; i < key->len; i++) {
+    key->n[i] = avb_be32toh(((uint32_t*)n)[key->len - i - 1]);
+    key->rr[i] = avb_be32toh(((uint32_t*)rr)[key->len - i - 1]);
+  }
+  return key;
+
+fail:
+  if (key != NULL) {
+    avb_free(key);
+  }
+  return NULL;
+}
+
+static void iavb_free_parsed_key(IAvbKey* key) {
+  avb_free(key);
+}
+
+/* a[] -= mod */
+static void subM(const IAvbKey* key, uint32_t* a) {
+  int64_t A = 0;
+  uint32_t i;
+  for (i = 0; i < key->len; ++i) {
+    A += (uint64_t)a[i] - key->n[i];
+    a[i] = (uint32_t)A;
+    A >>= 32;
+  }
+}
+
+/* return a[] >= mod */
+static int geM(const IAvbKey* key, uint32_t* a) {
+  uint32_t i;
+  for (i = key->len; i;) {
+    --i;
+    if (a[i] < key->n[i]) {
+      return 0;
+    }
+    if (a[i] > key->n[i]) {
+      return 1;
+    }
+  }
+  return 1; /* equal */
+}
+
+/* montgomery c[] += a * b[] / R % mod */
+static void montMulAdd(const IAvbKey* key,
+                       uint32_t* c,
+                       const uint32_t a,
+                       const uint32_t* b) {
+  uint64_t A = (uint64_t)a * b[0] + c[0];
+  uint32_t d0 = (uint32_t)A * key->n0inv;
+  uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+  uint32_t i;
+
+  for (i = 1; i < key->len; ++i) {
+    A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+    B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+    c[i - 1] = (uint32_t)B;
+  }
+
+  A = (A >> 32) + (B >> 32);
+
+  c[i - 1] = (uint32_t)A;
+
+  if (A >> 32) {
+    subM(key, c);
+  }
+}
+
+/* montgomery c[] = a[] * b[] / R % mod */
+static void montMul(const IAvbKey* key, uint32_t* c, uint32_t* a, uint32_t* b) {
+  uint32_t i;
+  for (i = 0; i < key->len; ++i) {
+    c[i] = 0;
+  }
+  for (i = 0; i < key->len; ++i) {
+    montMulAdd(key, c, a[i], b);
+  }
+}
+
+/* In-place public exponentiation. (65537}
+ * Input and output big-endian byte array in inout.
+ */
+static void modpowF4(const IAvbKey* key, uint8_t* inout) {
+  uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  if (a == NULL || aR == NULL || aaR == NULL) {
+    goto out;
+  }
+
+  uint32_t* aaa = aaR; /* Re-use location. */
+  int i;
+
+  /* Convert from big endian byte array to little endian word array. */
+  for (i = 0; i < (int)key->len; ++i) {
+    uint32_t tmp = (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+                   (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+                   (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+                   (inout[((key->len - 1 - i) * 4) + 3] << 0);
+    a[i] = tmp;
+  }
+
+  montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M   */
+  for (i = 0; i < 16; i += 2) {
+    montMul(key, aaR, aR, aR);  /* aaR = aR * aR / R mod M */
+    montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */
+  }
+  montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */
+
+  /* Make sure aaa < mod; aaa is at most 1x mod too large. */
+  if (geM(key, aaa)) {
+    subM(key, aaa);
+  }
+
+  /* Convert to bigendian byte array */
+  for (i = (int)key->len - 1; i >= 0; --i) {
+    uint32_t tmp = aaa[i];
+    *inout++ = (uint8_t)(tmp >> 24);
+    *inout++ = (uint8_t)(tmp >> 16);
+    *inout++ = (uint8_t)(tmp >> 8);
+    *inout++ = (uint8_t)(tmp >> 0);
+  }
+
+out:
+  if (a != NULL) {
+    avb_free(a);
+  }
+  if (aR != NULL) {
+    avb_free(aR);
+  }
+  if (aaR != NULL) {
+    avb_free(aaR);
+  }
+}
+
+/* Verify a RSA PKCS1.5 signature against an expected hash.
+ * Returns false on failure, true on success.
+ */
+bool avb_rsa_verify(const uint8_t* key,
+                    size_t key_num_bytes,
+                    const uint8_t* sig,
+                    size_t sig_num_bytes,
+                    const uint8_t* hash,
+                    size_t hash_num_bytes,
+                    const uint8_t* padding,
+                    size_t padding_num_bytes) {
+  uint8_t* buf = NULL;
+  IAvbKey* parsed_key = NULL;
+  bool success = false;
+
+  if (key == NULL || sig == NULL || hash == NULL || padding == NULL) {
+    avb_error("Invalid input.\n");
+    goto out;
+  }
+
+  parsed_key = iavb_parse_key_data(key, key_num_bytes);
+  if (parsed_key == NULL) {
+    avb_error("Error parsing key.\n");
+    goto out;
+  }
+
+  if (sig_num_bytes != (parsed_key->len * sizeof(uint32_t))) {
+    avb_error("Signature length does not match key length.\n");
+    goto out;
+  }
+
+  if (padding_num_bytes != sig_num_bytes - hash_num_bytes) {
+    avb_error("Padding length does not match hash and signature lengths.\n");
+    goto out;
+  }
+
+  buf = (uint8_t*)avb_malloc(sig_num_bytes);
+  if (buf == NULL) {
+    avb_error("Error allocating memory.\n");
+    goto out;
+  }
+  avb_memcpy(buf, sig, sig_num_bytes);
+
+  modpowF4(parsed_key, buf);
+
+  /* Check padding bytes.
+   *
+   * Even though there are probably no timing issues here, we use
+   * avb_safe_memcmp() just to be on the safe side.
+   */
+  if (avb_safe_memcmp(buf, padding, padding_num_bytes)) {
+    avb_error("Padding check failed.\n");
+    goto out;
+  }
+
+  /* Check hash. */
+  if (avb_safe_memcmp(buf + padding_num_bytes, hash, hash_num_bytes)) {
+    avb_error("Hash check failed.\n");
+    goto out;
+  }
+
+  success = true;
+
+out:
+  if (parsed_key != NULL) {
+    iavb_free_parsed_key(parsed_key);
+  }
+  if (buf != NULL) {
+    avb_free(buf);
+  }
+  return success;
+}
diff --git a/lib/libavb/avb_rsa.h b/lib/libavb/avb_rsa.h
new file mode 100644 (file)
index 0000000..8741790
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: MIT OR BSD-3-Clause */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifdef AVB_INSIDE_LIBAVB_H
+#error "You can't include avb_rsa.h in the public header libavb.h."
+#endif
+
+#ifndef AVB_COMPILATION
+#error "Never include this file, it may only be used from internal avb code."
+#endif
+
+#ifndef AVB_RSA_H_
+#define AVB_RSA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_sysdeps.h"
+
+/* Using the key given by |key|, verify a RSA signature |sig| of
+ * length |sig_num_bytes| against an expected |hash| of length
+ * |hash_num_bytes|. The padding to expect must be passed in using
+ * |padding| of length |padding_num_bytes|.
+ *
+ * The data in |key| must match the format defined in
+ * |AvbRSAPublicKeyHeader|, including the two large numbers
+ * following. The |key_num_bytes| must be the size of the entire
+ * serialized key.
+ *
+ * Returns false if verification fails, true otherwise.
+ */
+bool avb_rsa_verify(const uint8_t* key,
+                    size_t key_num_bytes,
+                    const uint8_t* sig,
+                    size_t sig_num_bytes,
+                    const uint8_t* hash,
+                    size_t hash_num_bytes,
+                    const uint8_t* padding,
+                    size_t padding_num_bytes) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_RSA_H_ */
diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
new file mode 100644 (file)
index 0000000..365aaad
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#ifdef AVB_INSIDE_LIBAVB_H
+#error "You can't include avb_sha.h in the public header libavb.h."
+#endif
+
+#ifndef AVB_COMPILATION
+#error "Never include this file, it may only be used from internal avb code."
+#endif
+
+#ifndef AVB_SHA_H_
+#define AVB_SHA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_sysdeps.h"
+
+/* Block size in bytes of a SHA-256 digest. */
+#define AVB_SHA256_BLOCK_SIZE 64
+
+
+/* Block size in bytes of a SHA-512 digest. */
+#define AVB_SHA512_BLOCK_SIZE 128
+
+/* Data structure used for SHA-256. */
+typedef struct {
+  uint32_t h[8];
+  uint32_t tot_len;
+  uint32_t len;
+  uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
+  uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
+} AvbSHA256Ctx;
+
+/* Data structure used for SHA-512. */
+typedef struct {
+  uint64_t h[8];
+  uint32_t tot_len;
+  uint32_t len;
+  uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
+  uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
+} AvbSHA512Ctx;
+
+/* Initializes the SHA-256 context. */
+void avb_sha256_init(AvbSHA256Ctx* ctx);
+
+/* Updates the SHA-256 context with |len| bytes from |data|. */
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
+
+/* Returns the SHA-256 digest. */
+uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Initializes the SHA-512 context. */
+void avb_sha512_init(AvbSHA512Ctx* ctx);
+
+/* Updates the SHA-512 context with |len| bytes from |data|. */
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
+
+/* Returns the SHA-512 digest. */
+uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SHA_H_ */
diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
new file mode 100644 (file)
index 0000000..d24c701
--- /dev/null
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date:  04/30/2005
+ */
+
+#include "avb_sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str)                 \
+  {                                      \
+    *((str) + 3) = (uint8_t)((x));       \
+    *((str) + 2) = (uint8_t)((x) >> 8);  \
+    *((str) + 1) = (uint8_t)((x) >> 16); \
+    *((str) + 0) = (uint8_t)((x) >> 24); \
+  }
+
+#define PACK32(str, x)                                                    \
+  {                                                                       \
+    *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
+           ((uint32_t) * ((str) + 1) << 16) |                             \
+           ((uint32_t) * ((str) + 0) << 24);                              \
+  }
+
+/* Macros used for loops unrolling */
+
+#define SHA256_SCR(i) \
+  { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; }
+
+#define SHA256_EXP(a, b, c, d, e, f, g, h, j)                               \
+  {                                                                         \
+    t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha256_k[j] + \
+         w[j];                                                              \
+    t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);                       \
+    wv[d] += t1;                                                            \
+    wv[h] = t1 + t2;                                                        \
+  }
+
+static const uint32_t sha256_h0[8] = {0x6a09e667,
+                                      0xbb67ae85,
+                                      0x3c6ef372,
+                                      0xa54ff53a,
+                                      0x510e527f,
+                                      0x9b05688c,
+                                      0x1f83d9ab,
+                                      0x5be0cd19};
+
+static const uint32_t sha256_k[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
+
+/* SHA-256 implementation */
+void avb_sha256_init(AvbSHA256Ctx* ctx) {
+#ifndef UNROLL_LOOPS
+  int i;
+  for (i = 0; i < 8; i++) {
+    ctx->h[i] = sha256_h0[i];
+  }
+#else
+  ctx->h[0] = sha256_h0[0];
+  ctx->h[1] = sha256_h0[1];
+  ctx->h[2] = sha256_h0[2];
+  ctx->h[3] = sha256_h0[3];
+  ctx->h[4] = sha256_h0[4];
+  ctx->h[5] = sha256_h0[5];
+  ctx->h[6] = sha256_h0[6];
+  ctx->h[7] = sha256_h0[7];
+#endif /* !UNROLL_LOOPS */
+
+  ctx->len = 0;
+  ctx->tot_len = 0;
+}
+
+static void SHA256_transform(AvbSHA256Ctx* ctx,
+                             const uint8_t* message,
+                             unsigned int block_nb) {
+  uint32_t w[64];
+  uint32_t wv[8];
+  uint32_t t1, t2;
+  const unsigned char* sub_block;
+  int i;
+
+#ifndef UNROLL_LOOPS
+  int j;
+#endif
+
+  for (i = 0; i < (int)block_nb; i++) {
+    sub_block = message + (i << 6);
+
+#ifndef UNROLL_LOOPS
+    for (j = 0; j < 16; j++) {
+      PACK32(&sub_block[j << 2], &w[j]);
+    }
+
+    for (j = 16; j < 64; j++) {
+      SHA256_SCR(j);
+    }
+
+    for (j = 0; j < 8; j++) {
+      wv[j] = ctx->h[j];
+    }
+
+    for (j = 0; j < 64; j++) {
+      t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] +
+           w[j];
+      t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+      wv[7] = wv[6];
+      wv[6] = wv[5];
+      wv[5] = wv[4];
+      wv[4] = wv[3] + t1;
+      wv[3] = wv[2];
+      wv[2] = wv[1];
+      wv[1] = wv[0];
+      wv[0] = t1 + t2;
+    }
+
+    for (j = 0; j < 8; j++) {
+      ctx->h[j] += wv[j];
+    }
+#else
+    PACK32(&sub_block[0], &w[0]);
+    PACK32(&sub_block[4], &w[1]);
+    PACK32(&sub_block[8], &w[2]);
+    PACK32(&sub_block[12], &w[3]);
+    PACK32(&sub_block[16], &w[4]);
+    PACK32(&sub_block[20], &w[5]);
+    PACK32(&sub_block[24], &w[6]);
+    PACK32(&sub_block[28], &w[7]);
+    PACK32(&sub_block[32], &w[8]);
+    PACK32(&sub_block[36], &w[9]);
+    PACK32(&sub_block[40], &w[10]);
+    PACK32(&sub_block[44], &w[11]);
+    PACK32(&sub_block[48], &w[12]);
+    PACK32(&sub_block[52], &w[13]);
+    PACK32(&sub_block[56], &w[14]);
+    PACK32(&sub_block[60], &w[15]);
+
+    SHA256_SCR(16);
+    SHA256_SCR(17);
+    SHA256_SCR(18);
+    SHA256_SCR(19);
+    SHA256_SCR(20);
+    SHA256_SCR(21);
+    SHA256_SCR(22);
+    SHA256_SCR(23);
+    SHA256_SCR(24);
+    SHA256_SCR(25);
+    SHA256_SCR(26);
+    SHA256_SCR(27);
+    SHA256_SCR(28);
+    SHA256_SCR(29);
+    SHA256_SCR(30);
+    SHA256_SCR(31);
+    SHA256_SCR(32);
+    SHA256_SCR(33);
+    SHA256_SCR(34);
+    SHA256_SCR(35);
+    SHA256_SCR(36);
+    SHA256_SCR(37);
+    SHA256_SCR(38);
+    SHA256_SCR(39);
+    SHA256_SCR(40);
+    SHA256_SCR(41);
+    SHA256_SCR(42);
+    SHA256_SCR(43);
+    SHA256_SCR(44);
+    SHA256_SCR(45);
+    SHA256_SCR(46);
+    SHA256_SCR(47);
+    SHA256_SCR(48);
+    SHA256_SCR(49);
+    SHA256_SCR(50);
+    SHA256_SCR(51);
+    SHA256_SCR(52);
+    SHA256_SCR(53);
+    SHA256_SCR(54);
+    SHA256_SCR(55);
+    SHA256_SCR(56);
+    SHA256_SCR(57);
+    SHA256_SCR(58);
+    SHA256_SCR(59);
+    SHA256_SCR(60);
+    SHA256_SCR(61);
+    SHA256_SCR(62);
+    SHA256_SCR(63);
+
+    wv[0] = ctx->h[0];
+    wv[1] = ctx->h[1];
+    wv[2] = ctx->h[2];
+    wv[3] = ctx->h[3];
+    wv[4] = ctx->h[4];
+    wv[5] = ctx->h[5];
+    wv[6] = ctx->h[6];
+    wv[7] = ctx->h[7];
+
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 0);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 1);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 2);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 3);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 4);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 5);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 6);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 7);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 8);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 9);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 10);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 11);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 12);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 13);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 14);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 15);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 16);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 17);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 18);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 19);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 20);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 21);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 22);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 23);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 24);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 25);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 26);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 27);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 28);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 29);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 30);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 31);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 32);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 33);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 34);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 35);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 36);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 37);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 38);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 39);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 40);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 41);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 42);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 43);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 44);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 45);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 46);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 47);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 48);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 49);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 50);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 51);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 52);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 53);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 54);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 55);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 56);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 57);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 58);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 59);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 60);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 61);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 62);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 63);
+
+    ctx->h[0] += wv[0];
+    ctx->h[1] += wv[1];
+    ctx->h[2] += wv[2];
+    ctx->h[3] += wv[3];
+    ctx->h[4] += wv[4];
+    ctx->h[5] += wv[5];
+    ctx->h[6] += wv[6];
+    ctx->h[7] += wv[7];
+#endif /* !UNROLL_LOOPS */
+  }
+}
+
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
+  unsigned int block_nb;
+  unsigned int new_len, rem_len, tmp_len;
+  const uint8_t* shifted_data;
+
+  tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
+  rem_len = len < tmp_len ? len : tmp_len;
+
+  avb_memcpy(&ctx->block[ctx->len], data, rem_len);
+
+  if (ctx->len + len < AVB_SHA256_BLOCK_SIZE) {
+    ctx->len += len;
+    return;
+  }
+
+  new_len = len - rem_len;
+  block_nb = new_len / AVB_SHA256_BLOCK_SIZE;
+
+  shifted_data = data + rem_len;
+
+  SHA256_transform(ctx, ctx->block, 1);
+  SHA256_transform(ctx, shifted_data, block_nb);
+
+  rem_len = new_len % AVB_SHA256_BLOCK_SIZE;
+
+  avb_memcpy(ctx->block, &shifted_data[block_nb << 6], rem_len);
+
+  ctx->len = rem_len;
+  ctx->tot_len += (block_nb + 1) << 6;
+}
+
+uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
+  unsigned int block_nb;
+  unsigned int pm_len;
+  unsigned int len_b;
+#ifndef UNROLL_LOOPS
+  int i;
+#endif
+
+  block_nb =
+      (1 + ((AVB_SHA256_BLOCK_SIZE - 9) < (ctx->len % AVB_SHA256_BLOCK_SIZE)));
+
+  len_b = (ctx->tot_len + ctx->len) << 3;
+  pm_len = block_nb << 6;
+
+  avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+  ctx->block[ctx->len] = 0x80;
+  UNPACK32(len_b, ctx->block + pm_len - 4);
+
+  SHA256_transform(ctx, ctx->block, block_nb);
+
+#ifndef UNROLL_LOOPS
+  for (i = 0; i < 8; i++) {
+    UNPACK32(ctx->h[i], &ctx->buf[i << 2]);
+  }
+#else
+  UNPACK32(ctx->h[0], &ctx->buf[0]);
+  UNPACK32(ctx->h[1], &ctx->buf[4]);
+  UNPACK32(ctx->h[2], &ctx->buf[8]);
+  UNPACK32(ctx->h[3], &ctx->buf[12]);
+  UNPACK32(ctx->h[4], &ctx->buf[16]);
+  UNPACK32(ctx->h[5], &ctx->buf[20]);
+  UNPACK32(ctx->h[6], &ctx->buf[24]);
+  UNPACK32(ctx->h[7], &ctx->buf[28]);
+#endif /* !UNROLL_LOOPS */
+
+  return ctx->buf;
+}
diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
new file mode 100644 (file)
index 0000000..a5e7297
--- /dev/null
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date:  04/30/2005
+ */
+
+#include "avb_sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
+#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
+
+#define UNPACK32(x, str)                 \
+  {                                      \
+    *((str) + 3) = (uint8_t)((x));       \
+    *((str) + 2) = (uint8_t)((x) >> 8);  \
+    *((str) + 1) = (uint8_t)((x) >> 16); \
+    *((str) + 0) = (uint8_t)((x) >> 24); \
+  }
+
+#define UNPACK64(x, str)                         \
+  {                                              \
+    *((str) + 7) = (uint8_t)x;                   \
+    *((str) + 6) = (uint8_t)((uint64_t)x >> 8);  \
+    *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
+    *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
+    *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
+    *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
+    *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
+    *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
+  }
+
+#define PACK64(str, x)                                                        \
+  {                                                                           \
+    *(x) =                                                                    \
+        ((uint64_t) * ((str) + 7)) | ((uint64_t) * ((str) + 6) << 8) |        \
+        ((uint64_t) * ((str) + 5) << 16) | ((uint64_t) * ((str) + 4) << 24) | \
+        ((uint64_t) * ((str) + 3) << 32) | ((uint64_t) * ((str) + 2) << 40) | \
+        ((uint64_t) * ((str) + 1) << 48) | ((uint64_t) * ((str) + 0) << 56);  \
+  }
+
+/* Macros used for loops unrolling */
+
+#define SHA512_SCR(i) \
+  { w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16]; }
+
+#define SHA512_EXP(a, b, c, d, e, f, g, h, j)                               \
+  {                                                                         \
+    t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha512_k[j] + \
+         w[j];                                                              \
+    t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);                       \
+    wv[d] += t1;                                                            \
+    wv[h] = t1 + t2;                                                        \
+  }
+
+static const uint64_t sha512_h0[8] = {0x6a09e667f3bcc908ULL,
+                                      0xbb67ae8584caa73bULL,
+                                      0x3c6ef372fe94f82bULL,
+                                      0xa54ff53a5f1d36f1ULL,
+                                      0x510e527fade682d1ULL,
+                                      0x9b05688c2b3e6c1fULL,
+                                      0x1f83d9abfb41bd6bULL,
+                                      0x5be0cd19137e2179ULL};
+
+static const uint64_t sha512_k[80] = {
+    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
+
+/* SHA-512 implementation */
+
+void avb_sha512_init(AvbSHA512Ctx* ctx) {
+#ifdef UNROLL_LOOPS_SHA512
+  ctx->h[0] = sha512_h0[0];
+  ctx->h[1] = sha512_h0[1];
+  ctx->h[2] = sha512_h0[2];
+  ctx->h[3] = sha512_h0[3];
+  ctx->h[4] = sha512_h0[4];
+  ctx->h[5] = sha512_h0[5];
+  ctx->h[6] = sha512_h0[6];
+  ctx->h[7] = sha512_h0[7];
+#else
+  int i;
+
+  for (i = 0; i < 8; i++)
+    ctx->h[i] = sha512_h0[i];
+#endif /* UNROLL_LOOPS_SHA512 */
+
+  ctx->len = 0;
+  ctx->tot_len = 0;
+}
+
+static void SHA512_transform(AvbSHA512Ctx* ctx,
+                             const uint8_t* message,
+                             unsigned int block_nb) {
+  uint64_t w[80];
+  uint64_t wv[8];
+  uint64_t t1, t2;
+  const uint8_t* sub_block;
+  int i, j;
+
+  for (i = 0; i < (int)block_nb; i++) {
+    sub_block = message + (i << 7);
+
+#ifdef UNROLL_LOOPS_SHA512
+    PACK64(&sub_block[0], &w[0]);
+    PACK64(&sub_block[8], &w[1]);
+    PACK64(&sub_block[16], &w[2]);
+    PACK64(&sub_block[24], &w[3]);
+    PACK64(&sub_block[32], &w[4]);
+    PACK64(&sub_block[40], &w[5]);
+    PACK64(&sub_block[48], &w[6]);
+    PACK64(&sub_block[56], &w[7]);
+    PACK64(&sub_block[64], &w[8]);
+    PACK64(&sub_block[72], &w[9]);
+    PACK64(&sub_block[80], &w[10]);
+    PACK64(&sub_block[88], &w[11]);
+    PACK64(&sub_block[96], &w[12]);
+    PACK64(&sub_block[104], &w[13]);
+    PACK64(&sub_block[112], &w[14]);
+    PACK64(&sub_block[120], &w[15]);
+
+    SHA512_SCR(16);
+    SHA512_SCR(17);
+    SHA512_SCR(18);
+    SHA512_SCR(19);
+    SHA512_SCR(20);
+    SHA512_SCR(21);
+    SHA512_SCR(22);
+    SHA512_SCR(23);
+    SHA512_SCR(24);
+    SHA512_SCR(25);
+    SHA512_SCR(26);
+    SHA512_SCR(27);
+    SHA512_SCR(28);
+    SHA512_SCR(29);
+    SHA512_SCR(30);
+    SHA512_SCR(31);
+    SHA512_SCR(32);
+    SHA512_SCR(33);
+    SHA512_SCR(34);
+    SHA512_SCR(35);
+    SHA512_SCR(36);
+    SHA512_SCR(37);
+    SHA512_SCR(38);
+    SHA512_SCR(39);
+    SHA512_SCR(40);
+    SHA512_SCR(41);
+    SHA512_SCR(42);
+    SHA512_SCR(43);
+    SHA512_SCR(44);
+    SHA512_SCR(45);
+    SHA512_SCR(46);
+    SHA512_SCR(47);
+    SHA512_SCR(48);
+    SHA512_SCR(49);
+    SHA512_SCR(50);
+    SHA512_SCR(51);
+    SHA512_SCR(52);
+    SHA512_SCR(53);
+    SHA512_SCR(54);
+    SHA512_SCR(55);
+    SHA512_SCR(56);
+    SHA512_SCR(57);
+    SHA512_SCR(58);
+    SHA512_SCR(59);
+    SHA512_SCR(60);
+    SHA512_SCR(61);
+    SHA512_SCR(62);
+    SHA512_SCR(63);
+    SHA512_SCR(64);
+    SHA512_SCR(65);
+    SHA512_SCR(66);
+    SHA512_SCR(67);
+    SHA512_SCR(68);
+    SHA512_SCR(69);
+    SHA512_SCR(70);
+    SHA512_SCR(71);
+    SHA512_SCR(72);
+    SHA512_SCR(73);
+    SHA512_SCR(74);
+    SHA512_SCR(75);
+    SHA512_SCR(76);
+    SHA512_SCR(77);
+    SHA512_SCR(78);
+    SHA512_SCR(79);
+
+    wv[0] = ctx->h[0];
+    wv[1] = ctx->h[1];
+    wv[2] = ctx->h[2];
+    wv[3] = ctx->h[3];
+    wv[4] = ctx->h[4];
+    wv[5] = ctx->h[5];
+    wv[6] = ctx->h[6];
+    wv[7] = ctx->h[7];
+
+    j = 0;
+
+    do {
+      SHA512_EXP(0, 1, 2, 3, 4, 5, 6, 7, j);
+      j++;
+      SHA512_EXP(7, 0, 1, 2, 3, 4, 5, 6, j);
+      j++;
+      SHA512_EXP(6, 7, 0, 1, 2, 3, 4, 5, j);
+      j++;
+      SHA512_EXP(5, 6, 7, 0, 1, 2, 3, 4, j);
+      j++;
+      SHA512_EXP(4, 5, 6, 7, 0, 1, 2, 3, j);
+      j++;
+      SHA512_EXP(3, 4, 5, 6, 7, 0, 1, 2, j);
+      j++;
+      SHA512_EXP(2, 3, 4, 5, 6, 7, 0, 1, j);
+      j++;
+      SHA512_EXP(1, 2, 3, 4, 5, 6, 7, 0, j);
+      j++;
+    } while (j < 80);
+
+    ctx->h[0] += wv[0];
+    ctx->h[1] += wv[1];
+    ctx->h[2] += wv[2];
+    ctx->h[3] += wv[3];
+    ctx->h[4] += wv[4];
+    ctx->h[5] += wv[5];
+    ctx->h[6] += wv[6];
+    ctx->h[7] += wv[7];
+#else
+    for (j = 0; j < 16; j++) {
+      PACK64(&sub_block[j << 3], &w[j]);
+    }
+
+    for (j = 16; j < 80; j++) {
+      SHA512_SCR(j);
+    }
+
+    for (j = 0; j < 8; j++) {
+      wv[j] = ctx->h[j];
+    }
+
+    for (j = 0; j < 80; j++) {
+      t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] +
+           w[j];
+      t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+      wv[7] = wv[6];
+      wv[6] = wv[5];
+      wv[5] = wv[4];
+      wv[4] = wv[3] + t1;
+      wv[3] = wv[2];
+      wv[2] = wv[1];
+      wv[1] = wv[0];
+      wv[0] = t1 + t2;
+    }
+
+    for (j = 0; j < 8; j++)
+      ctx->h[j] += wv[j];
+#endif /* UNROLL_LOOPS_SHA512 */
+  }
+}
+
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
+  unsigned int block_nb;
+  unsigned int new_len, rem_len, tmp_len;
+  const uint8_t* shifted_data;
+
+  tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
+  rem_len = len < tmp_len ? len : tmp_len;
+
+  avb_memcpy(&ctx->block[ctx->len], data, rem_len);
+
+  if (ctx->len + len < AVB_SHA512_BLOCK_SIZE) {
+    ctx->len += len;
+    return;
+  }
+
+  new_len = len - rem_len;
+  block_nb = new_len / AVB_SHA512_BLOCK_SIZE;
+
+  shifted_data = data + rem_len;
+
+  SHA512_transform(ctx, ctx->block, 1);
+  SHA512_transform(ctx, shifted_data, block_nb);
+
+  rem_len = new_len % AVB_SHA512_BLOCK_SIZE;
+
+  avb_memcpy(ctx->block, &shifted_data[block_nb << 7], rem_len);
+
+  ctx->len = rem_len;
+  ctx->tot_len += (block_nb + 1) << 7;
+}
+
+uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
+  unsigned int block_nb;
+  unsigned int pm_len;
+  unsigned int len_b;
+
+#ifndef UNROLL_LOOPS_SHA512
+  int i;
+#endif
+
+  block_nb =
+      1 + ((AVB_SHA512_BLOCK_SIZE - 17) < (ctx->len % AVB_SHA512_BLOCK_SIZE));
+
+  len_b = (ctx->tot_len + ctx->len) << 3;
+  pm_len = block_nb << 7;
+
+  avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+  ctx->block[ctx->len] = 0x80;
+  UNPACK32(len_b, ctx->block + pm_len - 4);
+
+  SHA512_transform(ctx, ctx->block, block_nb);
+
+#ifdef UNROLL_LOOPS_SHA512
+  UNPACK64(ctx->h[0], &ctx->buf[0]);
+  UNPACK64(ctx->h[1], &ctx->buf[8]);
+  UNPACK64(ctx->h[2], &ctx->buf[16]);
+  UNPACK64(ctx->h[3], &ctx->buf[24]);
+  UNPACK64(ctx->h[4], &ctx->buf[32]);
+  UNPACK64(ctx->h[5], &ctx->buf[40]);
+  UNPACK64(ctx->h[6], &ctx->buf[48]);
+  UNPACK64(ctx->h[7], &ctx->buf[56]);
+#else
+  for (i = 0; i < 8; i++)
+    UNPACK64(ctx->h[i], &ctx->buf[i << 3]);
+#endif /* UNROLL_LOOPS_SHA512 */
+
+  return ctx->buf;
+}
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
new file mode 100644 (file)
index 0000000..a941850
--- /dev/null
@@ -0,0 +1,1366 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_slot_verify.h"
+#include "avb_chain_partition_descriptor.h"
+#include "avb_cmdline.h"
+#include "avb_footer.h"
+#include "avb_hash_descriptor.h"
+#include "avb_hashtree_descriptor.h"
+#include "avb_kernel_cmdline_descriptor.h"
+#include "avb_sha.h"
+#include "avb_util.h"
+#include "avb_vbmeta_image.h"
+#include "avb_version.h"
+
+/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
+#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
+
+/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
+#define MAX_NUMBER_OF_VBMETA_IMAGES 32
+
+/* Maximum size of a vbmeta image - 64 KiB. */
+#define VBMETA_MAX_SIZE (64 * 1024)
+
+/* Helper function to see if we should continue with verification in
+ * allow_verification_error=true mode if something goes wrong. See the
+ * comments for the avb_slot_verify() function for more information.
+ */
+static inline bool result_should_continue(AvbSlotVerifyResult result) {
+  switch (result) {
+    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+      return false;
+
+    case AVB_SLOT_VERIFY_RESULT_OK:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+      return true;
+  }
+
+  return false;
+}
+
+static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
+                                               const char* part_name,
+                                               uint64_t image_size,
+                                               uint8_t** out_image_buf,
+                                               bool* out_image_preloaded) {
+  size_t part_num_read;
+  AvbIOResult io_ret;
+
+  /* Make sure that we do not overwrite existing data. */
+  avb_assert(*out_image_buf == NULL);
+  avb_assert(!*out_image_preloaded);
+
+  /* We are going to implicitly cast image_size from uint64_t to size_t in the
+   * following code, so we need to make sure that the cast is safe. */
+  if (image_size != (size_t)(image_size)) {
+    avb_errorv(part_name, ": Partition size too large to load.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  }
+
+  /* Try use a preloaded one. */
+  if (ops->get_preloaded_partition != NULL) {
+    io_ret = ops->get_preloaded_partition(
+        ops, part_name, image_size, out_image_buf, &part_num_read);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+      return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    }
+
+    if (*out_image_buf != NULL) {
+      if (part_num_read != image_size) {
+        avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+        return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      }
+      *out_image_preloaded = true;
+    }
+  }
+
+  /* Allocate and copy the partition. */
+  if (!*out_image_preloaded) {
+    *out_image_buf = avb_malloc(image_size);
+    if (*out_image_buf == NULL) {
+      return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    }
+
+    io_ret = ops->read_from_partition(ops,
+                                      part_name,
+                                      0 /* offset */,
+                                      image_size,
+                                      *out_image_buf,
+                                      &part_num_read);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+      return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    }
+    if (part_num_read != image_size) {
+      avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+      return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    }
+  }
+
+  return AVB_SLOT_VERIFY_RESULT_OK;
+}
+
+static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
+                                                  const char* part_name,
+                                                  size_t expected_digest_size,
+                                                  uint8_t* out_digest) {
+  char* persistent_value_name = NULL;
+  AvbIOResult io_ret = AVB_IO_RESULT_OK;
+  size_t stored_digest_size = 0;
+
+  if (ops->read_persistent_value == NULL) {
+    avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  }
+  persistent_value_name =
+      avb_strdupv(AVB_NPV_PERSISTENT_DIGEST_PREFIX, part_name, NULL);
+  if (persistent_value_name == NULL) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  }
+  io_ret = ops->read_persistent_value(ops,
+                                      persistent_value_name,
+                                      expected_digest_size,
+                                      out_digest,
+                                      &stored_digest_size);
+  avb_free(persistent_value_name);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
+    avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
+             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
+             expected_digest_size != stored_digest_size) {
+    avb_errorv(
+        part_name, ": Persistent digest is not of expected size.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  }
+  return AVB_SLOT_VERIFY_RESULT_OK;
+}
+
+static AvbSlotVerifyResult load_and_verify_hash_partition(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    bool allow_verification_error,
+    const AvbDescriptor* descriptor,
+    AvbSlotVerifyData* slot_data) {
+  AvbHashDescriptor hash_desc;
+  const uint8_t* desc_partition_name = NULL;
+  const uint8_t* desc_salt;
+  const uint8_t* desc_digest;
+  char part_name[AVB_PART_NAME_MAX_SIZE];
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret;
+  uint8_t* image_buf = NULL;
+  bool image_preloaded = false;
+  uint8_t* digest;
+  size_t digest_len;
+  const char* found;
+  uint64_t image_size;
+  size_t expected_digest_len = 0;
+  uint8_t expected_digest_buf[AVB_SHA512_DIGEST_SIZE];
+  const uint8_t* expected_digest = NULL;
+
+  if (!avb_hash_descriptor_validate_and_byteswap(
+          (const AvbHashDescriptor*)descriptor, &hash_desc)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  desc_partition_name =
+      ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
+  desc_salt = desc_partition_name + hash_desc.partition_name_len;
+  desc_digest = desc_salt + hash_desc.salt_len;
+
+  if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
+    avb_error("Partition name is not valid UTF-8.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  /* Don't bother loading or validating unless the partition was
+   * requested in the first place.
+   */
+  found = avb_strv_find_str(requested_partitions,
+                            (const char*)desc_partition_name,
+                            hash_desc.partition_name_len);
+  if (found == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_OK;
+    goto out;
+  }
+
+  if ((hash_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0) {
+    /* No ab_suffix, just copy the partition name as is. */
+    if (hash_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+      avb_error("Partition name does not fit.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+    avb_memcpy(part_name, desc_partition_name, hash_desc.partition_name_len);
+    part_name[hash_desc.partition_name_len] = '\0';
+  } else if (hash_desc.digest_len == 0 && avb_strlen(ab_suffix) != 0) {
+    /* No ab_suffix allowed for partitions without a digest in the descriptor
+     * because these partitions hold data unique to this device and are not
+     * updated using an A/B scheme.
+     */
+    avb_error("Cannot use A/B with a persistent digest.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  } else {
+    /* Add ab_suffix to the partition name. */
+    if (!avb_str_concat(part_name,
+                        sizeof part_name,
+                        (const char*)desc_partition_name,
+                        hash_desc.partition_name_len,
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+  }
+
+  /* If we're allowing verification errors then hash_desc.image_size
+   * may no longer match what's in the partition... so in this case
+   * just load the entire partition.
+   *
+   * For example, this can happen if a developer does 'fastboot flash
+   * boot /path/to/new/and/bigger/boot.img'. We want this to work
+   * since it's such a common workflow.
+   */
+  image_size = hash_desc.image_size;
+  if (allow_verification_error) {
+    if (ops->get_size_of_partition == NULL) {
+      avb_errorv(part_name,
+                 ": The get_size_of_partition() operation is "
+                 "not implemented so we may not load the entire partition. "
+                 "Please implement.",
+                 NULL);
+    } else {
+      io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      } else if (io_ret != AVB_IO_RESULT_OK) {
+        avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+        goto out;
+      }
+      avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+    }
+  }
+
+  ret = load_full_partition(
+      ops, part_name, image_size, &image_buf, &image_preloaded);
+  if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+    goto out;
+  }
+
+  if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
+    AvbSHA256Ctx sha256_ctx;
+    avb_sha256_init(&sha256_ctx);
+    avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
+    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+    digest = avb_sha256_final(&sha256_ctx);
+    digest_len = AVB_SHA256_DIGEST_SIZE;
+  } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
+    AvbSHA512Ctx sha512_ctx;
+    avb_sha512_init(&sha512_ctx);
+    avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
+    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+    digest = avb_sha512_final(&sha512_ctx);
+    digest_len = AVB_SHA512_DIGEST_SIZE;
+  } else {
+    avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  if (hash_desc.digest_len == 0) {
+    // Expect a match to a persistent digest.
+    avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
+    expected_digest_len = digest_len;
+    expected_digest = expected_digest_buf;
+    avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
+    ret =
+        read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
+    if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      goto out;
+    }
+  } else {
+    // Expect a match to the digest in the descriptor.
+    expected_digest_len = hash_desc.digest_len;
+    expected_digest = desc_digest;
+  }
+
+  if (digest_len != expected_digest_len) {
+    avb_errorv(
+        part_name, ": Digest in descriptor not of expected size.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) {
+    avb_errorv(part_name,
+               ": Hash of data does not match digest in descriptor.\n",
+               NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+    goto out;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+  /* If it worked and something was loaded, copy to slot_data. */
+  if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
+      image_buf != NULL) {
+    AvbPartitionData* loaded_partition;
+    if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+      avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+    loaded_partition =
+        &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+    loaded_partition->partition_name = avb_strdup(found);
+    loaded_partition->data_size = image_size;
+    loaded_partition->data = image_buf;
+    loaded_partition->preloaded = image_preloaded;
+    image_buf = NULL;
+  }
+
+fail:
+  if (image_buf != NULL && !image_preloaded) {
+    avb_free(image_buf);
+  }
+  return ret;
+}
+
+static AvbSlotVerifyResult load_requested_partitions(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    AvbSlotVerifyData* slot_data) {
+  AvbSlotVerifyResult ret;
+  uint8_t* image_buf = NULL;
+  bool image_preloaded = false;
+  size_t n;
+
+  if (ops->get_size_of_partition == NULL) {
+    avb_error("get_size_of_partition() not implemented.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+    goto out;
+  }
+
+  for (n = 0; requested_partitions[n] != NULL; n++) {
+    char part_name[AVB_PART_NAME_MAX_SIZE];
+    AvbIOResult io_ret;
+    uint64_t image_size;
+    AvbPartitionData* loaded_partition;
+
+    if (!avb_str_concat(part_name,
+                        sizeof part_name,
+                        requested_partitions[n],
+                        avb_strlen(requested_partitions[n]),
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+    avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+
+    ret = load_full_partition(
+        ops, part_name, image_size, &image_buf, &image_preloaded);
+    if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      goto out;
+    }
+
+    /* Move to slot_data. */
+    if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+      avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+    loaded_partition =
+        &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+    loaded_partition->partition_name = avb_strdup(requested_partitions[n]);
+    if (loaded_partition->partition_name == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+    loaded_partition->data_size = image_size;
+    loaded_partition->data = image_buf; /* Transferring the owner. */
+    loaded_partition->preloaded = image_preloaded;
+    image_buf = NULL;
+    image_preloaded = false;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+  /* Free the current buffer if any. */
+  if (image_buf != NULL && !image_preloaded) {
+    avb_free(image_buf);
+  }
+  /* Buffers that are already saved in slot_data will be handled by the caller
+   * even on failure. */
+  return ret;
+}
+
+static AvbSlotVerifyResult load_and_verify_vbmeta(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    bool allow_verification_error,
+    AvbVBMetaImageFlags toplevel_vbmeta_flags,
+    int rollback_index_location,
+    const char* partition_name,
+    size_t partition_name_len,
+    const uint8_t* expected_public_key,
+    size_t expected_public_key_length,
+    AvbSlotVerifyData* slot_data,
+    AvbAlgorithmType* out_algorithm_type,
+    AvbCmdlineSubstList* out_additional_cmdline_subst) {
+  char full_partition_name[AVB_PART_NAME_MAX_SIZE];
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret;
+  size_t vbmeta_offset;
+  size_t vbmeta_size;
+  uint8_t* vbmeta_buf = NULL;
+  size_t vbmeta_num_read;
+  AvbVBMetaVerifyResult vbmeta_ret;
+  const uint8_t* pk_data;
+  size_t pk_len;
+  AvbVBMetaImageHeader vbmeta_header;
+  uint64_t stored_rollback_index;
+  const AvbDescriptor** descriptors = NULL;
+  size_t num_descriptors;
+  size_t n;
+  bool is_main_vbmeta;
+  bool is_vbmeta_partition;
+  AvbVBMetaData* vbmeta_image_data = NULL;
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+  avb_assert(slot_data != NULL);
+
+  /* Since we allow top-level vbmeta in 'boot', use
+   * rollback_index_location to determine whether we're the main
+   * vbmeta struct.
+   */
+  is_main_vbmeta = (rollback_index_location == 0);
+  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
+
+  if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
+    avb_error("Partition name is not valid UTF-8.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  /* Construct full partition name. */
+  if (!avb_str_concat(full_partition_name,
+                      sizeof full_partition_name,
+                      partition_name,
+                      partition_name_len,
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("Partition name and suffix does not fit.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  avb_debugv("Loading vbmeta struct from partition '",
+             full_partition_name,
+             "'.\n",
+             NULL);
+
+  /* If we're loading from the main vbmeta partition, the vbmeta
+   * struct is in the beginning. Otherwise we have to locate it via a
+   * footer.
+   */
+  if (is_vbmeta_partition) {
+    vbmeta_offset = 0;
+    vbmeta_size = VBMETA_MAX_SIZE;
+  } else {
+    uint8_t footer_buf[AVB_FOOTER_SIZE];
+    size_t footer_num_read;
+    AvbFooter footer;
+
+    io_ret = ops->read_from_partition(ops,
+                                      full_partition_name,
+                                      -AVB_FOOTER_SIZE,
+                                      AVB_FOOTER_SIZE,
+                                      footer_buf,
+                                      &footer_num_read);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+    avb_assert(footer_num_read == AVB_FOOTER_SIZE);
+
+    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
+                                          &footer)) {
+      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    /* Basic footer sanity check since the data is untrusted. */
+    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
+      avb_errorv(
+          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    vbmeta_offset = footer.vbmeta_offset;
+    vbmeta_size = footer.vbmeta_size;
+  }
+
+  vbmeta_buf = avb_malloc(vbmeta_size);
+  if (vbmeta_buf == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  io_ret = ops->read_from_partition(ops,
+                                    full_partition_name,
+                                    vbmeta_offset,
+                                    vbmeta_size,
+                                    vbmeta_buf,
+                                    &vbmeta_num_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    /* If we're looking for 'vbmeta' but there is no such partition,
+     * go try to get it from the boot partition instead.
+     */
+    if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
+        is_vbmeta_partition) {
+      avb_debugv(full_partition_name,
+                 ": No such partition. Trying 'boot' instead.\n",
+                 NULL);
+      ret = load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   allow_verification_error,
+                                   0 /* toplevel_vbmeta_flags */,
+                                   0 /* rollback_index_location */,
+                                   "boot",
+                                   avb_strlen("boot"),
+                                   NULL /* expected_public_key */,
+                                   0 /* expected_public_key_length */,
+                                   slot_data,
+                                   out_algorithm_type,
+                                   out_additional_cmdline_subst);
+      goto out;
+    } else {
+      avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+  }
+  avb_assert(vbmeta_num_read <= vbmeta_size);
+
+  /* Check if the image is properly signed and get the public key used
+   * to sign the image.
+   */
+  vbmeta_ret =
+      avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
+  switch (vbmeta_ret) {
+    case AVB_VBMETA_VERIFY_RESULT_OK:
+      avb_assert(pk_data != NULL && pk_len > 0);
+      break;
+
+    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
+    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
+    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: ",
+                 avb_vbmeta_verify_result_to_string(vbmeta_ret),
+                 "\n",
+                 NULL);
+      if (!allow_verification_error) {
+        goto out;
+      }
+      break;
+
+    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
+      /* No way to continue this case. */
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: invalid vbmeta header\n",
+                 NULL);
+      goto out;
+
+    case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
+      /* No way to continue this case. */
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: unsupported AVB version\n",
+                 NULL);
+      goto out;
+  }
+
+  /* Byteswap the header. */
+  avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
+                                             &vbmeta_header);
+
+  /* If we're the toplevel, assign flags so they'll be passed down. */
+  if (is_main_vbmeta) {
+    toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
+  } else {
+    if (vbmeta_header.flags != 0) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      avb_errorv(full_partition_name,
+                 ": chained vbmeta image has non-zero flags\n",
+                 NULL);
+      goto out;
+    }
+  }
+
+  /* Check if key used to make signature matches what is expected. */
+  if (pk_data != NULL) {
+    if (expected_public_key != NULL) {
+      avb_assert(!is_main_vbmeta);
+      if (expected_public_key_length != pk_len ||
+          avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
+        avb_errorv(full_partition_name,
+                   ": Public key used to sign data does not match key in chain "
+                   "partition descriptor.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
+        if (!allow_verification_error) {
+          goto out;
+        }
+      }
+    } else {
+      bool key_is_trusted = false;
+      const uint8_t* pk_metadata = NULL;
+      size_t pk_metadata_len = 0;
+
+      if (vbmeta_header.public_key_metadata_size > 0) {
+        pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
+                      vbmeta_header.authentication_data_block_size +
+                      vbmeta_header.public_key_metadata_offset;
+        pk_metadata_len = vbmeta_header.public_key_metadata_size;
+      }
+
+      avb_assert(is_main_vbmeta);
+      io_ret = ops->validate_vbmeta_public_key(
+          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
+      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      } else if (io_ret != AVB_IO_RESULT_OK) {
+        avb_errorv(full_partition_name,
+                   ": Error while checking public key used to sign data.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+        goto out;
+      }
+      if (!key_is_trusted) {
+        avb_errorv(full_partition_name,
+                   ": Public key used to sign data rejected.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
+        if (!allow_verification_error) {
+          goto out;
+        }
+      }
+    }
+  }
+
+  /* Check rollback index. */
+  io_ret = ops->read_rollback_index(
+      ops, rollback_index_location, &stored_rollback_index);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(full_partition_name,
+               ": Error getting rollback index for location.\n",
+               NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+  if (vbmeta_header.rollback_index < stored_rollback_index) {
+    avb_errorv(
+        full_partition_name,
+        ": Image rollback index is less than the stored rollback index.\n",
+        NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
+    if (!allow_verification_error) {
+      goto out;
+    }
+  }
+
+  /* Copy vbmeta to vbmeta_images before recursing. */
+  if (is_main_vbmeta) {
+    avb_assert(slot_data->num_vbmeta_images == 0);
+  } else {
+    avb_assert(slot_data->num_vbmeta_images > 0);
+  }
+  if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
+    avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+  vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
+  vbmeta_image_data->partition_name = avb_strdup(partition_name);
+  vbmeta_image_data->vbmeta_data = vbmeta_buf;
+  /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
+   * and this includes data past the end of the image. Pass the
+   * actual size of the vbmeta image. Also, no need to use
+   * avb_safe_add() since the header has already been verified.
+   */
+  vbmeta_image_data->vbmeta_size =
+      sizeof(AvbVBMetaImageHeader) +
+      vbmeta_header.authentication_data_block_size +
+      vbmeta_header.auxiliary_data_block_size;
+  vbmeta_image_data->verify_result = vbmeta_ret;
+
+  /* If verification has been disabled by setting a bit in the image,
+   * we're done... except that we need to load the entirety of the
+   * requested partitions.
+   */
+  if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+    AvbSlotVerifyResult sub_ret;
+    avb_debugv(
+        full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
+    /* If load_requested_partitions() fail it is always a fatal
+     * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
+     * than recoverable (e.g. one where result_should_continue()
+     * returns true) and we want to convey that error.
+     */
+    sub_ret = load_requested_partitions(
+        ops, requested_partitions, ab_suffix, slot_data);
+    if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      ret = sub_ret;
+    }
+    goto out;
+  }
+
+  /* Now go through all descriptors and take the appropriate action:
+   *
+   * - hash descriptor: Load data from partition, calculate hash, and
+   *   checks that it matches what's in the hash descriptor.
+   *
+   * - hashtree descriptor: Do nothing since verification happens
+   *   on-the-fly from within the OS. (Unless the descriptor uses a
+   *   persistent digest, in which case we need to find it).
+   *
+   * - chained partition descriptor: Load the footer, load the vbmeta
+   *   image, verify vbmeta image (includes rollback checks, hash
+   *   checks, bail on chained partitions).
+   */
+  descriptors =
+      avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
+  for (n = 0; n < num_descriptors; n++) {
+    AvbDescriptor desc;
+
+    if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+      avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    switch (desc.tag) {
+      case AVB_DESCRIPTOR_TAG_HASH: {
+        AvbSlotVerifyResult sub_ret;
+        sub_ret = load_and_verify_hash_partition(ops,
+                                                 requested_partitions,
+                                                 ab_suffix,
+                                                 allow_verification_error,
+                                                 descriptors[n],
+                                                 slot_data);
+        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+          ret = sub_ret;
+          if (!allow_verification_error || !result_should_continue(ret)) {
+            goto out;
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
+        AvbSlotVerifyResult sub_ret;
+        AvbChainPartitionDescriptor chain_desc;
+        const uint8_t* chain_partition_name;
+        const uint8_t* chain_public_key;
+
+        /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
+        if (!is_main_vbmeta) {
+          avb_errorv(full_partition_name,
+                     ": Encountered chain descriptor not in main image.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        if (!avb_chain_partition_descriptor_validate_and_byteswap(
+                (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
+          avb_errorv(full_partition_name,
+                     ": Chain partition descriptor is invalid.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        if (chain_desc.rollback_index_location == 0) {
+          avb_errorv(full_partition_name,
+                     ": Chain partition has invalid "
+                     "rollback_index_location field.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        chain_partition_name = ((const uint8_t*)descriptors[n]) +
+                               sizeof(AvbChainPartitionDescriptor);
+        chain_public_key = chain_partition_name + chain_desc.partition_name_len;
+
+        sub_ret =
+            load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   allow_verification_error,
+                                   toplevel_vbmeta_flags,
+                                   chain_desc.rollback_index_location,
+                                   (const char*)chain_partition_name,
+                                   chain_desc.partition_name_len,
+                                   chain_public_key,
+                                   chain_desc.public_key_len,
+                                   slot_data,
+                                   NULL, /* out_algorithm_type */
+                                   NULL /* out_additional_cmdline_subst */);
+        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+          ret = sub_ret;
+          if (!result_should_continue(ret)) {
+            goto out;
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
+        const uint8_t* kernel_cmdline;
+        AvbKernelCmdlineDescriptor kernel_cmdline_desc;
+        bool apply_cmdline;
+
+        if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
+                (AvbKernelCmdlineDescriptor*)descriptors[n],
+                &kernel_cmdline_desc)) {
+          avb_errorv(full_partition_name,
+                     ": Kernel cmdline descriptor is invalid.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        kernel_cmdline = ((const uint8_t*)descriptors[n]) +
+                         sizeof(AvbKernelCmdlineDescriptor);
+
+        if (!avb_validate_utf8(kernel_cmdline,
+                               kernel_cmdline_desc.kernel_cmdline_length)) {
+          avb_errorv(full_partition_name,
+                     ": Kernel cmdline is not valid UTF-8.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        /* Compare the flags for top-level VBMeta struct with flags in
+         * the command-line descriptor so command-line snippets only
+         * intended for a certain mode (dm-verity enabled/disabled)
+         * are skipped if applicable.
+         */
+        apply_cmdline = true;
+        if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+          if (kernel_cmdline_desc.flags &
+              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
+            apply_cmdline = false;
+          }
+        } else {
+          if (kernel_cmdline_desc.flags &
+              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
+            apply_cmdline = false;
+          }
+        }
+
+        if (apply_cmdline) {
+          if (slot_data->cmdline == NULL) {
+            slot_data->cmdline =
+                avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
+            if (slot_data->cmdline == NULL) {
+              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+              goto out;
+            }
+            avb_memcpy(slot_data->cmdline,
+                       kernel_cmdline,
+                       kernel_cmdline_desc.kernel_cmdline_length);
+          } else {
+            /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
+            size_t orig_size = avb_strlen(slot_data->cmdline);
+            size_t new_size =
+                orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
+            char* new_cmdline = avb_calloc(new_size);
+            if (new_cmdline == NULL) {
+              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+              goto out;
+            }
+            avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
+            new_cmdline[orig_size] = ' ';
+            avb_memcpy(new_cmdline + orig_size + 1,
+                       kernel_cmdline,
+                       kernel_cmdline_desc.kernel_cmdline_length);
+            avb_free(slot_data->cmdline);
+            slot_data->cmdline = new_cmdline;
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_HASHTREE: {
+        AvbHashtreeDescriptor hashtree_desc;
+
+        if (!avb_hashtree_descriptor_validate_and_byteswap(
+                (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {
+          avb_errorv(
+              full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        /* We only need to continue when there is no digest in the descriptor.
+         * This is because the only processing here is to find the digest and
+         * make it available on the kernel command line.
+         */
+        if (hashtree_desc.root_digest_len == 0) {
+          char part_name[AVB_PART_NAME_MAX_SIZE];
+          size_t digest_len = 0;
+          uint8_t digest_buf[AVB_SHA512_DIGEST_SIZE];
+          const uint8_t* desc_partition_name =
+              ((const uint8_t*)descriptors[n]) + sizeof(AvbHashtreeDescriptor);
+
+          if (!avb_validate_utf8(desc_partition_name,
+                                 hashtree_desc.partition_name_len)) {
+            avb_error("Partition name is not valid UTF-8.\n");
+            ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+            goto out;
+          }
+
+          /* No ab_suffix for partitions without a digest in the descriptor
+           * because these partitions hold data unique to this device and are
+           * not updated using an A/B scheme.
+           */
+          if ((hashtree_desc.flags &
+               AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) == 0 &&
+              avb_strlen(ab_suffix) != 0) {
+            avb_error("Cannot use A/B with a persistent root digest.\n");
+            ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+            goto out;
+          }
+          if (hashtree_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+            avb_error("Partition name does not fit.\n");
+            ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+            goto out;
+          }
+          avb_memcpy(
+              part_name, desc_partition_name, hashtree_desc.partition_name_len);
+          part_name[hashtree_desc.partition_name_len] = '\0';
+
+          /* Determine the expected digest size from the hash algorithm. */
+          if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, "sha1") ==
+              0) {
+            digest_len = AVB_SHA1_DIGEST_SIZE;
+          } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
+                                "sha256") == 0) {
+            digest_len = AVB_SHA256_DIGEST_SIZE;
+          } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
+                                "sha512") == 0) {
+            digest_len = AVB_SHA512_DIGEST_SIZE;
+          } else {
+            avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+            ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+            goto out;
+          }
+
+          ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
+          if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+            goto out;
+          }
+
+          if (out_additional_cmdline_subst) {
+            ret =
+                avb_add_root_digest_substitution(part_name,
+                                                 digest_buf,
+                                                 digest_len,
+                                                 out_additional_cmdline_subst);
+            if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+              goto out;
+            }
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_PROPERTY:
+        /* Do nothing. */
+        break;
+    }
+  }
+
+  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+    avb_errorv(
+        full_partition_name, ": Invalid rollback_index_location.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  slot_data->rollback_indexes[rollback_index_location] =
+      vbmeta_header.rollback_index;
+
+  if (out_algorithm_type != NULL) {
+    *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
+  }
+
+out:
+  /* If |vbmeta_image_data| isn't NULL it means that it adopted
+   * |vbmeta_buf| so in that case don't free it here.
+   */
+  if (vbmeta_image_data == NULL) {
+    if (vbmeta_buf != NULL) {
+      avb_free(vbmeta_buf);
+    }
+  }
+  if (descriptors != NULL) {
+    avb_free(descriptors);
+  }
+  return ret;
+}
+
+AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
+                                    const char* const* requested_partitions,
+                                    const char* ab_suffix,
+                                    AvbSlotVerifyFlags flags,
+                                    AvbHashtreeErrorMode hashtree_error_mode,
+                                    AvbSlotVerifyData** out_data) {
+  AvbSlotVerifyResult ret;
+  AvbSlotVerifyData* slot_data = NULL;
+  AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
+  bool using_boot_for_vbmeta = false;
+  AvbVBMetaImageHeader toplevel_vbmeta;
+  bool allow_verification_error =
+      (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
+  AvbCmdlineSubstList* additional_cmdline_subst = NULL;
+
+  /* Fail early if we're missing the AvbOps needed for slot verification.
+   *
+   * For now, handle get_size_of_partition() not being implemented. In
+   * a later release we may change that.
+   */
+  avb_assert(ops->read_is_device_unlocked != NULL);
+  avb_assert(ops->read_from_partition != NULL);
+  avb_assert(ops->validate_vbmeta_public_key != NULL);
+  avb_assert(ops->read_rollback_index != NULL);
+  avb_assert(ops->get_unique_guid_for_partition != NULL);
+
+  if (out_data != NULL) {
+    *out_data = NULL;
+  }
+
+  /* Allowing dm-verity errors defeats the purpose of verified boot so
+   * only allow this if set up to allow verification errors
+   * (e.g. typically only UNLOCKED mode).
+   */
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
+      !allow_verification_error) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+    goto fail;
+  }
+
+  slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
+  if (slot_data == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+  slot_data->vbmeta_images =
+      avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
+  if (slot_data->vbmeta_images == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+  slot_data->loaded_partitions =
+      avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
+  if (slot_data->loaded_partitions == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+
+  additional_cmdline_subst = avb_new_cmdline_subst_list();
+  if (additional_cmdline_subst == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+
+  ret = load_and_verify_vbmeta(ops,
+                               requested_partitions,
+                               ab_suffix,
+                               allow_verification_error,
+                               0 /* toplevel_vbmeta_flags */,
+                               0 /* rollback_index_location */,
+                               "vbmeta",
+                               avb_strlen("vbmeta"),
+                               NULL /* expected_public_key */,
+                               0 /* expected_public_key_length */,
+                               slot_data,
+                               &algorithm_type,
+                               additional_cmdline_subst);
+  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+    goto fail;
+  }
+
+  /* If things check out, mangle the kernel command-line as needed. */
+  if (result_should_continue(ret)) {
+    if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
+      avb_assert(
+          avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
+      using_boot_for_vbmeta = true;
+    }
+
+    /* Byteswap top-level vbmeta header since we'll need it below. */
+    avb_vbmeta_image_header_to_host_byte_order(
+        (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
+        &toplevel_vbmeta);
+
+    /* Fill in |ab_suffix| field. */
+    slot_data->ab_suffix = avb_strdup(ab_suffix);
+    if (slot_data->ab_suffix == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+
+    /* If verification is disabled, we are done ... we specifically
+     * don't want to add any androidboot.* options since verification
+     * is disabled.
+     */
+    if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+      /* Since verification is disabled we didn't process any
+       * descriptors and thus there's no cmdline... so set root= such
+       * that the system partition is mounted.
+       */
+      avb_assert(slot_data->cmdline == NULL);
+      slot_data->cmdline =
+          avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
+      if (slot_data->cmdline == NULL) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto fail;
+      }
+    } else {
+      /* Add options - any failure in avb_append_options() is either an
+       * I/O or OOM error.
+       */
+      AvbSlotVerifyResult sub_ret = avb_append_options(ops,
+                                                       slot_data,
+                                                       &toplevel_vbmeta,
+                                                       algorithm_type,
+                                                       hashtree_error_mode);
+      if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+        ret = sub_ret;
+        goto fail;
+      }
+    }
+
+    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+    if (slot_data->cmdline != NULL) {
+      char* new_cmdline;
+      new_cmdline = avb_sub_cmdline(ops,
+                                    slot_data->cmdline,
+                                    ab_suffix,
+                                    using_boot_for_vbmeta,
+                                    additional_cmdline_subst);
+      if (new_cmdline != slot_data->cmdline) {
+        if (new_cmdline == NULL) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto fail;
+        }
+        avb_free(slot_data->cmdline);
+        slot_data->cmdline = new_cmdline;
+      }
+    }
+
+    if (out_data != NULL) {
+      *out_data = slot_data;
+    } else {
+      avb_slot_verify_data_free(slot_data);
+    }
+  }
+
+  avb_free_cmdline_subst_list(additional_cmdline_subst);
+  additional_cmdline_subst = NULL;
+
+  if (!allow_verification_error) {
+    avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
+  }
+
+  return ret;
+
+fail:
+  if (slot_data != NULL) {
+    avb_slot_verify_data_free(slot_data);
+  }
+  if (additional_cmdline_subst != NULL) {
+    avb_free_cmdline_subst_list(additional_cmdline_subst);
+  }
+  return ret;
+}
+
+void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
+  if (data->ab_suffix != NULL) {
+    avb_free(data->ab_suffix);
+  }
+  if (data->cmdline != NULL) {
+    avb_free(data->cmdline);
+  }
+  if (data->vbmeta_images != NULL) {
+    size_t n;
+    for (n = 0; n < data->num_vbmeta_images; n++) {
+      AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
+      if (vbmeta_image->partition_name != NULL) {
+        avb_free(vbmeta_image->partition_name);
+      }
+      if (vbmeta_image->vbmeta_data != NULL) {
+        avb_free(vbmeta_image->vbmeta_data);
+      }
+    }
+    avb_free(data->vbmeta_images);
+  }
+  if (data->loaded_partitions != NULL) {
+    size_t n;
+    for (n = 0; n < data->num_loaded_partitions; n++) {
+      AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
+      if (loaded_partition->partition_name != NULL) {
+        avb_free(loaded_partition->partition_name);
+      }
+      if (loaded_partition->data != NULL && !loaded_partition->preloaded) {
+        avb_free(loaded_partition->data);
+      }
+    }
+    avb_free(data->loaded_partitions);
+  }
+  avb_free(data);
+}
+
+const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
+  const char* ret = NULL;
+
+  switch (result) {
+    case AVB_SLOT_VERIFY_RESULT_OK:
+      ret = "OK";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+      ret = "ERROR_OOM";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+      ret = "ERROR_IO";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+      ret = "ERROR_VERIFICATION";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+      ret = "ERROR_ROLLBACK_INDEX";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+      ret = "ERROR_PUBLIC_KEY_REJECTED";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+      ret = "ERROR_INVALID_METADATA";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+      ret = "ERROR_UNSUPPORTED_VERSION";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+      ret = "ERROR_INVALID_ARGUMENT";
+      break;
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (ret == NULL) {
+    avb_error("Unknown AvbSlotVerifyResult value.\n");
+    ret = "(unknown)";
+  }
+
+  return ret;
+}
+
+void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+                                                  AvbDigestType digest_type,
+                                                  uint8_t* out_digest) {
+  bool ret = false;
+  size_t n;
+
+  switch (digest_type) {
+    case AVB_DIGEST_TYPE_SHA256: {
+      AvbSHA256Ctx ctx;
+      avb_sha256_init(&ctx);
+      for (n = 0; n < data->num_vbmeta_images; n++) {
+        avb_sha256_update(&ctx,
+                          data->vbmeta_images[n].vbmeta_data,
+                          data->vbmeta_images[n].vbmeta_size);
+      }
+      avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE);
+      ret = true;
+    } break;
+
+    case AVB_DIGEST_TYPE_SHA512: {
+      AvbSHA512Ctx ctx;
+      avb_sha512_init(&ctx);
+      for (n = 0; n < data->num_vbmeta_images; n++) {
+        avb_sha512_update(&ctx,
+                          data->vbmeta_images[n].vbmeta_data,
+                          data->vbmeta_images[n].vbmeta_size);
+      }
+      avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE);
+      ret = true;
+    } break;
+
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (!ret) {
+    avb_fatal("Unknown digest type");
+  }
+}
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
new file mode 100644 (file)
index 0000000..73fd70d
--- /dev/null
@@ -0,0 +1,340 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_SLOT_VERIFY_H_
+#define AVB_SLOT_VERIFY_H_
+
+#include "avb_ops.h"
+#include "avb_vbmeta_image.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Return codes used in avb_slot_verify(), see that function for
+ * documentation for each field.
+ *
+ * Use avb_slot_verify_result_to_string() to get a textual
+ * representation usable for error/debug output.
+ */
+typedef enum {
+  AVB_SLOT_VERIFY_RESULT_OK,
+  AVB_SLOT_VERIFY_RESULT_ERROR_OOM,
+  AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+  AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION,
+  AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX,
+  AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+  AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA,
+  AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION,
+  AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT
+} AvbSlotVerifyResult;
+
+/* Various error handling modes for when verification fails using a
+ * hashtree at runtime inside the HLOS.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE means that the OS
+ * will invalidate the current slot and restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART means that the OS will restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_EIO means that an EIO error will be
+ * returned to applications.
+ *
+ * AVB_HASHTREE_ERROR_MODE_LOGGING means that errors will be logged
+ * and corrupt data may be returned to applications. This mode should
+ * be used ONLY for diagnostics and debugging. It cannot be used
+ * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
+ * used.
+ */
+typedef enum {
+  AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+  AVB_HASHTREE_ERROR_MODE_RESTART,
+  AVB_HASHTREE_ERROR_MODE_EIO,
+  AVB_HASHTREE_ERROR_MODE_LOGGING
+} AvbHashtreeErrorMode;
+
+/* Flags that influence how avb_slot_verify() works.
+ *
+ * If AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is NOT set then
+ * avb_slot_verify() will bail out as soon as an error is encountered
+ * and |out_data| is set only if AVB_SLOT_VERIFY_RESULT_OK is
+ * returned.
+ *
+ * Otherwise if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set
+ * avb_slot_verify() will continue verification efforts and |out_data|
+ * is also set if AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
+ * undefined which error is returned if more than one distinct error
+ * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
+ * returned if, and only if, there are no errors. This mode is needed
+ * to boot valid but unverified slots when the device is unlocked.
+ *
+ * Also, if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set the
+ * contents loaded from |requested_partition| will be the contents of
+ * the entire partition instead of just the size specified in the hash
+ * descriptor.
+ */
+typedef enum {
+  AVB_SLOT_VERIFY_FLAGS_NONE = 0,
+  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+} AvbSlotVerifyFlags;
+
+/* Get a textual representation of |result|. */
+const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result);
+
+/* Maximum number of rollback index locations supported. */
+#define AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS 32
+
+/* AvbPartitionData contains data loaded from partitions when using
+ * avb_slot_verify(). The |partition_name| field contains the name of
+ * the partition (without A/B suffix), |data| points to the loaded
+ * data which is |data_size| bytes long. If |preloaded| is set to true,
+ * this structure dose not own |data|. The caller of |avb_slot_verify|
+ * needs to make sure that the preloaded data outlives this
+ * |AvbPartitionData| structure.
+ *
+ * Note that this is strictly less than the partition size - it's only
+ * the image stored there, not the entire partition nor any of the
+ * metadata.
+ */
+typedef struct {
+  char* partition_name;
+  uint8_t* data;
+  size_t data_size;
+  bool preloaded;
+} AvbPartitionData;
+
+/* AvbVBMetaData contains a vbmeta struct loaded from a partition when
+ * using avb_slot_verify(). The |partition_name| field contains the
+ * name of the partition (without A/B suffix), |vbmeta_data| points to
+ * the loaded data which is |vbmeta_size| bytes long.
+ *
+ * The |verify_result| field contains the result of
+ * avb_vbmeta_image_verify() on the data. This is guaranteed to be
+ * AVB_VBMETA_VERIFY_RESULT_OK for all vbmeta images if
+ * avb_slot_verify() returns AVB_SLOT_VERIFY_RESULT_OK.
+ *
+ * You can use avb_descriptor_get_all(), avb_descriptor_foreach(), and
+ * avb_vbmeta_image_header_to_host_byte_order() with this data.
+ */
+typedef struct {
+  char* partition_name;
+  uint8_t* vbmeta_data;
+  size_t vbmeta_size;
+  AvbVBMetaVerifyResult verify_result;
+} AvbVBMetaData;
+
+/* AvbSlotVerifyData contains data needed to boot a particular slot
+ * and is returned by avb_slot_verify() if partitions in a slot are
+ * successfully verified.
+ *
+ * All data pointed to by this struct - including data in each item in
+ * the |partitions| array - will be freed when the
+ * avb_slot_verify_data_free() function is called.
+ *
+ * The |ab_suffix| field is the copy of the of |ab_suffix| field
+ * passed to avb_slot_verify(). It is the A/B suffix of the slot. This
+ * value includes the leading underscore - typical values are "" (if
+ * no slots are in use), "_a" (for the first slot), and "_b" (for the
+ * second slot).
+ *
+ * The VBMeta images that were checked are available in the
+ * |vbmeta_images| field. The field |num_vbmeta_images| contains the
+ * number of elements in this array. The first element -
+ * vbmeta_images[0] - is guaranteed to be from the partition with the
+ * top-level vbmeta struct. This is usually the "vbmeta" partition in
+ * the requested slot but if there is no "vbmeta" partition it can
+ * also be the "boot" partition.
+ *
+ * The partitions loaded and verified from from the slot are
+ * accessible in the |loaded_partitions| array. The field
+ * |num_loaded_partitions| contains the number of elements in this
+ * array. The order of partitions in this array may not necessarily be
+ * the same order as in the passed-in |requested_partitions| array.
+ *
+ * Rollback indexes for the verified slot are stored in the
+ * |rollback_indexes| field. Note that avb_slot_verify() will NEVER
+ * modify stored_rollback_index[n] locations e.g. it will never use
+ * the write_rollback_index() AvbOps operation. Instead it is the job
+ * of the caller of avb_slot_verify() to do this based on e.g. A/B
+ * policy and other factors. See libavb_ab/avb_ab_flow.c for an
+ * example of how to do this.
+ *
+ * The |cmdline| field is a NUL-terminated string in UTF-8 resulting
+ * from concatenating all |AvbKernelCmdlineDescriptor| and then
+ * performing proper substitution of the variables
+ * $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and
+ * $(ANDROID_VBMETA_PARTUUID) using the
+ * get_unique_guid_for_partition() operation in |AvbOps|. Additionally
+ * $(ANDROID_VERITY_MODE) will be replaced with the proper dm-verity
+ * option depending on the value of |hashtree_error_mode|.
+ *
+ * Additionally, the |cmdline| field will have the following kernel
+ * command-line options set (unless verification is disabled, see
+ * below):
+ *
+ *   androidboot.veritymode: This is set to 'disabled' if the
+ *   AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED flag is set in top-level
+ *   vbmeta struct. Otherwise it is set to 'enforcing' if the
+ *   passed-in hashtree error mode is AVB_HASHTREE_ERROR_MODE_RESTART
+ *   or AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 'eio' if it's
+ *   set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
+ *   AVB_HASHTREE_ERROR_MODE_LOGGING.
+ *
+ *   androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only
+ *   if hashtree validation isn't disabled and the passed-in hashtree
+ *   error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE.
+ *
+ *   androidboot.vbmeta.device_state: set to "locked" or "unlocked"
+ *   depending on the result of the result of AvbOps's
+ *   read_is_unlocked() function.
+ *
+ *   androidboot.vbmeta.{hash_alg, size, digest}: Will be set to
+ *   the digest of all images in |vbmeta_images|.
+ *
+ *   androidboot.vbmeta.device: This is set to the value
+ *   PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
+ *   will end up pointing to the vbmeta partition for the verified
+ *   slot. If there is no vbmeta partition it will point to the boot
+ *   partition of the verified slot.
+ *
+ *   androidboot.vbmeta.avb_version: This is set to the decimal value
+ *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
+ *   value of AVB_VERSION_MINOR, for example "1.0" or "1.4". This
+ *   version number represents the vbmeta file format version
+ *   supported by libavb copy used in the boot loader. This is not
+ *   necessarily the same version number of the on-disk metadata for
+ *   the slot that was verified.
+ *
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to set this yourself.
+ *
+ * If the |AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED| flag is set
+ * in the top-level vbmeta struct then only the top-level vbmeta
+ * struct is verified and descriptors will not processed. The return
+ * value will be set accordingly (if this flag is set via 'avbctl
+ * disable-verification' then the return value will be
+ * |AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION|) and
+ * |AvbSlotVerifyData| is returned. Additionally all partitions in the
+ * |requested_partitions| are loaded and the |cmdline| field is set to
+ * "root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)" and the GUID for the
+ * appropriate system partition is substituted in. Note that none of
+ * the androidboot.* options mentioned above will be set.
+ *
+ * This struct may grow in the future without it being considered an
+ * ABI break.
+ */
+typedef struct {
+  char* ab_suffix;
+  AvbVBMetaData* vbmeta_images;
+  size_t num_vbmeta_images;
+  AvbPartitionData* loaded_partitions;
+  size_t num_loaded_partitions;
+  char* cmdline;
+  uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+} AvbSlotVerifyData;
+
+/* Calculates a digest of all vbmeta images in |data| using
+ * the digest indicated by |digest_type|. Stores the result
+ * in |out_digest| which must be large enough to hold a digest
+ * of the requested type.
+ */
+void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+                                                  AvbDigestType digest_type,
+                                                  uint8_t* out_digest);
+
+/* Frees a |AvbSlotVerifyData| including all data it points to. */
+void avb_slot_verify_data_free(AvbSlotVerifyData* data);
+
+/* Performs a full verification of the slot identified by |ab_suffix|
+ * and load and verify the contents of the partitions whose name is in
+ * the NULL-terminated string array |requested_partitions| (each
+ * partition must use hash verification). If not using A/B, pass an
+ * empty string (e.g. "", not NULL) for |ab_suffix|. This parameter
+ * must include the leading underscore, for example "_a" should be
+ * used to refer to the first slot.
+ *
+ * Typically the |requested_partitions| array only contains a single
+ * item for the boot partition, 'boot'.
+ *
+ * Verification includes loading and verifying data from the 'vbmeta',
+ * the requested hash partitions, and possibly other partitions (with
+ * |ab_suffix| appended), inspecting rollback indexes, and checking if
+ * the public key used to sign the data is acceptable. The functions
+ * in |ops| will be used to do this.
+ *
+ * If |out_data| is not NULL, it will be set to a newly allocated
+ * |AvbSlotVerifyData| struct containing all the data needed to
+ * actually boot the slot. This data structure should be freed with
+ * avb_slot_verify_data_free() when you are done with it. See below
+ * for when this is returned.
+ *
+ * The |flags| parameter is used to influence the semantics of
+ * avb_slot_verify() - for example the
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag can be used to
+ * ignore verification errors which is something needed in the
+ * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
+ *
+ * The |hashtree_error_mode| parameter should be set to the desired
+ * error handling mode when hashtree validation fails inside the
+ * HLOS. This value isn't used by libavb per se - it is forwarded to
+ * the HLOS through the androidboot.veritymode and
+ * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the
+ * AvbHashtreeErrorMode enumeration for details.
+ *
+ * Also note that |out_data| is never set if
+ * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+ * or AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned.
+ *
+ * AVB_SLOT_VERIFY_RESULT_OK is returned if everything is verified
+ * correctly and all public keys are accepted.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED is returned if
+ * everything is verified correctly out but one or more public keys
+ * are not accepted. This includes the case where integrity data is
+ * not signed.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_OOM is returned if unable to
+ * allocate memory.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_IO is returned if an I/O error
+ * occurred while trying to load data or get a rollback index.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION is returned if the data
+ * did not verify, e.g. the digest didn't match or signature checks
+ * failed.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned if a
+ * rollback index was less than its stored value.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned if some
+ * of the metadata is invalid or inconsistent.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if
+ * some of the metadata requires a newer version of libavb than what
+ * is in use.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT is returned if the
+ * caller passed invalid parameters, for example trying to use
+ * AVB_HASHTREE_ERROR_MODE_LOGGING without
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR.
+ */
+AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
+                                    const char* const* requested_partitions,
+                                    const char* ab_suffix,
+                                    AvbSlotVerifyFlags flags,
+                                    AvbHashtreeErrorMode hashtree_error_mode,
+                                    AvbSlotVerifyData** out_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SLOT_VERIFY_H_ */
diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h
new file mode 100644 (file)
index 0000000..f032de4
--- /dev/null
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_SYSDEPS_H_
+#define AVB_SYSDEPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Change these includes to match your platform to bring in the
+ * equivalent types available in a normal C runtime. At least things
+ * like uint8_t, uint64_t, and bool (with |false|, |true| keywords)
+ * must be present.
+ */
+#include <common.h>
+
+/* If you don't have gcc or clang, these attribute macros may need to
+ * be adjusted.
+ */
+#define AVB_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#define AVB_ATTR_PACKED __attribute__((packed))
+#define AVB_ATTR_NO_RETURN __attribute__((noreturn))
+#define AVB_ATTR_SENTINEL __attribute__((__sentinel__))
+
+/* Size in bytes used for alignment. */
+#ifdef __LP64__
+#define AVB_ALIGNMENT_SIZE 8
+#else
+#define AVB_ALIGNMENT_SIZE 4
+#endif
+
+/* Compare |n| bytes in |src1| and |src2|.
+ *
+ * Returns an integer less than, equal to, or greater than zero if the
+ * first |n| bytes of |src1| is found, respectively, to be less than,
+ * to match, or be greater than the first |n| bytes of |src2|. */
+int avb_memcmp(const void* src1,
+               const void* src2,
+               size_t n) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Compare two strings.
+ *
+ * Return an integer less than, equal to, or greater than zero if |s1|
+ * is found, respectively, to be less than, to match, or be greater
+ * than |s2|.
+ */
+int avb_strcmp(const char* s1, const char* s2);
+
+/* Copy |n| bytes from |src| to |dest|. */
+void* avb_memcpy(void* dest, const void* src, size_t n);
+
+/* Set |n| bytes starting at |s| to |c|.  Returns |dest|. */
+void* avb_memset(void* dest, const int c, size_t n);
+
+/* Prints out a message. The string passed must be a NUL-terminated
+ * UTF-8 string.
+ */
+void avb_print(const char* message);
+
+/* Prints out a vector of strings. Each argument must point to a
+ * NUL-terminated UTF-8 string and NULL should be the last argument.
+ */
+void avb_printv(const char* message, ...) AVB_ATTR_SENTINEL;
+
+/* Aborts the program or reboots the device. */
+void avb_abort(void) AVB_ATTR_NO_RETURN;
+
+/* Allocates |size| bytes. Returns NULL if no memory is available,
+ * otherwise a pointer to the allocated memory.
+ *
+ * The memory is not initialized.
+ *
+ * The pointer returned is guaranteed to be word-aligned.
+ *
+ * The memory should be freed with avb_free() when you are done with it.
+ */
+void* avb_malloc_(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Frees memory previously allocated with avb_malloc(). */
+void avb_free(void* ptr);
+
+/* Returns the lenght of |str|, excluding the terminating NUL-byte. */
+size_t avb_strlen(const char* str) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Divide the |dividend| by 10 and saves back to the pointer. Return the
+ * remainder. */
+uint32_t avb_div_by_10(uint64_t* dividend);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SYSDEPS_H_ */
diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
new file mode 100644 (file)
index 0000000..e9addc1
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "avb_sysdeps.h"
+
+int avb_memcmp(const void* src1, const void* src2, size_t n) {
+  return memcmp(src1, src2, n);
+}
+
+void* avb_memcpy(void* dest, const void* src, size_t n) {
+  return memcpy(dest, src, n);
+}
+
+void* avb_memset(void* dest, const int c, size_t n) {
+  return memset(dest, c, n);
+}
+
+int avb_strcmp(const char* s1, const char* s2) {
+  return strcmp(s1, s2);
+}
+
+size_t avb_strlen(const char* str) {
+  return strlen(str);
+}
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+  uint32_t rem = (uint32_t)(*dividend % 10);
+  *dividend /= 10;
+  return rem;
+}
+
+void avb_abort(void) {
+  hang();
+}
+
+void avb_print(const char* message) {
+  printf("%s", message);
+}
+
+void avb_printv(const char* message, ...) {
+  va_list ap;
+  const char* m;
+
+  va_start(ap, message);
+  for (m = message; m != NULL; m = va_arg(ap, const char*)) {
+    printf("%s", m);
+  }
+  va_end(ap);
+}
+
+void* avb_malloc_(size_t size) {
+  return malloc(size);
+}
+
+void avb_free(void* ptr) {
+  free(ptr);
+}
diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c
new file mode 100644 (file)
index 0000000..405d625
--- /dev/null
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_util.h"
+
+#include <stdarg.h>
+
+uint32_t avb_be32toh(uint32_t in) {
+  uint8_t* d = (uint8_t*)&in;
+  uint32_t ret;
+  ret = ((uint32_t)d[0]) << 24;
+  ret |= ((uint32_t)d[1]) << 16;
+  ret |= ((uint32_t)d[2]) << 8;
+  ret |= ((uint32_t)d[3]);
+  return ret;
+}
+
+uint64_t avb_be64toh(uint64_t in) {
+  uint8_t* d = (uint8_t*)&in;
+  uint64_t ret;
+  ret = ((uint64_t)d[0]) << 56;
+  ret |= ((uint64_t)d[1]) << 48;
+  ret |= ((uint64_t)d[2]) << 40;
+  ret |= ((uint64_t)d[3]) << 32;
+  ret |= ((uint64_t)d[4]) << 24;
+  ret |= ((uint64_t)d[5]) << 16;
+  ret |= ((uint64_t)d[6]) << 8;
+  ret |= ((uint64_t)d[7]);
+  return ret;
+}
+
+/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
+uint32_t avb_htobe32(uint32_t in) {
+  union {
+    uint32_t word;
+    uint8_t bytes[4];
+  } ret;
+  ret.bytes[0] = (in >> 24) & 0xff;
+  ret.bytes[1] = (in >> 16) & 0xff;
+  ret.bytes[2] = (in >> 8) & 0xff;
+  ret.bytes[3] = in & 0xff;
+  return ret.word;
+}
+
+/* Converts a 64-bit unsigned integer from host to big-endian byte order. */
+uint64_t avb_htobe64(uint64_t in) {
+  union {
+    uint64_t word;
+    uint8_t bytes[8];
+  } ret;
+  ret.bytes[0] = (in >> 56) & 0xff;
+  ret.bytes[1] = (in >> 48) & 0xff;
+  ret.bytes[2] = (in >> 40) & 0xff;
+  ret.bytes[3] = (in >> 32) & 0xff;
+  ret.bytes[4] = (in >> 24) & 0xff;
+  ret.bytes[5] = (in >> 16) & 0xff;
+  ret.bytes[6] = (in >> 8) & 0xff;
+  ret.bytes[7] = in & 0xff;
+  return ret.word;
+}
+
+int avb_safe_memcmp(const void* s1, const void* s2, size_t n) {
+  const unsigned char* us1 = s1;
+  const unsigned char* us2 = s2;
+  int result = 0;
+
+  if (0 == n) {
+    return 0;
+  }
+
+  /*
+   * Code snippet without data-dependent branch due to Nate Lawson
+   * (nate@root.org) of Root Labs.
+   */
+  while (n--) {
+    result |= *us1++ ^ *us2++;
+  }
+
+  return result != 0;
+}
+
+bool avb_safe_add_to(uint64_t* value, uint64_t value_to_add) {
+  uint64_t original_value;
+
+  avb_assert(value != NULL);
+
+  original_value = *value;
+
+  *value += value_to_add;
+  if (*value < original_value) {
+    avb_error("Overflow when adding values.\n");
+    return false;
+  }
+
+  return true;
+}
+
+bool avb_safe_add(uint64_t* out_result, uint64_t a, uint64_t b) {
+  uint64_t dummy;
+  if (out_result == NULL) {
+    out_result = &dummy;
+  }
+  *out_result = a;
+  return avb_safe_add_to(out_result, b);
+}
+
+bool avb_validate_utf8(const uint8_t* data, size_t num_bytes) {
+  size_t n;
+  unsigned int num_cc;
+
+  for (n = 0, num_cc = 0; n < num_bytes; n++) {
+    uint8_t c = data[n];
+
+    if (num_cc > 0) {
+      if ((c & (0x80 | 0x40)) == 0x80) {
+        /* 10xx xxxx */
+      } else {
+        goto fail;
+      }
+      num_cc--;
+    } else {
+      if (c < 0x80) {
+        num_cc = 0;
+      } else if ((c & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40)) {
+        /* 110x xxxx */
+        num_cc = 1;
+      } else if ((c & (0x80 | 0x40 | 0x20 | 0x10)) == (0x80 | 0x40 | 0x20)) {
+        /* 1110 xxxx */
+        num_cc = 2;
+      } else if ((c & (0x80 | 0x40 | 0x20 | 0x10 | 0x08)) ==
+                 (0x80 | 0x40 | 0x20 | 0x10)) {
+        /* 1111 0xxx */
+        num_cc = 3;
+      } else {
+        goto fail;
+      }
+    }
+  }
+
+  if (num_cc != 0) {
+    goto fail;
+  }
+
+  return true;
+
+fail:
+  return false;
+}
+
+bool avb_str_concat(char* buf,
+                    size_t buf_size,
+                    const char* str1,
+                    size_t str1_len,
+                    const char* str2,
+                    size_t str2_len) {
+  uint64_t combined_len;
+
+  if (!avb_safe_add(&combined_len, str1_len, str2_len)) {
+    avb_error("Overflow when adding string sizes.\n");
+    return false;
+  }
+
+  if (combined_len > buf_size - 1) {
+    avb_error("Insufficient buffer space.\n");
+    return false;
+  }
+
+  avb_memcpy(buf, str1, str1_len);
+  avb_memcpy(buf + str1_len, str2, str2_len);
+  buf[combined_len] = '\0';
+
+  return true;
+}
+
+void* avb_malloc(size_t size) {
+  void* ret = avb_malloc_(size);
+  if (ret == NULL) {
+    avb_error("Failed to allocate memory.\n");
+    return NULL;
+  }
+  return ret;
+}
+
+void* avb_calloc(size_t size) {
+  void* ret = avb_malloc(size);
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  avb_memset(ret, '\0', size);
+  return ret;
+}
+
+char* avb_strdup(const char* str) {
+  size_t len = avb_strlen(str);
+  char* ret = avb_malloc(len + 1);
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  avb_memcpy(ret, str, len);
+  ret[len] = '\0';
+
+  return ret;
+}
+
+const char* avb_strstr(const char* haystack, const char* needle) {
+  size_t n, m;
+
+  /* Look through |haystack| and check if the first character of
+   * |needle| matches. If so, check the rest of |needle|.
+   */
+  for (n = 0; haystack[n] != '\0'; n++) {
+    if (haystack[n] != needle[0]) {
+      continue;
+    }
+
+    for (m = 1;; m++) {
+      if (needle[m] == '\0') {
+        return haystack + n;
+      }
+
+      if (haystack[n + m] != needle[m]) {
+        break;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+const char* avb_strv_find_str(const char* const* strings,
+                              const char* str,
+                              size_t str_size) {
+  size_t n;
+  for (n = 0; strings[n] != NULL; n++) {
+    if (avb_strlen(strings[n]) == str_size &&
+        avb_memcmp(strings[n], str, str_size) == 0) {
+      return strings[n];
+    }
+  }
+  return NULL;
+}
+
+char* avb_replace(const char* str, const char* search, const char* replace) {
+  char* ret = NULL;
+  size_t ret_len = 0;
+  size_t search_len, replace_len;
+  const char* str_after_last_replace;
+
+  search_len = avb_strlen(search);
+  replace_len = avb_strlen(replace);
+
+  str_after_last_replace = str;
+  while (*str != '\0') {
+    const char* s;
+    size_t num_before;
+    size_t num_new;
+
+    s = avb_strstr(str, search);
+    if (s == NULL) {
+      break;
+    }
+
+    num_before = s - str;
+
+    if (ret == NULL) {
+      num_new = num_before + replace_len + 1;
+      ret = avb_malloc(num_new);
+      if (ret == NULL) {
+        goto out;
+      }
+      avb_memcpy(ret, str, num_before);
+      avb_memcpy(ret + num_before, replace, replace_len);
+      ret[num_new - 1] = '\0';
+      ret_len = num_new - 1;
+    } else {
+      char* new_str;
+      num_new = ret_len + num_before + replace_len + 1;
+      new_str = avb_malloc(num_new);
+      if (new_str == NULL) {
+        goto out;
+      }
+      avb_memcpy(new_str, ret, ret_len);
+      avb_memcpy(new_str + ret_len, str, num_before);
+      avb_memcpy(new_str + ret_len + num_before, replace, replace_len);
+      new_str[num_new - 1] = '\0';
+      avb_free(ret);
+      ret = new_str;
+      ret_len = num_new - 1;
+    }
+
+    str = s + search_len;
+    str_after_last_replace = str;
+  }
+
+  if (ret == NULL) {
+    ret = avb_strdup(str_after_last_replace);
+    if (ret == NULL) {
+      goto out;
+    }
+  } else {
+    size_t num_remaining = avb_strlen(str_after_last_replace);
+    size_t num_new = ret_len + num_remaining + 1;
+    char* new_str = avb_malloc(num_new);
+    if (new_str == NULL) {
+      goto out;
+    }
+    avb_memcpy(new_str, ret, ret_len);
+    avb_memcpy(new_str + ret_len, str_after_last_replace, num_remaining);
+    new_str[num_new - 1] = '\0';
+    avb_free(ret);
+    ret = new_str;
+    ret_len = num_new - 1;
+  }
+
+out:
+  return ret;
+}
+
+/* We only support a limited amount of strings in avb_strdupv(). */
+#define AVB_STRDUPV_MAX_NUM_STRINGS 32
+
+char* avb_strdupv(const char* str, ...) {
+  va_list ap;
+  const char* strings[AVB_STRDUPV_MAX_NUM_STRINGS];
+  size_t lengths[AVB_STRDUPV_MAX_NUM_STRINGS];
+  size_t num_strings, n;
+  uint64_t total_length;
+  char *ret = NULL, *dest;
+
+  num_strings = 0;
+  total_length = 0;
+  va_start(ap, str);
+  do {
+    size_t str_len = avb_strlen(str);
+    strings[num_strings] = str;
+    lengths[num_strings] = str_len;
+    if (!avb_safe_add_to(&total_length, str_len)) {
+      avb_fatal("Overflow while determining total length.\n");
+      break;
+    }
+    num_strings++;
+    if (num_strings == AVB_STRDUPV_MAX_NUM_STRINGS) {
+      avb_fatal("Too many strings passed.\n");
+      break;
+    }
+    str = va_arg(ap, const char*);
+  } while (str != NULL);
+  va_end(ap);
+
+  ret = avb_malloc(total_length + 1);
+  if (ret == NULL) {
+    goto out;
+  }
+
+  dest = ret;
+  for (n = 0; n < num_strings; n++) {
+    avb_memcpy(dest, strings[n], lengths[n]);
+    dest += lengths[n];
+  }
+  *dest = '\0';
+  avb_assert(dest == ret + total_length);
+
+out:
+  return ret;
+}
+
+const char* avb_basename(const char* str) {
+  int64_t n;
+  size_t len;
+
+  len = avb_strlen(str);
+  if (len >= 2) {
+    for (n = len - 2; n >= 0; n--) {
+      if (str[n] == '/') {
+        return str + n + 1;
+      }
+    }
+  }
+  return str;
+}
+
+void avb_uppercase(char* str) {
+  size_t i;
+  for (i = 0; str[i] != '\0'; ++i) {
+    if (str[i] <= 0x7A && str[i] >= 0x61) {
+      str[i] -= 0x20;
+    }
+  }
+}
+
+char* avb_bin2hex(const uint8_t* data, size_t data_len) {
+  const char hex_digits[17] = "0123456789abcdef";
+  char* hex_data;
+  size_t n;
+
+  hex_data = avb_malloc(data_len * 2 + 1);
+  if (hex_data == NULL) {
+    return NULL;
+  }
+
+  for (n = 0; n < data_len; n++) {
+    hex_data[n * 2] = hex_digits[data[n] >> 4];
+    hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
+  }
+  hex_data[n * 2] = '\0';
+  return hex_data;
+}
diff --git a/lib/libavb/avb_util.h b/lib/libavb/avb_util.h
new file mode 100644 (file)
index 0000000..26dc6b0
--- /dev/null
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_UTIL_H_
+#define AVB_UTIL_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AVB_STRINGIFY(x) #x
+#define AVB_TO_STRING(x) AVB_STRINGIFY(x)
+
+#ifdef AVB_ENABLE_DEBUG
+/* Aborts the program if |expr| is false.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_assert(expr)                     \
+  do {                                       \
+    if (!(expr)) {                           \
+      avb_fatal("assert fail: " #expr "\n"); \
+    }                                        \
+  } while (0)
+#else
+#define avb_assert(expr)
+#endif
+
+/* Aborts the program if reached.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#ifdef AVB_ENABLE_DEBUG
+#define avb_assert_not_reached()         \
+  do {                                   \
+    avb_fatal("assert_not_reached()\n"); \
+  } while (0)
+#else
+#define avb_assert_not_reached()
+#endif
+
+/* Aborts the program if |addr| is not word-aligned.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_assert_aligned(addr) \
+  avb_assert((((uintptr_t)addr) & (AVB_ALIGNMENT_SIZE - 1)) == 0)
+
+#ifdef AVB_ENABLE_DEBUG
+/* Print functions, used for diagnostics.
+ *
+ * These have no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_debug(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": DEBUG: ",             \
+               message,                 \
+               NULL);                   \
+  } while (0)
+#define avb_debugv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": DEBUG: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+  } while (0)
+#else
+#define avb_debug(message)
+#define avb_debugv(message, ...)
+#endif
+
+/* Prints out a message. This is typically used if a runtime-error
+ * occurs.
+ */
+#define avb_error(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": ERROR: ",             \
+               message,                 \
+               NULL);                   \
+  } while (0)
+#define avb_errorv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": ERROR: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+  } while (0)
+
+/* Prints out a message and calls avb_abort().
+ */
+#define avb_fatal(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": FATAL: ",             \
+               message,                 \
+               NULL);                   \
+    avb_abort();                        \
+  } while (0)
+#define avb_fatalv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": FATAL: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+    avb_abort();                        \
+  } while (0)
+
+/* Converts a 32-bit unsigned integer from big-endian to host byte order. */
+uint32_t avb_be32toh(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 64-bit unsigned integer from big-endian to host byte order. */
+uint64_t avb_be64toh(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
+uint32_t avb_htobe32(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 64-bit unsigned integer from host to big-endian byte order. */
+uint64_t avb_htobe64(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Compare |n| bytes starting at |s1| with |s2| and return 0 if they
+ * match, 1 if they don't.  Returns 0 if |n|==0, since no bytes
+ * mismatched.
+ *
+ * Time taken to perform the comparison is only dependent on |n| and
+ * not on the relationship of the match between |s1| and |s2|.
+ *
+ * Note that unlike avb_memcmp(), this only indicates inequality, not
+ * whether |s1| is less than or greater than |s2|.
+ */
+int avb_safe_memcmp(const void* s1,
+                    const void* s2,
+                    size_t n) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Adds |value_to_add| to |value| with overflow protection.
+ *
+ * Returns false if the addition overflows, true otherwise. In either
+ * case, |value| is always modified.
+ */
+bool avb_safe_add_to(uint64_t* value,
+                     uint64_t value_to_add) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Adds |a| and |b| with overflow protection, returning the value in
+ * |out_result|.
+ *
+ * It's permissible to pass NULL for |out_result| if you just want to
+ * check that the addition would not overflow.
+ *
+ * Returns false if the addition overflows, true otherwise.
+ */
+bool avb_safe_add(uint64_t* out_result,
+                  uint64_t a,
+                  uint64_t b) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Checks if |num_bytes| data at |data| is a valid UTF-8
+ * string. Returns true if valid UTF-8, false otherwise.
+ */
+bool avb_validate_utf8(const uint8_t* data,
+                       size_t num_bytes) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Concatenates |str1| (of |str1_len| bytes) and |str2| (of |str2_len|
+ * bytes) and puts the result in |buf| which holds |buf_size|
+ * bytes. The result is also guaranteed to be NUL terminated. Fail if
+ * there is not enough room in |buf| for the resulting string plus
+ * terminating NUL byte.
+ *
+ * Returns true if the operation succeeds, false otherwise.
+ */
+bool avb_str_concat(char* buf,
+                    size_t buf_size,
+                    const char* str1,
+                    size_t str1_len,
+                    const char* str2,
+                    size_t str2_len);
+
+/* Like avb_malloc_() but prints a error using avb_error() if memory
+ * allocation fails.
+ */
+void* avb_malloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Like avb_malloc() but sets the memory with zeroes. */
+void* avb_calloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Duplicates a NUL-terminated string. Returns NULL on OOM. */
+char* avb_strdup(const char* str) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Duplicates a NULL-terminated array of NUL-terminated strings by
+ * concatenating them. The returned string will be
+ * NUL-terminated. Returns NULL on OOM.
+ */
+char* avb_strdupv(const char* str,
+                  ...) AVB_ATTR_WARN_UNUSED_RESULT AVB_ATTR_SENTINEL;
+
+/* Finds the first occurrence of |needle| in the string |haystack|
+ * where both strings are NUL-terminated strings. The terminating NUL
+ * bytes are not compared.
+ *
+ * Returns NULL if not found, otherwise points into |haystack| for the
+ * first occurrence of |needle|.
+ */
+const char* avb_strstr(const char* haystack,
+                       const char* needle) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Finds the first occurrence of |str| in the NULL-terminated string
+ * array |strings|. Each element in |strings| must be
+ * NUL-terminated. The string given by |str| need not be
+ * NUL-terminated but its size must be given in |str_size|.
+ *
+ * Returns NULL if not found, otherwise points into |strings| for the
+ * first occurrence of |str|.
+ */
+const char* avb_strv_find_str(const char* const* strings,
+                              const char* str,
+                              size_t str_size);
+
+/* Replaces all occurrences of |search| with |replace| in |str|.
+ *
+ * Returns a newly allocated string or NULL if out of memory.
+ */
+char* avb_replace(const char* str,
+                  const char* search,
+                  const char* replace) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Calculates the CRC-32 for data in |buf| of size |buf_size|. */
+uint32_t avb_crc32(const uint8_t* buf, size_t buf_size);
+
+/* Returns the basename of |str|. This is defined as the last path
+ * component, assuming the normal POSIX separator '/'. If there are no
+ * separators, returns |str|.
+ */
+const char* avb_basename(const char* str);
+
+/* Converts any ascii lowercase characters in |str| to uppercase in-place.
+ * |str| must be NUL-terminated and valid UTF-8.
+ */
+void avb_uppercase(char* str);
+
+/* Converts |data_len| bytes of |data| to hex and returns the result. Returns
+ * NULL on OOM. Caller must free the returned string with avb_free.
+ */
+char* avb_bin2hex(const uint8_t* data, size_t data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_UTIL_H_ */
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
new file mode 100644 (file)
index 0000000..a7e2322
--- /dev/null
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include "avb_vbmeta_image.h"
+#include "avb_crypto.h"
+#include "avb_rsa.h"
+#include "avb_sha.h"
+#include "avb_util.h"
+#include "avb_version.h"
+
+AvbVBMetaVerifyResult avb_vbmeta_image_verify(
+    const uint8_t* data,
+    size_t length,
+    const uint8_t** out_public_key_data,
+    size_t* out_public_key_length) {
+  AvbVBMetaVerifyResult ret;
+  AvbVBMetaImageHeader h;
+  uint8_t* computed_hash;
+  const AvbAlgorithmData* algorithm;
+  AvbSHA256Ctx sha256_ctx;
+  AvbSHA512Ctx sha512_ctx;
+  const uint8_t* header_block;
+  const uint8_t* authentication_block;
+  const uint8_t* auxiliary_block;
+  int verification_result;
+
+  ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER;
+
+  if (out_public_key_data != NULL) {
+    *out_public_key_data = NULL;
+  }
+  if (out_public_key_length != NULL) {
+    *out_public_key_length = 0;
+  }
+
+  /* Ensure magic is correct. */
+  if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    goto out;
+  }
+
+  /* Before we byteswap, ensure length is long enough. */
+  if (length < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+  avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
+                                             &h);
+
+  /* Ensure we don't attempt to access any fields if we do not meet
+   * the specified minimum version of libavb.
+   */
+  if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||
+      (h.required_libavb_version_minor > AVB_VERSION_MINOR)) {
+    avb_error("Mismatch between image version and libavb version.\n");
+    ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;
+    goto out;
+  }
+
+  /* Ensure |release_string| ends with a NUL byte. */
+  if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') {
+    avb_error("Release string does not end with a NUL byte.\n");
+    goto out;
+  }
+
+  /* Ensure inner block sizes are multiple of 64. */
+  if ((h.authentication_data_block_size & 0x3f) != 0 ||
+      (h.auxiliary_data_block_size & 0x3f) != 0) {
+    avb_error("Block size is not a multiple of 64.\n");
+    goto out;
+  }
+
+  /* Ensure block sizes all add up to at most |length|. */
+  uint64_t block_total = sizeof(AvbVBMetaImageHeader);
+  if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) ||
+      !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) {
+    avb_error("Overflow while computing size of boot image.\n");
+    goto out;
+  }
+  if (block_total > length) {
+    avb_error("Block sizes add up to more than given length.\n");
+    goto out;
+  }
+
+  uintptr_t data_ptr = (uintptr_t)data;
+  /* Ensure passed in memory doesn't wrap. */
+  if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) {
+    avb_error("Boot image location and length mismatch.\n");
+    goto out;
+  }
+
+  /* Ensure hash and signature are entirely in the Authentication data block. */
+  uint64_t hash_end;
+  if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||
+      hash_end > h.authentication_data_block_size) {
+    avb_error("Hash is not entirely in its block.\n");
+    goto out;
+  }
+  uint64_t signature_end;
+  if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||
+      signature_end > h.authentication_data_block_size) {
+    avb_error("Signature is not entirely in its block.\n");
+    goto out;
+  }
+
+  /* Ensure public key is entirely in the Auxiliary data block. */
+  uint64_t pubkey_end;
+  if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||
+      pubkey_end > h.auxiliary_data_block_size) {
+    avb_error("Public key is not entirely in its block.\n");
+    goto out;
+  }
+
+  /* Ensure public key metadata (if set) is entirely in the Auxiliary
+   * data block. */
+  if (h.public_key_metadata_size > 0) {
+    uint64_t pubkey_md_end;
+    if (!avb_safe_add(&pubkey_md_end,
+                      h.public_key_metadata_offset,
+                      h.public_key_metadata_size) ||
+        pubkey_md_end > h.auxiliary_data_block_size) {
+      avb_error("Public key metadata is not entirely in its block.\n");
+      goto out;
+    }
+  }
+
+  /* Bail early if there's no hash or signature. */
+  if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {
+    ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;
+    goto out;
+  }
+
+  /* Ensure algorithm field is supported. */
+  algorithm = avb_get_algorithm_data(h.algorithm_type);
+  if (!algorithm) {
+    avb_error("Invalid or unknown algorithm.\n");
+    goto out;
+  }
+
+  /* Bail if the embedded hash size doesn't match the chosen algorithm. */
+  if (h.hash_size != algorithm->hash_len) {
+    avb_error("Embedded hash has wrong size.\n");
+    goto out;
+  }
+
+  /* No overflow checks needed from here-on after since all block
+   * sizes and offsets have been verified above.
+   */
+
+  header_block = data;
+  authentication_block = header_block + sizeof(AvbVBMetaImageHeader);
+  auxiliary_block = authentication_block + h.authentication_data_block_size;
+
+  switch (h.algorithm_type) {
+    /* Explicit fall-through: */
+    case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA8192:
+      avb_sha256_init(&sha256_ctx);
+      avb_sha256_update(
+          &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
+      avb_sha256_update(
+          &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
+      computed_hash = avb_sha256_final(&sha256_ctx);
+      break;
+    /* Explicit fall-through: */
+    case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA8192:
+      avb_sha512_init(&sha512_ctx);
+      avb_sha512_update(
+          &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader));
+      avb_sha512_update(
+          &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size);
+      computed_hash = avb_sha512_final(&sha512_ctx);
+      break;
+    default:
+      avb_error("Unknown algorithm.\n");
+      goto out;
+  }
+
+  if (avb_safe_memcmp(authentication_block + h.hash_offset,
+                      computed_hash,
+                      h.hash_size) != 0) {
+    avb_error("Hash does not match!\n");
+    ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
+    goto out;
+  }
+
+  verification_result =
+      avb_rsa_verify(auxiliary_block + h.public_key_offset,
+                     h.public_key_size,
+                     authentication_block + h.signature_offset,
+                     h.signature_size,
+                     authentication_block + h.hash_offset,
+                     h.hash_size,
+                     algorithm->padding,
+                     algorithm->padding_len);
+
+  if (verification_result == 0) {
+    ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH;
+    goto out;
+  }
+
+  if (h.public_key_size > 0) {
+    if (out_public_key_data != NULL) {
+      *out_public_key_data = auxiliary_block + h.public_key_offset;
+    }
+    if (out_public_key_length != NULL) {
+      *out_public_key_length = h.public_key_size;
+    }
+  }
+
+  ret = AVB_VBMETA_VERIFY_RESULT_OK;
+
+out:
+  return ret;
+}
+
+void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
+                                                AvbVBMetaImageHeader* dest) {
+  avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader));
+
+  dest->required_libavb_version_major =
+      avb_be32toh(dest->required_libavb_version_major);
+  dest->required_libavb_version_minor =
+      avb_be32toh(dest->required_libavb_version_minor);
+
+  dest->authentication_data_block_size =
+      avb_be64toh(dest->authentication_data_block_size);
+  dest->auxiliary_data_block_size =
+      avb_be64toh(dest->auxiliary_data_block_size);
+
+  dest->algorithm_type = avb_be32toh(dest->algorithm_type);
+
+  dest->hash_offset = avb_be64toh(dest->hash_offset);
+  dest->hash_size = avb_be64toh(dest->hash_size);
+
+  dest->signature_offset = avb_be64toh(dest->signature_offset);
+  dest->signature_size = avb_be64toh(dest->signature_size);
+
+  dest->public_key_offset = avb_be64toh(dest->public_key_offset);
+  dest->public_key_size = avb_be64toh(dest->public_key_size);
+
+  dest->public_key_metadata_offset =
+      avb_be64toh(dest->public_key_metadata_offset);
+  dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size);
+
+  dest->descriptors_offset = avb_be64toh(dest->descriptors_offset);
+  dest->descriptors_size = avb_be64toh(dest->descriptors_size);
+
+  dest->rollback_index = avb_be64toh(dest->rollback_index);
+  dest->flags = avb_be32toh(dest->flags);
+}
+
+const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
+  const char* ret = NULL;
+
+  switch (result) {
+    case AVB_VBMETA_VERIFY_RESULT_OK:
+      ret = "OK";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
+      ret = "OK_NOT_SIGNED";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
+      ret = "INVALID_VBMETA_HEADER";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
+      ret = "UNSUPPORTED_VERSION";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
+      ret = "HASH_MISMATCH";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
+      ret = "SIGNATURE_MISMATCH";
+      break;
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (ret == NULL) {
+    avb_error("Unknown AvbVBMetaVerifyResult value.\n");
+    ret = "(unknown)";
+  }
+
+  return ret;
+}
diff --git a/lib/libavb/avb_vbmeta_image.h b/lib/libavb/avb_vbmeta_image.h
new file mode 100644 (file)
index 0000000..24f8519
--- /dev/null
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_VBMETA_IMAGE_H_
+#define AVB_VBMETA_IMAGE_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_descriptor.h"
+
+/* Size of the vbmeta image header. */
+#define AVB_VBMETA_IMAGE_HEADER_SIZE 256
+
+/* Magic for the vbmeta image header. */
+#define AVB_MAGIC "AVB0"
+#define AVB_MAGIC_LEN 4
+
+/* Maximum size of the release string including the terminating NUL byte. */
+#define AVB_RELEASE_STRING_SIZE 48
+
+/* Flags for the vbmeta image.
+ *
+ * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set,
+ * hashtree image verification will be disabled.
+ *
+ * AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set,
+ * verification will be disabled and descriptors will not be parsed.
+ */
+typedef enum {
+  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0),
+  AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1)
+} AvbVBMetaImageFlags;
+
+/* Binary format for header of the vbmeta image.
+ *
+ * The vbmeta image consists of three blocks:
+ *
+ *  +-----------------------------------------+
+ *  | Header data - fixed size                |
+ *  +-----------------------------------------+
+ *  | Authentication data - variable size     |
+ *  +-----------------------------------------+
+ *  | Auxiliary data - variable size          |
+ *  +-----------------------------------------+
+ *
+ * The "Header data" block is described by this struct and is always
+ * |AVB_VBMETA_IMAGE_HEADER_SIZE| bytes long.
+ *
+ * The "Authentication data" block is |authentication_data_block_size|
+ * bytes long and contains the hash and signature used to authenticate
+ * the vbmeta image. The type of the hash and signature is defined by
+ * the |algorithm_type| field.
+ *
+ * The "Auxiliary data" is |auxiliary_data_block_size| bytes long and
+ * contains the auxiliary data including the public key used to make
+ * the signature and descriptors.
+ *
+ * The public key is at offset |public_key_offset| with size
+ * |public_key_size| in this block. The size of the public key data is
+ * defined by the |algorithm_type| field. The format of the public key
+ * data is described in the |AvbRSAPublicKeyHeader| struct.
+ *
+ * The descriptors starts at |descriptors_offset| from the beginning
+ * of the "Auxiliary Data" block and take up |descriptors_size|
+ * bytes. Each descriptor is stored as a |AvbDescriptor| with tag and
+ * number of bytes following. The number of descriptors can be
+ * determined by walking this data until |descriptors_size| is
+ * exhausted.
+ *
+ * The size of each of the "Authentication data" and "Auxiliary data"
+ * blocks must be divisible by 64. This is to ensure proper alignment.
+ *
+ * Descriptors are free-form blocks stored in a part of the vbmeta
+ * image subject to the same integrity checks as the rest of the
+ * image. See the documentation for |AvbDescriptor| for well-known
+ * descriptors. See avb_descriptor_foreach() for a convenience
+ * function to iterate over descriptors.
+ *
+ * This struct is versioned, see the |required_libavb_version_major|
+ * and |required_libavb_version_minor| fields. This represents the
+ * minimum version of libavb required to verify the header and depends
+ * on the features (e.g. algorithms, descriptors) used. Note that this
+ * may be 1.0 even if generated by an avbtool from 1.4 but where no
+ * features introduced after 1.0 has been used. See the "Versioning
+ * and compatibility" section in the README.md file for more details.
+ *
+ * All fields are stored in network byte order when serialized. To
+ * generate a copy with fields swapped to native byte order, use the
+ * function avb_vbmeta_image_header_to_host_byte_order().
+ *
+ * Before reading and/or using any of this data, you MUST verify it
+ * using avb_vbmeta_image_verify() and reject it unless it's signed by
+ * a known good public key.
+ */
+typedef struct AvbVBMetaImageHeader {
+  /*   0: Four bytes equal to "AVB0" (AVB_MAGIC). */
+  uint8_t magic[AVB_MAGIC_LEN];
+
+  /*   4: The major version of libavb required for this header. */
+  uint32_t required_libavb_version_major;
+  /*   8: The minor version of libavb required for this header. */
+  uint32_t required_libavb_version_minor;
+
+  /*  12: The size of the signature block. */
+  uint64_t authentication_data_block_size;
+  /*  20: The size of the auxiliary data block. */
+  uint64_t auxiliary_data_block_size;
+
+  /*  28: The verification algorithm used, see |AvbAlgorithmType| enum. */
+  uint32_t algorithm_type;
+
+  /*  32: Offset into the "Authentication data" block of hash data. */
+  uint64_t hash_offset;
+  /*  40: Length of the hash data. */
+  uint64_t hash_size;
+
+  /*  48: Offset into the "Authentication data" block of signature data. */
+  uint64_t signature_offset;
+  /*  56: Length of the signature data. */
+  uint64_t signature_size;
+
+  /*  64: Offset into the "Auxiliary data" block of public key data. */
+  uint64_t public_key_offset;
+  /*  72: Length of the public key data. */
+  uint64_t public_key_size;
+
+  /*  80: Offset into the "Auxiliary data" block of public key metadata. */
+  uint64_t public_key_metadata_offset;
+  /*  88: Length of the public key metadata. Must be set to zero if there
+   *  is no public key metadata.
+   */
+  uint64_t public_key_metadata_size;
+
+  /*  96: Offset into the "Auxiliary data" block of descriptor data. */
+  uint64_t descriptors_offset;
+  /* 104: Length of descriptor data. */
+  uint64_t descriptors_size;
+
+  /* 112: The rollback index which can be used to prevent rollback to
+   *  older versions.
+   */
+  uint64_t rollback_index;
+
+  /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
+   * set to zero if the vbmeta image is not a top-level image.
+   */
+  uint32_t flags;
+
+  /* 124: Reserved to ensure |release_string| start on a 16-byte
+   * boundary. Must be set to zeroes.
+   */
+  uint8_t reserved0[4];
+
+  /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
+   * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
+   * terminated. Applications must not make assumptions about how this
+   * string is formatted.
+   */
+  uint8_t release_string[AVB_RELEASE_STRING_SIZE];
+
+  /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
+   * bytes. This must be set to zeroes.
+   */
+  uint8_t reserved[80];
+} AVB_ATTR_PACKED AvbVBMetaImageHeader;
+
+/* Copies |src| to |dest|, byte-swapping fields in the process.
+ *
+ * Make sure you've verified |src| using avb_vbmeta_image_verify()
+ * before accessing the data and/or using this function.
+ */
+void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
+                                                AvbVBMetaImageHeader* dest);
+
+/* Return codes used in avb_vbmeta_image_verify().
+ *
+ * AVB_VBMETA_VERIFY_RESULT_OK is returned if the vbmeta image header
+ * is valid, the hash is correct and the signature is correct. Keep in
+ * mind that you still need to check that you know the public key used
+ * to sign the image, see avb_vbmeta_image_verify() for details.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED is returned if the vbmeta
+ * image header is valid but there is no signature or hash.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER is returned if the
+ * header of the vbmeta image is invalid, for example, invalid magic
+ * or inconsistent data.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION is returned if a) the
+ * vbmeta image requires a minimum version of libavb which exceeds the
+ * version of libavb used; or b) the vbmeta image major version
+ * differs from the major version of libavb in use.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH is returned if the hash
+ * stored in the "Authentication data" block does not match the
+ * calculated hash.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH is returned if the
+ * signature stored in the "Authentication data" block is invalid or
+ * doesn't match the public key stored in the vbmeta image.
+ */
+typedef enum {
+  AVB_VBMETA_VERIFY_RESULT_OK,
+  AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED,
+  AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER,
+  AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION,
+  AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH,
+  AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH,
+} AvbVBMetaVerifyResult;
+
+/* Get a textual representation of |result|. */
+const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result);
+
+/* Checks that vbmeta image at |data| of size |length| is a valid
+ * vbmeta image. The complete contents of the vbmeta image must be
+ * passed in. It's fine if |length| is bigger than the actual image,
+ * typically callers of this function will load the entire contents of
+ * the 'vbmeta_a' or 'vbmeta_b' partition and pass in its length (for
+ * example, 1 MiB).
+ *
+ * See the |AvbVBMetaImageHeader| struct for information about the
+ * three blocks (header, authentication, auxiliary) that make up a
+ * vbmeta image.
+ *
+ * If the function returns |AVB_VBMETA_VERIFY_RESULT_OK| and
+ * |out_public_key_data| is non-NULL, it will be set to point inside
+ * |data| for where the serialized public key data is stored and
+ * |out_public_key_length|, if non-NULL, will be set to the length of
+ * the public key data. If there is no public key in the metadata then
+ * |out_public_key_data| is set to NULL.
+ *
+ * See the |AvbVBMetaVerifyResult| enum for possible return values.
+ *
+ * VERY IMPORTANT:
+ *
+ *   1. Even if |AVB_VBMETA_VERIFY_RESULT_OK| is returned, you still
+ *      need to check that the public key embedded in the image
+ *      matches a known key! You can use 'avbtool extract_public_key'
+ *      to extract the key (at build time, then store it along your
+ *      code) and compare it to what is returned in
+ *      |out_public_key_data|.
+ *
+ *   2. You need to check the |rollback_index| field against a stored
+ *      value in NVRAM and reject the vbmeta image if the value in
+ *      NVRAM is bigger than |rollback_index|. You must also update
+ *      the value stored in NVRAM to the smallest value of
+ *      |rollback_index| field from boot images in all bootable and
+ *      authentic slots marked as GOOD.
+ *
+ * This is a low-level function to only verify the vbmeta data - you
+ * are likely looking for avb_slot_verify() instead for verifying
+ * integrity data for a whole set of partitions.
+ */
+AvbVBMetaVerifyResult avb_vbmeta_image_verify(
+    const uint8_t* data,
+    size_t length,
+    const uint8_t** out_public_key_data,
+    size_t* out_public_key_length) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_VBMETA_IMAGE_H_ */
diff --git a/lib/libavb/avb_version.c b/lib/libavb/avb_version.c
new file mode 100644 (file)
index 0000000..1f20722
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+
+#include "avb_version.h"
+
+#define AVB_QUOTE(str) #str
+#define AVB_EXPAND_AND_QUOTE(str) AVB_QUOTE(str)
+
+/* Keep in sync with get_release_string() in avbtool. */
+const char* avb_version_string(void) {
+  return AVB_EXPAND_AND_QUOTE(AVB_VERSION_MAJOR) "." AVB_EXPAND_AND_QUOTE(
+      AVB_VERSION_MINOR) "." AVB_EXPAND_AND_QUOTE(AVB_VERSION_SUB);
+}
diff --git a/lib/libavb/avb_version.h b/lib/libavb/avb_version.h
new file mode 100644 (file)
index 0000000..57c6ece
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_VERSION_H_
+#define AVB_VERSION_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The version number of AVB - keep in sync with avbtool. */
+#define AVB_VERSION_MAJOR 1
+#define AVB_VERSION_MINOR 1
+#define AVB_VERSION_SUB 0
+
+/* Returns a NUL-terminated string for the libavb version in use.  The
+ * returned string usually looks like "%d.%d.%d". Applications must
+ * not make assumptions about the content of this string.
+ *
+ * Boot loaders should display this string in debug/diagnostics output
+ * to aid with debugging.
+ *
+ * This is similar to the string put in the |release_string| string
+ * field in the VBMeta struct by avbtool.
+ */
+const char* avb_version_string(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_VERSION_H_ */
diff --git a/lib/libavb/libavb.h b/lib/libavb/libavb.h
new file mode 100644 (file)
index 0000000..ac92a2b
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#ifndef LIBAVB_H_
+#define LIBAVB_H_
+
+/* The AVB_INSIDE_LIBAVB_H preprocessor symbol is used to enforce
+ * library users to include only this file. All public interfaces, and
+ * only public interfaces, must be included here.
+ */
+
+#define AVB_INSIDE_LIBAVB_H
+#include "avb_chain_partition_descriptor.h"
+#include "avb_crypto.h"
+#include "avb_descriptor.h"
+#include "avb_footer.h"
+#include "avb_hash_descriptor.h"
+#include "avb_hashtree_descriptor.h"
+#include "avb_kernel_cmdline_descriptor.h"
+#include "avb_ops.h"
+#include "avb_property_descriptor.h"
+#include "avb_slot_verify.h"
+#include "avb_sysdeps.h"
+#include "avb_util.h"
+#include "avb_vbmeta_image.h"
+#include "avb_version.h"
+#undef AVB_INSIDE_LIBAVB_H
+
+#endif /* LIBAVB_H_ */
index d2788bf79a4ef81ec5b78d097ae53ca3d08d99e4..cfe09cc94c23273ed2f57b1549efb1ab201d2e2a 100644 (file)
@@ -635,6 +635,15 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
        big2 = BN_new();
        big32 = BN_new();
        big2_32 = BN_new();
+
+       /*
+        * Note: This code assumes that all of the above succeed, or all fail.
+        * In practice memory allocations generally do not fail (unless the
+        * process is killed), so it does not seem worth handling each of these
+        * as a separate case. Technicaly this could leak memory on failure,
+        * but a) it won't happen in practice, and b) it doesn't matter as we
+        * will immediately exit with a failure code.
+        */
        if (!tmp || !big2 || !big32 || !big2_32) {
                fprintf(stderr, "Out of memory (bignum)\n");
                return -ENOMEM;
@@ -667,15 +676,13 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
         * might fail several times
         */
        ret = fdt_setprop(blob, noffset, prop_name, buf, size);
-       if (ret)
-               return -FDT_ERR_NOSPACE;
        free(buf);
        BN_free(tmp);
        BN_free(big2);
        BN_free(big32);
        BN_free(big2_32);
 
-       return ret;
+       return ret ? -FDT_ERR_NOSPACE : 0;
 }
 
 int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
diff --git a/test/py/tests/test_avb.py b/test/py/tests/test_avb.py
new file mode 100644 (file)
index 0000000..7996e48
--- /dev/null
@@ -0,0 +1,116 @@
+# Copyright (c) 2018, Linaro Limited
+#
+# SPDX-License-Identifier:  GPL-2.0+
+#
+# Android Verified Boot 2.0 Test
+
+"""
+This tests Android Verified Boot 2.0 support in U-boot:
+
+For additional details about how to build proper vbmeta partition
+check doc/README.avb2
+
+For configuration verification:
+- Corrupt boot partition and check for failure
+- Corrupt vbmeta partition and check for failure
+"""
+
+import pytest
+import u_boot_utils as util
+
+# defauld mmc id
+mmc_dev = 1
+temp_addr = 0x90000000
+temp_addr2 = 0x90002000
+
+@pytest.mark.buildconfigspec('cmd_avb')
+def test_avb_verify(u_boot_console):
+    """Run AVB 2.0 boot verification chain with avb subset of commands
+    """
+
+    success_str = "Verification passed successfully"
+
+    response = u_boot_console.run_command('avb init %s' %str(mmc_dev))
+    assert response == ''
+    response = u_boot_console.run_command('avb verify')
+    assert response.find(success_str)
+
+
+@pytest.mark.buildconfigspec('cmd_avb')
+def test_avb_mmc_uuid(u_boot_console):
+    """Check if 'avb get_uuid' works, compare results with
+    'part list mmc 1' output
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('mmc rescan; mmc dev %s' %
+                                          str(mmc_dev))
+    assert response.find('is current device')
+
+    part_lines = u_boot_console.run_command('mmc part').splitlines()
+    part_list = {}
+    cur_partname = ""
+
+    for line in part_lines:
+        if "\"" in line:
+            start_pt = line.find("\"")
+            end_pt = line.find("\"", start_pt + 1)
+            cur_partname = line[start_pt + 1: end_pt]
+
+        if "guid:" in line:
+            guid_to_check = line.split("guid:\t")
+            part_list[cur_partname] = guid_to_check[1]
+
+    # lets check all guids with avb get_guid
+    for part, guid in part_list.iteritems():
+        avb_guid_resp = u_boot_console.run_command('avb get_uuid %s' % part)
+        assert guid == avb_guid_resp.split("UUID: ")[1]
+
+
+@pytest.mark.buildconfigspec('cmd_avb')
+def test_avb_read_rb(u_boot_console):
+    """Test reading rollback indexes
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb read_rb 1')
+
+
+@pytest.mark.buildconfigspec('cmd_avb')
+def test_avb_is_unlocked(u_boot_console):
+    """Test if device is in the unlocked state
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb is_unlocked')
+
+
+@pytest.mark.buildconfigspec('cmd_avb')
+def test_avb_mmc_read(u_boot_console):
+    """Test mmc read operation
+    """
+
+    response = u_boot_console.run_command('mmc rescan; mmc dev %s 0' %
+                                          str(mmc_dev))
+    assert response.find('is current device')
+
+    response = u_boot_console.run_command('mmc read 0x%x 0x100 0x1' % temp_addr)
+    assert response.find('read: OK')
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb read_part xloader 0 100 0x%x' %
+                                           temp_addr2)
+    assert response.find('Read 512 bytes')
+
+    # Now lets compare two buffers
+    response = u_boot_console.run_command('cmp 0x%x 0x%x 40' %
+                                          (temp_addr, temp_addr2))
+    assert response.find('64 word')
index f2b8b71ed743478be80cb91375a7670c7f6e38d9..8f44f599c1c437525b9bfe9cb405ce6e9838a257 100644 (file)
@@ -133,11 +133,11 @@ static int value_add(struct display_info *disp, struct value_node **headp,
        }
 
        str = strdup(str);
+       if (!str)
+               goto err_mem;
        node = malloc(sizeof(*node));
-       if (!str || !node) {
-               fprintf(stderr, "Out of memory\n");
-               return -1;
-       }
+       if (!node)
+               goto err_mem;
        node->next = *headp;
        node->type = type;
        node->include = include;
@@ -145,6 +145,9 @@ static int value_add(struct display_info *disp, struct value_node **headp,
        *headp = node;
 
        return 0;
+err_mem:
+       fprintf(stderr, "Out of memory\n");
+       return -1;
 }
 
 static bool util_is_printable_string(const void *data, int len)
@@ -773,7 +776,7 @@ char *utilfdt_read(const char *filename)
  */
 static int do_fdtgrep(struct display_info *disp, const char *filename)
 {
-       struct fdt_region *region;
+       struct fdt_region *region = NULL;
        int max_regions;
        int count = 100;
        char path[1024];
@@ -801,7 +804,7 @@ static int do_fdtgrep(struct display_info *disp, const char *filename)
         * The first pass will count the regions, but if it is too many,
         * we do another pass to actually record them.
         */
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < 2; i++) {
                region = malloc(count * sizeof(struct fdt_region));
                if (!region) {
                        fprintf(stderr, "Out of memory for %d regions\n",
@@ -815,11 +818,14 @@ static int do_fdtgrep(struct display_info *disp, const char *filename)
                                disp->flags);
                if (count < 0) {
                        report_error("fdt_find_regions", count);
+                       free(region);
                        return -1;
                }
                if (count <= max_regions)
                        break;
                free(region);
+               fprintf(stderr, "Internal error with fdtgrep_find_region)(\n");
+               return -1;
        }
 
        /* Optionally print a list of regions */