diff --git a/Android.mk b/Android.mk
index 4b6b2334..948645d5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,21 +1,517 @@
-LOCAL_PATH := $(call my-dir)
+KERNELFLINGER_LOCAL_PATH := $(call my-dir)
+KERNELFLINGER_CFLAGS := -Wall -Wextra -Werror -mrdrnd
-ifeq ($(TARGET_UEFI_ARCH),i386)
-arch_name := x86
+ifeq ($(KERNELFLINGER_NON-ANDROID),true)
+KERNELFLINGER_CFLAGS += -DFASTBOOT_FOR_NON_ANDROID
+endif
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+ KERNELFLINGER_CFLAGS += -DAVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED
+endif
+
+ifeq ($(TARGET_UEFI_ARCH),x86_64)
+ KERNELFLINGER_CFLAGS += -D__STDC_VERSION__=199901L
+ KERNELFLINGER_CFLAGS += -DARCH_X86_64=1
+endif
+
+ifeq ($(TARGET_USE_TRUSTY),true)
+ KERNELFLINGER_CFLAGS += -DUSE_TRUSTY
+endif
+
+ifeq ($(TARGET_USE_MULTIBOOT),true)
+ KERNELFLINGER_CFLAGS += -DUSE_MULTIBOOT
+endif
+
+ifeq ($(TARGET_USE_ACPI),true)
+ KERNELFLINGER_CFLAGS += -DUSE_ACPI
+endif
+ifeq ($(TARGET_USE_ACPIO),true)
+ KERNELFLINGER_CFLAGS += -DUSE_ACPIO
+endif
+
+ifeq ($(TARGET_USE_PRODUCT),true)
+ KERNELFLINGER_CFLAGS += -DUSE_PRODUCT
+endif
+
+ifeq ($(IOC_USE_SLCAN),true)
+ KERNELFLINGER_CFLAGS += -DIOC_USE_SLCAN
else
-arch_name := x86_64
+ifeq ($(IOC_USE_CBC),true)
+ KERNELFLINGER_CFLAGS += -DIOC_USE_CBC
+endif
+endif
+
+ifeq ($(TARGET_BUILD_VARIANT),user)
+ KERNELFLINGER_CFLAGS += -DUSER -DUSERDEBUG
+endif
+
+ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+ KERNELFLINGER_CFLAGS += -DUSERDEBUG
+endif
+
+ifeq ($(TARGET_USE_TPM),true)
+ KERNELFLINGER_CFLAGS += -DUSE_TPM -DSOFT_FUSE
+endif
+
+ifeq ($(TARGET_NO_DEVICE_UNLOCK),true)
+ KERNELFLINGER_CFLAGS += -DNO_DEVICE_UNLOCK
+endif
+
+ifeq ($(BUILD_ANDROID_THINGS),true)
+ KERNELFLINGER_CFLAGS += -DBUILD_ANDROID_THINGS
+endif
+
+ifeq ($(HAL_AUTODETECT),true)
+ KERNELFLINGER_CFLAGS += -DHAL_AUTODETECT
+endif
+
+ifeq ($(TARGET_USE_USERFASTBOOT),true)
+ $(error Userfastboot is not supported anymore)
+endif
+
+ifeq ($(KERNELFLINGER_USE_POWER_BUTTON),true)
+ KERNELFLINGER_CFLAGS += -DUSE_POWER_BUTTON
+endif
+
+# adb in crashmode allows to pull the entire RAM and MUST never be
+# disabled allowed on a USER build for security reasons:
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ KERNELFLINGER_CFLAGS += -DCRASHMODE_USE_ADB
+endif
+
+ifneq ($(strip $(KERNELFLINGER_USE_UI)),false)
+ KERNELFLINGER_CFLAGS += -DUSE_UI
+endif
+
+ifneq ($(strip $(TARGET_BOOTLOADER_POLICY)),)
+ KERNELFLINGER_CFLAGS += -DBOOTLOADER_POLICY=$(TARGET_BOOTLOADER_POLICY)
+ # Double negation to enforce the use of the EFI variable storage
+ # as the default behavior.
+ ifneq ($(strip $(TARGET_BOOTLOADER_POLICY_USE_EFI_VAR)),False)
+ KERNELFLINGER_CFLAGS += -DBOOTLOADER_POLICY_EFI_VAR
+ endif
+endif
+
+ifeq ($(KERNELFLINGER_OS_SECURE_BOOT),true)
+ KERNELFLINGER_CFLAGS += -DOS_SECURE_BOOT
+endif
+
+#Enable android verifed boot support(libavb)
+ifeq ($(BOARD_AVB_ENABLE),true)
+ KERNELFLINGER_CFLAGS += -DUSE_AVB
+ ifneq ($(KERNELFLINGER_DISABLE_DEBUG_PRINT),true)
+ ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+ KERNELFLINGER_CFLAGS += -DAVB_ENABLE_DEBUG
+ endif
+ endif
+endif
+
+ifeq ($(BOARD_SLOT_AB_ENABLE),true)
+ KERNELFLINGER_CFLAGS += -DUSE_SLOT
+endif
+
+ifeq ($(KERNELFLINGER_SUPPORT_USB_STORAGE),true)
+ KERNELFLINGER_CFLAGS += -DUSB_STORAGE
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB),true)
+ KERNELFLINGER_CFLAGS += -DRPMB_STORAGE
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB_SIMULATE),true)
+ KERNELFLINGER_CFLAGS += -DRPMB_STORAGE -DRPMB_SIMULATE
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB_SIMULATE),true)
+ KERNELFLINGER_CFLAGS += -DSECURE_STORAGE_EFIVAR
+else # KERNELFLINGER_USE_RPMB_SIMULATE == false
+ifeq ($(KERNELFLINGER_USE_RPMB),true)
+ KERNELFLINGER_CFLAGS += -DSECURE_STORAGE_RPMB
+else # KERNELFLINGER_USE_RPMB == false
+ KERNELFLINGER_CFLAGS += -DSECURE_STORAGE_EFIVAR
+endif # KERNELFLINGER_USE_RPMB
+endif # KERNELFLINGER_USE_RPMB_SIMULATE
+
+ifeq ($(BOARD_SD_PASS_THRU_ENABLE),true)
+ KERNELFLINGER_CFLAGS += -DUSE_SD_PASS_THRU
+endif
+
+
+KERNELFLINGER_STATIC_LIBRARIES := \
+ libuefi_ssl_static \
+ libuefi_crypto_static \
+ libgnuefi \
+ libsslsupport \
+ libefi
+
+include $(call all-subdir-makefiles)
+LOCAL_PATH := $(KERNELFLINGER_LOCAL_PATH)
+
+SHARED_CFLAGS := $(KERNELFLINGER_CFLAGS) -Wno-error
+SHARED_STATIC_LIBRARIES := \
+ $(KERNELFLINGER_STATIC_LIBRARIES) \
+ libkernelflinger-$(TARGET_BUILD_VARIANT)
+
+ifeq ($(TARGET_USE_TPM),true)
+ SHARED_STATIC_LIBRARIES += libedk2_tpm
endif
include $(CLEAR_VARS)
-LOCAL_MODULE := gummiboot.efi
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)/efi
-LOCAL_MODULE_STEM := gummiboot.efi
-LOCAL_SRC_FILES := ../../prebuilts/tools/linux-$(arch_name)/gummiboot/gummiboot.efi
-LOCAL_CERTIFICATE := SBSIGN
-LOCAL_SBSIGN_CERTIFICATE := uefi_bios_db_key
-include $(BUILD_PREBUILT)
-
-GUMMIBOOT_EFI := $(PRODUCT_OUT)/efi/gummiboot.efi
+LOCAL_MODULE := kernelflinger-$(TARGET_BUILD_VARIANT)
+
+
+# if dm-verity is disabled for eng purpose skip the oem-cert
+ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY), true)
+kf_intermediates := $(call intermediates-dir-for,EFI,kernelflinger)
+
+VERITY_CERT := $(kf_intermediates)/verity.cer
+PADDED_VERITY_CERT := $(kf_intermediates)/verity.padded.cer
+OEMCERT_OBJ := $(kf_intermediates)/oemcert.o
+
+$(VERITY_CERT): $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem $(OPENSSL)
+ $(transform-pem-cert-to-der-cert)
+
+$(PADDED_VERITY_CERT): $(VERITY_CERT)
+ $(call pad-binary, 4096)
+
+ifeq ($(TARGET_UEFI_ARCH),x86_64)
+ ELF_OUTPUT := elf64-x86-64
+else
+ ELF_OUTPUT := elf32-i386
+endif
+
+sym_binary := $(shell echo _binary_$(PADDED_VERITY_CERT) | sed "s/[\/\.-]/_/g")
+$(OEMCERT_OBJ): $(PADDED_VERITY_CERT)
+ mkdir -p $(@D) && \
+ $(EFI_OBJCOPY) --input binary --output $(ELF_OUTPUT) --binary-architecture i386 $< $@ && \
+ $(EFI_OBJCOPY) --redefine-sym $(sym_binary)_start=_binary_oemcert_start \
+ --redefine-sym $(sym_binary)_end=_binary_oemcert_end \
+ --redefine-sym $(sym_binary)_size=_binary_oemcert_size \
+ --rename-section .data=.oemkeys $@ $@
+
+LOCAL_GENERATED_SOURCES := $(OEMCERT_OBJ)
+else # PRODUCT_SUPPORTS_VERITY
+ifneq (,$(filter user userdebug, $(TARGET_BUILD_VARIANT)))
+
+ifeq ($(BOARD_AVB_ENABLE),false)
+fail_no_oem_cert:
+ $(error Trying to build kernelflinger-$(TARGET_BUILD_VARIANT)\
+without oem-cert, this is allowed only for eng builds)
+
+LOCAL_GENERATED_SOURCES := fail_no_oem_cert
+endif # BOARD_AVB_ENABLE
+endif
+endif # PRODUCT_SUPPORTS_VERITY
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+kf_intermediates := $(call intermediates-dir-for,EFI,kernelflingeravb)
+
+AVB_PK := $(kf_intermediates)/avb_pk.bin
+PADDED_AVB_PK := $(kf_intermediates)/avb_pk.padded.bin
+AVB_PK_OBJ := $(kf_intermediates)/avb_pk.o
+ifndef BOARD_AVB_KEY_PATH
+BOOTLOADER_AVB_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
+else
+BOOTLOADER_AVB_KEY_PATH := $(BOARD_AVB_KEY_PATH)
+endif
+
+$(AVB_PK): $(BOOTLOADER_AVB_KEY_PATH) avbtool
+ avbtool extract_public_key --key $< --output $@
+
+$(PADDED_AVB_PK): $(AVB_PK)
+ $(call pad-binary, 4096)
+
+ifeq ($(TARGET_UEFI_ARCH),x86_64)
+ ELF_OUTPUT := elf64-x86-64
+else
+ ELF_OUTPUT := elf32-i386
+endif
+
+avb_sym_binary := $(shell echo _binary_$(PADDED_AVB_PK) | sed "s/[\/\.-]/_/g")
+$(AVB_PK_OBJ): $(PADDED_AVB_PK)
+ mkdir -p $(@D) && \
+ $(EFI_OBJCOPY) --input binary --output $(ELF_OUTPUT) --binary-architecture i386 $< $@ && \
+ $(EFI_OBJCOPY) --redefine-sym $(avb_sym_binary)_start=_binary_avb_pk_start \
+ --redefine-sym $(avb_sym_binary)_end=_binary_avb_pk_end \
+ --redefine-sym $(avb_sym_binary)_size=_binary_avb_pk_size \
+ --rename-section .data=.oemkeys $@ $@
+
+LOCAL_GENERATED_SOURCES += $(AVB_PK_OBJ)
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,avb)
+endif # BOARD_AVB_ENABLE
+
+
+LOCAL_SRC_FILES := \
+ kernelflinger.c
+ifneq ($(strip $(KERNELFLINGER_USE_UI)),false)
+ LOCAL_SRC_FILES += \
+ ux.c
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+ libfastboot-$(TARGET_BUILD_VARIANT) \
+ libefiusb-$(TARGET_BUILD_VARIANT) \
+ libefitcp-$(TARGET_BUILD_VARIANT) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libheci-$(TARGET_BUILD_VARIANT)
+
+ifeq ($(TARGET_USE_TRUSTY),true)
+ LOCAL_STATIC_LIBRARIES += libqltipc-$(TARGET_BUILD_VARIANT)
+endif
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_STATIC_LIBRARIES += libadb-$(TARGET_BUILD_VARIANT)
+endif
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_SRC_FILES += unittest.c
+endif
+
+LOCAL_CFLAGS := $(SHARED_CFLAGS)
+
+ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY), true)
+LOCAL_OBJCOPY_FLAGS := -j .oemkeys
+endif
+
+ifeq ($(BOARD_AVB_ENABLE), true)
+LOCAL_OBJCOPY_FLAGS := -j .oemkeys
+endif
+
+LOCAL_STATIC_LIBRARIES += $(SHARED_STATIC_LIBRARIES)
+LOCAL_MODULE_STEM := kernelflinger
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+LOCAL_SRC_FILES += avb_init.c
+LOCAL_STATIC_LIBRARIES += libavb_kernelflinger-$(TARGET_BUILD_VARIANT)
+endif
+
+include $(BUILD_EFI_EXECUTABLE) # For kernelflinger-$(TARGET_BUILD_VARIANT)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := installer-$(TARGET_BUILD_VARIANT)
+LOCAL_STATIC_LIBRARIES := \
+ $(SHARED_STATIC_LIBRARIES) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libfastboot-for-installer-$(TARGET_BUILD_VARIANT)
+LOCAL_CFLAGS := $(SHARED_CFLAGS)
+LOCAL_SRC_FILES := installer.c
+LOCAL_MODULE_STEM := installer
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,libfastboot)
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+kfins_intermediates := $(call intermediates-dir-for,EFI,kernelflingerins)
+
+KFINS_AVB_PK := $(kfins_intermediates)/avb_pk.bin
+KFINS_PADDED_AVB_PK := $(kfins_intermediates)/avb_pk.padded.bin
+KFINS_AVB_PK_OBJ := $(kfins_intermediates)/avb_pk.o
+ifndef BOARD_AVB_KEY_PATH
+BOOTLOADER_AVB_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
+else
+BOOTLOADER_AVB_KEY_PATH := $(BOARD_AVB_KEY_PATH)
+endif
+
+$(KFINS_AVB_PK): $(BOOTLOADER_AVB_KEY_PATH) avbtool
+ avbtool extract_public_key --key $< --output $@
+
+$(KFINS_PADDED_AVB_PK): $(KFINS_AVB_PK)
+ $(call pad-binary, 4096)
+
+ifeq ($(TARGET_UEFI_ARCH),x86_64)
+ ELF_OUTPUT := elf64-x86-64
+else
+ ELF_OUTPUT := elf32-i386
+endif
+
+kfins_avb_sym_binary := $(shell echo _binary_$(KFINS_PADDED_AVB_PK) | sed "s/[\/\.-]/_/g")
+$(KFINS_AVB_PK_OBJ): $(KFINS_PADDED_AVB_PK)
+ mkdir -p $(@D) && \
+ $(EFI_OBJCOPY) --input binary --output $(ELF_OUTPUT) --binary-architecture i386 $< $@ && \
+ $(EFI_OBJCOPY) --redefine-sym $(kfins_avb_sym_binary)_start=_binary_avb_pk_start \
+ --redefine-sym $(kfins_avb_sym_binary)_end=_binary_avb_pk_end \
+ --redefine-sym $(kfins_avb_sym_binary)_size=_binary_avb_pk_size \
+ --rename-section .data=.oemkeys $@ $@
+
+LOCAL_GENERATED_SOURCES += $(KFINS_AVB_PK_OBJ)
+LOCAL_SRC_FILES += avb_init.c
+LOCAL_C_INCLUDES += $(addprefix $(LOCAL_PATH)/,avb)
+LOCAL_STATIC_LIBRARIES += libavb_kernelflinger-$(TARGET_BUILD_VARIANT)
+endif # BOARD_AVB_ENABLE
+
+include $(BUILD_EFI_EXECUTABLE) # For installer-$(TARGET_BUILD_VARIANT)
+
+
+ifeq ($(KERNELFLINGER_SUPPORT_NON_EFI_BOOT),true)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := kf4abl-$(TARGET_BUILD_VARIANT)
+LOCAL_MODULE_STEM := kf4abl
+LOCAL_CFLAGS := $(SHARED_CFLAGS)
+
+ifeq ($(KERNELFLINGER_DISABLE_DEBUG_PRINT),true)
+ LOCAL_CFLAGS += -D__DISABLE_DEBUG_PRINT
+endif
+
+LOCAL_STATIC_LIBRARIES += \
+ libfastboot-$(TARGET_BUILD_VARIANT) \
+ libefiusb-$(TARGET_BUILD_VARIANT) \
+ libefitcp-$(TARGET_BUILD_VARIANT) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libheci-$(TARGET_BUILD_VARIANT) \
+ $(SHARED_STATIC_LIBRARIES) \
+ libpayload \
+ libefiwrapper-$(TARGET_BUILD_VARIANT) \
+ libefiwrapper_drivers-$(TARGET_BUILD_VARIANT) \
+ efiwrapper-$(TARGET_BUILD_VARIANT) \
+ libelfloader-$(TARGET_BUILD_VARIANT)
+
+ifeq ($(TARGET_USE_TRUSTY),true)
+ LOCAL_STATIC_LIBRARIES += libqltipc-$(TARGET_BUILD_VARIANT)
+endif
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+ LOCAL_STATIC_LIBRARIES += libavb_kernelflinger-$(TARGET_BUILD_VARIANT)
+endif
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_STATIC_LIBRARIES += libadb-$(TARGET_BUILD_VARIANT)
+endif
+LOCAL_SRC_FILES := \
+ kf4abl.c
+
+ifneq ($(strip $(KERNELFLINGER_USE_UI)),false)
+ LOCAL_SRC_FILES += \
+ ux.c
+endif
+ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
+keys4abl_intermediates := $(call intermediates-dir-for,ABL,keys)
+
+ABL_VERITY_CERT := $(keys4abl_intermediates)/verity.cer
+ABL_PADDED_VERITY_CERT := $(keys4abl_intermediates)/verity.padded.cer
+ABL_OEMCERT_OBJ := $(keys4abl_intermediates)/oemcert.o
+
+$(ABL_VERITY_CERT): $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem $(OPENSSL)
+ $(transform-pem-cert-to-der-cert)
+
+$(ABL_PADDED_VERITY_CERT): $(ABL_VERITY_CERT)
+ $(call pad-binary, 4096)
+
+ifeq ($(TARGET_IAFW_ARCH),x86_64)
+ ELF_OUTPUT := elf64-x86-64
+else
+ ELF_OUTPUT := elf32-i386
+endif
+
+abl_sym_binary := $(shell echo _binary_$(ABL_PADDED_VERITY_CERT) | sed "s/[\/\.-]/_/g")
+$(ABL_OEMCERT_OBJ): $(ABL_PADDED_VERITY_CERT)
+ mkdir -p $(@D) && \
+ $(EFI_OBJCOPY) --input binary --output $(ELF_OUTPUT) --binary-architecture i386 $< $@ && \
+ $(EFI_OBJCOPY) --redefine-sym $(abl_sym_binary)_start=_binary_oemcert_start \
+ --redefine-sym $(abl_sym_binary)_end=_binary_oemcert_end \
+ --redefine-sym $(abl_sym_binary)_size=_binary_oemcert_size \
+ --rename-section .data=.oemkeys $@ $@
+
+LOCAL_GENERATED_SOURCES := $(ABL_OEMCERT_OBJ)
+endif #.PRODUCT_SUPPORTS_VERITY == true
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+keys4abl_intermediates := $(call intermediates-dir-for,ABL,keys4abl)
+
+ABL_AVB_PK := $(keys4abl_intermediates)/avb_pk.bin
+ABL_PADDED_AVB_PK := $(keys4abl_intermediates)/avb_pk.padded.bin
+ABL_AVB_PK_OBJ := $(keys4abl_intermediates)/avb_pk.o
+ifndef BOARD_AVB_KEY_PATH
+BOOTLOADER_AVB_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
+else
+BOOTLOADER_AVB_KEY_PATH := $(BOARD_AVB_KEY_PATH)
+endif
+
+$(ABL_AVB_PK): $(BOOTLOADER_AVB_KEY_PATH) avbtool
+ avbtool extract_public_key --key $< --output $@
+
+$(ABL_PADDED_AVB_PK): $(ABL_AVB_PK)
+ $(call pad-binary, 4096)
+
+ifeq ($(TARGET_IAFW_ARCH),x86_64)
+ ELF_OUTPUT := elf64-x86-64
+else
+ ELF_OUTPUT := elf32-i386
+endif
+
+avb_sym_binary := $(shell echo _binary_$(ABL_PADDED_AVB_PK) | sed "s/[\/\.-]/_/g")
+$(ABL_AVB_PK_OBJ): $(ABL_PADDED_AVB_PK)
+ mkdir -p $(@D) && \
+ $(EFI_OBJCOPY) --input binary --output $(ELF_OUTPUT) --binary-architecture i386 $< $@ && \
+ $(EFI_OBJCOPY) --redefine-sym $(avb_sym_binary)_start=_binary_avb_pk_start \
+ --redefine-sym $(avb_sym_binary)_end=_binary_avb_pk_end \
+ --redefine-sym $(avb_sym_binary)_size=_binary_avb_pk_size \
+ --rename-section .data=.oemkeys $@ $@
+
+LOCAL_GENERATED_SOURCES += $(ABL_AVB_PK_OBJ)
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,avb)
+
+LOCAL_SRC_FILES += avb_init.c
+
+endif
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,libkernelflinger)
+include $(BUILD_ABL_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := fb4abl-$(TARGET_BUILD_VARIANT)
+LOCAL_MODULE_STEM := fb4abl
+LOCAL_CFLAGS := $(SHARED_CFLAGS)
+
+LOCAL_CFLAGS += -D__FORCE_FASTBOOT
+
+LOCAL_STATIC_LIBRARIES += \
+ libfastboot-$(TARGET_BUILD_VARIANT) \
+ libefiusb-$(TARGET_BUILD_VARIANT) \
+ libefitcp-$(TARGET_BUILD_VARIANT) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libheci-$(TARGET_BUILD_VARIANT) \
+ $(SHARED_STATIC_LIBRARIES) \
+ libpayload \
+ libefiwrapper-$(TARGET_BUILD_VARIANT) \
+ libefiwrapper_drivers-$(TARGET_BUILD_VARIANT) \
+ efiwrapper-$(TARGET_BUILD_VARIANT) \
+ libelfloader-$(TARGET_BUILD_VARIANT)
+
+ifeq ($(TARGET_USE_TRUSTY),true)
+ LOCAL_STATIC_LIBRARIES += libqltipc-$(TARGET_BUILD_VARIANT)
+endif
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_STATIC_LIBRARIES += libadb-$(TARGET_BUILD_VARIANT)
+endif
+ifeq ($(BOARD_AVB_ENABLE),true)
+ LOCAL_STATIC_LIBRARIES += libavb_kernelflinger-$(TARGET_BUILD_VARIANT)
+endif
+LOCAL_SRC_FILES := \
+ kf4abl.c
+
+ifneq ($(strip $(KERNELFLINGER_USE_UI)),false)
+ LOCAL_SRC_FILES += \
+ ux.c
+endif
+ifeq ($(BOARD_AVB_ENABLE),true)
+LOCAL_SRC_FILES += \
+ avb_init.c
+endif
+
+ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
+LOCAL_GENERATED_SOURCES := $(ABL_OEMCERT_OBJ)
+endif
+
+ifeq ($(BOARD_AVB_ENABLE),true)
+LOCAL_GENERATED_SOURCES += $(ABL_AVB_PK_OBJ)
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,avb)
+endif
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,libkernelflinger)
+include $(BUILD_ABL_EXECUTABLE)
+endif #KERNELFLINGER_SUPPORT_NON_EFI_BOOT
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..517d5b11
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2016, Intel Corportaion
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE
deleted file mode 100644
index e69de29b..00000000
diff --git a/Makefile b/Makefile
deleted file mode 100644
index f623842d..00000000
--- a/Makefile
+++ /dev/null
@@ -1,74 +0,0 @@
-ifeq ($(ARCH),x86_64)
-ARCH_DIR := linux-x86_64
-else
-ARCH_DIR := linux-x86
-endif
-
-GNU_EFI_TOP := $(ANDROID_BUILD_TOP)/hardware/intel/efi_prebuilts/gnu-efi/$(ARCH_DIR)/
-GNU_EFI_INCLUDE := $(GNU_EFI_TOP)/include/efi
-GNU_EFI_LIB := $(GNU_EFI_TOP)/lib
-
-EFI_LIBS := -lefi -lgnuefi -lopenssl $(shell $(CC) -print-libgcc-file-name)
-
-OPENSSL_TOP := $(ANDROID_BUILD_TOP)/hardware/intel/efi_prebuilts/uefi_shim/$(ARCH_DIR)/
-OPENSSL_INCLUDE := $(OPENSSL_TOP)/Include
-
-GUMMIBOOT_KEY_PAIR ?= $(ANDROID_BUILD_TOP)/device/intel/build/testkeys/vendor
-
-CPPFLAGS := -I$(GNU_EFI_INCLUDE) -I$(GNU_EFI_INCLUDE)/$(ARCH) -I$(OPENSSL_INCLUDE)
-CFLAGS := -ggdb -O3 -fno-stack-protector -fno-strict-aliasing -fpic \
- -fshort-wchar -Wall -Werror -mno-red-zone -maccumulate-outgoing-args \
- -mno-mmx -mno-sse -fno-builtin
-
-ifeq ($(ARCH),x86_64)
-# FIXME would like to use -DGNU_EFI_USE_MS_ABI, but that requires GCC 4.7
-CFLAGS += -DEFI_FUNCTION_WRAPPER
-else
-CFLAGS += -m32
-endif
-
-LDFLAGS := -nostdlib -znocombreloc -T $(GNU_EFI_LIB)/elf_$(ARCH)_efi.lds \
- -shared -Bsymbolic -L$(GNU_EFI_LIB) \
- -L$(OPENSSL_TOP) $(GNU_EFI_LIB)/crt0-efi-$(ARCH).o
-
-OBJS := kernelflinger.o \
- android.o \
- efilinux.o \
- options.o \
- acpi.o \
- security.o \
- lib.o \
- ux.o
-
-%.o: %.c
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-
-kernelflinger.efi: kernelflinger.unsigned.efi $(GUMMIBOOT_KEY_PAIR).x509.pem kernelflinger.key
- sbsign --key kernelflinger.key \
- --cert $(GUMMIBOOT_KEY_PAIR).x509.pem \
- --output $@ $<
-
-kernelflinger.key: $(GUMMIBOOT_KEY_PAIR).pk8
- openssl pkcs8 -nocrypt -inform DER -outform PEM -in $^ -out $@
-
-%.unsigned.efi: %.so
- objcopy -j .text -j .sdata -j .data \
- -j .dynamic -j .dynsym -j .rel \
- -j .rela -j .reloc -j .eh_frame \
- -j .vendor_cert \
- --target=efi-app-$(ARCH) $^ $@
-
-%.debug.efi: %.so
- objcopy -j .text -j .sdata -j .data \
- -j .dynamic -j .dynsym -j .rel \
- -j .rela -j .reloc -j .eh_frame \
- -j .debug_info -j .debug_abbrev -j .debug_aranges \
- -j .debug_line -j .debug_str -j .debug_ranges \
- --target=efi-app-$(ARCH) $^ $@
-
-kernelflinger.so: $(OBJS)
- $(LD) $(LDFLAGS) $^ -o $@ -lefi $(EFI_LIBS)
-
-clean:
- rm -f $(OBJS) kernelflinger.so kernelflinger.efi kernelflinger.unsigned.efi kernelflinger.key
-
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..91698a7d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,127 @@
+Kernelflinger
+=============
+
+Overview
+--------
+
+Kernelflinger is the Intel UEFI bootloader for
+AndroidTM/BrilloTM. It is compatible with the
+[UEFI 2.4 specification](http://www.uefi.org/sites/default/files/resources/2_4_Errata_B.pdf).
+
+Kernelflinger implements the Google Bootloader requirements for
+AndroidTM L, M, N and O desserts.
+
+The key features are:
+
+1. [Google verified boot](https://source.android.com/security/verifiedboot/verified-boot.html)
+ support.
+2. [Android verified boot](https://android.googlesource.com/platform/external/avb/)
+ support.
+3. [Fastboot](./doc/fastboot.md) support over USB and TCP.
+4. [Installer](./doc/installer.md): Standalone EFI application that
+ can be used to flash a device from the EFI shell using an external
+ storage.
+5. [Crashmode](./doc/crashmode.md): provides a simple access using adb
+ commmand to retrieve data from memory, partitions, EFI variables or
+ ACPI tables in case of OS crash.
+6. [Trusty](./libqltipc/ql-tipc/README.md): support load and verify
+ TEE OS, and setup the IPC between TEE OS.
+
+Basic architecture
+------------------
+
+* libkernelflinger: library that provides all the tools necessary to
+ access ACPI and SMBIOS tables, run image verification, use storage
+ (SATA, eMMC, SDCard and UFS) and draw graphic widgets.
+* [libfastboot](./doc/fastboot.md): Fastboot protocol implementation.
+ [fastboot protocol](https://android.googlesource.com/platform/system/core/+/master/fastboot/)
+* libadb: used by [Crashmode](./doc/crashmode.md).
+* libefiusb: based on the non-standard DeviceMode protocol it provides
+ easy to use USB configuration, read and write functions and TX/RX
+ events callbacks.
+* libefitcp: based on the standard UEFI TCP protocol, it provides easy
+ to use TCP configuration, read and write functions and TX/RX events
+ callbacks.
+* libtransport: is a framework to abstract the transport layer. Used
+ by both libfastboot and libadb to support USB and TCP transport.
+* libqltipc: used for setup the IPC between TEE OS.
+* libheci: support HECI protocol.
+* kernelflinger.c: main program that implements the boot flow.
+* installer.c: main program of the [Installer](./doc/installer.md)
+
+Dependencies
+------------
+
+Kernelflinger depends on the following libraries:
+* gnu-efi (TODO: github link)
+* openssl (TODO: github link)
+
+Kernelflinger's compilation requires the following tools:
+* [sbsigntool](https://github.com/android-ia/platform_external_sbsigntool):
+ EFI binary signer.
+* [vendor\_intel\_build](https://github.com/android-ia/vendor_intel_build):
+ EFI compilation definitions for AndroidTM.
+
+Compilation
+-----------
+
+Kernelflinger's compilation relies on the AndroidTM
+compilation system. In an AndroidTM tree, with all the
+dependencies checked out, run the following command to build
+`$OUT/efi/kernelflinger.efi`.
+
+```bash
+$ make kernelflinger-$TARGET_BUILD_VARIANT
+```
+
+Run the following command to build `$OUT/efi/installer.efi`:
+
+```bash
+$ make installer-$TARGET_BUILD_VARIANT
+```
+
+Kerneflinger specific configuration flags:
+
+* `TARGET_NO_DEVICE_UNLOCK`: if true, any attempt to unlock the device
+ (`fastboot flashing unlock`) will systematically fail.
+* `HAL_AUTODETECT`: Cf. [Autodetect](./doc/autodetect.md).
+* `TARGET_BOOTLOADER_POLICY`:
+ Cf. [Bootloader Policy and Factory Reset Protection](./doc/FRP.md)
+* `KERNELFLINGER_ALLOW_UNSUPPORTED_ACPI_TABLE`: makes kernelflinger
+ ignore ACPI table oem\_id, oem\_table\_id and revision fields.
+* `KERNELFLINGER_USE_POWER_BUTTON`: makes kernelflinger use the power
+ key as an input source.
+* `KERNELFLINGER_USE_WATCHDOG`: makes kernelflinger start the "kernel"
+ watchdog prior booting the kernel.
+* `KERNELFLINGER_USE_CHARGING_APPLET`: makes Kernelflinger use the
+ non-standard ChargingApplet protocol to get the battery and charger
+ status, and modify the boot flow in consequence.
+* `KERNELFLINGER_IGNORE_RSCI`: makes Kernelflinger ignore the
+ non-standard RSCI ACPI table. This APCI table provides the reset
+ and wake source reasons.
+* `KERNELFLINGER_IGNORE_NOT_APPLICABLE_RESET`: makes Kernelflinger
+ ignore the ACPI table RSCI reset source "not_applicable" when
+ setting the bootreason.
+* `KERNELFLINGER_SSL_LIBRARY`: either 'openssl' or 'boringssl', makes
+ Kernelflinger build against the OpenSSL library, respectively, the
+ BoringSSL library. Note: the `TARGET_BOOTLOADER_POLICY` flag
+ cannot be used if `KERNELFLINGER_SSL_LIBRARY` is set to 'boringssl'
+ because the BoringSSL does not support the PKCS7 message format
+ which is used by the RMA force unlock feature
+ (Cf. [Bootloader Policy and Factory Reset Protection](./doc/FRP.md)).
+* `BOARD_AVB_ENABLE`: support AVB (Android Verify Boot)
+* `BOARD_SLOT_AB_ENABLE`: support AVB A/B slot.
+* `KERNELFLINGER_USE_RPMB`: support use RPMB, it can be used by Trusty,
+ or save the AVB rollback index.
+* `BUILD_ANDROID_THINGS`: enable some feature for Android Things.
+
+Command line parameters
+-----------------------
+
+* `-f`: enforce kernelfliner to enter Fastboot mode
+* `-U` [test-suite-name]: run unittest test (see
+ [unittest.c](./unittest.c)).
+
+Copyright and Licence
+---------------------
+Kernelflinger is licensed under the terms of the BSD 2-Clause.
diff --git a/acpi.c b/acpi.c
deleted file mode 100644
index 2f87a4eb..00000000
--- a/acpi.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2013, Intel Corporation
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include
-#include
-#include "acpi.h"
-
-#include "kernelflinger.h"
-#include "efilinux.h"
-
-static struct RSCI_TABLE *RSCI_table = NULL;
-
-#define RSDT_SIG "RSDT"
-#define RSDP_SIG "RSD PTR "
-
-#define offsetof(TYPE, MEMBER) ((UINTN) &((TYPE *)0)->MEMBER)
-
-/* This macro is defined to get a specified field from an acpi table
- * which will be loader if necessary.
- * parameter is the name of the requested table passed as-is.
- *
- * Example: get_acpi_field(RSCI, wake_source)
- *
- * In this example, the macro requires that :
- *
- * - RSCI_SIG is a define of the RSCI table signature,
- * - RSCI_table is a global variable which will contains the table data,
- * - struct RSCI_TABLE is the type of the requested table.
- */
-#define get_acpi_field(table, field) \
- (typeof(table##_table->field)) \
- _get_acpi_field((CHAR8 *)#table, (CHAR8 *)#field, \
- (VOID **)&table##_table, \
- offsetof(struct table##_TABLE, field), sizeof(table##_table->field))
-
-static UINT64 _get_acpi_field(CHAR8 *name, CHAR8 *fieldname _unused, VOID **var, UINTN offset, UINTN size)
-{
- if (size > sizeof(UINT64)) {
- return -1;
- }
-
- if (!*var) {
- EFI_STATUS ret = get_acpi_table((CHAR8 *)name, (VOID **)var);
- if (EFI_ERROR(ret)) {
- return -1;
- }
- }
-
- UINT64 ret = 0;
- CopyMem((CHAR8 *)&ret, (CHAR8 *)*var + offset, size);
- return ret;
-}
-
-EFI_STATUS get_rsdt_table(struct RSDT_TABLE **rsdt)
-{
- EFI_GUID acpi2_guid = ACPI_20_TABLE_GUID;
- struct RSDP_TABLE *rsdp;
- EFI_STATUS ret;
-
- ret = LibGetSystemConfigurationTable(&acpi2_guid, (VOID **)&rsdp);
- if (EFI_ERROR(ret)) {
- goto out;
- }
-
- if (strncmpa((CHAR8 *)rsdp->signature, (CHAR8 *)RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
- ret = EFI_COMPROMISED_DATA;
- goto out;
- }
-
- *rsdt = (struct RSDT_TABLE *)(UINTN)rsdp->rsdt_address;
- if (strncmpa((CHAR8 *)(*rsdt)->header.signature, (CHAR8 *)RSDT_SIG, sizeof(RSDT_SIG) - 1)) {
- ret = EFI_COMPROMISED_DATA;
- goto out;
- }
-out:
- return ret;
-}
-
-EFI_STATUS get_acpi_table(CHAR8 *signature, VOID **table)
-{
- struct RSDT_TABLE *rsdt;
- EFI_STATUS ret;
- int nb_acpi_tables;
- int i;
-
- ret = get_rsdt_table(&rsdt);
- if (EFI_ERROR(ret))
- goto out;
-
- nb_acpi_tables = (rsdt->header.length - sizeof(rsdt->header)) / sizeof(rsdt->entry[1]);
- ret = EFI_NOT_FOUND;
- for (i = 0 ; i < nb_acpi_tables; i++) {
- struct ACPI_DESC_HEADER *header = (VOID *)(UINTN)rsdt->entry[i];
- if (!strncmpa(header->signature, signature, strlena(signature))) {
- debug("Found %c%c%c%c table\n", signature[0], signature[1], signature[2], signature[3]);
- *table = header;
- ret = EFI_SUCCESS;
- break;
- }
- }
-out:
- return ret;
-}
-
-enum wake_sources rsci_get_wake_source(void)
-{
- return get_acpi_field(RSCI, wake_source);
-}
-
diff --git a/acpi.h b/acpi.h
deleted file mode 100644
index 0d3fc2b6..00000000
--- a/acpi.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2013, Intel Corporation
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef __ACPI_H__
-#define __ACPI_H__
-
-#include "bootlogic.h"
-
-/** Generic ACPI table header **/
-struct ACPI_DESC_HEADER {
- CHAR8 signature[4]; /* ASCII Table identifier */
- UINT32 length; /* Length of the table, including the header */
- CHAR8 revision; /* Revision of the structure */
- CHAR8 checksum; /* Sum of all fields must be 0 */
- CHAR8 oem_id[6]; /* ASCII OEM identifier */
- CHAR8 oem_table_id[8]; /* ASCII OEM table identifier */
- UINT32 oem_revision; /* OEM supplied revision number */
- CHAR8 creator_id[4]; /* Vendor ID of utility creator of the table */
- UINT32 creator_revision; /* Revision of utility creator of the table */
-};
-
-struct RSDP_TABLE {
- CHAR8 signature[8]; /* "RSD PTR " */
- CHAR8 checksum; /* RSDP Checksum (bytes 0-19) */
- CHAR8 oem_id[6]; /* OEM ID String */
- CHAR8 revision; /* ACPI Revision (0=1.0,2=2.0) */
- UINT32 rsdt_address; /* 32-bit RSDT Pointer */
- UINT32 length; /* RSDP Length */
- UINT64 xsdt_address; /* 64-bit XSDT Pointer */
- CHAR8 extended_checksum; /* RSDP Checksum (full) */
- CHAR8 reserved[3]; /* Reserved */
-};
-
-struct RSDT_TABLE {
- struct ACPI_DESC_HEADER header; /* System Description Table Header */
- UINT32 entry[1]; /* Table Entries */
-};
-
-struct RSCI_TABLE {
- struct ACPI_DESC_HEADER header; /* System Description Table Header */
- CHAR8 wake_source; /* How system woken up from S4 or S5 */
- CHAR8 reset_source; /* How system was reset */
- CHAR8 reset_type; /* Identify type of reset */
- CHAR8 shutdown_source; /* How system was last shutdown */
- UINT32 indicators; /* Bitmap with additional info */
-};
-
-EFI_STATUS get_acpi_table(CHAR8 *signature, VOID **table);
-
-enum wake_sources rsci_get_wake_source(void);
-
-#endif /* __ACPI_H__ */
diff --git a/android.c b/android.c
deleted file mode 100644
index 9d7d0ce9..00000000
--- a/android.c
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (c) 2013, Intel Corporation
- * All rights reserved.
- *
- * Author: Andrew Boie
- * Some Linux bootstrapping code adapted from efilinux by
- * Matt Fleming
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-#include
-#include
-
-#include "kernelflinger.h"
-#include "acpi.h"
-#include "android.h"
-#include "efilinux.h"
-#include "lib.h"
-#include "security.h"
-
-EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
-
-EFI_GUID FASTBOOT_GUID = { 0x1ac80a82, 0x4f0c, 0x456b, {0x9a, 0x99, 0xde, 0xbe, 0xb4, 0x31, 0xfc, 0xc1} };
-#define SERIAL_PORT_VAR L"SerialPort"
-
-struct setup_header {
- UINT8 setup_secs; /* Sectors for setup code */
- UINT16 root_flags;
- UINT32 sys_size;
- UINT16 ram_size;
- UINT16 video_mode;
- UINT16 root_dev;
- UINT16 signature; /* Boot signature */
- UINT16 jump;
- UINT32 header;
- UINT16 version;
- UINT16 su_switch;
- UINT16 setup_seg;
- UINT16 start_sys;
- UINT16 kernel_ver;
- UINT8 loader_id;
- UINT8 load_flags;
- UINT16 movesize;
- UINT32 code32_start; /* Start of code loaded high */
- UINT32 ramdisk_start; /* Start of initial ramdisk */
- UINT32 ramdisk_len; /* Lenght of initial ramdisk */
- UINT32 bootsect_kludge;
- UINT16 heap_end;
- UINT8 ext_loader_ver; /* Extended boot loader version */
- UINT8 ext_loader_type; /* Extended boot loader ID */
- UINT32 cmd_line_ptr; /* 32-bit pointer to the kernel command line */
- UINT32 ramdisk_max; /* Highest legal initrd address */
- UINT32 kernel_alignment; /* Physical addr alignment required for kernel */
- UINT8 relocatable_kernel; /* Whether kernel is relocatable or not */
- UINT8 min_alignment;
- UINT16 xloadflags;
- UINT32 cmdline_size;
- UINT32 hardware_subarch;
- UINT64 hardware_subarch_data;
- UINT32 payload_offset;
- UINT32 payload_length;
- UINT64 setup_data;
- UINT64 pref_address;
- UINT32 init_size;
- UINT32 handover_offset;
-} __attribute__((packed));
-
-struct efi_info {
- UINT32 efi_loader_signature;
- UINT32 efi_systab;
- UINT32 efi_memdesc_size;
- UINT32 efi_memdesc_version;
- UINT32 efi_memmap;
- UINT32 efi_memmap_size;
- UINT32 efi_systab_hi;
- UINT32 efi_memmap_hi;
-};
-
-struct e820_entry {
- UINT64 addr; /* start of memory segment */
- UINT64 size; /* size of memory segment */
- UINT32 type; /* type of memory segment */
-} __attribute__((packed));
-
-struct screen_info {
- UINT8 orig_x; /* 0x00 */
- UINT8 orig_y; /* 0x01 */
- UINT16 ext_mem_k; /* 0x02 */
- UINT16 orig_video_page; /* 0x04 */
- UINT8 orig_video_mode; /* 0x06 */
- UINT8 orig_video_cols; /* 0x07 */
- UINT8 flags; /* 0x08 */
- UINT8 unused2; /* 0x09 */
- UINT16 orig_video_ega_bx;/* 0x0a */
- UINT16 unused3; /* 0x0c */
- UINT8 orig_video_lines; /* 0x0e */
- UINT8 orig_video_isVGA; /* 0x0f */
- UINT16 orig_video_points;/* 0x10 */
-
- /* VESA graphic mode -- linear frame buffer */
- UINT16 lfb_width; /* 0x12 */
- UINT16 lfb_height; /* 0x14 */
- UINT16 lfb_depth; /* 0x16 */
- UINT32 lfb_base; /* 0x18 */
- UINT32 lfb_size; /* 0x1c */
- UINT16 cl_magic, cl_offset; /* 0x20 */
- UINT16 lfb_linelength; /* 0x24 */
- UINT8 red_size; /* 0x26 */
- UINT8 red_pos; /* 0x27 */
- UINT8 green_size; /* 0x28 */
- UINT8 green_pos; /* 0x29 */
- UINT8 blue_size; /* 0x2a */
- UINT8 blue_pos; /* 0x2b */
- UINT8 rsvd_size; /* 0x2c */
- UINT8 rsvd_pos; /* 0x2d */
- UINT16 vesapm_seg; /* 0x2e */
- UINT16 vesapm_off; /* 0x30 */
- UINT16 pages; /* 0x32 */
- UINT16 vesa_attributes; /* 0x34 */
- UINT32 capabilities; /* 0x36 */
- UINT8 _reserved[6]; /* 0x3a */
-} __attribute__((packed));
-
-struct boot_params {
- struct screen_info screen_info;
- UINT8 apm_bios_info[0x14];
- UINT8 _pad2[4];
- UINT64 tboot_addr;
- UINT8 ist_info[0x10];
- UINT8 _pad3[16];
- UINT8 hd0_info[16];
- UINT8 hd1_info[16];
- UINT8 sys_desc_table[0x10];
- UINT8 olpc_ofw_header[0x10];
- UINT8 _pad4[128];
- UINT8 edid_info[0x80];
- struct efi_info efi_info;
- UINT32 alt_mem_k;
- UINT32 scratch;
- UINT8 e820_entries;
- UINT8 eddbuf_entries;
- UINT8 edd_mbr_sig_buf_entries;
- UINT8 _pad6[6];
- struct setup_header hdr;
- UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
- UINT32 edd_mbr_sig_buffer[16];
- struct e820_entry e820_map[128];
- UINT8 _pad8[48];
- UINT8 eddbuf[0x1ec];
- UINT8 _pad9[276];
-};
-
-typedef void(*handover_func)(void *, EFI_SYSTEM_TABLE *, struct boot_params *) \
- __attribute__((regparm(0)));
-
-static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
- EFI_PHYSICAL_ADDRESS kernel_start)
-{
- UINTN offset = bp->hdr.handover_offset;
- handover_func hf;
-
- asm volatile ("cli");
-
-#if __LP64__
- /* The 64-bit kernel entry is 512 bytes after the start. */
- kernel_start += 512;
-#endif
-
- hf = (handover_func)((UINTN)kernel_start + offset);
- hf(image, ST, bp);
-}
-
-
-static VOID error(CHAR16 *str, EFI_STATUS ret)
-{
- Print(L"ERROR %s: %r\n", str, ret);
- uefi_call_wrapper(BS->Stall, 1, 2 * 1000 * 1000);
-}
-
-
-
-static UINT32 pagealign(struct boot_img_hdr *hdr, UINT32 blob_size)
-{
- UINT32 page_mask = hdr->page_size - 1;
- return (blob_size + page_mask) & (~page_mask);
-}
-
-
-UINTN bootimage_size(struct boot_img_hdr *aosp_header)
-{
- UINTN size;
-
- size = pagealign(aosp_header, aosp_header->kernel_size) +
- pagealign(aosp_header, aosp_header->ramdisk_size) +
- pagealign(aosp_header, aosp_header->second_size) +
- aosp_header->page_size;
-
- return size;
-}
-
-
-struct boot_img_hdr *get_bootimage_header(VOID *bootimage_blob)
-{
- struct boot_img_hdr *hdr;
-
- if (!bootimage_blob)
- return NULL;
-
- hdr = (struct boot_img_hdr *)bootimage_blob;
- if (strncmpa((CHAR8 *)BOOT_MAGIC, hdr->magic, BOOT_MAGIC_SIZE))
- return NULL;
- return hdr;
-}
-
-
-static EFI_STATUS setup_ramdisk(UINT8 *bootimage)
-{
- struct boot_img_hdr *aosp_header;
- struct boot_params *bp;
- UINT32 roffset, rsize;
- EFI_PHYSICAL_ADDRESS ramdisk_addr;
- EFI_STATUS ret;
-
- aosp_header = (struct boot_img_hdr *)bootimage;
- bp = (struct boot_params *)(bootimage + aosp_header->page_size);
-
- roffset = aosp_header->page_size + pagealign(aosp_header,
- aosp_header->kernel_size);
- rsize = aosp_header->ramdisk_size;
- if (!rsize) {
- debug("boot image has no ramdisk");
- return EFI_SUCCESS; // no ramdisk, so nothing to do
- }
-
- /* FIXME Crashes here with GCC 4.7 in some cases, why? */
- bp->hdr.ramdisk_len = rsize;
- debug("ramdisk size %d", rsize);
- ret = emalloc(rsize, 0x1000, &ramdisk_addr);
- if (EFI_ERROR(ret))
- return ret;
-
- if ((UINTN)ramdisk_addr > bp->hdr.ramdisk_max) {
- Print(L"Ramdisk address is too high!\n");
- efree(ramdisk_addr, rsize);
- return EFI_OUT_OF_RESOURCES;
- }
- memcpy((VOID *)(UINTN)ramdisk_addr, bootimage + roffset, rsize);
- bp->hdr.ramdisk_start = (UINT32)(UINTN)ramdisk_addr;
- return EFI_SUCCESS;
-}
-
-
-static BOOLEAN get_charge_mode(void)
-{
- enum wake_sources wake_source;
-
- wake_source = rsci_get_wake_source();
- if ((wake_source == WAKE_USB_CHARGER_INSERTED) ||
- (wake_source == WAKE_ACDC_CHARGER_INSERTED))
- return TRUE;
-
- return FALSE;
-}
-
-
-static CHAR16 *get_serial_number(void)
-{
- /* Per Android CDD, the value must be 7-bit ASCII and
- * match the regex ^[a-zA-Z0-9](0,20)$ */
- CHAR8 *tmp, *pos;
- CHAR16 *ret;
- CHAR8 *serialno;
- EFI_GUID guid;
- UINTN len;
-
- if (EFI_ERROR(LibGetSmbiosSystemGuidAndSerialNumber(&guid,
- &serialno)))
- return NULL;
-
- len = strlena(serialno);
- tmp = AllocatePool(len + 1);
- if (!tmp)
- return NULL;
- tmp[len] = '\0';
- memcpy(tmp, serialno, strlena(serialno));
-
- pos = tmp;
- while (*pos) {
- /* Truncate if greater than 20 chars */
- if ((pos - tmp) >= 20) {
- *pos = '\0';
- break;
- }
- /* Replace foreign characters with zeroes */
- if (!((*pos >= '0' && *pos <= '9') ||
- (*pos >= 'a' && *pos <= 'z') ||
- (*pos >= 'A' && *pos <= 'Z')))
- *pos = '0';
- pos++;
- }
- ret = stra_to_str(tmp);
- FreePool(tmp);
- return ret;
-}
-
-
-static CHAR16 *get_serial_port(void)
-{
- CHAR16 *val, *pos;
-
- val = get_efi_variable_str(&fastboot_guid, SERIAL_PORT_VAR);
- if (!val)
- return NULL;
-
- pos = val;
-
- /* Only [0-9a-zA-Z,] acceptable. Any funny business, return NULL */
- while (*pos) {
- if ( ! ( (*pos >= L'0' && *pos <= L'9') ||
- (*pos >= L'a' && *pos <= L'z') ||
- (*pos >= L'A' && *pos <= L'Z') ||
- *pos == L',')) {
- FreePool(val);
- return NULL;
- }
- pos++;
- }
- return val;
-}
-
-
-static EFI_STATUS setup_command_line(
- IN UINT8 *bootimage,
- BOOLEAN enable_charger,
- IN EFI_GUID *swap_guid)
-{
- CHAR16 *cmdline16 = NULL;
- CHAR16 *serialno;
- CHAR16 *tmp;
- CHAR16 *serialport;
-
- EFI_PHYSICAL_ADDRESS cmdline_addr;
- CHAR8 *full_cmdline;
- CHAR8 *cmdline;
- UINTN cmdlen;
- EFI_STATUS ret;
- struct boot_img_hdr *aosp_header;
- struct boot_params *buf;
-
- aosp_header = (struct boot_img_hdr *)bootimage;
- buf = (struct boot_params *)(bootimage + aosp_header->page_size);
-
- full_cmdline = AllocatePool(BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE);
- if (!full_cmdline) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- memcpy(full_cmdline, aosp_header->cmdline, (BOOT_ARGS_SIZE - 1));
- if (aosp_header->cmdline[BOOT_ARGS_SIZE - 2]) {
- memcpy(full_cmdline + (BOOT_ARGS_SIZE - 1),
- aosp_header->extra_cmdline,
- BOOT_EXTRA_ARGS_SIZE);
- }
- cmdline16 = stra_to_str(full_cmdline);
- if (!cmdline16) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
-
- /* Append serial number from DMI */
- serialno = get_serial_number();
- if (serialno) {
- tmp = cmdline16;
- cmdline16 = PoolPrint(L"androidboot.serialno=%s g_ffs.iSerialNumber=%s %s",
- serialno, serialno, cmdline16);
- FreePool(tmp);
- FreePool(serialno);
- if (!cmdline16) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- }
-
- if (enable_charger && get_charge_mode()) {
- tmp = cmdline16;
- cmdline16 = PoolPrint(L"androidboot.mode=charger %s", cmdline16);
-
- FreePool(tmp);
- if (!cmdline16) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- }
-
- if (swap_guid) {
- tmp = cmdline16;
- cmdline16 = PoolPrint(L"resume=PARTUUID=%g %s",
- swap_guid, cmdline16);
- FreePool(tmp);
- if (!cmdline16) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- }
-
- serialport = get_serial_port();
- if (serialport) {
- tmp = cmdline16;
- cmdline16 = PoolPrint(L"console=%s %s",
- serialport, cmdline16);
- FreePool(serialport);
- FreePool(tmp);
- if (!cmdline16) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- }
-
- /* Documentation/x86/boot.txt: "The kernel command line can be located
- * anywhere between the end of the setup heap and 0xA0000" */
- cmdline_addr = 0xA0000;
- cmdlen = StrLen(cmdline16);
- ret = allocate_pages(AllocateMaxAddress, EfiLoaderData,
- EFI_SIZE_TO_PAGES(cmdlen + 1),
- &cmdline_addr);
- if (EFI_ERROR(ret))
- goto out;
-
- cmdline = (CHAR8 *)(UINTN)cmdline_addr;
- ret = str_to_stra(cmdline, cmdline16, cmdlen + 1);
- if (EFI_ERROR(ret)) {
- Print(L"Non-ascii characters in command line\n");
- free_pages(cmdline_addr, EFI_SIZE_TO_PAGES(cmdlen + 1));
- goto out;
- }
-
- buf->hdr.cmd_line_ptr = (UINT32)(UINTN)cmdline;
- ret = EFI_SUCCESS;
-out:
- FreePool(cmdline16);
- FreePool(full_cmdline);
-
- return ret;
-}
-
-
-static EFI_STATUS handover_kernel(CHAR8 *bootimage, EFI_HANDLE parent_image)
-{
- EFI_PHYSICAL_ADDRESS kernel_start;
- EFI_PHYSICAL_ADDRESS boot_addr;
- struct boot_params *boot_params;
- UINT64 init_size;
- EFI_STATUS ret;
- struct boot_img_hdr *aosp_header;
- struct boot_params *buf;
- UINT8 setup_sectors;
- UINT32 setup_size;
- UINT32 ksize;
- UINT32 koffset;
-
- aosp_header = (struct boot_img_hdr *)bootimage;
- buf = (struct boot_params *)(bootimage + aosp_header->page_size);
-
- koffset = aosp_header->page_size;
- setup_sectors = buf->hdr.setup_secs;
- setup_sectors++; /* Add boot sector */
- setup_size = (UINT32)setup_sectors * 512;
- ksize = aosp_header->kernel_size - setup_size;
- kernel_start = buf->hdr.pref_address;
- init_size = buf->hdr.init_size;
- buf->hdr.loader_id = 0x1;
- /* FIXME why does this crash with GCC 4.7? */
- memset(&buf->screen_info, 0x0, sizeof(buf->screen_info));
-
- ret = allocate_pages(AllocateAddress, EfiLoaderData,
- EFI_SIZE_TO_PAGES(init_size), &kernel_start);
- if (EFI_ERROR(ret)) {
- /*
- * We failed to allocate the preferred address, so
- * just allocate some memory and hope for the best.
- */
- ret = emalloc(init_size, buf->hdr.kernel_alignment, &kernel_start);
- if (EFI_ERROR(ret))
- return ret;
- }
-
- memcpy((CHAR8 *)(UINTN)kernel_start, bootimage + koffset + setup_size, ksize);
-
- boot_addr = 0x3fffffff;
- ret = allocate_pages(AllocateMaxAddress, EfiLoaderData,
- EFI_SIZE_TO_PAGES(16384), &boot_addr);
- if (EFI_ERROR(ret))
- goto out;
-
- boot_params = (struct boot_params *)(UINTN)boot_addr;
- /* FIXME why does this crash with GCC 4.7? */
- memset(boot_params, 0x0, 16384);
-
- /* Copy first two sectors to boot_params */
- memcpy(boot_params, (CHAR8 *)buf, 2 * 512);
- boot_params->hdr.code32_start = (UINT32)((UINT64)kernel_start);
-
- ret = EFI_LOAD_ERROR;
- handover_jump(parent_image, boot_params, kernel_start);
- /* Shouldn't get here */
-
- free_pages(boot_addr, EFI_SIZE_TO_PAGES(16384));
-out:
- efree(kernel_start, ksize);
- return ret;
-}
-
-
-static UINT32 swap_bytes32(UINT32 n)
-{
- return ((n & 0x000000FF) << 24) |
- ((n & 0x0000FF00) << 8 ) |
- ((n & 0x00FF0000) >> 8 ) |
- ((n & 0xFF000000) >> 24);
-}
-
-
-static UINT16 swap_bytes16(UINT16 n)
-{
- return ((n & 0x00FF) << 8) | ((n & 0xFF00) >> 8);
-}
-
-
-static void copy_and_swap_guid(EFI_GUID *dst, const EFI_GUID *src)
-{
- memcpy((CHAR8 *)&dst->Data4, (CHAR8 *)src->Data4, sizeof(src->Data4));
- dst->Data1 = swap_bytes32(src->Data1);
- dst->Data2 = swap_bytes16(src->Data2);
- dst->Data3 = swap_bytes16(src->Data3);
-}
-
-
-static EFI_STATUS open_partition(
- IN const EFI_GUID *guid,
- OUT UINT32 *MediaIdPtr,
- OUT EFI_BLOCK_IO **BlockIoPtr,
- OUT EFI_DISK_IO **DiskIoPtr)
-{
- EFI_STATUS ret;
- EFI_BLOCK_IO *BlockIo;
- EFI_DISK_IO *DiskIo;
- UINT32 MediaId;
- UINTN NoHandles = 0;
- EFI_HANDLE *HandleBuffer = NULL;
-
- /* Get a handle on the partition containing the boot image */
- ret = LibLocateHandleByDiskSignature(
- MBR_TYPE_EFI_PARTITION_TABLE_HEADER,
- SIGNATURE_TYPE_GUID,
- (void *)guid,
- &NoHandles,
- &HandleBuffer);
- if (EFI_ERROR(ret) || NoHandles == 0) {
- /* Workaround for old installers which incorrectly wrote
- * GUIDs strings as little-endian */
- EFI_GUID g;
- copy_and_swap_guid(&g, guid);
- ret = LibLocateHandleByDiskSignature(
- MBR_TYPE_EFI_PARTITION_TABLE_HEADER,
- SIGNATURE_TYPE_GUID,
- (void *)&g,
- &NoHandles,
- &HandleBuffer);
- if (EFI_ERROR(ret)) {
- error(L"LibLocateHandle", ret);
- return ret;
- }
- }
- if (NoHandles != 1) {
- Print(L"%d handles found for GUID, expecting 1: %g\n",
- NoHandles, guid);
- ret = EFI_VOLUME_CORRUPTED;
- goto out;
- }
-
- /* Call to connect to the controller. Don't check for errors
- * as it will report error if the controller is already
- * connected (when not booted in 'fast boot' mode */
- ret = uefi_call_wrapper(BS->ConnectController, 4, HandleBuffer[0],
- NULL, NULL, TRUE);
-
- /* Instantiate BlockIO and DiskIO protocols so we can read various data */
- ret = uefi_call_wrapper(BS->HandleProtocol, 3, HandleBuffer[0],
- &BlockIoProtocol,
- (void **)&BlockIo);
- if (EFI_ERROR(ret)) {
- error(L"HandleProtocol (BlockIoProtocol)", ret);
- goto out;;
- }
- ret = uefi_call_wrapper(BS->HandleProtocol, 3, HandleBuffer[0],
- &DiskIoProtocol, (void **)&DiskIo);
- if (EFI_ERROR(ret)) {
- error(L"HandleProtocol (DiskIoProtocol)", ret);
- goto out;
- }
- MediaId = BlockIo->Media->MediaId;
-
- *MediaIdPtr = MediaId;
- *BlockIoPtr = BlockIo;
- *DiskIoPtr = DiskIo;
-out:
- FreePool(HandleBuffer);
- return ret;
-}
-
-
-EFI_STATUS android_image_load_partition(
- IN const EFI_GUID *guid,
- OUT VOID **bootimage_p)
-{
- EFI_BLOCK_IO *BlockIo;
- EFI_DISK_IO *DiskIo;
- UINT32 MediaId;
- UINT32 img_size;
- VOID *bootimage;
- EFI_STATUS ret;
- struct boot_img_hdr aosp_header;
-
- debug("Locating boot image");
- ret = open_partition(guid, &MediaId, &BlockIo, &DiskIo);
- if (EFI_ERROR(ret))
- return ret;
-
- debug("Reading boot image header");
- ret = uefi_call_wrapper(DiskIo->ReadDisk, 5, DiskIo, MediaId, 0,
- sizeof(aosp_header), &aosp_header);
- if (EFI_ERROR(ret)) {
- error(L"ReadDisk (header)", ret);
- return ret;
- }
- if (strncmpa((CHAR8 *)BOOT_MAGIC, aosp_header.magic, BOOT_MAGIC_SIZE)) {
- Print(L"This partition does not appear to contain an Android boot image\n");
- return EFI_INVALID_PARAMETER;
- }
-
- img_size = bootimage_size(&aosp_header) + BOOT_SIGNATURE_MAX_SIZE;
- bootimage = AllocatePool(img_size);
- if (!bootimage)
- return EFI_OUT_OF_RESOURCES;
-
- debug("Reading full boot image (%d bytes)", img_size);
- ret = uefi_call_wrapper(DiskIo->ReadDisk, 5, DiskIo, MediaId, 0,
- img_size, bootimage);
- if (EFI_ERROR(ret)) {
- error(L"ReadDisk", ret);
- FreePool(bootimage);
- return ret;
- }
-
- *bootimage_p = bootimage;
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS android_image_load_file(
- IN EFI_HANDLE device,
- IN CHAR16 *loader,
- IN BOOLEAN delete,
- OUT VOID **bootimage_p)
-{
- EFI_STATUS ret, ret2;
- VOID *bootimage = NULL;
- EFI_DEVICE_PATH *path;
- EFI_GUID SimpleFileSystemProtocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
- EFI_GUID EfiFileInfoId = EFI_FILE_INFO_ID;
- EFI_FILE_IO_INTERFACE *drive;
- EFI_FILE_INFO *fileinfo = NULL;
- EFI_FILE *imagefile, *root;
- UINTN buffersize = sizeof(EFI_FILE_INFO);
- struct boot_img_hdr *aosp_header;
-
- debug("Locating boot image from file %s", loader);
- path = FileDevicePath(device, loader);
- if (!path) {
- Print(L"Error getting device path.");
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return EFI_INVALID_PARAMETER;
- }
-
- /* Open the device */
- ret = uefi_call_wrapper(BS->HandleProtocol, 3, device,
- &SimpleFileSystemProtocol, (void **)&drive);
- if (EFI_ERROR(ret)) {
- error(L"HandleProtocol", ret);
- return ret;
- }
- ret = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
- if (EFI_ERROR(ret)) {
- error(L"OpenVolume", ret);
- return ret;
- }
-
- /* Get information about the boot image file, we need to know
- * how big it is, and allocate a suitable buffer */
- ret = uefi_call_wrapper(root->Open, 5, root, &imagefile, loader,
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
- if (EFI_ERROR(ret)) {
- error(L"Open", ret);
- return ret;
- }
- fileinfo = AllocatePool(buffersize);
- if (!fileinfo)
- return EFI_OUT_OF_RESOURCES;
-
- ret = uefi_call_wrapper(imagefile->GetInfo, 4, imagefile,
- &EfiFileInfoId, &buffersize, fileinfo);
- if (ret == EFI_BUFFER_TOO_SMALL) {
- /* buffersize updated with the required space for
- * the request */
- FreePool(fileinfo);
- fileinfo = AllocatePool(buffersize);
- if (!fileinfo)
- return EFI_OUT_OF_RESOURCES;
- ret = uefi_call_wrapper(imagefile->GetInfo, 4, imagefile,
- &EfiFileInfoId, &buffersize, fileinfo);
- }
- if (EFI_ERROR(ret)) {
- error(L"GetInfo", ret);
- goto out;
- }
- buffersize = fileinfo->FileSize;
-
- /* Add BOOT_SIGNATURE_MAX_SIZE just in case the image is unsigned */
- bootimage = AllocatePool(buffersize) + BOOT_SIGNATURE_MAX_SIZE;
- if (!bootimage) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
-
- /* Read the file into the buffer */
- ret = uefi_call_wrapper(imagefile->Read, 3, imagefile,
- &buffersize, bootimage);
- if (ret == EFI_BUFFER_TOO_SMALL) {
- /* buffersize updated with the required space for
- * the request. By the way it doesn't make any
- * sense to me why this is needed since we supposedly
- * got the file size from the GetInfo call but
- * whatever... */
- FreePool(bootimage);
- bootimage = AllocatePool(buffersize);
- if (!fileinfo) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- ret = uefi_call_wrapper(imagefile->Read, 3, imagefile,
- &buffersize, bootimage);
- }
- if (EFI_ERROR(ret)) {
- error(L"Read", ret);
- goto out;
- }
-
- debug("Read boot image from file (%d bytes)", buffersize);
-
- aosp_header = (struct boot_img_hdr *)bootimage;
- if (strncmpa((CHAR8 *)BOOT_MAGIC, aosp_header->magic, BOOT_MAGIC_SIZE)) {
- Print(L"File does not appear to contain an Android boot image\n");
- ret = EFI_INVALID_PARAMETER;
- }
-out:
- if (delete) {
- //this should close handle and flush FS
- ret2 = uefi_call_wrapper(imagefile->Delete, 1, imagefile);
- if (EFI_ERROR(ret2)) {
- error(L"Couldn't delete source file", ret2);
- goto out_free;
- }
- } else {
- ret2 = uefi_call_wrapper(imagefile->Close, 1, imagefile);
- if (EFI_ERROR(ret2)) {
- error(L"Couldn't close source file", ret2);
- goto out_free;
- }
- }
-
-out_free:
- FreePool(fileinfo);
- if (ret == EFI_SUCCESS) {
- *bootimage_p = bootimage;
- } else {
- FreePool(bootimage);
- }
- return ret;
-}
-
-
-EFI_STATUS android_image_start_buffer(
- IN EFI_HANDLE parent_image,
- IN VOID *bootimage,
- IN BOOLEAN enable_charger,
- IN EFI_GUID *swap_guid)
-{
- struct boot_img_hdr *aosp_header;
- struct boot_params *buf;
- EFI_STATUS ret;
-
- if (!bootimage)
- return EFI_INVALID_PARAMETER;
-
- aosp_header = (struct boot_img_hdr *)bootimage;
- if (strncmpa((CHAR8 *)BOOT_MAGIC, aosp_header->magic, BOOT_MAGIC_SIZE)) {
- Print(L"buffer does not appear to contain an Android boot image\n");
- return EFI_INVALID_PARAMETER;
- }
-
- buf = (struct boot_params *)(bootimage + aosp_header->page_size);
-
- /* Check boot sector signature */
- if (buf->hdr.signature != 0xAA55) {
- Print(L"bzImage kernel corrupt\n");
- return EFI_INVALID_PARAMETER;
- }
-
- if (buf->hdr.header != SETUP_HDR) {
- Print(L"Setup code version is invalid\n");
- return EFI_INVALID_PARAMETER;
- }
-
- if (buf->hdr.version < 0x20c) {
- /* Protocol 2.12, kernel 3.8 required */
- Print(L"Kernel header version %x too old\n", buf->hdr.version);
- return EFI_INVALID_PARAMETER;
- }
-
-#if __LP64__
- if (!(buf->hdr.xloadflags & XLF_EFI_HANDOVER_64)) {
- Print(L"This kernel does not support 64-bit EFI Handover protocol\n");
-#else
- if (!(buf->hdr.xloadflags & XLF_EFI_HANDOVER_32)) {
- Print(L"This kernel does not support 32-bit EFI Handover protocol\n");
-#endif
- return EFI_INVALID_PARAMETER;
- }
-
- if (!buf->hdr.relocatable_kernel) {
- Print(L"Expected relocatable kernel\n");
- return EFI_INVALID_PARAMETER;
- }
-
- debug("Creating command line");
- ret = setup_command_line(bootimage, enable_charger, swap_guid);
- if (EFI_ERROR(ret)) {
- error(L"setup_command_line", ret);
- return ret;
- }
-
- debug("Loading the ramdisk");
- ret = setup_ramdisk(bootimage);
- if (EFI_ERROR(ret)) {
- error(L"setup_ramdisk", ret);
- goto out_cmdline;
- }
-
- debug("Loading the kernel");
- ret = handover_kernel(bootimage, parent_image);
- error(L"handover_kernel", ret);
-
- efree(buf->hdr.ramdisk_start, buf->hdr.ramdisk_len);
- buf->hdr.ramdisk_start = 0;
- buf->hdr.ramdisk_len = 0;
-out_cmdline:
- free_pages(buf->hdr.cmd_line_ptr,
- strlena((CHAR8 *)(UINTN)buf->hdr.cmd_line_ptr) + 1);
- buf->hdr.cmd_line_ptr = 0;
- return ret;
-}
-
-
-#if DEBUG_MESSAGES
-VOID dump_bcb(IN struct bootloader_message *bcb)
-{
- CHAR16 *cmd16, *stat16;
-
- cmd16 = stra_to_str(bcb->command);
- stat16 = stra_to_str(bcb->status);
- if (cmd16 && stat16)
- debug("BCB: cmd '%s' status '%s'",
- cmd16, stat16);
- FreePool(cmd16);
- FreePool(stat16);
-}
-#else
-#define dump_bcb(b) (void)0
-#endif
-
-EFI_STATUS read_bcb(
- IN const EFI_GUID *bcb_guid,
- OUT struct bootloader_message *bcb)
-{
- EFI_STATUS ret;
- EFI_BLOCK_IO *BlockIo;
- EFI_DISK_IO *DiskIo;
- UINT32 MediaId;
-
- debug("Locating BCB");
- ret = open_partition(bcb_guid, &MediaId, &BlockIo, &DiskIo);
- if (EFI_ERROR(ret))
- return EFI_INVALID_PARAMETER;
-
- debug("Reading BCB");
- ret = uefi_call_wrapper(DiskIo->ReadDisk, 5, DiskIo, MediaId, 0,
- sizeof(*bcb), bcb);
- if (EFI_ERROR(ret)) {
- error(L"ReadDisk (bcb)", ret);
- return ret;
- }
- bcb->command[31] = '\0';
- bcb->status[31] = '\0';
- dump_bcb(bcb);
-
- return EFI_SUCCESS;
-}
-
-
-
-EFI_STATUS write_bcb(
- IN const EFI_GUID *bcb_guid,
- IN struct bootloader_message *bcb)
-{
- EFI_STATUS ret;
- EFI_BLOCK_IO *BlockIo;
- EFI_DISK_IO *DiskIo;
- UINT32 MediaId;
-
- debug("Locating BCB");
- ret = open_partition(bcb_guid, &MediaId, &BlockIo, &DiskIo);
- if (EFI_ERROR(ret))
- return EFI_INVALID_PARAMETER;
-
- debug("Writing BCB");
- ret = uefi_call_wrapper(DiskIo->WriteDisk, 5, DiskIo, MediaId, 0,
- sizeof(*bcb), bcb);
- if (EFI_ERROR(ret)) {
- error(L"WriteDisk (bcb)", ret);
- return ret;
- }
- dump_bcb(bcb);
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS android_clear_memory()
-{
- UINTN nr_entries, key, entry_sz;
- CHAR8 *mem_entries;
- UINT32 entry_ver;
- UINTN i;
- UINTN counter;
- CHAR8 *mem_map;
-
- mem_entries = (CHAR8 *)LibMemoryMap(&nr_entries, &key, &entry_sz, &entry_ver);
- if (!mem_entries)
- return EFI_OUT_OF_RESOURCES;
-
- counter = 0;
- mem_map = mem_entries;
- for (i = 0; i < nr_entries; mem_entries += entry_sz, i++) {
- EFI_MEMORY_DESCRIPTOR *entry;
- UINT64 map_sz;
-
- entry = (EFI_MEMORY_DESCRIPTOR *)mem_entries;
- map_sz = entry->NumberOfPages * EFI_PAGE_SIZE;
-
- if (entry->Type == EfiConventionalMemory) {
- ZeroMem((void *) (UINTN)entry->PhysicalStart, map_sz);
- counter += entry->NumberOfPages;
- }
- }
-
- FreePool((void *)mem_map);
- return EFI_SUCCESS;
-}
-
-/* vim: softtabstop=8:shiftwidth=8:expandtab
- */
diff --git a/android.h b/android.h
deleted file mode 100644
index a9cccc25..00000000
--- a/android.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GUMMIBOOT_ANDROID_H
-
-#include "efi.h"
-#include "efilib.h"
-
-#define BOOT_MAGIC "ANDROID!"
-#define BOOT_MAGIC_SIZE 8
-#define BOOT_NAME_SIZE 16
-#define BOOT_ARGS_SIZE 512
-#define BOOT_EXTRA_ARGS_SIZE 1024
-
-struct boot_img_hdr
-{
- unsigned char magic[BOOT_MAGIC_SIZE];
-
- unsigned kernel_size; /* size in bytes */
- unsigned kernel_addr; /* physical load addr */
-
- unsigned ramdisk_size; /* size in bytes */
- unsigned ramdisk_addr; /* physical load addr */
-
- unsigned second_size; /* size in bytes */
- unsigned second_addr; /* physical load addr */
-
- unsigned tags_addr; /* physical addr for kernel tags */
- unsigned page_size; /* flash page size we assume */
- unsigned unused[2]; /* future expansion: should be 0 */
-
- unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-
- unsigned char cmdline[BOOT_ARGS_SIZE];
-
- unsigned id[8]; /* timestamp / checksum / sha1 / etc */
-
- /* Supplemental command line data; kept here to maintain
- * binary compatibility with older versions of mkbootimg */
- unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
-};
-
-/*
-** +-----------------+
-** | boot header | 1 page
-** +-----------------+
-** | kernel | n pages
-** +-----------------+
-** | ramdisk | m pages
-** +-----------------+
-** | second stage | o pages
-** +-----------------+
-**
-** n = (kernel_size + page_size - 1) / page_size
-** m = (ramdisk_size + page_size - 1) / page_size
-** o = (second_size + page_size - 1) / page_size
-**
-** 0. all entities are page_size aligned in flash
-** 1. kernel and ramdisk are required (size != 0)
-** 2. second is optional (second_size == 0 -> no second)
-** 3. load each element (kernel, ramdisk, second) at
-** the specified physical address (kernel_addr, etc)
-** 4. prepare tags at tag_addr. kernel_args[] is
-** appended to the kernel commandline in the tags.
-** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
-** 6. if second_size != 0: jump to second_addr
-** else: jump to kernel_addr
-*/
-
-
-/* Bootloader Message
- *
- * This structure describes the content of a block in flash
- * that is used for recovery and the bootloader to talk to
- * each other.
- *
- * The command field is updated by linux when it wants to
- * reboot into recovery or to update radio or bootloader firmware.
- * It is also updated by the bootloader when firmware update
- * is complete (to boot into recovery for any final cleanup)
- *
- * The status field is written by the bootloader after the
- * completion of an "update-radio" or "update-hboot" command.
- *
- * The recovery field is only written by linux and used
- * for the system to send a message to recovery or the
- * other way around.
- */
-struct bootloader_message {
- CHAR8 command[32];
- CHAR8 status[32];
- CHAR8 recovery[1024];
-};
-
-/* Functions to load an Android boot image.
- * You can do this from a file, a partition GUID, or
- * from a RAM buffer */
-EFI_STATUS android_image_start_buffer(
- IN EFI_HANDLE parent_image,
- IN VOID *bootimage,
- IN BOOLEAN enable_charger,
- IN EFI_GUID *swap);
-
-EFI_STATUS android_image_load_partition(
- IN const EFI_GUID *guid,
- OUT VOID **bootimage_p);
-
-EFI_STATUS android_image_load_file(
- IN EFI_HANDLE device,
- IN CHAR16 *loader,
- IN BOOLEAN delete,
- OUT VOID **bootimage_p);
-
-EFI_STATUS read_bcb(
- IN const EFI_GUID *bcb_guid,
- OUT struct bootloader_message *bcb);
-
-EFI_STATUS write_bcb(
- IN const EFI_GUID *bcb_guid,
- IN struct bootloader_message *bcb);
-
-/* Perform a security RAM wipe */
-EFI_STATUS android_clear_memory(void);
-
-/* Sanity check the data and return a pointer to the header.
- * Return NULL if the sanity check fails */
-struct boot_img_hdr *get_bootimage_header(VOID *bootimage_blob);
-
-/* Return the size of a boot image, DOES NOT include any signature
- * block */
-UINTN bootimage_size(struct boot_img_hdr *aosp_header);
-
-#endif
-
-/* vim: softtabstop=8:shiftwidth=8:expandtab
- */
diff --git a/avb/Android.mk b/avb/Android.mk
new file mode 100644
index 00000000..b79a0864
--- /dev/null
+++ b/avb/Android.mk
@@ -0,0 +1,130 @@
+#
+# Copyright 2016, The Android Open Source Project
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+LOCAL_PATH := $(my-dir)
+
+avb_common_cflags := \
+ -D_FILE_OFFSET_BITS=64 \
+ -D_POSIX_C_SOURCE=199309L \
+ -Wa,--noexecstack \
+ -Wall \
+ -Wextra \
+ -Wformat=2 \
+ -Wno-psabi \
+ -Wno-unused-parameter \
+ -ffunction-sections \
+ -fstack-protector-strong \
+ -std=c99
+avb_common_cppflags := \
+ -Wnon-virtual-dtor \
+ -fno-strict-aliasing
+avb_common_ldflags := \
+ -Wl,--gc-sections
+
+
+# Build libavb for the target (for e.g. fs_mgr usage).
+include $(CLEAR_VARS)
+LOCAL_MODULE := libavb_kernelflinger-$(TARGET_BUILD_VARIANT)
+LOCAL_MODULE_HOST_OS := linux
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+#LOCAL_CLANG := true
+LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_COMPILATION -DUSE_AVB -Wno-error
+
+ifneq ($(KERNELFLINGER_DISABLE_DEBUG_PRINT),true)
+ LOCAL_CFLAGS += -DAVB_ENABLE_DEBUG
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB),true)
+ LOCAL_CFLAGS += -DRPMB_STORAGE
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB_SIMULATE),true)
+ LOCAL_CFLAGS += -DRPMB_STORAGE -DRPMB_SIMULATE
+endif
+
+ifeq ($(KERNELFLINGER_USE_RPMB_SIMULATE),true)
+ LOCAL_CFLAGS += -DSECURE_STORAGE_EFIVAR
+else # KERNELFLINGER_USE_RPMB_SIMULATE == false
+ifeq ($(KERNELFLINGER_USE_RPMB),true)
+ LOCAL_CFLAGS += -DSECURE_STORAGE_RPMB
+else # KERNELFLINGER_USE_RPMB == false
+ LOCAL_CFLAGS += -DSECURE_STORAGE_EFIVAR
+endif # KERNELFLINGER_USE_RPMB
+endif # KERNELFLINGER_USE_RPMB_SIMULATE
+
+LOCAL_LDFLAGS := $(avb_common_ldflags)
+LOCAL_STATIC_LIBRARIES := \
+ $(KERNELFLINGER_STATIC_LIBRARIES) \
+ libefiusb-$(TARGET_BUILD_VARIANT) \
+ libefitcp-$(TARGET_BUILD_VARIANT) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libkernelflinger-$(TARGET_BUILD_VARIANT)
+
+ifeq ($(KERNELFLINGER_USE_IPP_SHA256),true)
+ LOCAL_CFLAGS += -DUSE_IPP_SHA256
+ LOCAL_CFLAGS += -msse4 -msha
+endif
+ifneq ($(strip $(KERNELFLINGER_USE_UI)),false)
+ LOCAL_CFLAGS += -DUSE_UI
+endif
+
+LOCAL_SRC_FILES := \
+ libavb/avb_chain_partition_descriptor.c \
+ libavb/avb_crc32.c \
+ libavb/avb_crypto.c \
+ libavb/avb_cmdline.c \
+ libavb/avb_descriptor.c \
+ libavb/avb_footer.c \
+ libavb/avb_hash_descriptor.c \
+ libavb/avb_hashtree_descriptor.c \
+ libavb/avb_kernel_cmdline_descriptor.c \
+ libavb/avb_property_descriptor.c \
+ libavb/avb_rsa.c \
+ libavb/avb_sha512.c \
+ libavb/avb_slot_verify.c \
+ libavb/uefi_avb_sysdeps.c \
+ libavb/uefi_avb_ops.c \
+ libavb/uefi_avb_util.c \
+ libavb/avb_util.c \
+ libavb/avb_vbmeta_image.c \
+ libavb_ab/avb_ab_flow.c
+
+ifeq ($(BUILD_ANDROID_THINGS),true)
+LOCAL_SRC_FILES += \
+ libavb_atx/avb_atx_validate.c
+endif
+
+ifeq ($(KERNELFLINGER_USE_IPP_SHA256),true)
+LOCAL_SRC_FILES += \
+ libavb/avb_sha256_ipps.c
+else
+LOCAL_SRC_FILES += \
+ libavb/avb_sha256.c
+endif
+
+LOCAL_C_INCLUDES := \
+ $(addprefix $(LOCAL_PATH)/,../libkernelflinger)
+
+include $(BUILD_EFI_STATIC_LIBRARY)
+
diff --git a/avb/libavb/avb_chain_partition_descriptor.c b/avb/libavb/avb_chain_partition_descriptor.c
new file mode 100644
index 00000000..3f142325
--- /dev/null
+++ b/avb/libavb/avb_chain_partition_descriptor.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_chain_partition_descriptor.h b/avb/libavb/avb_chain_partition_descriptor.h
new file mode 100644
index 00000000..f2c92501
--- /dev/null
+++ b/avb/libavb/avb_chain_partition_descriptor.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_cmdline.c b/avb/libavb/avb_cmdline.c
new file mode 100644
index 00000000..426f909a
--- /dev/null
+++ b/avb/libavb/avb_cmdline.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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: {
+ AvbSHA256Ctx ctx;
+ size_t n, total_size = 0;
+ avb_sha256_init(&ctx);
+ for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+ avb_sha256_update(&ctx,
+ slot_data->vbmeta_images[n].vbmeta_data,
+ slot_data->vbmeta_images[n].vbmeta_size);
+ 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",
+ avb_sha256_final(&ctx),
+ 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: {
+ AvbSHA512Ctx ctx;
+ size_t n, total_size = 0;
+ avb_sha512_init(&ctx);
+ for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+ avb_sha512_update(&ctx,
+ slot_data->vbmeta_images[n].vbmeta_data,
+ slot_data->vbmeta_images[n].vbmeta_size);
+ 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",
+ avb_sha512_final(&ctx),
+ 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/avb/libavb/avb_cmdline.h b/avb/libavb/avb_cmdline.h
new file mode 100644
index 00000000..996535d0
--- /dev/null
+++ b/avb/libavb/avb_cmdline.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_crc32.c b/avb/libavb/avb_crc32.c
new file mode 100644
index 00000000..7d4cb090
--- /dev/null
+++ b/avb/libavb/avb_crc32.c
@@ -0,0 +1,114 @@
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/*
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ *
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include "avb_sysdeps.h"
+#include "avb_util.h"
+
+/* Code taken from FreeBSD 8 */
+
+static uint32_t iavb_crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+/*
+ * A function that calculates the CRC-32 based on the table above is
+ * given below for documentation purposes. An equivalent implementation
+ * of this function that's actually used in the kernel can be found
+ * in sys/libkern.h, where it can be inlined.
+ */
+
+static uint32_t iavb_crc32(uint32_t crc_in, const uint8_t* buf, int size) {
+ const uint8_t* p = buf;
+ uint32_t crc;
+
+ crc = crc_in ^ ~0U;
+ while (size--)
+ crc = iavb_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ return crc ^ ~0U;
+}
+
+uint32_t avb_crc32(const uint8_t* buf, size_t size) {
+ return iavb_crc32(0, buf, size);
+}
diff --git a/avb/libavb/avb_crypto.c b/avb/libavb/avb_crypto.c
new file mode 100755
index 00000000..a99ff80d
--- /dev/null
+++ b/avb/libavb/avb_crypto.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_crypto.h b/avb/libavb/avb_crypto.h
new file mode 100755
index 00000000..0903baa8
--- /dev/null
+++ b/avb/libavb/avb_crypto.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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
+
+/* 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/avb/libavb/avb_descriptor.c b/avb/libavb/avb_descriptor.c
new file mode 100644
index 00000000..4f8e9253
--- /dev/null
+++ b/avb/libavb/avb_descriptor.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_descriptor.h b/avb/libavb/avb_descriptor.h
new file mode 100644
index 00000000..5d0f0c69
--- /dev/null
+++ b/avb/libavb/avb_descriptor.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_footer.c b/avb/libavb/avb_footer.c
new file mode 100644
index 00000000..b8b82115
--- /dev/null
+++ b/avb/libavb/avb_footer.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_footer.h b/avb/libavb/avb_footer.h
new file mode 100644
index 00000000..e84826fa
--- /dev/null
+++ b/avb/libavb/avb_footer.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_hash_descriptor.c b/avb/libavb/avb_hash_descriptor.c
new file mode 100755
index 00000000..3a6b8c88
--- /dev/null
+++ b/avb/libavb/avb_hash_descriptor.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_hash_descriptor.h b/avb/libavb/avb_hash_descriptor.h
new file mode 100755
index 00000000..9ee89971
--- /dev/null
+++ b/avb/libavb/avb_hash_descriptor.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_hashtree_descriptor.c b/avb/libavb/avb_hashtree_descriptor.c
new file mode 100755
index 00000000..0822458f
--- /dev/null
+++ b/avb/libavb/avb_hashtree_descriptor.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_hashtree_descriptor.h b/avb/libavb/avb_hashtree_descriptor.h
new file mode 100755
index 00000000..d0f7e2c2
--- /dev/null
+++ b/avb/libavb/avb_hashtree_descriptor.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_kernel_cmdline_descriptor.c b/avb/libavb/avb_kernel_cmdline_descriptor.c
new file mode 100644
index 00000000..67521f23
--- /dev/null
+++ b/avb/libavb/avb_kernel_cmdline_descriptor.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_kernel_cmdline_descriptor.h b/avb/libavb/avb_kernel_cmdline_descriptor.h
new file mode 100644
index 00000000..6908b3b1
--- /dev/null
+++ b/avb/libavb/avb_kernel_cmdline_descriptor.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_ops.h b/avb/libavb/avb_ops.h
new file mode 100755
index 00000000..77f7ec3c
--- /dev/null
+++ b/avb/libavb/avb_ops.h
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_property_descriptor.c b/avb/libavb/avb_property_descriptor.c
new file mode 100644
index 00000000..7eba2c00
--- /dev/null
+++ b/avb/libavb/avb_property_descriptor.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_property_descriptor.h b/avb/libavb/avb_property_descriptor.h
new file mode 100644
index 00000000..a2fef696
--- /dev/null
+++ b/avb/libavb/avb_property_descriptor.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_rsa.c b/avb/libavb/avb_rsa.c
new file mode 100644
index 00000000..f4cb322b
--- /dev/null
+++ b/avb/libavb/avb_rsa.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* 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.
+ */
+
+/* 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/avb/libavb/avb_rsa.h b/avb/libavb/avb_rsa.h
new file mode 100644
index 00000000..c2dcf471
--- /dev/null
+++ b/avb/libavb/avb_rsa.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* 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/avb/libavb/avb_sha.h b/avb/libavb/avb_sha.h
new file mode 100755
index 00000000..abad7969
--- /dev/null
+++ b/avb/libavb/avb_sha.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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. */
+#ifdef USE_IPP_SHA256
+typedef struct __attribute__((aligned (16))){
+ 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;
+#else
+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;
+#endif
+
+/* 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/avb/libavb/avb_sha256.c b/avb/libavb/avb_sha256.c
new file mode 100644
index 00000000..cdd143a9
--- /dev/null
+++ b/avb/libavb/avb_sha256.c
@@ -0,0 +1,390 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#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/avb/libavb/avb_sha256_ipps.c b/avb/libavb/avb_sha256_ipps.c
new file mode 100755
index 00000000..8fff49d8
--- /dev/null
+++ b/avb/libavb/avb_sha256_ipps.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+
+#include "avb_sha.h"
+
+#define SHA256_BLOCK_SIZE 64
+#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); \
+ }
+
+static void sha256_update(uint32_t *digest, const uint8_t *data, uint32_t num_blks)
+{
+ __m128i state0, state1;
+ __m128i msg;
+ __m128i msgtmp0, msgtmp1, msgtmp2, msgtmp3;
+ __m128i tmp;
+ __m128i shuf_mask;
+ __m128i abef_save, cdgh_save;
+
+ /* Load initial hash values */
+ /* Need to reorder these appropriately */
+ /* DCBA, HGFE -> ABEF, CDGH */
+ tmp = _mm_loadu_si128((__m128i *) digest);
+ state1 = _mm_loadu_si128((__m128i *) (digest + 4));
+
+ tmp = _mm_shuffle_epi32(tmp, 0xB1); /* CDAB */
+ state1 = _mm_shuffle_epi32(state1, 0x1B); /* EFGH */
+ state0 = _mm_alignr_epi8(tmp, state1, 8); /* ABEF */
+ state1 = _mm_blend_epi16(state1, tmp, 0xF0); /* CDGH */
+
+ shuf_mask = _mm_set_epi64x(0x0c0d0e0f08090a0bull, 0x0405060700010203ull);
+
+ while (num_blks > 0) {
+ /* Save hash values for addition after rounds */
+ abef_save = state0;
+ cdgh_save = state1;
+
+ /* Rounds 0-3 */
+ msg = _mm_loadu_si128((__m128i *) data);
+ msgtmp0 = _mm_shuffle_epi8(msg, shuf_mask);
+ msg = _mm_add_epi32(msgtmp0,
+ _mm_set_epi64x(0xE9B5DBA5B5C0FBCFull, 0x71374491428A2F98ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+
+ /* Rounds 4-7 */
+ msgtmp1 = _mm_loadu_si128((__m128i *) ((uint8_t *)data + 16));
+ msgtmp1 = _mm_shuffle_epi8(msgtmp1, shuf_mask);
+ msg = _mm_add_epi32(msgtmp1,
+ _mm_set_epi64x(0xAB1C5ED5923F82A4ull, 0x59F111F13956C25Bull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp0 = _mm_sha256msg1_epu32(msgtmp0, msgtmp1);
+
+ /* Rounds 8-11 */
+ msgtmp2 = _mm_loadu_si128((__m128i *) ((uint8_t *)data + 32));
+ msgtmp2 = _mm_shuffle_epi8(msgtmp2, shuf_mask);
+ msg = _mm_add_epi32(msgtmp2,
+ _mm_set_epi64x(0x550C7DC3243185BEull, 0x12835B01D807AA98ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp1 = _mm_sha256msg1_epu32(msgtmp1, msgtmp2);
+
+ /* Rounds 12-15 */
+ msgtmp3 = _mm_loadu_si128((__m128i *) ((uint8_t *)data + 48));
+ msgtmp3 = _mm_shuffle_epi8(msgtmp3, shuf_mask);
+ msg = _mm_add_epi32(msgtmp3,
+ _mm_set_epi64x(0xC19BF1749BDC06A7ull, 0x80DEB1FE72BE5D74ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp3, msgtmp2, 4);
+ msgtmp0 = _mm_add_epi32(msgtmp0, tmp);
+ msgtmp0 = _mm_sha256msg2_epu32(msgtmp0, msgtmp3);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp2 = _mm_sha256msg1_epu32(msgtmp2, msgtmp3);
+
+ /* Rounds 16-19 */
+ msg = _mm_add_epi32(msgtmp0,
+ _mm_set_epi64x(0x240CA1CC0FC19DC6ull, 0xEFBE4786E49B69C1ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp0, msgtmp3, 4);
+ msgtmp1 = _mm_add_epi32(msgtmp1, tmp);
+ msgtmp1 = _mm_sha256msg2_epu32(msgtmp1, msgtmp0);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp3 = _mm_sha256msg1_epu32(msgtmp3, msgtmp0);
+
+ /* Rounds 20-23 */
+ msg = _mm_add_epi32(msgtmp1,
+ _mm_set_epi64x(0x76F988DA5CB0A9DCull, 0x4A7484AA2DE92C6Full));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp1, msgtmp0, 4);
+ msgtmp2 = _mm_add_epi32(msgtmp2, tmp);
+ msgtmp2 = _mm_sha256msg2_epu32(msgtmp2, msgtmp1);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp0 = _mm_sha256msg1_epu32(msgtmp0, msgtmp1);
+
+ /* Rounds 24-27 */
+ msg = _mm_add_epi32(msgtmp2,
+ _mm_set_epi64x(0xBF597FC7B00327C8ull, 0xA831C66D983E5152ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp2, msgtmp1, 4);
+ msgtmp3 = _mm_add_epi32(msgtmp3, tmp);
+ msgtmp3 = _mm_sha256msg2_epu32(msgtmp3, msgtmp2);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp1 = _mm_sha256msg1_epu32(msgtmp1, msgtmp2);
+
+ /* Rounds 28-31 */
+ msg = _mm_add_epi32(msgtmp3,
+ _mm_set_epi64x(0x1429296706CA6351ull, 0xD5A79147C6E00BF3ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp3, msgtmp2, 4);
+ msgtmp0 = _mm_add_epi32(msgtmp0, tmp);
+ msgtmp0 = _mm_sha256msg2_epu32(msgtmp0, msgtmp3);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp2 = _mm_sha256msg1_epu32(msgtmp2, msgtmp3);
+
+ /* Rounds 32-35 */
+ msg = _mm_add_epi32(msgtmp0,
+ _mm_set_epi64x(0x53380D134D2C6DFCull, 0x2E1B213827B70A85ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp0, msgtmp3, 4);
+ msgtmp1 = _mm_add_epi32(msgtmp1, tmp);
+ msgtmp1 = _mm_sha256msg2_epu32(msgtmp1, msgtmp0);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp3 = _mm_sha256msg1_epu32(msgtmp3, msgtmp0);
+
+ /* Rounds 36-39 */
+ msg = _mm_add_epi32(msgtmp1,
+ _mm_set_epi64x(0x92722C8581C2C92Eull, 0x766A0ABB650A7354ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp1, msgtmp0, 4);
+ msgtmp2 = _mm_add_epi32(msgtmp2, tmp);
+ msgtmp2 = _mm_sha256msg2_epu32(msgtmp2, msgtmp1);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp0 = _mm_sha256msg1_epu32(msgtmp0, msgtmp1);
+
+ /* Rounds 40-43 */
+ msg = _mm_add_epi32(msgtmp2,
+ _mm_set_epi64x(0xC76C51A3C24B8B70ull, 0xA81A664BA2BFE8A1ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp2, msgtmp1, 4);
+ msgtmp3 = _mm_add_epi32(msgtmp3, tmp);
+ msgtmp3 = _mm_sha256msg2_epu32(msgtmp3, msgtmp2);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp1 = _mm_sha256msg1_epu32(msgtmp1, msgtmp2);
+
+ /* Rounds 44-47 */
+ msg = _mm_add_epi32(msgtmp3,
+ _mm_set_epi64x(0x106AA070F40E3585ull, 0xD6990624D192E819ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp3, msgtmp2, 4);
+ msgtmp0 = _mm_add_epi32(msgtmp0, tmp);
+ msgtmp0 = _mm_sha256msg2_epu32(msgtmp0, msgtmp3);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp2 = _mm_sha256msg1_epu32(msgtmp2, msgtmp3);
+
+ /* Rounds 48-51 */
+ msg = _mm_add_epi32(msgtmp0,
+ _mm_set_epi64x(0x34B0BCB52748774Cull, 0x1E376C0819A4C116ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp0, msgtmp3, 4);
+ msgtmp1 = _mm_add_epi32(msgtmp1, tmp);
+ msgtmp1 = _mm_sha256msg2_epu32(msgtmp1, msgtmp0);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+ msgtmp3 = _mm_sha256msg1_epu32(msgtmp3, msgtmp0);
+
+ /* Rounds 52-55 */
+ msg = _mm_add_epi32(msgtmp1,
+ _mm_set_epi64x(0x682E6FF35B9CCA4Full, 0x4ED8AA4A391C0CB3ull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp1, msgtmp0, 4);
+ msgtmp2 = _mm_add_epi32(msgtmp2, tmp);
+ msgtmp2 = _mm_sha256msg2_epu32(msgtmp2, msgtmp1);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+
+ /* Rounds 56-59 */
+ msg = _mm_add_epi32(msgtmp2,
+ _mm_set_epi64x(0x8CC7020884C87814ull, 0x78A5636F748F82EEull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ tmp = _mm_alignr_epi8(msgtmp2, msgtmp1, 4);
+ msgtmp3 = _mm_add_epi32(msgtmp3, tmp);
+ msgtmp3 = _mm_sha256msg2_epu32(msgtmp3, msgtmp2);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+
+ /* Rounds 60-63 */
+ msg = _mm_add_epi32(msgtmp3,
+ _mm_set_epi64x(0xC67178F2BEF9A3F7ull, 0xA4506CEB90BEFFFAull));
+ state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
+ msg = _mm_shuffle_epi32(msg, 0x0E);
+ state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
+
+ /* Add current hash values with previously saved */
+ state0 = _mm_add_epi32(state0, abef_save);
+ state1 = _mm_add_epi32(state1, cdgh_save);
+
+ data += 64;
+ num_blks--;
+ }
+
+ /* Write hash values back in the correct order */
+ tmp = _mm_shuffle_epi32(state0, 0x1B); /* FEBA */
+ state1 = _mm_shuffle_epi32(state1, 0xB1); /* DCHG */
+ state0 = _mm_blend_epi16(tmp, state1, 0xF0); /* DCBA */
+ state1 = _mm_alignr_epi8(state1, tmp, 8); /* ABEF */
+
+ _mm_store_si128((__m128i *)digest, state0);
+ _mm_store_si128((__m128i *)(digest + 4), state1);
+}
+
+
+void avb_sha256_init(AvbSHA256Ctx* ctx)
+{
+ ctx->len = 0;
+
+ ctx->h[0] = 0x6A09E667UL;
+ ctx->h[1] = 0xBB67AE85UL;
+ ctx->h[2] = 0x3C6EF372UL;
+ ctx->h[3] = 0xA54FF53AUL;
+ ctx->h[4] = 0x510E527FUL;
+ ctx->h[5] = 0x9B05688CUL;
+ ctx->h[6] = 0x1F83D9ABUL;
+ ctx->h[7] = 0x5BE0CD19UL;
+}
+
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* buf, uint32_t size)
+{
+ uint32_t i;
+ uint32_t num;
+ uint32_t blocks;
+ uint32_t *digest = ctx->h;
+ uint8_t *data = (uint8_t *)ctx->block;
+ uint32_t kn = ctx->len % SHA256_BLOCK_SIZE;
+
+ ctx->len += size;
+ if (size + kn < SHA256_BLOCK_SIZE) {
+ for (i = 0; i < size; i++)
+ data[kn + i] = buf[i];
+
+ return;
+ }
+
+ if (kn != 0) {
+ num = SHA256_BLOCK_SIZE - kn;
+ for (i = 0; i < num; i++)
+ data[kn + i] = buf[i];
+
+ sha256_update(digest, data, 1);
+ buf += num;
+ size -= num;
+ }
+
+ blocks = size/SHA256_BLOCK_SIZE;
+ if (blocks > 0)
+ sha256_update(digest, buf, blocks);
+
+ num = size - blocks * SHA256_BLOCK_SIZE;
+ for (i = 0; i < num; i++)
+ data[i] = buf[i + blocks * SHA256_BLOCK_SIZE];
+}
+
+uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx)
+{
+ uint32_t i;
+ uint32_t len;
+ uint8_t buffer[SHA256_BLOCK_SIZE * 2];
+ uint8_t *p8bits;
+ uint8_t *data = (uint8_t *)ctx->block;
+ uint32_t *digest = ctx->h;
+ uint64_t u64bits = (uint64_t)ctx->len * 8;
+ uint32_t kn = ctx->len % SHA256_BLOCK_SIZE;
+
+ len = kn < (int)(SHA256_BLOCK_SIZE-8) ? SHA256_BLOCK_SIZE : SHA256_BLOCK_SIZE * 2;
+
+ /* copy end of message */
+ for (i = 0; i < kn; i++)
+ buffer[i] = data[i];
+
+ /* end of message bit */
+ buffer[kn++] = 0x80;
+
+ for (i = kn; i < len - 8; i++)
+ buffer[i] = 0x00;
+
+ p8bits = (uint8_t *)(&u64bits);
+ for (i = 0; i < 8; i++)
+ buffer[i + len - 8] = p8bits[7 - i];
+
+ sha256_update(digest, buffer, len / SHA256_BLOCK_SIZE);
+
+ for (i = 0; i < 8; i++)
+ UNPACK32(digest[i], &ctx->buf[i << 2]);
+
+ return ctx->buf;
+}
+
+
diff --git a/avb/libavb/avb_sha512.c b/avb/libavb/avb_sha512.c
new file mode 100644
index 00000000..8df63193
--- /dev/null
+++ b/avb/libavb/avb_sha512.c
@@ -0,0 +1,388 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#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/avb/libavb/avb_slot_verify.c b/avb/libavb/avb_slot_verify.c
new file mode 100755
index 00000000..3e6b04c1
--- /dev/null
+++ b/avb/libavb/avb_slot_verify.c
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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: + ' ' + + '\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;
+}
diff --git a/avb/libavb/avb_slot_verify.h b/avb/libavb/avb_slot_verify.h
new file mode 100755
index 00000000..78e7dcc2
--- /dev/null
+++ b/avb/libavb/avb_slot_verify.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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;
+
+/* 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/avb/libavb/avb_sysdeps.h b/avb/libavb/avb_sysdeps.h
new file mode 100755
index 00000000..6a562ef9
--- /dev/null
+++ b/avb/libavb/avb_sysdeps.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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
+#include
+#include
+#include
+
+/* 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;
+
+#ifdef USE_UI
+/* Prints out a message in UI. The string passed must be a NUL-terminated
+ * UTF-8 string.
+ */
+void avb_print_ui(const char* message);
+
+/* Prints out a vector of strings in UI. Each argument must point to a
+ * NUL-terminated UTF-8 string and NULL should be the last argument.
+ */
+void avb_printv_ui(const char* message, ...) AVB_ATTR_SENTINEL;
+#endif
+
+/* 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/avb/libavb/avb_sysdeps_posix.c b/avb/libavb/avb_sysdeps_posix.c
new file mode 100755
index 00000000..0cbabee0
--- /dev/null
+++ b/avb/libavb/avb_sysdeps_posix.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#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);
+}
+
+void avb_abort(void) {
+ abort();
+}
+
+void avb_print(const char* message) {
+ fprintf(stderr, "%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*)) {
+ fprintf(stderr, "%s", m);
+ }
+ va_end(ap);
+}
+
+void* avb_malloc_(size_t size) {
+ return malloc(size);
+}
+
+void avb_free(void* ptr) {
+ free(ptr);
+}
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+ uint32_t rem = (uint32_t)(*dividend % 10);
+ *dividend /= 10;
+ return rem;
+}
diff --git a/avb/libavb/avb_util.c b/avb/libavb/avb_util.c
new file mode 100755
index 00000000..c04c79ae
--- /dev/null
+++ b/avb/libavb/avb_util.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_util.h"
+
+#include
+
+uint32_t avb_be32toh(uint32_t in) {
+ uint8_t* d = (uint8_t*)∈
+ 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*)∈
+ 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/avb/libavb/avb_util.h b/avb/libavb/avb_util.h
new file mode 100755
index 00000000..a5cbbd46
--- /dev/null
+++ b/avb/libavb/avb_util.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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"
+#include "lib.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
+
+#ifdef USE_UI
+/* 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); \
+ if (ui_is_ready()) { \
+ avb_printv_ui(message, NULL); \
+ } \
+ } while (0)
+#define avb_errorv(message, ...) \
+ do { \
+ avb_printv(avb_basename(__FILE__), \
+ ":", \
+ AVB_TO_STRING(__LINE__), \
+ ": ERROR: ", \
+ message, \
+ ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ avb_printv_ui(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); \
+ if (ui_is_ready()) { \
+ avb_printv_ui(message, NULL); \
+ } \
+ avb_abort(); \
+ } while (0)
+#define avb_fatalv(message, ...) \
+ do { \
+ avb_printv(avb_basename(__FILE__), \
+ ":", \
+ AVB_TO_STRING(__LINE__), \
+ ": FATAL: ", \
+ message, \
+ ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ avb_printv_ui(message, \
+ ##__VA_ARGS__); \
+ } \
+ avb_abort(); \
+ } while (0)
+#else
+/* 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)
+#endif
+
+/* 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/avb/libavb/avb_vbmeta_image.c b/avb/libavb/avb_vbmeta_image.c
new file mode 100644
index 00000000..21bbf929
--- /dev/null
+++ b/avb/libavb/avb_vbmeta_image.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_vbmeta_image.h b/avb/libavb/avb_vbmeta_image.h
new file mode 100644
index 00000000..d0c9f153
--- /dev/null
+++ b/avb/libavb/avb_vbmeta_image.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_version.c b/avb/libavb/avb_version.c
new file mode 100644
index 00000000..31f5fa6b
--- /dev/null
+++ b/avb/libavb/avb_version.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/avb_version.h b/avb/libavb/avb_version.h
new file mode 100755
index 00000000..ce431360
--- /dev/null
+++ b/avb/libavb/avb_version.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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/avb/libavb/libavb.h b/avb/libavb/libavb.h
new file mode 100644
index 00000000..d5115846
--- /dev/null
+++ b/avb/libavb/libavb.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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_ */
diff --git a/avb/libavb/uefi_avb_ops.c b/avb/libavb/uefi_avb_ops.c
new file mode 100644
index 00000000..505d92c4
--- /dev/null
+++ b/avb/libavb/uefi_avb_ops.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include "uefi_avb_ops.h"
+#include "uefi_avb_util.h"
+#include "vars.h"
+#include "gpt.h"
+#include "lib.h"
+#include "log.h"
+#ifdef RPMB_STORAGE
+#include "rpmb_storage.h"
+#endif
+
+extern char _binary_avb_pk_start;
+extern char _binary_avb_pk_end;
+#define avb_pk (&_binary_avb_pk_start)
+#define avb_pk_size (&_binary_avb_pk_end - &_binary_avb_pk_start)
+
+static AvbIOResult read_from_partition(__attribute__((unused)) AvbOps* ops,
+ const char* partition_name,
+ int64_t offset_from_partition,
+ size_t num_bytes,
+ void* buf,
+ size_t* out_num_read) {
+ EFI_STATUS efi_ret;
+ struct gpt_partition_interface gpart;
+ int64_t partition_size;
+ const CHAR16 *label;
+
+ avb_assert(partition_name != NULL);
+ avb_assert(buf != NULL);
+ avb_assert(out_num_read != NULL);
+
+ label = stra_to_str((const CHAR8 *)partition_name);
+
+ if (!label) {
+ error(L"out of memory");
+ return AVB_IO_RESULT_ERROR_OOM;
+ }
+
+ efi_ret = gpt_get_partition_by_label(label, &gpart, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(efi_ret)) {
+ error(L"Partition %s not found", label);
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+
+ partition_size =
+ (gpart.part.ending_lba - gpart.part.starting_lba + 1) *
+ gpart.bio->Media->BlockSize;
+
+ if (offset_from_partition < 0) {
+ if ((-offset_from_partition) > partition_size) {
+ avb_error("Offset outside range.\n");
+ return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
+ }
+ offset_from_partition = partition_size - (-offset_from_partition);
+ }
+
+ /* Check if num_bytes goes beyond partition end. If so, don't read beyond
+ * this boundary -- do a partial I/O instead.
+ */
+ if (num_bytes > (size_t)(partition_size - offset_from_partition))
+ *out_num_read = partition_size - offset_from_partition;
+ else
+ *out_num_read = num_bytes;
+
+ efi_ret = uefi_call_wrapper(
+ gpart.dio->ReadDisk,
+ 5,
+ gpart.dio,
+ gpart.bio->Media->MediaId,
+ (gpart.part.starting_lba * gpart.bio->Media->BlockSize) +
+ offset_from_partition,
+ *out_num_read,
+ buf);
+ if (EFI_ERROR(efi_ret)) {
+ avb_error("Could not read from Disk.\n");
+ *out_num_read = 0;
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult write_to_partition(__attribute__((unused)) AvbOps* ops,
+ const char* partition_name,
+ int64_t offset_from_partition,
+ size_t num_bytes,
+ const void* buf) {
+ EFI_STATUS efi_ret;
+ struct gpt_partition_interface gpart;
+ uint64_t partition_size;
+ const CHAR16 * label;
+
+ avb_assert(partition_name != NULL);
+ avb_assert(buf != NULL);
+
+ label = stra_to_str((const CHAR8 *)partition_name);
+ if (!label) {
+ error(L"out of memory");
+ return AVB_IO_RESULT_ERROR_OOM;
+ }
+
+ efi_ret = gpt_get_partition_by_label(label, &gpart, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(efi_ret)) {
+ error(L"Partition %s not found", label);
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+
+ partition_size =
+ (gpart.part.ending_lba - gpart.part.starting_lba + 1) *
+ gpart.bio->Media->BlockSize;
+
+ if (offset_from_partition < 0) {
+ if ((-offset_from_partition) > (int)partition_size) {
+ avb_error("Offset outside range.\n");
+ return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
+ }
+ offset_from_partition = partition_size - (-offset_from_partition);
+ }
+
+ /* Check if num_bytes goes beyond partition end. If so, error out -- no
+ * partial I/O.
+ */
+ if (num_bytes > partition_size - offset_from_partition) {
+ avb_error("Cannot write beyond partition boundary.\n");
+ return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
+ }
+
+ efi_ret = uefi_call_wrapper(
+ gpart.dio->WriteDisk,
+ 5,
+ gpart.dio,
+ gpart.bio->Media->MediaId,
+ (gpart.part.starting_lba * gpart.bio->Media->BlockSize) +
+ offset_from_partition,
+ num_bytes,
+ (void *)buf);
+
+ if (EFI_ERROR(efi_ret)) {
+ avb_error("Could not write to Disk.\n");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult get_size_of_partition(__attribute__((unused)) AvbOps* ops,
+ const char* partition_name,
+ uint64_t* out_size) {
+ EFI_STATUS efi_ret;
+ struct gpt_partition_interface gpart;
+ uint64_t partition_size;
+ const CHAR16 * label;
+
+ avb_assert(partition_name != NULL);
+
+ label = stra_to_str((const CHAR8 *)partition_name);
+ if (!label) {
+ error(L"out of memory");
+ return AVB_IO_RESULT_ERROR_OOM;
+ }
+
+ efi_ret = gpt_get_partition_by_label(label, &gpart, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(efi_ret)) {
+ error(L"Partition %s not found", label);
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+
+ partition_size =
+ (gpart.part.ending_lba - gpart.part.starting_lba + 1) *
+ gpart.bio->Media->BlockSize;
+
+ if (out_size != NULL) {
+ *out_size = partition_size;
+ }
+
+ return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult validate_vbmeta_public_key(
+ __attribute__((unused)) AvbOps* ops,
+ const uint8_t* public_key_data,
+ size_t public_key_length,
+ __attribute__((unused)) const uint8_t* public_key_metadata,
+ __attribute__((unused)) size_t public_key_metadata_length,
+ bool* out_key_is_trusted) {
+
+ if (out_key_is_trusted != NULL) {
+ *out_key_is_trusted = false;
+ }
+
+ if ((!public_key_data) || (public_key_length == 0))
+ {
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ if ((public_key_length <= (size_t)avb_pk_size) && !memcmp(avb_pk, public_key_data, public_key_length))
+ {
+ if (out_key_is_trusted != NULL) {
+ *out_key_is_trusted = true;
+ }
+ }
+ return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult read_rollback_index(__attribute__((unused)) AvbOps* ops,
+ size_t rollback_index_slot,
+ uint64_t* out_rollback_index) {
+ EFI_STATUS ret = AVB_IO_RESULT_OK;
+
+ if (out_rollback_index == NULL)
+ return ret;
+
+#if defined(SECURE_STORAGE_EFIVAR)
+ ret = read_efi_rollback_index(rollback_index_slot, out_rollback_index);
+#elif defined(SECURE_STORAGE_RPMB)
+ ret = read_rpmb_rollback_index(rollback_index_slot, out_rollback_index);
+#else
+ *out_rollback_index = 0;
+#endif
+
+ if (ret == EFI_NOT_FOUND) {
+ *out_rollback_index = 0;
+ ret = EFI_SUCCESS;
+ }
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Couldn't read rollback index");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ return ret;
+}
+
+static AvbIOResult write_rollback_index(__attribute__((unused)) AvbOps* ops,
+ size_t rollback_index_slot,
+ uint64_t rollback_index) {
+ EFI_STATUS ret = AVB_IO_RESULT_OK;
+
+ if (rollback_index == 0)
+ return ret;
+
+#if defined(SECURE_STORAGE_EFIVAR)
+ ret = write_efi_rollback_index(rollback_index_slot, rollback_index);
+#elif defined(SECURE_STORAGE_RPMB)
+ ret = write_rpmb_rollback_index(rollback_index_slot, rollback_index);
+#endif
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Couldn't write rollback index");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ return ret;
+}
+
+static AvbIOResult read_is_device_unlocked(__attribute__((unused)) AvbOps* ops, bool* out_is_unlocked) {
+ avb_debug("read_is_device_unlocked().\n");
+ *out_is_unlocked = device_is_unlocked();
+ return AVB_IO_RESULT_OK;
+}
+
+static void set_hex(char* buf, uint8_t value) {
+ char hex_digits[17] = "0123456789abcdef";
+ buf[0] = hex_digits[value >> 4];
+ buf[1] = hex_digits[value & 0x0f];
+}
+
+static AvbIOResult get_unique_guid_for_partition(__attribute__((unused)) AvbOps* ops,
+ const char* partition,
+ char* guid_buf,
+ size_t guid_buf_size) {
+ EFI_STATUS efi_ret;
+ struct gpt_partition_interface gpart;
+ uint8_t * unique_guid;
+ const CHAR16 * label;
+
+
+
+ avb_assert(partition != NULL);
+ avb_assert(guid_buf != NULL);
+
+ label = stra_to_str((const CHAR8 *)partition);
+ if (!label) {
+ error(L"out of memory");
+ return AVB_IO_RESULT_ERROR_OOM;
+ }
+
+ efi_ret = gpt_get_partition_by_label(label, &gpart, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(efi_ret)) {
+ error(L"Partition %s not found", label);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ if (guid_buf_size < 37) {
+ avb_error("GUID buffer size too small.\n");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ unique_guid =(uint8_t *)&(gpart.part.unique);
+ /* The GUID encoding is somewhat peculiar in terms of byte order. It
+ * is what it is.
+ */
+ set_hex(guid_buf + 0, unique_guid[3]);
+ set_hex(guid_buf + 2, unique_guid[2]);
+ set_hex(guid_buf + 4, unique_guid[1]);
+ set_hex(guid_buf + 6, unique_guid[0]);
+ guid_buf[8] = '-';
+ set_hex(guid_buf + 9, unique_guid[5]);
+ set_hex(guid_buf + 11, unique_guid[4]);
+ guid_buf[13] = '-';
+ set_hex(guid_buf + 14, unique_guid[7]);
+ set_hex(guid_buf + 16, unique_guid[6]);
+ guid_buf[18] = '-';
+ set_hex(guid_buf + 19, unique_guid[8]);
+ set_hex(guid_buf + 21, unique_guid[9]);
+ guid_buf[23] = '-';
+ set_hex(guid_buf + 24, unique_guid[10]);
+ set_hex(guid_buf + 26, unique_guid[11]);
+ set_hex(guid_buf + 28, unique_guid[12]);
+ set_hex(guid_buf + 30, unique_guid[13]);
+ set_hex(guid_buf + 32, unique_guid[14]);
+ set_hex(guid_buf + 34, unique_guid[15]);
+ guid_buf[36] = '\0';
+ return AVB_IO_RESULT_OK;
+}
+
+AvbOps* uefi_avb_ops_new(void) {
+ UEFIAvbOpsData* data;
+ EFI_STATUS err;
+ //EFI_LOADED_IMAGE* loaded_app_image = NULL;
+ //EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
+ struct gpt_partition_interface gparti;
+
+ err = gpt_get_root_disk(&gparti, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(err)) {
+ avb_error("Failed to get disk information.\n");
+ return NULL;
+ }
+
+ data = avb_calloc(sizeof(UEFIAvbOpsData));
+ data->ops.user_data = data;
+ data->ops.ab_ops = NULL;
+ data->block_io = gparti.bio;
+ data->disk_io = gparti.dio;
+ data->ops.read_from_partition = read_from_partition;
+ data->ops.write_to_partition = write_to_partition;
+ data->ops.get_size_of_partition = get_size_of_partition;
+ data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
+ data->ops.read_rollback_index = read_rollback_index;
+ data->ops.write_rollback_index = write_rollback_index;
+ data->ops.read_is_device_unlocked = read_is_device_unlocked;
+ data->ops.get_unique_guid_for_partition = get_unique_guid_for_partition;
+
+ return &data->ops;
+}
+
+void uefi_avb_ops_free(AvbOps* ops) {
+ UEFIAvbOpsData* data = ops->user_data;
+ avb_free(data);
+}
diff --git a/avb/libavb/uefi_avb_ops.h b/avb/libavb/uefi_avb_ops.h
new file mode 100644
index 00000000..862d2c8c
--- /dev/null
+++ b/avb/libavb/uefi_avb_ops.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef UEFI_AVB_OPS_H_
+#define UEFI_AVB_OPS_H_
+
+#include
+#include "libavb/libavb.h"
+/* The |user_data| member of AvbOps points to a struct of this type. */
+typedef struct UEFIAvbOpsData {
+ AvbOps ops;
+ //AVbops_AB ops_ab;
+ EFI_BLOCK_IO* block_io;
+ EFI_DISK_IO* disk_io;
+} UEFIAvbOpsData;
+
+/* Returns an AvbOps for use with UEFI. */
+AvbOps* uefi_avb_ops_new(void);
+
+/* Frees the AvbOps allocated with uefi_avb_ops_new(). */
+void uefi_avb_ops_free(AvbOps* ops);
+
+#endif /* UEFI_AVB_OPS_H_ */
diff --git a/avb/libavb/uefi_avb_sysdeps.c b/avb/libavb/uefi_avb_sysdeps.c
new file mode 100644
index 00000000..53077c74
--- /dev/null
+++ b/avb/libavb/uefi_avb_sysdeps.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+
+#include
+
+#include "uefi_avb_util.h"
+#include "lib.h"
+#include "log.h"
+
+int avb_memcmp(const void* src1, const void* src2, size_t n) {
+ return (int)CompareMem((VOID*)src1, (VOID*)src2, (UINTN)n);
+}
+
+int avb_strcmp(const char* s1, const char* s2) {
+ return (int)strcmpa((CHAR8*)s1, (CHAR8*)s2);
+}
+
+void* avb_memcpy(void* dest, const void* src, size_t n) {
+ CopyMem(dest, (VOID*)src, (UINTN)n);
+ return dest;
+}
+
+void* avb_memset(void* dest, const int c, size_t n) {
+ SetMem(dest, (UINTN)n, (UINT8)c);
+ return dest;
+}
+
+void avb_print(const char* message) {
+ CHAR16* p = NULL;
+
+ p = stra_to_str((const CHAR8 *)message);
+ if (p != NULL) {
+ log(L"%s", p);
+ FreePool(p);
+ }
+}
+
+void avb_printv(const char* message, ...) {
+ va_list ap;
+
+ va_start(ap, message);
+ do {
+ avb_print(message);
+ message = va_arg(ap, const char*);
+ } while (message != NULL);
+ va_end(ap);
+}
+
+void avb_abort(void) {
+ avb_print("\nABORTING...\n");
+ uefi_call_wrapper(BS->Stall, 1, 5 * 1000 * 1000);
+ uefi_call_wrapper(BS->Exit, 4, NULL, EFI_NOT_FOUND, 0, NULL);
+ while (true) {
+ ;
+ }
+}
+
+#ifdef USE_UI
+void avb_print_ui(const char* message) {
+ CHAR16* p = stra_to_str(message);
+ if (p != NULL) {
+ ui_error(p);
+ FreePool(p);
+ }
+}
+
+void avb_printv_ui(const char* message, ...) {
+ va_list ap;
+
+ va_start(ap, message);
+ do {
+ avb_print_ui(message);
+ message = va_arg(ap, const char*);
+ } while (message != NULL);
+ va_end(ap);
+}
+#endif
+
+void* avb_malloc_(size_t size) {
+ EFI_STATUS err;
+ void* x;
+
+ err = uefi_call_wrapper(
+ BS->AllocatePool, 3, EfiBootServicesData, (UINTN)size, &x);
+ if (EFI_ERROR(err)) {
+ return NULL;
+ }
+
+ return x;
+}
+
+void avb_free(void* ptr) {
+ EFI_STATUS err;
+ err = uefi_call_wrapper(BS->FreePool, 1, ptr);
+
+ if (EFI_ERROR(err)) {
+ Print(L"Warning: Bad avb_free: %r\n", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ }
+}
+
+size_t avb_strlen(const char* str) {
+ return strlena((CHAR8*)str);
+}
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+ uint32_t rem = (uint32_t)(*dividend % 10);
+ *dividend /= 10;
+ return rem;
+}
diff --git a/avb/libavb/uefi_avb_util.c b/avb/libavb/uefi_avb_util.c
new file mode 100644
index 00000000..1d59af7f
--- /dev/null
+++ b/avb/libavb/uefi_avb_util.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "uefi_avb_util.h"
+
+bool uefi_avb_utf8_to_ucs2(const uint8_t* utf8_data,
+ size_t utf8_num_bytes,
+ uint16_t* ucs2_data,
+ size_t ucs2_data_capacity_num_bytes,
+ size_t* out_ucs2_data_num_bytes) {
+ uint32_t i8 = 0;
+ uint32_t i2 = 0;
+
+ do {
+ if (i2 >= ucs2_data_capacity_num_bytes) {
+ break;
+ }
+
+ // cannot represent this character, too long
+ if ((utf8_data[i8] & 0xF8) == 0xF0) {
+ return false;
+ } else if ((utf8_data[i8] & 0xF0) == 0xE0) {
+ ucs2_data[i2] = (uint16_t)((uint16_t)utf8_data[i8] << 12) |
+ (uint16_t)(((uint16_t)utf8_data[i8 + 1] << 6) & 0x0FC0) |
+ (uint16_t)((uint16_t)utf8_data[i8 + 2] & 0x003F);
+ i8 += 3;
+ } else if ((utf8_data[i8] & 0xE0) == 0XC0) {
+ ucs2_data[i2] = (uint16_t)(((uint16_t)utf8_data[i8] << 6) & 0x07C0) |
+ (uint16_t)((uint16_t)utf8_data[i8 + 1] & 0x003F);
+ i8 += 2;
+ } else if (!(utf8_data[i8] >> 7)) {
+ ucs2_data[i2] = (uint16_t)((uint16_t)utf8_data[i8] & 0x00FF);
+ i8++;
+ } else {
+ // invalid utf-8
+ return false;
+ }
+ i2++;
+ } while (i8 < utf8_num_bytes);
+
+ if (out_ucs2_data_num_bytes != NULL) {
+ *out_ucs2_data_num_bytes = i2 * 2;
+ }
+ return true;
+}
diff --git a/avb/libavb/uefi_avb_util.h b/avb/libavb/uefi_avb_util.h
new file mode 100644
index 00000000..6a705577
--- /dev/null
+++ b/avb/libavb/uefi_avb_util.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+// NOTE: See avb_sysdeps.h
+
+#ifndef UEFI_AVB_UTIL_H_
+#define UEFI_AVB_UTIL_H_
+
+#include
+
+/* Converts UTF-8 to UCS-2. Returns |false| if invalid UTF-8 or if a
+ * rune cannot be represented as UCS-2.
+ */
+bool uefi_avb_utf8_to_ucs2(const uint8_t* utf8_data,
+ size_t utf8_num_bytes,
+ uint16_t* ucs2_data,
+ size_t ucs2_data_capacity_num_bytes,
+ size_t* out_ucs2_data_num_bytes);
+
+#endif /* UEFI_AVB_UTIL_H_ */
diff --git a/avb/libavb_ab/avb_ab_flow.c b/avb/libavb_ab/avb_ab_flow.c
new file mode 100644
index 00000000..bf6eab15
--- /dev/null
+++ b/avb/libavb_ab/avb_ab_flow.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_ab_flow.h"
+
+bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
+ /* Ensure magic is correct. */
+ if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
+ avb_error("Magic is incorrect.\n");
+ return false;
+ }
+
+ avb_memcpy(dest, src, sizeof(AvbABData));
+ dest->crc32 = avb_be32toh(dest->crc32);
+
+ /* Ensure we don't attempt to access any fields if the major version
+ * is not supported.
+ */
+ if (dest->version_major > AVB_AB_MAJOR_VERSION) {
+ avb_error("No support for given major version.\n");
+ return false;
+ }
+
+ /* Bail if CRC32 doesn't match. */
+ if (dest->crc32 !=
+ avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
+ avb_error("CRC32 does not match.\n");
+ return false;
+ }
+
+ return true;
+}
+
+void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
+ AvbABData* dest) {
+ avb_memcpy(dest, src, sizeof(AvbABData));
+ dest->crc32 = avb_htobe32(
+ avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
+}
+
+void avb_ab_data_init(AvbABData* data) {
+ avb_memset(data, '\0', sizeof(AvbABData));
+ avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
+ data->version_major = AVB_AB_MAJOR_VERSION;
+ data->version_minor = AVB_AB_MINOR_VERSION;
+ data->slots[0].priority = AVB_AB_MAX_PRIORITY;
+ data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+ data->slots[0].successful_boot = 0;
+ data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
+ data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+ data->slots[1].successful_boot = 0;
+}
+
+/* The AvbABData struct is stored 2048 bytes into the 'misc' partition
+ * following the 'struct bootloader_message' field. The struct is
+ * compatible with the guidelines in bootable/recovery/bootloader.h -
+ * e.g. it is stored in the |slot_suffix| field, starts with a
+ * NUL-byte, and is 32 bytes long.
+ */
+#define AB_METADATA_MISC_PARTITION_OFFSET 2048
+
+AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
+ AvbOps* ops = ab_ops->ops;
+ AvbABData serialized;
+ AvbIOResult io_ret;
+ size_t num_bytes_read;
+
+ io_ret = ops->read_from_partition(ops,
+ "misc",
+ AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ &serialized,
+ &num_bytes_read);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_IO_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK ||
+ num_bytes_read != sizeof(AvbABData)) {
+ avb_error("Error reading A/B metadata.\n");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
+ avb_error(
+ "Error validating A/B metadata from disk. "
+ "Resetting and writing new A/B metadata to disk.\n");
+ avb_ab_data_init(data);
+ return avb_ab_data_write(ab_ops, data);
+ }
+
+ return AVB_IO_RESULT_OK;
+}
+
+AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
+ AvbOps* ops = ab_ops->ops;
+ AvbABData serialized;
+ AvbIOResult io_ret;
+
+ avb_ab_data_update_crc_and_byteswap(data, &serialized);
+ io_ret = ops->write_to_partition(ops,
+ "misc",
+ AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ &serialized);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_IO_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error writing A/B metadata.\n");
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ return AVB_IO_RESULT_OK;
+}
+
+static bool slot_is_bootable(AvbABSlotData* slot) {
+ return slot->priority > 0 &&
+ (slot->successful_boot || (slot->tries_remaining > 0));
+}
+
+static void slot_set_unbootable(AvbABSlotData* slot) {
+ slot->priority = 0;
+ slot->tries_remaining = 0;
+ slot->successful_boot = 0;
+}
+
+/* Ensure all unbootable and/or illegal states are marked as the
+ * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
+ * and successful_boot=0.
+ */
+static void slot_normalize(AvbABSlotData* slot) {
+ if (slot->priority > 0) {
+ if (slot->tries_remaining == 0 && !slot->successful_boot) {
+ /* We've exhausted all tries -> unbootable. */
+ slot_set_unbootable(slot);
+ }
+ if (slot->tries_remaining > 0 && slot->successful_boot) {
+ /* Illegal state - avb_ab_mark_slot_successful() will clear
+ * tries_remaining when setting successful_boot.
+ */
+ slot_set_unbootable(slot);
+ }
+ } else {
+ slot_set_unbootable(slot);
+ }
+}
+
+static const char* slot_suffixes[2] = {"_a", "_b"};
+
+/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ */
+static AvbIOResult load_metadata(AvbABOps* ab_ops,
+ AvbABData* ab_data,
+ AvbABData* ab_data_orig) {
+ AvbIOResult io_ret;
+
+ io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("I/O error while loading A/B metadata.\n");
+ return io_ret;
+ }
+ *ab_data_orig = *ab_data;
+
+ /* Ensure data is normalized, e.g. illegal states will be marked as
+ * unbootable and all unbootable states are represented with
+ * (priority=0, tries_remaining=0, successful_boot=0).
+ */
+ slot_normalize(&ab_data->slots[0]);
+ slot_normalize(&ab_data->slots[1]);
+ return AVB_IO_RESULT_OK;
+}
+
+/* Writes A/B metadata to disk only if it has changed - returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ */
+static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
+ AvbABData* ab_data,
+ AvbABData* ab_data_orig) {
+ if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
+ avb_debug("Writing A/B metadata to disk.\n");
+ return ab_ops->write_ab_metadata(ab_ops, ab_data);
+ }
+ return AVB_IO_RESULT_OK;
+}
+
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+ const char* const* requested_partitions,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data) {
+ AvbOps* ops = ab_ops->ops;
+ AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
+ AvbSlotVerifyData* data = NULL;
+ AvbABFlowResult ret;
+ AvbABData ab_data, ab_data_orig;
+ size_t slot_index_to_boot, n;
+ AvbIOResult io_ret;
+ bool saw_and_allowed_verification_error = false;
+
+ io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+ goto out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+ goto out;
+ }
+
+ /* Validate all bootable slots. */
+ for (n = 0; n < 2; n++) {
+ if (slot_is_bootable(&ab_data.slots[n])) {
+ AvbSlotVerifyResult verify_result;
+ bool set_slot_unbootable = false;
+
+ verify_result = avb_slot_verify(ops,
+ requested_partitions,
+ slot_suffixes[n],
+ flags,
+ hashtree_error_mode,
+ &slot_data[n]);
+ switch (verify_result) {
+ case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+ ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+ goto out;
+
+ case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+ ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+ goto out;
+
+ case AVB_SLOT_VERIFY_RESULT_OK:
+ break;
+
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+ /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+ * these mean game over.
+ */
+ set_slot_unbootable = true;
+ break;
+
+ /* explicit fallthrough. */
+ case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+ if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) {
+ /* Do nothing since we allow this. */
+ avb_debugv("Allowing slot ",
+ slot_suffixes[n],
+ " which verified "
+ "with result ",
+ avb_slot_verify_result_to_string(verify_result),
+ " because "
+ "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR "
+ "is set.\n",
+ NULL);
+ saw_and_allowed_verification_error = true;
+ } else {
+ set_slot_unbootable = true;
+ }
+ break;
+
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+ ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT;
+ goto out;
+ /* Do not add a 'default:' case here because of -Wswitch. */
+ }
+
+ if (set_slot_unbootable) {
+ avb_errorv("Error verifying slot ",
+ slot_suffixes[n],
+ " with result ",
+ avb_slot_verify_result_to_string(verify_result),
+ " - setting unbootable.\n",
+ NULL);
+ slot_set_unbootable(&ab_data.slots[n]);
+ }
+ }
+ }
+
+ if (slot_is_bootable(&ab_data.slots[0]) &&
+ slot_is_bootable(&ab_data.slots[1])) {
+ if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
+ slot_index_to_boot = 1;
+ } else {
+ slot_index_to_boot = 0;
+ }
+ } else if (slot_is_bootable(&ab_data.slots[0])) {
+ slot_index_to_boot = 0;
+ } else if (slot_is_bootable(&ab_data.slots[1])) {
+ slot_index_to_boot = 1;
+ } else {
+ /* No bootable slots! */
+ avb_error("No bootable slots found.\n");
+ ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
+ goto out;
+ }
+
+ /* Update stored rollback index such that the stored rollback index
+ * is the largest value supporting all currently bootable slots. Do
+ * this for every rollback index location.
+ */
+ for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
+ uint64_t rollback_index_value = 0;
+
+ if (slot_data[0] != NULL && slot_data[1] != NULL) {
+ uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
+ uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
+ rollback_index_value =
+ (a_rollback_index < b_rollback_index ? a_rollback_index
+ : b_rollback_index);
+ } else if (slot_data[0] != NULL) {
+ rollback_index_value = slot_data[0]->rollback_indexes[n];
+ } else if (slot_data[1] != NULL) {
+ rollback_index_value = slot_data[1]->rollback_indexes[n];
+ }
+
+ if (rollback_index_value != 0) {
+ uint64_t current_rollback_index_value;
+ io_ret = ops->read_rollback_index(ops, n, ¤t_rollback_index_value);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+ goto out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error getting rollback index for slot.\n");
+ ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+ goto out;
+ }
+ if (current_rollback_index_value != rollback_index_value) {
+ io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+ goto out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error setting stored rollback index.\n");
+ ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* Finally, select this slot. */
+ avb_assert(slot_data[slot_index_to_boot] != NULL);
+ data = slot_data[slot_index_to_boot];
+ slot_data[slot_index_to_boot] = NULL;
+ if (saw_and_allowed_verification_error) {
+ avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
+ ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
+ } else {
+ ret = AVB_AB_FLOW_RESULT_OK;
+ }
+
+ /* ... and decrement tries remaining, if applicable. */
+ if (!ab_data.slots[slot_index_to_boot].successful_boot &&
+ ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
+ ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
+ }
+
+out:
+ io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+ } else {
+ ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+ }
+ if (data != NULL) {
+ avb_slot_verify_data_free(data);
+ data = NULL;
+ }
+ }
+
+ for (n = 0; n < 2; n++) {
+ if (slot_data[n] != NULL) {
+ avb_slot_verify_data_free(slot_data[n]);
+ }
+ }
+
+ if (out_data != NULL) {
+ *out_data = data;
+ } else {
+ if (data != NULL) {
+ avb_slot_verify_data_free(data);
+ }
+ }
+
+ return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
+ unsigned int slot_number) {
+ AvbABData ab_data, ab_data_orig;
+ unsigned int other_slot_number;
+ AvbIOResult ret;
+
+ avb_assert(slot_number < 2);
+
+ ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+ if (ret != AVB_IO_RESULT_OK) {
+ goto out;
+ }
+
+ /* Make requested slot top priority, unsuccessful, and with max tries. */
+ ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
+ ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+ ab_data.slots[slot_number].successful_boot = 0;
+
+ /* Ensure other slot doesn't have as high a priority. */
+ other_slot_number = 1 - slot_number;
+ if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
+ ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
+ }
+
+ ret = AVB_IO_RESULT_OK;
+
+out:
+ if (ret == AVB_IO_RESULT_OK) {
+ ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+ }
+ return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
+ unsigned int slot_number) {
+ AvbABData ab_data, ab_data_orig;
+ AvbIOResult ret;
+
+ avb_assert(slot_number < 2);
+
+ ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+ if (ret != AVB_IO_RESULT_OK) {
+ goto out;
+ }
+
+ slot_set_unbootable(&ab_data.slots[slot_number]);
+
+ ret = AVB_IO_RESULT_OK;
+
+out:
+ if (ret == AVB_IO_RESULT_OK) {
+ ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+ }
+ return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
+ unsigned int slot_number) {
+ AvbABData ab_data, ab_data_orig;
+ AvbIOResult ret;
+
+ avb_assert(slot_number < 2);
+
+ ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+ if (ret != AVB_IO_RESULT_OK) {
+ goto out;
+ }
+
+ if (!slot_is_bootable(&ab_data.slots[slot_number])) {
+ avb_error("Cannot mark unbootable slot as successful.\n");
+ ret = AVB_IO_RESULT_OK;
+ goto out;
+ }
+
+ ab_data.slots[slot_number].tries_remaining = 0;
+ ab_data.slots[slot_number].successful_boot = 1;
+
+ ret = AVB_IO_RESULT_OK;
+
+out:
+ if (ret == AVB_IO_RESULT_OK) {
+ ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+ }
+ return ret;
+}
+
+const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
+ const char* ret = NULL;
+
+ switch (result) {
+ case AVB_AB_FLOW_RESULT_OK:
+ ret = "OK";
+ break;
+
+ case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
+ ret = "OK_WITH_VERIFICATION_ERROR";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_OOM:
+ ret = "ERROR_OOM";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_IO:
+ ret = "ERROR_IO";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
+ ret = "ERROR_NO_BOOTABLE_SLOTS";
+ break;
+
+ case AVB_AB_FLOW_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 AvbABFlowResult value.\n");
+ ret = "(unknown)";
+ }
+
+ return ret;
+}
diff --git a/avb/libavb_ab/avb_ab_flow.h b/avb/libavb_ab/avb_ab_flow.h
new file mode 100644
index 00000000..588026d5
--- /dev/null
+++ b/avb/libavb_ab/avb_ab_flow.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_AB_H) && !defined(AVB_COMPILATION)
+#error \
+ "Never include this file directly, include libavb_ab/libavb_ab.h instead."
+#endif
+
+#ifndef AVB_AB_FLOW_H_
+#define AVB_AB_FLOW_H_
+
+#include "avb_ab_ops.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Magic for the A/B struct when serialized. */
+#define AVB_AB_MAGIC "\0AB0"
+#define AVB_AB_MAGIC_LEN 4
+
+/* Versioning for the on-disk A/B metadata - keep in sync with avbtool. */
+#define AVB_AB_MAJOR_VERSION 1
+#define AVB_AB_MINOR_VERSION 0
+
+/* Size of AvbABData struct. */
+#define AVB_AB_DATA_SIZE 32
+
+/* Maximum values for slot data */
+#define AVB_AB_MAX_PRIORITY 15
+#define AVB_AB_MAX_TRIES_REMAINING 7
+
+/* Struct used for recording per-slot metadata.
+ *
+ * When serialized, data is stored in network byte-order.
+ */
+typedef struct AvbABSlotData {
+ /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY,
+ * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY
+ * being the highest. The special value 0 is used to indicate the
+ * slot is unbootable.
+ */
+ uint8_t priority;
+
+ /* Number of times left attempting to boot this slot ranging from 0
+ * to AVB_AB_MAX_TRIES_REMAINING.
+ */
+ uint8_t tries_remaining;
+
+ /* Non-zero if this slot has booted successfully, 0 otherwise. */
+ uint8_t successful_boot;
+
+ /* Reserved for future use. */
+ uint8_t reserved[1];
+} AVB_ATTR_PACKED AvbABSlotData;
+
+/* Struct used for recording A/B metadata.
+ *
+ * When serialized, data is stored in network byte-order.
+ */
+typedef struct AvbABData {
+ /* Magic number used for identification - see AVB_AB_MAGIC. */
+ uint8_t magic[AVB_AB_MAGIC_LEN];
+
+ /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */
+ uint8_t version_major;
+ uint8_t version_minor;
+
+ /* Padding to ensure |slots| field start eight bytes in. */
+ uint8_t reserved1[2];
+
+ /* Per-slot metadata. */
+ AvbABSlotData slots[2];
+
+ /* Reserved for future use. */
+ uint8_t reserved2[12];
+
+ /* CRC32 of all 28 bytes preceding this field. */
+ uint32_t crc32;
+} AVB_ATTR_PACKED AvbABData;
+
+/* Copies |src| to |dest|, byte-swapping fields in the
+ * process. Returns false if the data is invalid (e.g. wrong magic,
+ * wrong CRC32 etc.), true otherwise.
+ */
+bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest);
+
+/* Copies |src| to |dest|, byte-swapping fields in the process. Also
+ * updates the |crc32| field in |dest|.
+ */
+void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, AvbABData* dest);
+
+/* Initializes |data| such that it has two slots and both slots have
+ * maximum tries remaining. The CRC is not set.
+ */
+void avb_ab_data_init(AvbABData* data);
+
+/* Reads A/B metadata from the 'misc' partition using |ops|. Returned
+ * data is properly byteswapped. Returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ *
+ * If the data read from disk is invalid (e.g. wrong magic or CRC
+ * checksum failure), the metadata will be reset using
+ * avb_ab_data_init() and then written to disk.
+ */
+AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data);
+
+/* Writes A/B metadata to the 'misc' partition using |ops|. This will
+ * byteswap and update the CRC as needed. Returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ */
+AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data);
+
+/* Return codes used in avb_ab_flow(), see that function for
+ * documentation of each value.
+ */
+typedef enum {
+ AVB_AB_FLOW_RESULT_OK,
+ AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR,
+ AVB_AB_FLOW_RESULT_ERROR_OOM,
+ AVB_AB_FLOW_RESULT_ERROR_IO,
+ AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS,
+ AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT
+} AvbABFlowResult;
+
+/* Get a textual representation of |result|. */
+const char* avb_ab_flow_result_to_string(AvbABFlowResult result);
+
+/* High-level function to select a slot to boot. The following
+ * algorithm is used:
+ *
+ * 1. A/B metadata is loaded and validated using the
+ * read_ab_metadata() operation. Typically this means it's read from
+ * the 'misc' partition and if it's invalid then it's reset using
+ * avb_ab_data_init() and this reset metadata is returned.
+ *
+ * 2. All bootable slots listed in the A/B metadata are verified using
+ * avb_slot_verify(). If a slot is invalid or if it fails verification
+ * (and AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is not set, see
+ * below), it will be marked as unbootable in the A/B metadata and the
+ * metadata will be saved to disk before returning.
+ *
+ * 3. If there are no bootable slots, the value
+ * AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS is returned.
+ *
+ * 4. For each bootable slot, the Stored Rollback Indexes are updated
+ * such that for each rollback index location, the Stored Rollback
+ * Index is the largest number smaller than or equal to the Rollback
+ * Index of each slot.
+ *
+ * 5. The bootable slot with the highest priority is selected and
+ * returned in |out_data|. If this slot is already marked as
+ * successful, the A/B metadata is not modified. However, if the slot
+ * is not marked as bootable its |tries_remaining| count is
+ * decremented and the A/B metadata is saved to disk before returning.
+ * In either case the value AVB_AB_FLOW_RESULT_OK is returning.
+ *
+ * The partitions to load is given in |requested_partitions| as a
+ * NULL-terminated array of NUL-terminated strings. Typically the
+ * |requested_partitions| array only contains a single item for the
+ * boot partition, 'boot'.
+ *
+ * If the device is unlocked (and _only_ if it's unlocked), the
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag should be set
+ * in the |flags| parameter. This will allow considering slots as
+ * verified even when avb_slot_verify() returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX for the slot in
+ * question.
+ *
+ * Note that neither androidboot.slot_suffix nor androidboot.slot are
+ * set in the |cmdline| field in |AvbSlotVerifyData| - you will have
+ * to pass these yourself.
+ *
+ * If a slot was selected and it verified then AVB_AB_FLOW_RESULT_OK
+ * is returned.
+ *
+ * If a slot was selected but it didn't verify then
+ * AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR is returned. This can
+ * only happen when the AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+ * flag is set.
+ *
+ * If an I/O operation - such as loading/saving metadata or checking
+ * rollback indexes - fail, the value AVB_AB_FLOW_RESULT_ERROR_IO is
+ * returned.
+ *
+ * If memory allocation fails, AVB_AB_FLOW_RESULT_ERROR_OOM is
+ * returned.
+ *
+ * If invalid arguments are passed,
+ * AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT is returned. For example
+ * this can happen if using AVB_HASHTREE_ERROR_MODE_LOGGING without
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR.
+ *
+ * Reasonable behavior for handling AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS
+ * is to initiate device repair (which is device-dependent).
+ */
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+ const char* const* requested_partitions,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data);
+
+/* Marks the slot with the given slot number as active. Returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ *
+ * This function is typically used by the OS updater when completing
+ * an update. It can also used by the firmware for implementing the
+ * "set_active" command.
+ */
+AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, unsigned int slot_number);
+
+/* Marks the slot with the given slot number as unbootable. Returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ *
+ * This function is typically used by the OS updater before writing to
+ * a slot.
+ */
+AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
+ unsigned int slot_number);
+
+/* Marks the slot with the given slot number as having booted
+ * successfully. Returns AVB_IO_RESULT_OK on success, error code
+ * otherwise.
+ *
+ * Calling this on an unbootable slot is an error - AVB_IO_RESULT_OK
+ * will be returned yet the function will have no side-effects.
+ *
+ * This function is typically used by the OS updater after having
+ * confirmed that the slot works as intended.
+ */
+AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
+ unsigned int slot_number);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_AB_FLOW_H_ */
diff --git a/avb/libavb_ab/avb_ab_ops.h b/avb/libavb_ab/avb_ab_ops.h
new file mode 100644
index 00000000..8d8fde7a
--- /dev/null
+++ b/avb/libavb_ab/avb_ab_ops.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_AB_H) && !defined(AVB_COMPILATION)
+#error \
+ "Never include this file directly, include libavb_ab/libavb_ab.h instead."
+#endif
+
+#ifndef AVB_AB_OPS_H_
+#define AVB_AB_OPS_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AvbABOps;
+typedef struct AvbABOps AvbABOps;
+
+struct AvbABData;
+
+/* High-level operations/functions/methods for A/B that are platform
+ * dependent.
+ */
+struct AvbABOps {
+ /* Operations from libavb. */
+ AvbOps* ops;
+
+ /* Reads A/B metadata from persistent storage. Returned data is
+ * properly byteswapped. Returns AVB_IO_RESULT_OK on success, error
+ * code otherwise.
+ *
+ * If the data read is invalid (e.g. wrong magic or CRC checksum
+ * failure), the metadata shoule be reset using avb_ab_data_init()
+ * and then written to persistent storage.
+ *
+ * Implementations will typically want to use avb_ab_data_read()
+ * here to use the 'misc' partition for persistent storage.
+ */
+ AvbIOResult (*read_ab_metadata)(AvbABOps* ab_ops, struct AvbABData* data);
+
+ /* Writes A/B metadata to persistent storage. This will byteswap and
+ * update the CRC as needed. Returns AVB_IO_RESULT_OK on success,
+ * error code otherwise.
+ *
+ * Implementations will typically want to use avb_ab_data_write()
+ * here to use the 'misc' partition for persistent storage.
+ */
+ AvbIOResult (*write_ab_metadata)(AvbABOps* ab_ops,
+ const struct AvbABData* data);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_AB_OPS_H_ */
diff --git a/avb/libavb_ab/libavb_ab.h b/avb/libavb_ab/libavb_ab.h
new file mode 100755
index 00000000..654ff5e7
--- /dev/null
+++ b/avb/libavb_ab/libavb_ab.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LIBAVB_AB_H_
+#define LIBAVB_AB_H_
+
+#include
+
+/* The libavb_ab/ and boot_control/ code has been marked for some time
+ * as experimental in anticipation of being removed in the future. It
+ * is now deprecated and to continue using it you must define
+ * AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED. It will be removed Jun
+ * 1 2018.
+ */
+#ifndef AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED
+#error \
+ "You must define AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED to use this library."
+#endif
+
+/* The AVB_INSIDE_LIBAVB_AB_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_AB_H
+#include "avb_ab_flow.h"
+#include "avb_ab_ops.h"
+#undef AVB_INSIDE_LIBAVB_AB_H
+
+#endif /* LIBAVB_AB_H_ */
diff --git a/avb/libavb_atx/avb_atx_ops.h b/avb/libavb_atx/avb_atx_ops.h
new file mode 100755
index 00000000..06c989f6
--- /dev/null
+++ b/avb/libavb_atx/avb_atx_ops.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_ATX_H) && !defined(AVB_COMPILATION)
+#error \
+ "Never include this file directly, include libavb_atx/libavb_atx.h instead."
+#endif
+
+#ifndef AVB_ATX_OPS_H_
+#define AVB_ATX_OPS_H_
+
+#include
+
+#include "libavb_atx/avb_atx_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AvbAtxOps;
+typedef struct AvbAtxOps AvbAtxOps;
+
+/* An extension to AvbOps required by avb_atx_validate_vbmeta_public_key(). */
+struct AvbAtxOps {
+ /* Operations from libavb. */
+ AvbOps* ops;
+
+ /* Reads permanent |attributes| data. There are no restrictions on where this
+ * data is stored. On success, returns AVB_IO_RESULT_OK and populates
+ * |attributes|.
+ */
+ AvbIOResult (*read_permanent_attributes)(
+ AvbAtxOps* atx_ops, AvbAtxPermanentAttributes* attributes);
+
+ /* Reads a |hash| of permanent attributes. This hash MUST be retrieved from a
+ * permanently read-only location (e.g. fuses) when a device is LOCKED. On
+ * success, returned AVB_IO_RESULT_OK and populates |hash|.
+ */
+ AvbIOResult (*read_permanent_attributes_hash)(
+ AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]);
+
+ /* Provides the key version of a key used during verification. This may be
+ * useful for managing the minimum key version.
+ */
+ void (*set_key_version)(AvbAtxOps* atx_ops,
+ size_t rollback_index_location,
+ uint64_t key_version);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_ATX_OPS_H_ */
diff --git a/avb/libavb_atx/avb_atx_types.h b/avb/libavb_atx/avb_atx_types.h
new file mode 100644
index 00000000..6d698592
--- /dev/null
+++ b/avb/libavb_atx/avb_atx_types.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_ATX_H) && !defined(AVB_COMPILATION)
+#error \
+ "Never include this file directly, include libavb_atx/libavb_atx.h instead."
+#endif
+
+#ifndef AVB_ATX_TYPES_H_
+#define AVB_ATX_TYPES_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Size in bytes of an Android Things product ID. */
+#define AVB_ATX_PRODUCT_ID_SIZE 16
+
+/* Size in bytes of a serialized public key with a 4096-bit modulus. */
+#define AVB_ATX_PUBLIC_KEY_SIZE (sizeof(AvbRSAPublicKeyHeader) + 1024)
+
+/* Data structure of Android Things permanent attributes. */
+typedef struct AvbAtxPermanentAttributes {
+ uint32_t version;
+ uint8_t product_root_public_key[AVB_ATX_PUBLIC_KEY_SIZE];
+ uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE];
+} AVB_ATTR_PACKED AvbAtxPermanentAttributes;
+
+/* Data structure of signed fields in an Android Things certificate. */
+typedef struct AvbAtxCertificateSignedData {
+ uint32_t version;
+ uint8_t public_key[AVB_ATX_PUBLIC_KEY_SIZE];
+ uint8_t subject[AVB_SHA256_DIGEST_SIZE];
+ uint8_t usage[AVB_SHA256_DIGEST_SIZE];
+ uint64_t key_version;
+} AVB_ATTR_PACKED AvbAtxCertificateSignedData;
+
+/* Data structure of an Android Things certificate. */
+typedef struct AvbAtxCertificate {
+ AvbAtxCertificateSignedData signed_data;
+ uint8_t signature[AVB_RSA4096_NUM_BYTES];
+} AVB_ATTR_PACKED AvbAtxCertificate;
+
+/* Data structure of Android Things public key metadata in vbmeta. */
+typedef struct AvbAtxPublicKeyMetadata {
+ uint32_t version;
+ AvbAtxCertificate product_intermediate_key_certificate;
+ AvbAtxCertificate product_signing_key_certificate;
+} AVB_ATTR_PACKED AvbAtxPublicKeyMetadata;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_ATX_TYPES_H_ */
diff --git a/avb/libavb_atx/avb_atx_validate.c b/avb/libavb_atx/avb_atx_validate.c
new file mode 100755
index 00000000..77082776
--- /dev/null
+++ b/avb/libavb_atx/avb_atx_validate.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "libavb_atx/avb_atx_validate.h"
+
+#include "libavb/avb_rsa.h"
+#include "libavb/avb_sha.h"
+#include "libavb/avb_sysdeps.h"
+#include "libavb/avb_util.h"
+
+/* Computes the SHA256 |hash| of |length| bytes of |data|. */
+static void sha256(const uint8_t* data,
+ uint32_t length,
+ uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
+ AvbSHA256Ctx context;
+ avb_sha256_init(&context);
+ avb_sha256_update(&context, data, length);
+ uint8_t* tmp = avb_sha256_final(&context);
+ avb_memcpy(hash, tmp, AVB_SHA256_DIGEST_SIZE);
+}
+
+/* Computes the SHA512 |hash| of |length| bytes of |data|. */
+static void sha512(const uint8_t* data,
+ uint32_t length,
+ uint8_t hash[AVB_SHA512_DIGEST_SIZE]) {
+ AvbSHA512Ctx context;
+ avb_sha512_init(&context);
+ avb_sha512_update(&context, data, length);
+ uint8_t* tmp = avb_sha512_final(&context);
+ avb_memcpy(hash, tmp, AVB_SHA512_DIGEST_SIZE);
+}
+
+/* Computes the SHA256 |hash| of a NUL-terminated |str|. */
+static void sha256_str(const char* str, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
+ sha256((const uint8_t*)str, avb_strlen(str), hash);
+}
+
+/* Verifies structure and |expected_hash| of permanent |attributes|. */
+static bool verify_permanent_attributes(
+ const AvbAtxPermanentAttributes* attributes,
+ uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) {
+ uint8_t hash[AVB_SHA256_DIGEST_SIZE];
+
+ if (attributes->version != 1) {
+ avb_error("Unsupported permanent attributes version.\n");
+ return false;
+ }
+ sha256((const uint8_t*)attributes, sizeof(AvbAtxPermanentAttributes), hash);
+ if (0 != avb_safe_memcmp(hash, expected_hash, AVB_SHA256_DIGEST_SIZE)) {
+ avb_error("Invalid permanent attributes.\n");
+ return false;
+ }
+ return true;
+}
+
+/* Verifies the format, key version, usage, and signature of a certificate. */
+static bool verify_certificate(AvbAtxCertificate* certificate,
+ uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
+ uint64_t minimum_key_version,
+ uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) {
+ const AvbAlgorithmData* algorithm_data;
+ uint8_t certificate_hash[AVB_SHA512_DIGEST_SIZE];
+
+ if (certificate->signed_data.version != 1) {
+ avb_error("Unsupported certificate format.\n");
+ return false;
+ }
+ algorithm_data = avb_get_algorithm_data(AVB_ALGORITHM_TYPE_SHA512_RSA4096);
+ sha512((const uint8_t*)&certificate->signed_data,
+ sizeof(AvbAtxCertificateSignedData),
+ certificate_hash);
+ if (!avb_rsa_verify(authority,
+ AVB_ATX_PUBLIC_KEY_SIZE,
+ certificate->signature,
+ AVB_RSA4096_NUM_BYTES,
+ certificate_hash,
+ AVB_SHA512_DIGEST_SIZE,
+ algorithm_data->padding,
+ algorithm_data->padding_len)) {
+ avb_error("Invalid certificate signature.\n");
+ return false;
+ }
+ if (certificate->signed_data.key_version < minimum_key_version) {
+ avb_error("Key rollback detected.\n");
+ return false;
+ }
+ if (0 != avb_safe_memcmp(certificate->signed_data.usage,
+ expected_usage,
+ AVB_SHA256_DIGEST_SIZE)) {
+ avb_error("Invalid certificate usage.\n");
+ return false;
+ }
+ return true;
+}
+
+/* Verifies signature and fields of a PIK certificate. */
+static bool verify_pik_certificate(AvbAtxCertificate* certificate,
+ uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
+ uint64_t minimum_version) {
+ uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE];
+
+ sha256_str("com.google.android.things.vboot.ca", expected_usage);
+ if (!verify_certificate(
+ certificate, authority, minimum_version, expected_usage)) {
+ avb_error("Invalid PIK certificate.\n");
+ return false;
+ }
+ return true;
+}
+
+/* Verifies signature and fields of a PSK certificate. */
+static bool verify_psk_certificate(
+ AvbAtxCertificate* certificate,
+ uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
+ uint64_t minimum_version,
+ uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) {
+ uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE];
+ uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE];
+
+ sha256_str("com.google.android.things.vboot", expected_usage);
+ if (!verify_certificate(
+ certificate, authority, minimum_version, expected_usage)) {
+ avb_error("Invalid PSK certificate.\n");
+ return false;
+ }
+ sha256(product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_subject);
+ if (0 != avb_safe_memcmp(certificate->signed_data.subject,
+ expected_subject,
+ AVB_SHA256_DIGEST_SIZE)) {
+ avb_error("Product ID mismatch.\n");
+ return false;
+ }
+ return true;
+}
+
+AvbIOResult avb_atx_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) {
+ AvbIOResult result = AVB_IO_RESULT_OK;
+ AvbAtxPermanentAttributes permanent_attributes;
+ uint8_t permanent_attributes_hash[AVB_SHA256_DIGEST_SIZE];
+ AvbAtxPublicKeyMetadata metadata;
+ uint64_t minimum_version;
+
+ /* Be pessimistic so we can exit early without having to remember to clear.
+ */
+ *out_is_trusted = false;
+
+ /* Read and verify permanent attributes. */
+ result = ops->atx_ops->read_permanent_attributes(ops->atx_ops,
+ &permanent_attributes);
+ if (result != AVB_IO_RESULT_OK) {
+ avb_error("Failed to read permanent attributes.\n");
+ return result;
+ }
+ result = ops->atx_ops->read_permanent_attributes_hash(
+ ops->atx_ops, permanent_attributes_hash);
+ if (result != AVB_IO_RESULT_OK) {
+ avb_error("Failed to read permanent attributes hash.\n");
+ return result;
+ }
+ if (!verify_permanent_attributes(&permanent_attributes,
+ permanent_attributes_hash)) {
+ return AVB_IO_RESULT_OK;
+ }
+
+ /* Sanity check public key metadata. */
+ if (public_key_metadata_length != sizeof(AvbAtxPublicKeyMetadata)) {
+ avb_error("Invalid public key metadata.\n");
+ return AVB_IO_RESULT_OK;
+ }
+ avb_memcpy(&metadata, public_key_metadata, sizeof(AvbAtxPublicKeyMetadata));
+ if (metadata.version != 1) {
+ avb_error("Unsupported public key metadata.\n");
+ return AVB_IO_RESULT_OK;
+ }
+
+ /* Verify the PIK certificate. */
+ result = ops->read_rollback_index(
+ ops, AVB_ATX_PIK_VERSION_LOCATION, &minimum_version);
+ if (result != AVB_IO_RESULT_OK) {
+ avb_error("Failed to read PIK minimum version.\n");
+ return result;
+ }
+ if (!verify_pik_certificate(&metadata.product_intermediate_key_certificate,
+ permanent_attributes.product_root_public_key,
+ minimum_version)) {
+ return AVB_IO_RESULT_OK;
+ }
+
+ /* Verify the PSK certificate. */
+ result = ops->read_rollback_index(
+ ops, AVB_ATX_PSK_VERSION_LOCATION, &minimum_version);
+ if (result != AVB_IO_RESULT_OK) {
+ avb_error("Failed to read PSK minimum version.\n");
+ return result;
+ }
+ if (!verify_psk_certificate(
+ &metadata.product_signing_key_certificate,
+ metadata.product_intermediate_key_certificate.signed_data.public_key,
+ minimum_version,
+ permanent_attributes.product_id)) {
+ return AVB_IO_RESULT_OK;
+ }
+
+ /* Verify the PSK is the same key that verified vbmeta. */
+ if (public_key_length != AVB_ATX_PUBLIC_KEY_SIZE) {
+ avb_error("Public key length mismatch.\n");
+ return AVB_IO_RESULT_OK;
+ }
+ if (0 != avb_safe_memcmp(
+ metadata.product_signing_key_certificate.signed_data.public_key,
+ public_key_data,
+ AVB_ATX_PUBLIC_KEY_SIZE)) {
+ avb_error("Public key mismatch.\n");
+ return AVB_IO_RESULT_OK;
+ }
+
+ /* Report the key versions used during verification. */
+ ops->atx_ops->set_key_version(
+ ops->atx_ops,
+ AVB_ATX_PIK_VERSION_LOCATION,
+ metadata.product_intermediate_key_certificate.signed_data.key_version);
+ ops->atx_ops->set_key_version(
+ ops->atx_ops,
+ AVB_ATX_PSK_VERSION_LOCATION,
+ metadata.product_signing_key_certificate.signed_data.key_version);
+
+ *out_is_trusted = true;
+ return AVB_IO_RESULT_OK;
+}
diff --git a/avb/libavb_atx/avb_atx_validate.h b/avb/libavb_atx/avb_atx_validate.h
new file mode 100644
index 00000000..41faac19
--- /dev/null
+++ b/avb/libavb_atx/avb_atx_validate.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_ATX_H) && !defined(AVB_COMPILATION)
+#error \
+ "Never include this file directly, include libavb_atx/libavb_atx.h instead."
+#endif
+
+#ifndef AVB_ATX_VALIDATE_H_
+#define AVB_ATX_VALIDATE_H_
+
+#include "libavb_atx/avb_atx_ops.h"
+#include "libavb_atx/avb_atx_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Rollback index locations for Android Things key versions. */
+#define AVB_ATX_PIK_VERSION_LOCATION 0x1000
+#define AVB_ATX_PSK_VERSION_LOCATION 0x1001
+
+/* An implementation of validate_vbmeta_public_key for Android Things. See
+ * libavb/avb_ops.h for details on validate_vbmeta_public_key in general. This
+ * implementation uses the metadata expected with Android Things vbmeta images
+ * to perform validation on the public key. The ATX ops must be implemented.
+ * That is, |ops->atx_ops| must be valid.
+ *
+ * There are a multiple values that need verification:
+ * - Permanent Product Attributes: A hash of these attributes is fused into
+ * hardware. Consistency is checked.
+ * - Product Root Key (PRK): This key is provided in permanent attributes and
+ * is the root authority for all Android Things
+ * products.
+ * - Product Intermediate Key (PIK): This key is a rotated intermediary. It is
+ * certified by the PRK.
+ * - Product Signing Key (PSK): This key is a rotated authority for a specific
+ * Android Things product. It is certified by a
+ * PIK and must match |public_key_data|.
+ * - Product ID: This value is provided in permanent attributes and is unique
+ * to a specific Android Things product. This value must match
+ * the subject of the PSK certificate.
+ */
+AvbIOResult avb_atx_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_ATX_VALIDATE_H_ */
diff --git a/avb/libavb_atx/libavb_atx.h b/avb/libavb_atx/libavb_atx.h
new file mode 100644
index 00000000..839c0afa
--- /dev/null
+++ b/avb/libavb_atx/libavb_atx.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LIBAVB_ATX_H_
+#define LIBAVB_ATX_H_
+
+#include
+
+/* The AVB_INSIDE_LIBAVB_ATX_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_ATX_H
+#include "avb_atx_ops.h"
+#include "avb_atx_types.h"
+#include "avb_atx_validate.h"
+#undef AVB_INSIDE_LIBAVB_ATX_H
+
+#endif /* LIBAVB_ATX_H_ */
diff --git a/avb_init.c b/avb_init.c
new file mode 100644
index 00000000..fcf2f0a3
--- /dev/null
+++ b/avb_init.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: genshen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "avb_init.h"
+
+//Global AvbOps data structure
+static AvbOps *ops = NULL;
+
+AvbOps *avb_init(void)
+{
+ avb_print("UEFI AVB-based bootloader\n");
+
+ if (ops != NULL) {
+ return ops;
+ }
+
+ ops = uefi_avb_ops_new();
+ if (!ops) {
+ avb_fatal("Error allocating AvbOps.\n");
+ return NULL;
+ }
+
+ return ops;
+}
+
+bool avb_update_stored_rollback_indexes_for_slot(AvbOps* ops, AvbSlotVerifyData* slot_data)
+{
+ int n;
+
+ for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
+ uint64_t rollback_index = slot_data->rollback_indexes[n];
+ if (rollback_index > 0) {
+ AvbIOResult io_ret;
+ uint64_t current_stored_rollback_index;
+
+ io_ret = ops->read_rollback_index(ops, n, ¤t_stored_rollback_index);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ return false;
+ }
+
+ if (rollback_index > current_stored_rollback_index) {
+ io_ret = ops->write_rollback_index(ops, n, rollback_index);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
diff --git a/avb_init.h b/avb_init.h
new file mode 100644
index 00000000..5e92d3ef
--- /dev/null
+++ b/avb_init.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: genshen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _AVB_INIT_H_
+#define _AVB_INIT_H_
+#include "libavb/libavb.h"
+#include "libavb/uefi_avb_ops.h"
+
+AvbOps *avb_init(void);
+
+bool avb_update_stored_rollback_indexes_for_slot(AvbOps* ops, AvbSlotVerifyData* slot_data);
+#endif
diff --git a/doc/FRP.md b/doc/FRP.md
new file mode 100644
index 00000000..0e9a5c3b
--- /dev/null
+++ b/doc/FRP.md
@@ -0,0 +1,156 @@
+Bootloader Policy and Factory Reset Protection
+==============================================
+
+[Google's verified boot](https://source.android.com/security/verifiedboot/verified-boot.html)
+(GVB) specification and Google Factory Reset Protection (FRP) for
+AndroidTM define a set of security protocols for ensuring
+system integrity and dis-incentivising device theft, respectively.
+
+There are legitimate reasons to unlock the bootloader without knowing
+the screen unlock PIN; specifically RMAs. An RMA processing center
+should be able to unlock device flashing restrictions in Fastboot and
+return the device to a factory pristine state without requiring the
+user to disclose their screen unlock PIN or potentially opening their
+user data to compromise.
+
+This documentation describes the solution for defining a class A
+device and a mechanism that allow for unlocking a device for RMA
+regardless of FRP or class A status. It meets Google FRP security
+requirements by ensuring that there is no single skeleton key to
+unlock devices if all security considerations are implemented. It also
+allows devices to be provisioned so that the entity with unlock
+authority could be Vendor, the OEM, ODM, a carrier, or an enterprise
+organization.
+
+Device User Experience
+----------------------
+
+1. User boots the device to Fastboot
+2. User obtains an action challenge
+```bash
+fastboot oem get-action-nonce force-unlock
+```
+3. User gives the challenge to the action authorization agent and
+ receives an action authorization token file (details later)
+4. User flashes the action authorization token
+```bash
+fastboot flash action-authorization token_file
+```
+5. Fastboot performs the authorized action
+
+Implementation
+--------------
+
+The OEM action authorization protocol is a simple challenge response
+where the device's Fastboot generates a one-time-nonce, the OEM action
+authorization agent signs the nonce and approved action using its
+private override authorization key (OAK) to generate an authorization
+token, and then the device's Fastboot validates the action
+authorization token and executes the action.
+
+Override Authorization Key
+--------------------------
+
+The override authorization key (OAK) is a public key that is set in
+the device during manufacturing and that is used to validate action
+authorization tokens. If an OAK is not set, then all action
+authorization features are disabled and default bootloader and
+Fastboot behavior specified in GVB and FRP is in effect. Since the OAK
+is capable of overriding the class A and FRP policies, it is important
+to ensure that it cannot be changed by unauthorized code, which would
+change the identity of who can override policy.
+
+The OAK may act as a validation root certificate if the certificate
+authority attribute of the certificate is "true" -- standard X.509v3
+certificate handling. This means that the OAK can be used to issue
+certificates that are also able to sign action authorization
+tokens. This is the preferred method of setting the OAK in cases where
+multiple entities need the ability to issue action authorization
+tokens without having access to a single key.
+
+OAK is stored as the `OAK` time-based authenticated EFI variable under
+the Fastboot GUID of `1ac80a82-4f0c-456b-9a99-debeb431fcc1`. The
+content of this variable is the SHA256 sum of the OAK certificate.
+
+Bootloader Policy Mask
+----------------------
+
+Bootloader policy mask (BPM) is a set of 64 boolean policy flags. If a
+BPM is not set, then Fastboot defaults to a policy matching a BPM
+value of zero. If a BPM value is set, a one bit indicates the
+corresponding policy is active.
+
+The BPM is set in the device during manufacturing.
+
+| Policy Name | Bit(s) | Description
+|------------------|---------|----------------------------------------------
+| CLASS\_A\_DEVICE | 0 | If set, the bootloader enforces the behavior defined by GVB for class A devices.
+| MIN\_BOOT\_STATE | 1-2 | Minimal boot state required to boot the device (0 for red, 1 for orange, 2 for yellow and 3 for green)
+
+BPM is stored as the `BPM` time-based authenticated EFI variable under
+the Fastboot GUID of `1ac80a82-4f0c-456b-9a99-debeb431fcc1`.
+
+Generating One-Time-Nonce
+-------------------------
+
+The one-time action authorization nonce has the form
+"::<8 bit action id>:<16 client random bytes>"
+with all fields hex encoded. It is generated when the `fastboot oem
+get-action-nonce ` command is used. Fastboot saves the value
+for a limited amount of time before it expires. Each time the command
+is run a new value is generated and previous value is overwritten. The
+value is not stored persistently. If Fastboot is restarted, the old
+nonce is no longer valid.
+
+The following actions are defined.
+
+| Name | Action ID | Description
+|--------------|-----------|------------
+| Force unlock | 0x00 | Makes Kernelfliner execute the Fastboot `flashing unlock` command as if the "enable oem unlock" developer option is enabled. All standard GVB properties apply, including secure erase of the user data partition.
+
+The version field is a one byte value. It must be zero for the current
+version.
+
+Creating an Action Authorization Token
+--------------------------------------
+
+An action authorization token is generated by signing the action
+authorization nonce with the OAK. The token is a PKCS #7 signed
+document, where the body takes the form "::<8
+bit action id>:<16 client random bytes>:<16 auth agent random bytes>"
+with all fields hex encoded. The auth agent random bytes added when
+creating the authorization is to prevent an attacker from mounting an
+attack by supplying known plain-text values.
+
+The token must contain all certificates required to validate the
+signature chain of the token.
+
+The action authorization agent must verify that the nonce is exactly
+in the prescribed format.
+
+The action authorization agent must verify that the action ID in nonce
+is a recognized value.
+
+If possible, the action authorization agent should verify that the
+serial number is valid.
+
+Flashing the Action Authorization Token
+---------------------------------------
+
+The authorization token is sent to Fastboot using the special
+"action-authorization" flash target. Fastboot verifies that the token
+is valid, invalidates the current one-time-nonce, and executes the
+authorized action.
+
+Fastboot must validate that there is no extra data after parsing the
+token.
+
+Fastboot must verify that the signature's certificate chains to the
+OAK set at manufacturing.
+
+Fastboot must verify that all values in the token body have the
+prescribed values.
+
+Fastboot must verify that the value returned by the "oem
+get-action-nonce " command matches the value in the token body
+and the nonce has not expired.
diff --git a/doc/autodetect.md b/doc/autodetect.md
new file mode 100644
index 00000000..c2ade668
--- /dev/null
+++ b/doc/autodetect.md
@@ -0,0 +1,40 @@
+Autodetect
+==========
+
+Overview
+--------
+
+Autodetect can be activated with the Kernelflinger `HAL_AUTODETECT`
+compilation flag.
+
+If Autodetect is enabled, Kernelflinger prepends some `androidboot`
+parameter to the kernel command line:
+
+- `androidboot.brand`: Combines the value of the DMI Board
+ `manufacturer` and Product `manufacturer` fields.
+- `androidboot.name`: Combines the value of the DMI Product
+ `product_name` and Board `product_name`.
+- `androidboot.device`: Combines the value of the DMI Board
+ `product_name` and Board `version`.
+- `androidboot.model`: same value than `androidboot.device`.
+
+The init process is converting these command line parameters to
+properties that can be used to identify the device product.
+
+If Autodetect is enabled, Kernelflinger also loads the Blobstore
+stored in the second stage area of the boot image, extract the OEMVARS
+blob for the current device variant and flash these product dependent
+EFI variables.
+
+Blobstore
+---------
+
+Blobstore is a structure storing any kind of data inside the second
+stage area of the bootimage. The data is organized as a dictionary in
+which the key is the string: `//`.
+(Cf. [blobstore.c](../libkernelflinger/blobstore.c).
+
+Blobstore current support the following data type: device tree blob,
+OEMVARS (Cf. [Fastboot](./fastboot.md)) and Kernel command line
+parameters. Kernelflinger does not make use of the device tree blob
+type.
diff --git a/doc/crashmode.md b/doc/crashmode.md
new file mode 100644
index 00000000..e85369fd
--- /dev/null
+++ b/doc/crashmode.md
@@ -0,0 +1,217 @@
+Crashmode
+=========
+
+When the AndroidTM boot image is corrupted or a crash
+occurs during the device initialization, the watchdogs or the kernel
+panic handle, reset the device.
+
+Crashmode goal is to:
+
+1. Catch such a situation and inform the end-user.
+2. Avoid an endless reboot loop and battery drain.
+3. Give a chance to the engineer to retrieve some debug information
+ for post-mortem analysis.
+
+Any type of watchdog is taken into account: kernel, security, PMC, EC
+and platform watchdog. Note that the watchdog reset reason is
+reported by Intel BIOS within the non-standard `RSCI` ACPI table while
+Kernel panic is reported in the `LoaderEntryRebootReason` EFI variable
+by the `drivers/staging/android/efibc.c` kernel driver.
+
+This menu informs the user of the situation and lets him choose which
+boot target he wants.
+
+*"WARNING: Multiple crash events have been reported. Use the above menu
+to select the next boot option. If the problem persists, please
+contact the technical assistance."*
+
+Crashmode automatically powers off the device after five minutes
+of inactivity.
+
+With `userdebug` and `eng` builds, Crashmode provides a way to
+retrieve some data from the device (Cf.
+[ADB support in Crashmode](#adb-support-in-crashmode)).
+
+*Important*: transitions between `Fastboot` and `Crashmode` with
+`fastboot oem reboot crashmode` and `adb reboot bootloader` do not
+reset the device in order to avoid any memory corruption. However,
+notice that any `fastboot flash` can result in big memory allocation
+and RAM corruption.
+
+Crashmode configuration
+-----------------------------------------------------
+
+By default, Crashmode is enabled on watchdog and kernel panic events.
+To disable it:
+
+```bash
+$ fastboot oem crash-event-menu 0
+```
+
+To re-enable it:
+
+```bash
+$ fastboot oem crash-event-menu 1
+```
+
+By default, Kernelflinger displays Crashmode when three crash events
+occur in less than ten minutes. The number of crashes before entering
+Crashmode can be configured:
+
+```bash
+$ fastboot oem set-watchdog-counter-max 0
+```
+
+It makes Kernelflinger display Crashmode each time a crash event is
+detected.
+
+See [fastboot documentation](./fastboot.md) for details.
+
+Manually enter crashmode
+------------------------
+
+With `userdebug` and `eng` builds, Crashmode can be be entered
+manually:
+
+* from AndroidTM or Recovery using the `adb reboot
+ crashmode` command
+* from Fastboot:
+
+1. using the `fastboot oem reboot crashmode` command
+2. using the Fastboot graphical menu
+
+ADB support in Crashmode
+------------------------
+
+In `userdebug` and `eng` builds, Crashmode also provide a way to
+retrieve some device data.
+
+Crashmode adb implementation enumerates as `bootloader`. It allows
+any script to detect that the device entered crashmode and use adb
+commands to retrieve some data before continuing the boot using the
+usual `adb reboot [TARGET]` command.
+
+Example:
+```bash
+$ adb devices
+List of devices attached
+INV144900553 bootloader
+```
+
+Crashmode adb implementation is limited to the following commands:
+
+```bash
+- reboot [TARGET]: reboot to TARGET. If TARGET parameter is not
+ supplied it reboots to AndroidTM.
+- pull ram:[:START[:LENGTH]]: retrieve RAM content.
+- pull vmcore:[:START[:LENGTH]]: retrieve crash dump vmcore.
+- pull acpi:TABLE_NAME: retrieve TABLE_NAME ACPI table.
+- pull part:PART_NAME[:START[:LENGTH]]: retrieve PART_NAME partition
+ content.
+- pull factory-part:PART_NAME[:START[:LENGTH]]: dump the PART_NAME
+ factory partition.
+- pull mbr: retrieve the Master Boot Record.
+- pull gpt-header: retrieve the GPT header.
+- pull gpt-parts: retrieve the GPT partition table.
+- pull gpt-factory-header: retrieve the factory GPT header.
+- pull gpt-factory-parts: retrieve the factory GPT partition table.
+- pull efivar:VAR_NAME[:GUID]: retrieve VAR_NAME EFI variable content.
+- pull bert-region: retrieve BERT region, prepended by "BERR" magic.
+```
+
+The optional `START` and `LENGTH` parameters allow to perform a
+partial dump of the data. They are expressed in hexadecimal with or
+without the "0x" prefix.
+
+### ACPI tables
+
+The `pull acpi:TABLE_NAME` command retrieves any ACPI tables. If
+several ACPI tables share the same signature, the first occurrence can
+be retrieved with:
+
+```bash
+$ adb pull ACPI:TABLE_NAME
+```
+
+or
+
+```bash
+$ adb pull ACPI:TABLE_NAME1
+```
+
+While the other instances tables can be retrieved with:
+
+```bash
+$ adb pull ACPI:TABLE_NAME
+```
+
+with `` going from 1 to the occurrence number of `TABLE_NAME` ACPI
+tables.
+
+### EFI variables
+
+The `pull efivar:VAR_NAME[:GUID]` command retrieves `VAR_NAME` EFI
+variable. If several instances of `VAR_NAME` exist, the `GUID`
+argument must be supplied.
+
+### RAM and VMCORE
+
+* `ram` dump generates an
+ [AndroidTM sparse file](http://www.2net.co.uk/tutorial/android-sparse-image-format)
+ with `DONT_CARE` chunk for non conventional memory regions. Use the
+ `simg2img` command from the AOSP tree (`make simg2img-host`) to
+ obtain the flat file you are looking for manual analysis.
+
+* `vmcore` dump generates an image of the main memory, exported as
+ [Executable and Linkable Format (ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
+ object. This `vmcore` file can be loaded into the
+ [RedHatTM Linux crash utility](http://people.redhat.com/anderson/crash_whitepaper/)
+ to perform a crash analysis. This `vmcore` file is a 64-bits ELF,
+ it only works with a 64-bits Linux kernel.
+
+*Memory flush and preservation*
+
+Crashmode runs after the system has crashed, rebooted and the IAFW has
+fully re-initialized. Hence:
+
+1. The platform must preserve the memory accross reboot due to crash.
+2. The system should flush the CPU cache before rebooting.
+3. The memory regions used by the IAFW must not be released to the OS.
+ The Linux kernel `memmap` command line parameter can be used to
+ prevent it to use some memory regions
+ (cf. [kernel-parameters.txt](https://www.kernel.org/doc/Documentation/kernel-parameters.txt)).
+
+*Note*:
+
+* `ram` and `vmcore` commands are limited to one `pull` command at a
+ time.
+* The `START` parameter is a physical address.
+
+### BERT region
+
+The `pull bert-region` command retrieves the
+[APEI](https://firmware.intel.com/sites/default/files/resources/A_Tour_beyond_BIOS_Implementing_APEI_with_UEFI_White_Paper.pdf)
+(ACPI Platform Error Interface, see
+[ACPI specification](http://uefi.org/specifications)) BERT (Boot Error
+Record Table) region prepended by `BERR` magic.
+
+### Example:
+
+```bash
+$ adb pull acpi:DSDT DSDT
+580 KB/s (131324 bytes in 0.220s)
+
+$ adb pull efivar:OEMLock OEMLock
+0 KB/s (4 bytes in 0.50s)
+
+$ adb pull ram:9F000:0F0000 ram.simg
+947 KB/s (585792 bytes in 0.603s)
+
+$ simg2img ram.sparse.bin ram.bin
+
+$ adb pull part:boot boot.img
+1189 KB/s (31457280 bytes in 25.832s)
+
+$ adb pull factory-part:modem1_cal
+1088 KB/s (1048576 bytes in 0.941s)
+```
diff --git a/doc/fastboot.md b/doc/fastboot.md
new file mode 100644
index 00000000..7dbf6bdc
--- /dev/null
+++ b/doc/fastboot.md
@@ -0,0 +1,401 @@
+Fastboot
+========
+
+This documentation presents the particularities of the Kernelflinger
+Fastboot implementation. For *fastboot* standard commands, please
+refer to `fastboot --help`.
+
+Non-standard `flash` commands
+-----------------------------
+
+### `flash gpt `
+
+Unlocked devices only. Provisions the GPT partition scheme on the
+device, accepting an `gpt.bin` file which contains a specification for
+the device's GPT.
+
+Two gpt.bin formats are accepted:
+
+#### 1. gpt_ini2bin.py
+
+`gpt.bin` file is generated using the
+[gpt_ini2bin.py](https://android.googlesource.com/platform/hardware/bsp/intel/+/de59ae73d7e3e139f1a5d31f4d107c996c377be5/soc/edison/tools/gpt_ini2bin.py)
+script from a `gpt.ini` file.
+
+Here is a `gpt.ini` file example:
+
+```ini
+[base]
+partitions = bootloader bootloader2 boot recovery misc metadata system cache data persistent
+device = auto
+
+[partition.bootloader]
+label = bootloader
+len = 60
+type = esp
+
+[partition.bootloader2]
+label = bootloader2
+len = 60
+type = fat
+
+[partition.boot]
+label = boot
+len = 30
+type = boot
+
+[partition.recovery]
+label = recovery
+len = 30
+type = recovery
+
+[partition.misc]
+label = misc
+len = 1
+type = misc
+
+[partition.metadata]
+label = metadata
+len = 16
+type = metadata
+
+[partition.system]
+label = system
+len = 2560
+type = linux
+
+[partition.cache]
+label = cache
+len = 100
+type = linux
+
+[partition.data]
+label = data
+len = -1
+type = linux
+
+[partition.persistent]
+label = persistent
+len = 1
+type = linux
+```
+
+If the Android build is using slot AB mechanism, the slot number is
+defined in the `[base]` section and every partition that have several
+slots have the `has_slot = true` parameter:
+
+```ini
+[base]
+partitions = bootloader bootloader2 boot misc metadata system cache data persistent
+nb_slot = 2
+
+[...]
+
+[partition.boot]
+label = boot
+len = 30
+type = boot
+has_slot = true
+
+[...]
+
+[partition.system]
+label = system
+len = 1024
+type = linux
+has_slot = true
+
+[...]
+```
+
+#### 2. bpttool
+
+[bpttool](https://android.googlesource.com/platform/system/tools/bpt/+/master)
+is an AOSP project that can be used to create the partition table.
+
+### `fastboot flash bootloader `
+
+Unlocked devices only. Kernelfinger Fastboot implementation requires
+two `bootloader` partitions labelled `bootloader` and
+`bootloader2`. The `flash bootloader` process is the following:
+
+1. Flash `FILENAME` into the `bootloader2` partition.
+2. Verify the content of the `bootloader2` partition:
+ * `bootloader2` contains a FAT16 or FAT32 file-system
+ * the usual bootloader EFI binary is present and loadable
+ * and all the EFI binaries described in the `/manifest.txt` file are
+ present and loadable.
+3. Switch the `bootloader` and `bootloader2` entries in the GPT
+ header.
+4. Create the load options based on the `bootloader` partition
+ `/manifest.txt` file.
+
+Here is an example of a `/manifest.txt` file:
+``` conf
+Android-IA=/EFI/BOOT/bootx64.efi
+Fastboot=/EFI/BOOT/bootx64.efi;-f
+```
+
+This `/manifest.txt` file makes Kernelflinger create two load options
+`Android-IA` and `Fastboot`. The `Fastboot` load option makes the EFI
+Boot Manager start Kernelflinger with the "-f" supplied argument,
+enforcing Kernelflinger to start in Fastboot mode.
+
+### `fastboot flash oemvars `
+
+Unlocked devices only. OEM variables are stored as EFI variables. By
+default, they are under the Loader GUID of
+`4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`.
+
+This flash command accepts a text file with a set of OEM variables to
+set. The syntax supports #-style end of line comments. Variable
+settings are specified as ` `. White space around the
+variable name is removed, as is trailing white space at the end of the
+line. The value can otherwise contain any printable character and is
+stored as an 8-bit string in the EFI variable's value. Non-printable
+bytes can be encoded with `%xx` URL-style notation. If `` is
+omitted, the variable is cleared instead.
+
+A line of the form follows:
+
+``` conf
+GUID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+```
+
+This line changes the GUID used for subsequent lines.
+
+Example file:
+
+``` conf
+##########################
+# Maximum timeout to check for magic key at boot; fastboot GUID
+
+MagicKeyTimeout 40
+
+##########################
+# atomisp camera variables
+
+GUID = ecb54cd9-e5ae-4fdc-a971-e877756068f7
+
+# ECS boards use this GPIO line to gate 2.8v camera power
+gmin_V2P8GPIO 402
+
+# OV5693 world-facing camera
+INT33BE:00_CsiPort 1
+INT33BE:00_CsiLanes 2
+INT33BE:00_CamClk 0
+INT33BE:00_CsiFmt 13
+INT33BE:00_CsiBayer 2
+
+# Aptina MT9M114 ("SOC-1040") user-facing camera
+INT33F0:00_CsiPort 0
+INT33F0:00_CsiLanes 1
+INT33F0:00_CamClk 1
+INT33F0:00_CsiFmt 13
+INT33F0:00_CsiBayer 0
+
+# Invert Audio Jack
+byt_rt5640_JackInvert 1
+```
+
+Additionally, lines may be prefixed with modifier codes in brackets to
+control the flags used when setting EFI variables. By default, all
+values are assumed to be 8-bit NUL-terminated strings with both boot
+and runtime services access. Supported modifier codes are:
+
+* `d`: Raw data, do not NUL terminate
+* `b`: Restrict to boot services access
+* `a`: Time-based authenticated variable
+
+For example:
+
+``` conf
+[db] MyBinaryVar %ab%cd%ef
+```
+
+This example sets MyBinaryVar to the hex values 0xAB 0xCD 0xEF with no
+terminating NUL byte and boot services access only.
+
+### `flash /ESP/ `
+
+Unlocked devices only. Copy `FILENAME` into the EFI system partition.
+Any directory included in `DEST` path will also be created.
+
+OEM commmands
+-------------
+
+### `oem setvar []`
+
+Unlocked devices only. Sets an EFI variable under the Loader GUID
+`4a67b082-0a4c-41cf-b6c7-440b29bb8c4f` with the specified key, to the
+value provided. The value is always stored as an 8-bit NUL-terminated
+string. Omitting the value will result in the variable being set to
+NUL which will erase the variable.
+
+Some interesting values that can be set are:
+
+* `SerialPort`: Value is appended to `console=` in the kernel command
+ line for setting the device's console port.
+* `AppendCmdline`, `PrependCmdline`, and `ReplaceCmdline`:
+
+1. The content of variable `PrependCmdline` will be prepended to the
+ original commandline.
+2. The content of variable `AppendCmdline` will be appended to the
+ original commandline.
+3. The content of variable `ReplaceCmdline` will replace the whole
+ original commandline.
+4. The `PrependCmdline` and `AppendCmdline` will still be effective,
+ using the content of `RepaceCmdline`.
+5. `AppendCmdline`, `PrependCmdline`, and `ReplaceCmdline` will be
+ ignored in a `user` build.
+
+Other values are inherently device-specific. Normally this command is
+only of interest to developers. Factory provisioning uses flash
+oemvars instead.
+
+### `oem garbage-disk`
+
+Unlocked devices only. Writes out the entire disk with random data,
+including the partition table. Used in device provisioning test cases
+to ensure that the previous device state does not influence the
+outcome of the tests applied.
+
+### `oem reboot `
+
+Works in any device state. Reboots the device into the specified boot
+TARGET. Functionally equivalent to `adb reboot `.
+
+### `oem reprovision`
+
+Works in any device state. This is only available in `eng` or
+`userdebug` builds. It puts the device back into provisioning mode,
+which allows several things:
+
+* The device may be unlocked without enforcing Factory Reset
+ Protection. The state of the persistent partition doesn't matter.
+* Transitions between `{locked|unlocked}` states do not require user
+ confirmation or erasing of the `userdata` partition.
+
+Provisioning mode is also the state the device is in when it is
+freshly manufactured. The device leaves provisioning mode once you run
+any of the `flashing {lock|unlock}` commands and you reset the device.
+
+### `oem rm /ESP/`
+
+Unlocked devices only. Erase FILENAME from the EFI system partition.
+
+### `oem get-hashes `
+
+Works in any device state. This is used by OTA Secure Boot Test Cases
+to verify the correctness of device provisioning and OTA
+updates. Various boot images, the contents of the EFI system
+partition, and the block-level /system and /vendor images (including
+verity tables and metadata) are HASH-ALGORITHM hashed and reported
+back to the user.
+
+Example:
+
+``` bash
+...
+& fastboot oem get-hashes
+(bootloader) target: /boot
+(bootloader) hash: d0448a1e91030e5c37277e4a77eabefc36fc8e6c
+(bootloader) target: /recovery
+(bootloader) hash: 411c61de23f6f73934b79eda4f64779706c220f4
+(bootloader) target: /bootloader/EFI/BOOT/bootx64.efi
+(bootloader) hash: 2773c4c039dc37b96171f6ef131f04dd8faf73e1
+(bootloader) target: /bootloader/loader.efi
+(bootloader) hash: 2773c4c039dc37b96171f6ef131f04dd8faf73e1
+(bootloader) target: /bootloader/fastboot.img
+(bootloader) hash: b0b3d122c4dca255ed2a75268ef30f6cbbc11085
+(bootloader) target: /system
+(bootloader) hash: d417239a25df718d73b6326e6c93a7fc1b00afb2
+OKAY [134.307s]
+finished. total time: 134.307s
+```
+
+This command takes an optional argument to specify which
+HASH-ALGORITHM must be used. Accepted values are "sha1" and "md5".
+The default behaviour (no argument supplied) is "sha1". Note that
+"md5" is by far faster than "sha1".
+
+### `oem get-provisioning-logs`
+
+Works in any state. Displays the contents of the `KernelflingerLogs`
+EFI variable. Useful if Kernelflinger crashes or hits an error at
+manufacturing where no debug board or screen is connected.
+
+### `oem set-storage `
+
+Works in any state but is limited to `non-user` builds. For devices
+with both EMMC and UFS, this command is used to enforce one or the
+other. `STORAGE` value is limited to `emmc` and `ufs`.
+
+### `fastboot oem crash-event-menu <0|1>`
+
+Enable (1) or disable(0) [Crashmode](./crashmode.md).
+
+### `fastboot oem slot-fallback <0|1>`
+
+Works in any state but is limited to `non-user` builds. Enable (1) or
+disable(0) slot fallback mechanism. If set to 0, the active slot and
+the recovery remaining tries number are not decremented.
+
+### `oem set-watchdog-counter-max `
+
+Works in any device state but is limited to `non-user` builds.
+
+This command sets the maximum number of crash events in a row before
+[Crashmode](./crashmode.md) is displayed. VALUE is comprised between
+0 included and 255 included.
+
+### `oem get-action-nonce `
+
+Works in any device state.
+See. [Bootloader policy and Factory Reset Protection](./FRP.md).
+
+### `oem erase-efivars`
+
+Works in any device state but is limited to `non-user` builds. This
+commands deletes all the EFI variables declared under the Loader GUID
+or Fastboot GUID except:
+- The "OEMLock" EFI variable declared under the Fastboot GUID
+- The "KernelflingerLogs" EFI variable declared under the Loader GUID
+- All the "Bootloader policy" time-based authenticated EFI variables
+ declared under the Fastboot
+ GUID. See. [Bootloader policy and Factory Reset Protection](./FRP.md).
+
+Non-standard Variables
+----------------------
+
+### `secureboot`
+
+Indicates whether UEFI Secure Boot is enabled. This is a pre-requisite
+for Verified Boot.
+
+### `product-name`
+
+Reports the product_name field in DMI.
+
+### `firmware`
+
+Reports the current device firmware version from DMI. Combines the
+values of the DMI `bios_vendor` and `bios_version` fields.
+
+### `boot-state`
+
+Indicates the device's color-coded boot state as per
+[Google verified boot](https://source.android.com/security/verifiedboot/verified-boot.html)'s
+specification. If the bootloader doesn't support Verified Boot,
+`unknown` will be returned.
+
+### `device-state`
+
+Indicates the device's lock state as per
+[Google verified boot](https://source.android.com/security/verifiedboot/verified-boot.html)'s
+specification.
+
+### `board`
+
+Indicates the board information, combining the values of the DMI
+`board_vendor`, `board_name`, and `board_version` fields.
diff --git a/doc/installer.md b/doc/installer.md
new file mode 100644
index 00000000..2c39bac3
--- /dev/null
+++ b/doc/installer.md
@@ -0,0 +1,151 @@
+Installer
+=========
+
+Basically, Installer (aka. installer.efi binary) is a wrapper of the
+[libfastboot](./fastboot.md). It allows to flash a device using an
+external storage (USB or SDCard for instance). The external storage
+must formatted using a filesystem supported by the BIOS (usually FAT16
+or FAT32).
+
+Installer supports all the Fastboot commands supported by
+libfastboot. For instance:
+
+```bash
+FS1:\> installer getvar all
+Found 18 block io protocols
+SDCard storage identified
+[...]
+SDCard storage identified
+Found disk as block io 0 for logical unit 0
+OEMLock not set, device is in provisioning mode
+Couldn't read timeout variable; assuming default
+err=Not Ready
+Installer for fastboot transport layer selected
+Starting command: 'getvar all'
+GOT getvar all
+(bootloader) unlocked: yes
+(bootloader) secure: no
+(bootloader) serialno: 001320FE4948
+(bootloader) board: Circuitco MinnowBoard MAX REV A
+(bootloader) device-state: unlocked
+(bootloader) boot-state: unknown
+(bootloader) firmware: Intel Corp. MNW2MAX1.X64.0090.R01.1601281003
+(bootloader) product-name: Minnowboard Max D0 PLATFORM
+(bootloader) secureboot: no
+(bootloader) off-mode-charge: 1
+(bootloader) has-slot:factory: no
+(bootloader) partition-type:factory: ext4
+(bootloader) partition-size:factory: 0x0000000000A00000
+(bootloader) has-slot:config: no
+(bootloader) partition-type:config: ext4
+(bootloader) partition-size:config: 0x0000000000800000
+(bootloader) has-slot:persistent: no
+(bootloader) partition-type:persistent: ext4
+(bootloader) partition-size:persistent: 0x0000000000100000
+(bootloader) has-slot:userdata: no
+(bootloader) partition-type:userdata: ext4
+(bootloader) partition-size:userdata: 0x0000000221600000
+(bootloader) has-slot:data: no
+(bootloader) partition-type:data: ext4
+(bootloader) partition-size:data: 0x0000000221600000
+(bootloader) has-slot:cache: no
+(bootloader) partition-type:cache: ext4
+(bootloader) partition-size:cache: 0x0000000006400000
+(bootloader) has-slot:vendor: no
+(bootloader) partition-type:vendor: ext4
+(bootloader) partition-size:vendor: 0x000000003E800000
+(bootloader) has-slot:system_b: no
+(bootloader) partition-type:system_b: ext4
+(bootloader) partition-size:system_b: 0x00000000A0000000
+(bootloader) has-slot:system_a: no
+(bootloader) partition-type:system_a: ext4
+(bootloader) partition-size:system_a: 0x00000000A0000000
+(bootloader) has-slot:metadata: no
+(bootloader) partition-type:metadata: none
+(bootloader) partition-size:metadata: 0x0000000001000000
+(bootloader) has-slot:misc: no
+(bootloader) partition-type:misc: none
+(bootloader) partition-size:misc: 0x0000000000100000
+(bootloader) has-slot:recovery: no
+(bootloader) partition-type:recovery: none
+(bootloader) partition-size:recovery: 0x0000000001E00000
+(bootloader) has-slot:boot_b: no
+(bootloader) partition-type:boot_b: none
+(bootloader) partition-size:boot_b: 0x0000000001E00000
+(bootloader) has-slot:boot_a: no
+(bootloader) partition-type:boot_a: none
+(bootloader) partition-size:boot_a: 0x0000000001E00000
+(bootloader) has-slot:bootloader2: no
+(bootloader) partition-type:bootloader2: none
+(bootloader) partition-size:bootloader2: 0x0000000003C00000
+(bootloader) has-slot:bootloader: no
+(bootloader) partition-type:bootloader: vfat
+(bootloader) partition-size:bootloader: 0x0000000003C00000
+(bootloader) max-download-size: 0x0000000010000000
+(bootloader) battery-voltage:
+(bootloader) version-bootloader: N/A
+(bootloader) product: r2_cht_ffd_m
+Command successfully executed
+FS1:\> installer flash recovery recovery.img
+Found 18 block io protocols
+SDCard storage identified
+[...]
+SDCard storage identified
+Found disk as block io 0 for logical unit 0
+OEMLock not set, device is in provisioning mode
+Couldn't read timeout variable; assuming default
+err=Not Ready
+Installer for fastboot transport layer selected
+Starting command: 'flash recovery recovery.img'
+GOT flash recovery recovery.img
+Flashing recovery ...
+Found label recovery in partition 4
+sparse header : magic 52444E41, major 18767, minor 8516, fdhrsz 16752, chdrsz 140, bz 268468224
+tot blk 14820014, tot chk 285212672
+Flash done.
+SENT OKAY
+Command successfully executed
+FS1:\>
+```
+
+With the `--batch ` parameter, Installer sequentially runs
+all the commands listed in FILENAME. The batch file format allows to
+prefix the command with a list of attribute, example:
+
+```conf
+<[]> flash system system.img
+```
+
+The only supported attribute is:
+- 'o': the command is optional. If the command fails to execute,
+ Installer does not abort the flash process and continue with the
+ next command.
+
+Example:
+```conf
+[o] flash system system.img
+```
+
+Without any parameter, Installer assumes `--batch installer.cmd`. It
+allows to create a USB stick that will automatically flash the device
+on boot.
+
+Here is a `installer.cmd` file example:
+```conf
+flashing unlock
+flash gpt gpt.bin
+erase misc
+erase persistent
+erase metadata
+format config
+format cache
+format data
+flash vendor vendor.img
+flash boot boot.img
+flash recovery recovery.img
+flash system system.img
+flash bootloader bootloader
+flash oemvars oemvars.txt
+flashing lock
+continue
+```
diff --git a/generate-prebuilts.sh b/generate-prebuilts.sh
deleted file mode 100755
index f287f2bd..00000000
--- a/generate-prebuilts.sh
+++ /dev/null
@@ -1,89 +0,0 @@
-#
-# This script is used to generate gnu_efi prebuilts for both ia32 and x86_64.
-# The resulting binaries will be copied into prebuilts/{ia32, x86_64}.
-#
-# Please make sure you have Android's build system setup first, and lunch
-# target defined.
-
-# Specify "-a" in command line to add these prebuilt binaries for
-# git commit.
-#
-# Note:
-# 1. ARCH ia32 and x86 are interchangable here.
-# Android uses x86, but EFI uses ia32.
-#
-
-set -e
-
-if [ -z "$ANDROID_BUILD_TOP" ]; then
- echo "[ERROR] \$ANDROID_BUILD_TOP not set, please run lunch"
- exit 2
-fi
-
-PREBUILT_TOP=$ANDROID_BUILD_TOP/hardware/intel/efi_prebuilts/
-
-copy_to_prebuilts()
-{
- # Sanity check
- if [ ! -s "kernelflinger.efi" ] ; then
- echo "[ERROR] *** $1: kernelflinger.efi does not exist or has size 0. aborting..."
- exit 1
- fi
-
- cp -v kernelflinger.efi kernelflinger.unsigned.efi $PREBUILT_TOP/gummiboot/linux-$1/
-}
-
-add_prebuilts=0
-while getopts "a" opt; do
- case "$opt" in
- a) add_prebuilts=1;;
- esac
-done
-
-# Check gnu-efi prebuilts are in place
-NEEDED_FILES=" \
- gnu-efi/linux-x86_64/lib/crt0-efi-x86_64.o \
- gnu-efi/linux-x86_64/lib/libefi.a
- gnu-efi/linux-x86_64/lib/libgnuefi.a \
- gnu-efi/linux-x86_64/lib/elf_x86_64_efi.lds \
- gnu-efi/linux-x86/lib/crt0-efi-ia32.o \
- gnu-efi/linux-x86/lib/libefi.a
- gnu-efi/linux-x86/lib/libgnuefi.a \
- gnu-efi/linux-x86/lib/elf_ia32_efi.lds \
- "
-have_all_files=1
-for file in $NEEDED_FILES; do
- if [ ! -s "$PREBUILT_TOP/$file" ]; then
- echo "[ERROR] --- $file does not exists in $PREBUILT_TOP."
- have_all_files=0
- fi
-done
-if [ "$have_all_files" == "0" ]; then
- echo "[ERROR] *** Please generate all necessary prebuilt binaries under external/gnu-efi before building kernelflinger."
- echo "[ERROR] *** Dependencies not satisfied. aborting..."
- exit 1
-fi
-
-# Clean up everything and create prebuilts directory
-mkdir -p $PREBUILT_TOP/kernelflinger/linux-x86
-mkdir -p $PREBUILT_TOP/kernelflinger/linux-x86_64
-
-MAKE_CMD="make -j8"
-
-$MAKE_CMD ARCH=x86_64 clean
-$MAKE_CMD ARCH=ia32 clean
-
-# FIXME remove CC definition and use a host compiler
-
-# Generate prebuilts for x86_64
-$MAKE_CMD ARCH=x86_64 \
- CC=$ANDROID_BUILD_TOP/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/bin/x86_64-linux-gcc
-copy_to_prebuilts x86_64
-$MAKE_CMD ARCH=x86_64 clean
-
-# Generate prebuilts for ia32
-$MAKE_CMD ARCH=ia32 \
- CC=$ANDROID_BUILD_TOP//prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/bin/i686-linux-gcc
-copy_to_prebuilts x86
-$MAKE_CMD ARCH=ia32 clean
-
diff --git a/include/libadb/adb.h b/include/libadb/adb.h
new file mode 100644
index 00000000..f3c98d50
--- /dev/null
+++ b/include/libadb/adb.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _ADB_H_
+#define _ADB_H_
+
+#include
+#include
+
+#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+
+/* ADB protocol types */
+#define A_SYNC MKID('S','Y','N','C')
+#define A_CNXN MKID('C','N','X','N')
+#define A_OPEN MKID('O','P','E','N')
+#define A_OKAY MKID('O','K','A','Y')
+#define A_CLSE MKID('C','L','S','E')
+#define A_WRTE MKID('W','R','T','E')
+#define A_AUTH MKID('A','U','T','H')
+
+typedef struct adb_msg {
+ UINT32 command; /* command identifier constant */
+ UINT32 arg0; /* first argument */
+ UINT32 arg1; /* second argument */
+ UINT32 data_length; /* length of payload (0 is allowed) */
+ UINT32 data_check; /* checksum of data payload */
+ UINT32 magic; /* command ^ 0xffffffff */
+} adb_msg_t;
+
+#define ADB_MIN_PAYLOAD 4096
+#define ADB_MAX_PAYLOAD 262144
+
+/* Negociated (CONNECT hand-shake) maximum buffer size */
+extern UINT32 adb_max_payload;
+
+typedef struct adb_pkt {
+ adb_msg_t msg;
+ unsigned char *data;
+} adb_pkt_t;
+
+EFI_STATUS adb_init();
+EFI_STATUS adb_run();
+EFI_STATUS adb_exit();
+enum boot_target adb_get_boot_target(void);
+void adb_set_boot_target(enum boot_target bt);
+
+EFI_STATUS adb_send_pkt(adb_pkt_t *pkt, UINT32 command, UINT32 arg0, UINT32 arg1);
+
+#endif /* _ADB_H_ */
diff --git a/include/libefitcp/tcp.h b/include/libefitcp/tcp.h
new file mode 100644
index 00000000..5db5c920
--- /dev/null
+++ b/include/libefitcp/tcp.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TCP_H_
+#define _TCP_H_
+
+#include
+#include
+
+EFI_STATUS tcp_start(UINT32 port, start_callback_t start_cb,
+ data_callback_t rx_cb, data_callback_t tx_cb,
+ EFI_IPv4_ADDRESS *station_address);
+EFI_STATUS tcp_stop(void);
+EFI_STATUS tcp_run(void);
+EFI_STATUS tcp_read(void *buf, UINT32 size);
+EFI_STATUS tcp_write(void *buf, UINT32 size);
+
+#endif /* _TCP_H_ */
diff --git a/include/libefiusb/usb.h b/include/libefiusb/usb.h
new file mode 100644
index 00000000..43fa2daf
--- /dev/null
+++ b/include/libefiusb/usb.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include
+
+EFI_STATUS usb_start(UINT8 subclass,
+ UINT8 protocol,
+ CHAR16 *str_configuration,
+ CHAR16 *str_interface,
+ start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb);
+EFI_STATUS usb_stop(void);
+EFI_STATUS usb_run(void);
+EFI_STATUS usb_read(void *buf, UINT32 size);
+EFI_STATUS usb_write(void *buf, UINT32 size);
+
+#endif /* _USB_H_ */
diff --git a/include/libelfloader/libelfloader.h b/include/libelfloader/libelfloader.h
new file mode 100644
index 00000000..32dbd6fc
--- /dev/null
+++ b/include/libelfloader/libelfloader.h
@@ -0,0 +1,29 @@
+/*******************************************************************************
+* Copyright (c) 2017 Intel Corporation
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*******************************************************************************/
+
+#ifndef _LIBELFLOADER_H_
+#define _LIBELFLOADER_H_
+
+#include "efi.h"
+#include "efilib.h"
+
+BOOLEAN relocate_elf_image( IN uint64_t ld_addr,
+ IN uint64_t ld_size,
+ IN uint64_t rt_addr,
+ IN uint64_t rt_size,
+ OUT uint64_t *p_entry);
+
+#endif /* _LIBELFLOADER_H_ */
diff --git a/include/libfastboot/fastboot.h b/include/libfastboot/fastboot.h
new file mode 100644
index 00000000..de5a5540
--- /dev/null
+++ b/include/libfastboot/fastboot.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _FASTBOOT_H_
+#define _FASTBOOT_H_
+
+#include
+#include
+#include
+
+#define MAGIC_LENGTH 64
+
+/* GUID for variables used to communicate with Fastboot */
+extern const EFI_GUID fastboot_guid;
+
+typedef void (*fastboot_handle) (INTN argc, CHAR8 **argv);
+
+struct fastboot_cmd {
+ const char *name;
+ enum device_state min_state;
+ fastboot_handle handle;
+};
+
+typedef struct cmdlist *cmdlist_t;
+
+struct download_buffer {
+ void *data;
+ UINTN size;
+ UINTN max_size;
+};
+
+struct download_buffer *fastboot_download_buffer(void);
+
+struct fastboot_cmd *fastboot_get_root_cmd(const char *name);
+EFI_STATUS fastboot_register(struct fastboot_cmd *cmd);
+EFI_STATUS fastboot_register_into(cmdlist_t *list, struct fastboot_cmd *cmd);
+void fastboot_cmdlist_unregister(cmdlist_t *list);
+void fastboot_run_cmd(cmdlist_t list, const char *name, INTN argc, CHAR8 **argv);
+void fastboot_run_root_cmd(const char *name, INTN argc, CHAR8 **argv);
+
+EFI_STATUS fastboot_publish(const char *name, const char *value);
+void fastboot_okay(const char *fmt, ...);
+void fastboot_fail(const char *fmt, ...);
+void fastboot_info(const char *fmt, ...);
+EFI_STATUS fastboot_info_long_string(char *str, void *context);
+
+EFI_STATUS fastboot_set_command_buffer(char *buffer, UINTN size);
+EFI_STATUS fastboot_start(void **bootimage, void **efiimage,
+ UINTN *imagesize, enum boot_target *target);
+EFI_STATUS fastboot_stop(void *bootimage, void *efiimage, UINTN imagesize,
+ enum boot_target target);
+void fastboot_free(void);
+EFI_STATUS refresh_partition_var(void);
+
+void fastboot_reboot(enum boot_target target, CHAR16 *msg);
+
+#endif /* _FASTBOOT_H_ */
diff --git a/include/libheci/hecisupport.h b/include/libheci/hecisupport.h
new file mode 100644
index 00000000..d7064c9e
--- /dev/null
+++ b/include/libheci/hecisupport.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _HECISUPPORT_H_
+#define _HECISUPPORT_H_
+
+#include "../../libkernelflinger/protocol/Heci.h"
+#include "../../libkernelflinger/protocol/MkhiMsgs.h"
+
+#define EOP_GROUP_ID 0xFF
+#define EOP_CMD_ID 0xC
+
+//EOP-REQ
+typedef struct _GEN_END_OF_POST
+{
+ MKHI_MESSAGE_HEADER MKHIHeader;
+} GEN_END_OF_POST;
+
+extern EFI_STATUS heci_end_of_post(void);
+
+#endif /* _HECISUPPORT_H_ */
diff --git a/include/libkernelflinger/acpi.h b/include/libkernelflinger/acpi.h
new file mode 100644
index 00000000..b13dbe50
--- /dev/null
+++ b/include/libkernelflinger/acpi.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __ACPI_H__
+#define __ACPI_H__
+
+#include
+#include
+#include
+#include "targets.h"
+
+#pragma pack(1)
+
+/** Generic ACPI table header **/
+struct ACPI_DESC_HEADER {
+ CHAR8 signature[4]; /* ASCII Table identifier */
+ UINT32 length; /* Length of the table, including the header */
+ CHAR8 revision; /* Revision of the structure */
+ CHAR8 checksum; /* Sum of all fields must be 0 */
+ CHAR8 oem_id[6]; /* ASCII OEM identifier */
+ CHAR8 oem_table_id[8]; /* ASCII OEM table identifier */
+ UINT32 oem_revision; /* OEM supplied revision number */
+ CHAR8 creator_id[4]; /* Vendor ID of utility creator of the table */
+ UINT32 creator_revision; /* Revision of utility creator of the table */
+};
+
+struct RSDP_TABLE {
+ CHAR8 signature[8]; /* "RSD PTR " */
+ CHAR8 checksum; /* RSDP Checksum (bytes 0-19) */
+ CHAR8 oem_id[6]; /* OEM ID String */
+ CHAR8 revision; /* ACPI Revision (0=1.0,2=2.0) */
+ UINT32 rsdt_address; /* 32-bit RSDT Pointer */
+ UINT32 length; /* RSDP Length */
+ UINT64 xsdt_address; /* 64-bit XSDT Pointer */
+ CHAR8 extended_checksum; /* RSDP Checksum (full) */
+ CHAR8 reserved[3]; /* Reserved */
+};
+
+struct XSDT_TABLE {
+ struct ACPI_DESC_HEADER header;
+ UINT64 entry[1]; /* Table Entries */
+};
+
+/* Minimal definition of the FACP to get the DSDT memory address. */
+struct FACP_TABLE {
+ struct ACPI_DESC_HEADER header;
+ UINT32 firmware_ctrl; /* Physical memory address of the FACS. */
+ UINT32 DSDT; /* Physical memory address (0-4 GB) of the DSDT. */
+ /* [...] */
+};
+
+struct RSCI_TABLE {
+ struct ACPI_DESC_HEADER header;
+ CHAR8 wake_source; /* How system woken up from S4 or S5 */
+ CHAR8 reset_source; /* How system was reset */
+ CHAR8 reset_type; /* Identify type of reset */
+ CHAR8 shutdown_source; /* How system was last shutdown */
+ UINT32 indicators; /* Bitmap with additional info */
+ UINT32 reset_extra_info; /* Reports system specific reset sources */
+};
+
+enum {
+ OEM1_USE_IA_APPS_CAP,
+ OEM1_USE_IA_APPS_RUN
+};
+
+struct OEM1_TABLE {
+ struct ACPI_DESC_HEADER header;
+ UINT8 fixedoptions0; /* Fixed Platform Options 0 */
+ UINT8 fixedoptions1; /* Fixed Platform Options 1*/
+ UINT8 dbiingpio; /* DBIIN GPIO number */
+ UINT8 dbioutgpio; /* DBIOUT GPIO number */
+ UINT8 batchptyp; /* Identification / Authentication chip
+ * inside the battery */
+ UINT16 ia_apps_run; /* Minimum battery voltage required to
+ * boot the platform if FG has been
+ * reset */
+ UINT8 batiddbibase; /* Resistance in KOhms for BSI used to
+ * indicate a digital battery */
+ UINT8 batidanlgbase; /* Resistance in KOhms for BSI beyond
+ * which the battery is an analog
+ * battery */
+ UINT8 ia_apps_cap; /* Minimum capacity at which to boot to Main
+ * OS */
+ UINT16 vbattfreqlmt; /* Battery Voltage up to which the CPU
+ * frequency should be limited */
+ UINT8 capfreqidx; /* Index into the Frequency table at which
+ * the CPU Frequency should be capped. */
+ UINT8 rsvd1; /* Reserved */
+ UINT8 battidx; /* Battery Index: Charging profile to use in
+ * case of fixed battery */
+ UINT8 ia_apps_to_use; /* Whether to use the IA_APPS_RUN (value
+ * = 1) or IA_APPS_CAP (value = 0) to
+ * while booting */
+ UINT8 turbochrg; /* Maximum Turbo charge supported (in
+ * multiples of 100mA). Zero means no Turbo
+ * charge */
+ UINT8 rsvd2[11]; /* Reserved */
+};
+
+/* BERT (Boot Error Record Table) as defined in ACPI spec, APEI chapter */
+struct BERT_TABLE {
+ struct ACPI_DESC_HEADER header;
+ UINT32 region_length; /* Length of BERT region */
+ UINT64 region; /* Physical address of BERT region */
+};
+
+
+struct ACPI_INFO {
+ UINT32 MediaId;
+ UINT32 img_size; /* ACPI or ACPIO image size */
+ UINT64 partition_start;
+ UINT64 partition_size;
+};
+
+#pragma pack()
+
+/* Some ACPI table signatures, SSDT for instance, might appear several
+ * times. An extra table number can be appended to the supplied
+ * SIGNATURE to specify which one is required. For instance, with
+ * SIGNATURE set to "SSDT2", the second SSDT table is returned. */
+EFI_STATUS get_acpi_table(const CHAR8 *signature, VOID **table);
+UINT16 oem1_get_ia_apps_run(void);
+UINT8 oem1_get_ia_apps_cap(void);
+UINT8 oem1_get_ia_apps_to_use(void);
+
+#define ACPI_TABLE_MAGIC 0x41435049
+#define ACPI_TABLE_MAGIC_SIZE 4
+#define ACPI_TABLE_MAX_LOAD_NUM 256
+
+EFI_STATUS install_acpi_table_from_partitions(VOID *image,
+ const char *part_name,
+ enum boot_target target);
+EFI_STATUS install_acpi_table_from_recovery_acpio(VOID *image,
+ enum boot_target target);
+EFI_STATUS install_acpi_table(VOID *acpi_table, UINTN acpi_table_size,
+ UINTN *tablekey);
+EFI_STATUS acpi_parse_selected_table_id(CHAR8 *selected_id_str,
+ UINT32 selected_id_str_len);
+EFI_STATUS acpi_image_get_length(const CHAR16 *label, struct ACPI_INFO **acpi_info);
+CHAR8 *acpi_loaded_table_idx_to_string(VOID);
+
+#endif /* __ACPI_H__ */
diff --git a/include/libkernelflinger/android.h b/include/libkernelflinger/android.h
new file mode 100644
index 00000000..311277b5
--- /dev/null
+++ b/include/libkernelflinger/android.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GUMMIBOOT_ANDROID_H
+
+#include
+
+#include "efi.h"
+#include "efilib.h"
+#ifdef HAL_AUTODETECT
+#include "blobstore.h"
+#endif
+#include "targets.h"
+#ifdef USE_AVB
+#include "libavb/libavb.h"
+#include "libavb_ab/libavb_ab.h"
+#endif
+
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+#define BOOT_NAME_SIZE 16
+#define BOOT_ARGS_SIZE 512
+#define BOOT_EXTRA_ARGS_SIZE 1024
+
+struct boot_img_hdr
+{
+ unsigned char magic[BOOT_MAGIC_SIZE];
+
+ unsigned kernel_size; /* size in bytes */
+ unsigned kernel_addr; /* physical load addr */
+
+ unsigned ramdisk_size; /* size in bytes */
+ unsigned ramdisk_addr; /* physical load addr */
+
+ unsigned second_size; /* size in bytes */
+ unsigned second_addr; /* physical load addr */
+
+ unsigned tags_addr; /* physical addr for kernel tags */
+ unsigned page_size; /* flash page size we assume */
+ unsigned header_version;
+
+ /* operating system version and security patch level; for
+ * version "A.B.C" and patch level "Y-M-D":
+ * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
+ * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
+ * os_version = ver << 11 | lvl */
+ unsigned os_version;
+ unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+
+ unsigned char cmdline[BOOT_ARGS_SIZE];
+
+ unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+
+ /* Supplemental command line data; kept here to maintain
+ * binary compatibility with older versions of mkbootimg */
+ unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
+
+ uint32_t recovery_dtbo_size; /* size of recovery dtbo image */
+ uint64_t recovery_dtbo_offset; /* offset in boot image */
+ uint32_t header_size; /* size of boot image header in bytes */
+};
+
+/*
+** +-----------------+
+** | boot header | 1 page
+** +-----------------+
+** | kernel | n pages
+** +-----------------+
+** | ramdisk | m pages
+** +-----------------+
+** | second stage | o pages
+** +-----------------+
+**
+** n = (kernel_size + page_size - 1) / page_size
+** m = (ramdisk_size + page_size - 1) / page_size
+** o = (second_size + page_size - 1) / page_size
+**
+** 0. all entities are page_size aligned in flash
+** 1. kernel and ramdisk are required (size != 0)
+** 2. second is optional (second_size == 0 -> no second)
+** 3. load each element (kernel, ramdisk, second) at
+** the specified physical address (kernel_addr, etc)
+** 4. prepare tags at tag_addr. kernel_args[] is
+** appended to the kernel commandline in the tags.
+** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+** 6. if second_size != 0: jump to second_addr
+** else: jump to kernel_addr
+*/
+
+
+/* Bootloader Message (2-KiB)
+ *
+ * This structure describes the content of a block in flash
+ * that is used for recovery and the bootloader to talk to
+ * each other.
+ *
+ * The command field is updated by linux when it wants to
+ * reboot into recovery or to update radio or bootloader firmware.
+ * It is also updated by the bootloader when firmware update
+ * is complete (to boot into recovery for any final cleanup)
+ *
+ * The status field is written by the bootloader after the
+ * completion of an "update-radio" or "update-hboot" command.
+ *
+ * The recovery field is only written by linux and used
+ * for the system to send a message to recovery or the
+ * other way around.
+ *
+ * The stage field is written by packages which restart themselves
+ * multiple times, so that the UI can reflect which invocation of the
+ * package it is. If the value is of the format "#/#" (eg, "1/3"),
+ * the UI will add a simple indicator of that status.
+ *
+ * We used to have slot_suffix field for A/B boot control metadata in
+ * this struct, which gets unintentionally cleared by recovery or
+ * uncrypt. Move it into struct bootloader_message_ab to avoid the
+ * issue.
+ */
+struct bootloader_message {
+ char command[32];
+ char status[32];
+ char recovery[768];
+
+ // The 'recovery' field used to be 1024 bytes. It has only ever
+ // been used to store the recovery command line, so 768 bytes
+ // should be plenty. We carve off the last 256 bytes to store the
+ // stage string (for multistage packages), abl boot info (for ivi abl
+ // platform usage) and possible future expansion.
+ char stage[32];
+ char abl[32];
+
+ // The 'reserved' field used to be 192 bytes when it was initially
+ // carved off from the 1024-byte recovery field. Bump it up to
+ // 1152-byte so that the entire bootloader_message struct rounds up
+ // to 2048-byte.
+ char reserved[1152];
+};
+
+/*
+ * We must be cautious when changing the bootloader_message struct size,
+ * because A/B-specific fields may end up with different offsets.
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+_Static_assert(sizeof(struct bootloader_message) == 2048,
+ "struct bootloader_message size changes, which may break A/B devices");
+#endif
+
+/*
+ * The A/B-specific bootloader message structure (4-KiB).
+ *
+ * We separate A/B boot control metadata from the regular bootloader
+ * message struct and keep it here. Everything that's A/B-specific
+ * stays after struct bootloader_message, which should be managed by
+ * the A/B-bootloader or boot control HAL.
+ *
+ * The slot_suffix field is used for A/B implementations where the
+ * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
+ * commandline parameter. This is used by fs_mgr to mount /system and
+ * other partitions with the slotselect flag set in fstab. A/B
+ * implementations are free to use all 32 bytes and may store private
+ * data past the first NUL-byte in this field. It is encouraged, but
+ * not mandatory, to use 'struct bootloader_control' described below.
+ */
+struct bootloader_message_ab {
+ struct bootloader_message message;
+ char slot_suffix[32];
+
+ // Round up the entire struct to 4096-byte.
+ char reserved[2016];
+};
+
+/*
+ * Be cautious about the struct size change, in case we put anything post
+ * bootloader_message_ab struct (b/29159185).
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+_Static_assert(sizeof(struct bootloader_message_ab) == 4096,
+ "struct bootloader_message_ab size changes");
+#endif
+
+#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
+#define BOOT_CTRL_VERSION 1
+
+struct slot_metadata {
+ // Slot priority with 15 meaning highest priority, 1 lowest
+ // priority and 0 the slot is unbootable.
+ uint8_t priority : 4;
+ // Number of times left attempting to boot this slot.
+ uint8_t tries_remaining : 3;
+ // 1 if this slot has booted successfully, 0 otherwise.
+ uint8_t successful_boot : 1;
+ // 1 if this slot is corrupted from a dm-verity corruption, 0
+ // otherwise.
+ uint8_t verity_corrupted : 1;
+ // Reserved for further use.
+ uint8_t reserved : 7;
+} __attribute__((packed));
+
+/* Bootloader Control AB
+ *
+ * This struct can be used to manage A/B metadata. It is designed to
+ * be put in the 'slot_suffix' field of the 'bootloader_message'
+ * structure described above. It is encouraged to use the
+ * 'bootloader_control' structure to store the A/B metadata, but not
+ * mandatory.
+ */
+struct bootloader_control {
+ // NUL terminated active slot suffix.
+ char slot_suffix[4];
+ // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
+ uint32_t magic;
+ // Version of struct being used (see BOOT_CTRL_VERSION).
+ uint8_t version;
+ // Number of slots being managed.
+ uint8_t nb_slot : 3;
+ // Number of times left attempting to boot recovery.
+ uint8_t recovery_tries_remaining : 3;
+ // Ensure 4-bytes alignment for slot_info field.
+ uint8_t reserved0[2];
+ // Per-slot information. Up to 4 slots.
+ struct slot_metadata slot_info[4];
+ // Reserved for further use.
+ uint8_t reserved1[8];
+ // CRC32 of all 28 bytes preceding this field (little endian
+ // format).
+ uint32_t crc32_le;
+} __attribute__((packed));
+
+#if (__STDC_VERSION__ >= 201112L || defined(__cplusplus))
+_Static_assert(sizeof(struct bootloader_control) ==
+ sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
+ "struct bootloader_control has wrong size");
+#endif
+
+/* Functions to load an Android boot image.
+ * You can do this from a file, a partition GUID, or
+ * from a RAM buffer */
+EFI_STATUS android_image_start_buffer(
+ IN EFI_HANDLE parent_image,
+ IN VOID *bootimage,
+ IN enum boot_target boot_target,
+ IN UINT8 boot_state,
+ IN EFI_GUID *swap,
+#ifdef USE_AVB
+ IN AvbSlotVerifyData *slot_data,
+#else
+ IN X509 *verity_cert,
+#endif
+ IN const CHAR8 *abl_cmd_line);
+
+EFI_STATUS setup_acpi_table(VOID *bootimage, enum boot_target target);
+
+EFI_STATUS android_image_load_partition(
+ IN const CHAR16 *label,
+ OUT VOID **bootimage_p);
+
+EFI_STATUS android_image_load_file(
+ IN EFI_HANDLE device,
+ IN CHAR16 *loader,
+ IN BOOLEAN delete,
+ OUT VOID **bootimage_p);
+#ifdef USE_AVB
+EFI_STATUS android_image_load_partition_avb(
+ IN const char *label,
+ OUT VOID **bootimage_p,
+ UINT8* boot_state,
+ AvbSlotVerifyData **slot_data);
+
+EFI_STATUS android_image_load_partition_avb_ab(
+ IN const char *label,
+ OUT VOID **bootimage_p,
+ UINT8* boot_state,
+ AvbSlotVerifyData **slot_data);
+
+EFI_STATUS get_avb_result(
+ IN AvbSlotVerifyData *slot_data,
+ IN bool allow_verification_error,
+ IN AvbSlotVerifyResult verify_result,
+ IN OUT UINT8 *boot_state);
+
+EFI_STATUS get_avb_flow_result(
+ IN AvbSlotVerifyData *slot_data,
+ IN bool allow_verification_error,
+ IN AvbABFlowResult flow_result,
+ IN OUT UINT8 *boot_state);
+#endif
+
+EFI_STATUS read_bcb(
+ IN const CHAR16 *label,
+ OUT struct bootloader_message *bcb);
+
+EFI_STATUS write_bcb(
+ IN const CHAR16 *label,
+ IN struct bootloader_message *bcb);
+
+/* Perform a security RAM wipe */
+EFI_STATUS android_clear_memory(void);
+
+/* True if the current Android configuration use slot and does not
+ * have a recovery partition. When true, it means that the current
+ * Android configuration requires to boot using the system partiton as
+ * root filesystem. It also means that the Recovery mode is provided
+ * by the boot partition ramdisk.
+ */
+BOOLEAN recovery_in_boot_partition(void);
+
+/* Sanity check the data and return a pointer to the header.
+ * Return NULL if the sanity check fails */
+struct boot_img_hdr *get_bootimage_header(VOID *bootimage_blob);
+
+/* Return the size of a boot image, DOES NOT include any signature
+ * block */
+UINTN bootimage_size(struct boot_img_hdr *aosp_header);
+
+/* Return the blob_size aligned on hdr->page_size. */
+UINT32 pagealign(struct boot_img_hdr *hdr, UINT32 blob_size);
+
+#ifdef HAL_AUTODETECT
+/* Get a particular blob type out of a boot image's blobstore, stored in
+ * the 'second stage' area.
+ *
+ * Return values:
+ * EFI_SUCCESS - Completed successfully. Do not free the blob pointer or
+ * modify its contents
+ * EFI_UNSUPPORTED - This boot image does not contain a blobstore
+ * EFI_INVALID_PARAMETER - Boot image corrupted, or 2ndstage data isn't a
+ * blobstore
+ * EFI_NOT_FOUND - Specified type not found
+ * EFI_OUT_OF_RESOURCES - Out of memory */
+EFI_STATUS get_bootimage_blob(VOID *bootimage, enum blobtype btype, VOID **blob,
+ UINT32 *blobsize);
+#endif
+
+/* Get a pointer and size to the 2ndstage area of a boot image */
+EFI_STATUS get_bootimage_2nd(VOID *bootimage, VOID **second, UINT32 *size);
+
+#endif
+
+/* vim: softtabstop=8:shiftwidth=8:expandtab
+ */
diff --git a/lib.h b/include/libkernelflinger/blobstore.h
similarity index 50%
rename from lib.h
rename to include/libkernelflinger/blobstore.h
index 1f6ba44a..e60cd4b5 100644
--- a/lib.h
+++ b/include/libkernelflinger/blobstore.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Intel Corporation
+ * Copyright (c) 2015, Intel Corporation
* All rights reserved.
*
* Author: Andrew Boie
@@ -30,63 +30,25 @@
*
*/
-#ifndef _KF_LIB_H_
-#define _KF_LIB_H_
+#ifndef BLOBSTORE_H_
+#define BLOBSTORE_H_
+struct blobstore;
-/*
- * EFI Variables
- */
-EFI_STATUS get_efi_variable(const EFI_GUID *guid, CHAR16 *key,
- UINTN *size_p, VOID **data_p);
-
-CHAR16 *get_efi_variable_str(const EFI_GUID *guid, CHAR16 *key);
-
-EFI_STATUS get_efi_variable_byte(const EFI_GUID *guid, CHAR16 *key, UINT8 *byte);
-
-EFI_STATUS set_efi_variable(const EFI_GUID *guid, CHAR16 *key,
- UINTN size, VOID *data, BOOLEAN nonvol, BOOLEAN runtime);
-
-EFI_STATUS set_efi_variable_str(const EFI_GUID *guid, CHAR16 *key,
- BOOLEAN nonvol, BOOLEAN runtime, CHAR16 *val);
-
-/*
- * File I/O
- */
-
-EFI_STATUS file_delete(IN EFI_HANDLE disk, IN const CHAR16 *name);
-
-BOOLEAN file_exists(IN EFI_HANDLE disk, IN const CHAR16 *path);
-
-/*
- * String manipulation
- */
-CHAR16 *stra_to_str(CHAR8 *stra);
-
-EFI_STATUS str_to_stra(CHAR8 *dst, CHAR16 *src, UINTN len);
-
-UINTN memcmp(const VOID *ptr1, const VOID *ptr2, UINTN num);
-
-VOID memcpy(VOID *dst, const VOID *src, UINTN size);
-
-VOID memset(VOID *dst, CHAR8 ch, UINTN size);
-
-VOID StrNCpy(OUT CHAR16 *dest, IN const CHAR16 *src, UINT32 n);
-
-UINT8 getdigit(IN CHAR16 *str);
-
-EFI_STATUS string_to_guid(IN CHAR16 *in_guid_str, OUT EFI_GUID *guid);
-
-UINTN strtoul(const CHAR16 *nptr, CHAR16 **endptr, UINTN base);
-
-/*
- * misc
- */
-
-EFI_STATUS halt_system(VOID);
+enum blobtype {
+ BLOB_TYPE_DTB,
+ BLOB_TYPE_OEMVARS,
+ BLOB_TYPE_BOOTVARS
+};
-VOID pause(UINTN seconds);
+/* Cast an arbitray pointer to a blobstore pointer. This just does some
+ * sanity checking, nothing is heap-allocated or changed in the data.
+ * Returns NULL if this isn't a blobstore or is corrupted */
+struct blobstore *blobstore_get(void *mem, unsigned int size);
-EFI_STATUS reboot(VOID);
+/* Fetch an item out of the blobstore. Returns nonzero if it isn't found
+ * or the blobstore is corrupted */
+int blobstore_get_item(struct blobstore *bs, char *key, enum blobtype type,
+ void **data, unsigned int *size);
#endif
diff --git a/include/libkernelflinger/dt_table.h b/include/libkernelflinger/dt_table.h
new file mode 100644
index 00000000..3da1d01d
--- /dev/null
+++ b/include/libkernelflinger/dt_table.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DT_TABLE_H
+#define DT_TABLE_H
+
+#include
+/*
+ * For the image layout, refer README.md for the detail
+ */
+
+#define DT_TABLE_MAGIC 0xd7b7ab1e
+#define DT_TABLE_DEFAULT_PAGE_SIZE 2048
+#define DT_TABLE_DEFAULT_VERSION 0
+
+struct dt_table_header {
+ UINT32 magic; /* DT_TABLE_MAGIC */
+ UINT32 total_size; /* includes dt_table_header + all dt_table_entry
+ and all dtb/dtbo */
+ UINT32 header_size; /* sizeof(dt_table_header) */
+
+ UINT32 dt_entry_size; /* sizeof(dt_table_entry) */
+ UINT32 dt_entry_count; /* number of dt_table_entry */
+ UINT32 dt_entries_offset; /* offset to the first dt_table_entry
+ from head of dt_table_header.
+ The value will be equal to header_size if
+ no padding is appended */
+
+ UINT32 page_size; /* flash page size we assume */
+ UINT32 version; /* DTBO image version, the current version is 0.
+ The version will be incremented when the
+ dt_table_header struct is updated. */
+};
+
+struct dt_table_entry {
+ UINT32 dt_size;
+ UINT32 dt_offset; /* offset from head of dt_table_header */
+
+ UINT32 id; /* optional, must be zero if unused */
+ UINT32 rev; /* optional, must be zero if unused */
+ UINT32 custom[4]; /* optional, must be zero if unused */
+};
+
+#endif
diff --git a/include/libkernelflinger/em.h b/include/libkernelflinger/em.h
new file mode 100644
index 00000000..5e780a0b
--- /dev/null
+++ b/include/libkernelflinger/em.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _EM_H_
+#define _EM_H_
+
+BOOLEAN is_charger_plugged_in(void);
+BOOLEAN is_battery_below_boot_OS_threshold(void);
+EFI_STATUS get_battery_voltage(UINTN *voltage);
+
+#endif /* _EM_H_ */
diff --git a/bootlogic.h b/include/libkernelflinger/endian.h
similarity index 76%
rename from bootlogic.h
rename to include/libkernelflinger/endian.h
index a172c49e..0a7f6a4e 100644
--- a/bootlogic.h
+++ b/include/libkernelflinger/endian.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Intel Corporation
+ * Copyright (c) 2015, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,21 +30,25 @@
* any external definitions in order to ease export of it.
*/
-#ifndef _BOOTLOGIC_H_
-#define _BOOTLOGIC_H_
+#ifndef _ENDIAN_H_
+#define _ENDIAN_H_
-/** RSCI Definitions **/
+#include
-/* Wake sources */
-enum wake_sources {
- WAKE_NOT_APPLICABLE,
- WAKE_BATTERY_INSERTED,
- WAKE_USB_CHARGER_INSERTED,
- WAKE_ACDC_CHARGER_INSERTED,
- WAKE_POWER_BUTTON_PRESSED,
- WAKE_RTC_TIMER,
- WAKE_BATTERY_REACHED_IA_THRESHOLD,
- WAKE_ERROR = -1,
-};
+#define htobe16 __builtin_bswap16
+#define htobe32 __builtin_bswap32
+#define htobe64 __builtin_bswap64
-#endif /* _BOOTLOGIC_H_ */
+#define be16toh __builtin_bswap16
+#define be32toh __builtin_bswap32
+#define be64toh __builtin_bswap64
+
+#define le32toh(x) (x)
+#define htole32(x) (x)
+
+typedef UINT8 __be8;
+typedef UINT16 __be16;
+typedef UINT32 __be32;
+typedef UINT64 __be64;
+
+#endif /* _ENDIAN_H_ */
diff --git a/include/libkernelflinger/firststage_mount.h b/include/libkernelflinger/firststage_mount.h
new file mode 100644
index 00000000..7626d120
--- /dev/null
+++ b/include/libkernelflinger/firststage_mount.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Haoyu Tang
+ * Chen, ZhiminX
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _FIRSTSTAGE_MOUNT_H_
+#define _FIRSTSTAGE_MOUNT_H_
+
+EFI_STATUS install_firststage_mount_ssdt(enum boot_target target);
+
+#endif /* ifndef _FIRSTSTAGE_MOUNT_H_ */
diff --git a/include/libkernelflinger/gpio.h b/include/libkernelflinger/gpio.h
new file mode 100644
index 00000000..c2f68acd
--- /dev/null
+++ b/include/libkernelflinger/gpio.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _GPIO_H_
+#define _GPIO_H_
+
+#include
+#include
+
+typedef enum
+{
+ GpInOut = 0,
+ GpIn = 1, /* GPI, input only in PAD_VALUE */
+ GpOut = 2, /* GPO, output only in PAD_VALUE */
+} GPIO_DIRECTION;
+
+typedef enum
+{
+ Low = 0,
+ High = 1,
+} GPIO_LEVEL;
+
+typedef enum
+{
+ Fn0 = 0, /* GPIO mode*/
+ Fn1 = 1,
+ Fn2 = 2,
+ Fn3 = 3,
+ Fn4 = 4,
+ Fn5 = 5
+} PAD_MODE;
+
+EFI_STATUS gpio_get_max_count(UINT32 *count);
+EFI_STATUS get_gpio_pin_dir(UINT32 PinNum, GPIO_DIRECTION *dir);
+EFI_STATUS set_gpio_pin_dir(UINT32 PinNum, GPIO_DIRECTION dir);
+EFI_STATUS get_gpio_pin_level(UINT32 PinNum, GPIO_LEVEL *level);
+EFI_STATUS set_gpio_pin_level(UINT32 PinNum, GPIO_LEVEL level);
+EFI_STATUS set_gpio_pin_mode(UINT32 PinNum, PAD_MODE mode);
+EFI_STATUS get_gpio_pin_mode(UINT32 PinNum, PAD_MODE *mode);
+
+#endif /*_GPIO_H_*/
diff --git a/include/libkernelflinger/gpt.h b/include/libkernelflinger/gpt.h
new file mode 100755
index 00000000..e6c69820
--- /dev/null
+++ b/include/libkernelflinger/gpt.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _GPT_H_
+#define _GPT_H_
+
+#include
+#include
+#include "gpt_bin.h"
+#include "storage.h"
+
+#define MBR_CODE_SIZE 440
+#define GPT_NAME_LEN 36
+
+struct gpt_header {
+ char signature[8];
+ UINT32 revision;
+ UINT32 size;
+ UINT32 header_crc32;
+ UINT32 reserved_zero;
+ UINT64 my_lba;
+ UINT64 alternate_lba;
+ UINT64 first_usable_lba;
+ UINT64 last_usable_lba;
+ EFI_GUID disk_uuid;
+ UINT64 entries_lba;
+ UINT32 number_of_entries;
+ UINT32 size_of_entry;
+ UINT32 entries_crc32;
+ /* Remainder of sector is reserved and should be 0 */
+} __attribute__((packed));
+
+struct gpt_partition {
+ EFI_GUID type;
+ EFI_GUID unique;
+ UINT64 starting_lba;
+ UINT64 ending_lba;
+ union {
+ struct {
+ UINT16 reserved[3];
+ UINT16 gpt_att;
+ } __attribute__((packed)) fields;
+ UINT64 whole;
+ } attrs;
+ UINT16 name[GPT_NAME_LEN]; /* UTF-16 encoded partition name */
+ /* Remainder of entry is reserved and should be 0 */
+} __attribute__((packed));
+
+#define GPT_ENTRIES 128
+#define GPT_ENTRY_SIZE 128
+#define GPT_HEADER_SIZE (is_cur_storage_ufs()? 4096:512)
+
+struct gpt_partition_interface {
+ struct gpt_partition part;
+ EFI_BLOCK_IO *bio;
+ EFI_DISK_IO *dio;
+ EFI_HANDLE handle;
+};
+
+EFI_STATUS gpt_get_partition_by_label(const CHAR16 *label, struct gpt_partition_interface *gpart, logical_unit_t log_unit);
+EFI_STATUS gpt_list_partition(struct gpt_partition_interface **gpartlist, UINTN *part_count, logical_unit_t log_unit);
+EFI_STATUS gpt_create(struct gpt_header *gh, UINTN gh_size,
+ UINT64 start_lba, UINTN part_count, struct gpt_bin_part *gbp, logical_unit_t log_unit);
+void gpt_free_cache(void);
+EFI_STATUS gpt_refresh(void);
+EFI_STATUS gpt_get_root_disk(struct gpt_partition_interface *gpart, logical_unit_t log_unit);
+EFI_STATUS gpt_get_partition_uuid(const CHAR16 *label, EFI_GUID *uuid, logical_unit_t log_unit);
+EFI_STATUS gpt_get_partition_type(const CHAR16 *label, EFI_GUID *type, logical_unit_t log_unit);
+EFI_STATUS gpt_swap_partition(const CHAR16 *label1, const CHAR16 *label2, logical_unit_t log_unit);
+EFI_STATUS gpt_sync(void);
+EFI_STATUS gpt_get_partition_handle(const CHAR16 *label, logical_unit_t log_unit, EFI_HANDLE *handle);
+EFI_STATUS gpt_get_header(struct gpt_header **header, UINTN *size, logical_unit_t log_unit);
+EFI_STATUS gpt_get_partitions(struct gpt_partition **partitions, UINTN *size, logical_unit_t log_unit);
+
+#endif /* _GPT_H_ */
diff --git a/include/libkernelflinger/gpt_bin.h b/include/libkernelflinger/gpt_bin.h
new file mode 100644
index 00000000..1eea0f98
--- /dev/null
+++ b/include/libkernelflinger/gpt_bin.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GPT_BIN_H__
+#define __GPT_BIN_H__
+
+#include
+
+#define GPT_BIN_MAGIC 0x6a8b0da1
+
+/* length unit is MiB */
+#define MiB (1024 * 1024)
+
+struct gpt_bin_header {
+ UINT32 magic;
+ UINT32 start_lba;
+ UINT32 npart;
+};
+
+struct gpt_bin_part {
+ INT32 length;
+ CHAR16 label[36];
+ EFI_GUID type;
+ EFI_GUID uuid;
+};
+
+#endif /* __GPT_BIN_H__ */
diff --git a/include/libkernelflinger/ioc_can.h b/include/libkernelflinger/ioc_can.h
new file mode 100644
index 00000000..15139be7
--- /dev/null
+++ b/include/libkernelflinger/ioc_can.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: kui.wen@intel.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IOC_CAN_H_
+#define _IOC_CAN_H_
+
+#include
+
+EFI_STATUS notify_ioc_ready();
+EFI_STATUS set_suppress_heart_beat_timeout(UINT32 timeout);
+
+#endif /* _IOC_CAN_H_ */
\ No newline at end of file
diff --git a/include/libkernelflinger/ioc_uart_protocol.h b/include/libkernelflinger/ioc_uart_protocol.h
new file mode 100644
index 00000000..e9e6866c
--- /dev/null
+++ b/include/libkernelflinger/ioc_uart_protocol.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: kui.wen@intel.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IOC_UART_PROTOCOL_H_
+#define _IOC_UART_PROTOCOL_H_
+
+#include
+
+#define EFI_IOC_UART_PROTOCOL_GUID \
+ {0x6152f300, 0x957f, 0x40b2, {0x9e, 0x4b, 0xe9, 0x22, 0x37, 0xa6, 0x66, 0xed}}
+
+typedef struct _IOC_UART_PROTOCOL IOC_UART_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_SUPPRESS_HEART_BEAT_TIMEOUT) (
+ IN IOC_UART_PROTOCOL *This,
+ IN UINT32 timeout
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_NOTIFY_IOC_CM_READY) (
+ IN IOC_UART_PROTOCOL *This
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FLASH_IOC_FIRMWARE) (
+ IN IOC_UART_PROTOCOL * This,
+ IN UINT8 * file_content,
+ IN UINT32 file_size
+);
+
+struct _IOC_UART_PROTOCOL {
+ EFI_SET_SUPPRESS_HEART_BEAT_TIMEOUT SetSuppressHeartBeatTimeout;
+ EFI_NOTIFY_IOC_CM_READY NotifyIOCCMReady;
+ EFI_FLASH_IOC_FIRMWARE flash_ioc_firmware;
+} __attribute__((packed));
+
+#endif /* _IOC_UART_PROTOCOL_H_ */
diff --git a/include/libkernelflinger/lib.h b/include/libkernelflinger/lib.h
new file mode 100644
index 00000000..eb5ba7f2
--- /dev/null
+++ b/include/libkernelflinger/lib.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Andrew Boie
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _KF_LIB_H_
+#define _KF_LIB_H_
+
+#include
+#include
+#include
+#include
+#include
+
+typedef UINTN size_t;
+typedef INTN ssize_t;
+
+#define offsetof(TYPE, MEMBER) ((UINTN) &((TYPE *)0)->MEMBER)
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
+
+#define max(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+
+#define min(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a < _b ? _a : _b; })
+
+#define _CONVERT_TO_WIDE(x) L ## x
+#define CONVERT_TO_WIDE(x) _CONVERT_TO_WIDE(x)
+
+#define ULONG_MAX ((unsigned long)-1)
+#define ULLONG_MAX ((unsigned long long)-1)
+
+#define panic(x, ...) do { \
+ error(x, ##__VA_ARGS__); \
+ pause(30); \
+ halt_system(); \
+} while(0)
+
+/* Current EFI image handle. To be use as parent image with the
+ LoadImage boot service */
+extern EFI_HANDLE g_parent_image;
+
+/*
+ * EFI Variables
+ */
+EFI_STATUS get_efi_variable(const EFI_GUID *guid, CHAR16 *key,
+ UINTN *size_p, VOID **data_p, UINT32 *flags_p);
+
+CHAR16 *get_efi_variable_str(const EFI_GUID *guid, CHAR16 *key);
+CHAR16 *get_efi_variable_str8(const EFI_GUID *guid, CHAR16 *key);
+
+EFI_STATUS get_efi_variable_byte(const EFI_GUID *guid, CHAR16 *key, UINT8 *byte);
+EFI_STATUS get_efi_variable_long_from_str8(const EFI_GUID *guid, CHAR16 *key,
+ unsigned long *i);
+
+EFI_STATUS del_efi_variable(const EFI_GUID *guid, CHAR16 *key);
+
+EFI_STATUS set_efi_variable(const EFI_GUID *guid, CHAR16 *key,
+ UINTN size, VOID *data, BOOLEAN nonvol, BOOLEAN runtime);
+
+EFI_STATUS set_efi_variable_str(const EFI_GUID *guid, CHAR16 *key,
+ BOOLEAN nonvol, BOOLEAN runtime, CHAR16 *val);
+
+/*
+ * File I/O
+ */
+
+EFI_STATUS file_delete(IN EFI_HANDLE disk, IN const CHAR16 *name);
+
+BOOLEAN file_exists(IN EFI_HANDLE disk, IN const CHAR16 *path);
+
+EFI_STATUS file_read(IN EFI_FILE_HANDLE dir, IN const CHAR16 *name,
+ OUT CHAR8 **content, OUT UINTN *len);
+
+/*
+ * String manipulation
+ */
+CHAR16 *stra_to_str(const CHAR8 *stra);
+
+EFI_STATUS str_to_stra(CHAR8 *dst, const CHAR16 *src, UINTN len);
+
+EFI_STATUS stra_to_guid(const char *str, EFI_GUID *g);
+
+int efi_vsnprintf(CHAR8 *dst, UINTN size, const CHAR8 *format, va_list ap);
+
+int efi_snprintf(CHAR8 *str, UINTN size, const CHAR8 *format, ...);
+
+VOID StrNCpy(OUT CHAR16 *dest, IN const CHAR16 *src, UINT32 n);
+
+UINT8 getdigit(IN CHAR16 *str);
+
+EFI_STATUS string_to_guid(IN CHAR16 *in_guid_str, OUT EFI_GUID *guid);
+
+char *strcasestr(const char *s, const char *find);
+
+char *strdup(const char *s)
+ __attribute__((weak));
+
+EFI_STATUS bytes_to_hex_stra(CHAR8 *bytes, UINTN length,
+ CHAR8 *str, UINTN str_size);
+
+char *strtok_r(char *str, const char *delim, char **saveptr)
+ __attribute__((weak));
+
+CHAR16 *StrStr(const CHAR16 *s, const CHAR16 *find);
+
+CHAR8 *strchr(const CHAR8 *s, int c)
+ __attribute__((weak));
+
+int strcmp(const CHAR8 *s1, const CHAR8 *s2)
+ __attribute__((weak));
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+ __attribute__((weak));
+
+int strncmp(const CHAR8 *s1, const CHAR8 *s2, size_t n)
+ __attribute__((weak));
+
+CHAR8 *strcpy(CHAR8 *dest, const CHAR8 *src)
+ __attribute__((weak));
+
+CHAR8 *strncpy(CHAR8 *dest, const CHAR8 *src, size_t n)
+ __attribute__((weak));
+
+size_t strlcat(CHAR8 *dst, const CHAR8 *src, size_t siz)
+ __attribute__((weak));
+
+size_t strlen(const CHAR8 *s)
+ __attribute__((weak));
+
+size_t strnlen(const CHAR8 *s, size_t maxlen)
+ __attribute__((weak));
+
+CHAR8 *itoa(int val, CHAR8 *buf, unsigned radix)
+ __attribute__((weak));
+
+void *memcpy(void *dest, const void *source, size_t count)
+ __attribute__((weak));
+
+void *memmove(void *dst, const void *src, size_t n)
+ __attribute__((weak));
+
+unsigned long long strtoull(const char *nptr, char **endptr, int base)
+ __attribute__((weak));
+
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+ __attribute__((weak));
+
+int isalnum(int c)
+ __attribute__((weak));
+
+int isspace(int c)
+ __attribute__((weak));
+
+int isdigit(int c)
+ __attribute__((weak));
+
+int isupper(int c)
+ __attribute__((weak));
+
+int isxdigit(int c)
+ __attribute__((weak));
+
+int tolower(int c)
+ __attribute__((weak));
+
+void qsort(void *base, size_t num, size_t width,
+ int (*compare)(const void *, const void *))
+ __attribute__((weak));
+
+INTN StrcaseCmp(CHAR16 *s1, CHAR16 *s2);
+
+/*
+ * misc
+ */
+#define _unused __attribute__((unused))
+
+VOID halt_system(VOID) __attribute__ ((noreturn));
+
+VOID pause(UINTN seconds);
+
+VOID reboot(CHAR16 *target, EFI_RESET_TYPE type) __attribute__ ((noreturn));
+
+void *memset(void *s, int c, size_t n)
+ __attribute__((weak));
+
+int memcmp(const void *s1, const void *s2, size_t n)
+ __attribute__((weak));
+
+EFI_STATUS alloc_aligned(VOID **free_addr, VOID **aligned_addr,
+ UINTN size, UINTN align);
+
+void sort_memory_map(void *descr, UINTN nr_descr, UINTN descr_sz);
+
+UINT64 efi_time_to_ctime(EFI_TIME *time);
+
+VOID cpuid(UINT32 op, UINT32 reg[4]);
+
+EFI_STATUS generate_random_numbers(CHAR8 *data, UINTN size);
+
+BOOLEAN no_device_unlock();
+
+UINT8 min_boot_state();
+
+#endif
diff --git a/include/libkernelflinger/life_cycle.h b/include/libkernelflinger/life_cycle.h
new file mode 100644
index 00000000..fedf4481
--- /dev/null
+++ b/include/libkernelflinger/life_cycle.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Leo Sartre
+ * Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LIFE_CYCLE_H_
+#define _LIFE_CYCLE_H_
+
+#include
+#include
+
+EFI_STATUS life_cycle_is_enduser(BOOLEAN *enduser);
+
+#endif /* _LIFE_CYCLE_H_ */
diff --git a/include/libkernelflinger/log.h b/include/libkernelflinger/log.h
new file mode 100644
index 00000000..974e5b5b
--- /dev/null
+++ b/include/libkernelflinger/log.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include
+#include
+#include
+
+EFI_STATUS log_flush_to_var(BOOLEAN nonvol);
+
+void log(const CHAR16 *fmt, ...);
+void vlog(const CHAR16 *fmt, va_list args);
+
+#ifdef __DISABLE_DEBUG_PRINT
+#define DEBUG_MESSAGES 0
+#else
+#ifdef USER
+#define DEBUG_MESSAGES 0
+#else
+#define DEBUG_MESSAGES 1
+#endif
+#endif
+
+#if DEBUG_MESSAGES
+#define debug(fmt, ...) do { \
+ log(fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+#ifdef USE_UI
+#define info(fmt, ...) do { \
+ log(fmt "\n", ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ ui_info(fmt, ##__VA_ARGS__); \
+ } else \
+ Print(fmt "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define info_n(fmt, ...) do { \
+ log(fmt "", ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ ui_info_n(fmt, ##__VA_ARGS__); \
+ } else \
+ Print(fmt, ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define warning(fmt, ...) do { \
+ log(fmt "\n", ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ ui_print(fmt, ##__VA_ARGS__); \
+ } else \
+ Print(fmt "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define warning_n(fmt, ...) do { \
+ log(fmt "", ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ ui_warning(fmt, ##__VA_ARGS__); \
+ } else \
+ Print(fmt, ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+#else /* USE_UI */
+#define warning(fmt, ...) do { \
+ log(fmt "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define warning_n(fmt, ...) do { \
+ log(fmt "", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define info(fmt, ...) do { \
+ log(fmt "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+
+#define info_n(fmt, ...) do { \
+ log(fmt "", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+#endif /* USE_UI */
+#define debug_pause(x) pause(x)
+#else /* DEBUG_MESSAGE */
+#define info(fmt, ...) (void)0
+#define info_n(fmt, ...) (void)0
+#define warning(fmt, ...) (void)0
+#define warning_n(fmt, ...) (void)0
+#define debug(fmt, ...) (void)0
+#define debug_pause(x) (void)(x)
+#endif /* DEBUG_MESSAGE */
+
+#ifdef USE_UI
+#define error(x, ...) do { \
+ log(x "\n", ##__VA_ARGS__); \
+ if (ui_is_ready()) { \
+ ui_error(x, ##__VA_ARGS__); \
+ } else \
+ Print(x "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+#else
+#define error(x, ...) do { \
+ log(x "\n", ##__VA_ARGS__); \
+ log_flush_to_var(TRUE); \
+} while(0)
+#endif /* USE_UI */
+
+#define efi_perror(ret, x, ...) do { \
+ error(x ": %r", ##__VA_ARGS__, ret); \
+} while (0)
+
+#endif /* _LOG_H_ */
diff --git a/include/libkernelflinger/oemvars.h b/include/libkernelflinger/oemvars.h
new file mode 100644
index 00000000..d35151f4
--- /dev/null
+++ b/include/libkernelflinger/oemvars.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __OEMVARS_H__
+#define __OEMVARS_H__
+
+#include
+
+EFI_STATUS flash_oemvars(VOID *data, UINTN size);
+EFI_STATUS flash_oemvars_silent_write_error(VOID *data, UINTN size,
+ const EFI_GUID *restricted_guid);
+
+#endif /* __OEMVARS_H__ */
diff --git a/options.h b/include/libkernelflinger/options.h
similarity index 100%
rename from options.h
rename to include/libkernelflinger/options.h
diff --git a/include/libkernelflinger/pae.h b/include/libkernelflinger/pae.h
new file mode 100644
index 00000000..44ccd640
--- /dev/null
+++ b/include/libkernelflinger/pae.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PAE_H_
+#define _PAE_H_
+
+EFI_STATUS pae_init(CHAR8 *entries, UINTN nr_entries, UINTN entry_sz);
+EFI_STATUS pae_map(EFI_PHYSICAL_ADDRESS addr, unsigned char **to, UINT64 *len);
+EFI_STATUS pae_exit(void);
+
+#endif /* _PAE_H_ */
diff --git a/include/libkernelflinger/pci.h b/include/libkernelflinger/pci.h
new file mode 100644
index 00000000..c26a4838
--- /dev/null
+++ b/include/libkernelflinger/pci.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file defines bootlogic data structures, try to keep it without
+ * any external definitions in order to ease export of it.
+ */
+
+#ifndef _PCI_H_
+#define _PCI_H_
+
+#include
+#include
+
+#define PCI_DEVICE_ID_ANY 0xFFFF
+
+typedef struct _pci_device_ids
+{
+ UINT16 vendor_id;
+ UINT16 device_id;
+} pci_device_ids_t;
+
+/**
+ * get_pci_device_path:
+ * @p - Pointer to a EFI_DEVICE_PATH structure
+ *
+ * Checks if the Device Path given as parameter contains a PCI Device Node
+ *
+ * Returns:
+ * a pointer to a PCI_DEVICE_PATH structure
+ * NULL if the device path given as parameter doesn't contain a PCI Device Node
+ */
+PCI_DEVICE_PATH *get_pci_device_path(EFI_DEVICE_PATH *p);
+
+/**
+ * get_pci_device:
+ * @p - Pointer to a EFI_DEVICE_PATH structure
+ * @p_pciio - A corresponding EFI_PCI_IO_PROTOCOL handle if a PCI device was
+ * found in the Device Path parameter
+ *
+ * Queries a Device Path to check if support the PciIoProtocol
+ *
+ * Returns:
+ * EFI_SUCCESS if the input path contains a PCI device
+ * an EFI error protocol handle could not be opened
+ */
+EFI_STATUS get_pci_device(IN EFI_DEVICE_PATH *p, OUT EFI_PCI_IO **p_pciio);
+
+/**
+ * get_pci_ids:
+ * @pciio - The EFI_PCI_IO_PROTOCOL handle for a device
+ * @ids - Vendor and Device Ids
+ *
+ * Reads the Vendor and Device IDs from the PCI configuration space
+ *
+ * Returns:
+ * EFI_SUCCESS - The operation succeeded
+ * an EFI Error if the values could not be read
+ */
+EFI_STATUS get_pci_ids(IN EFI_PCI_IO *pciio, OUT pci_device_ids_t *ids);
+
+#endif /* _PCI_H_ */
diff --git a/include/libkernelflinger/power.h b/include/libkernelflinger/power.h
new file mode 100644
index 00000000..8ac0c675
--- /dev/null
+++ b/include/libkernelflinger/power.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file defines bootlogic data structures, try to keep it without
+ * any external definitions in order to ease export of it.
+ */
+
+#ifndef _POWER_H_
+#define _POWER_H_
+
+/** RSCI Definitions **/
+
+/* Wake sources */
+enum wake_sources {
+ WAKE_NOT_APPLICABLE,
+ WAKE_BATTERY_INSERTED,
+ WAKE_USB_CHARGER_INSERTED,
+ WAKE_ACDC_CHARGER_INSERTED,
+ WAKE_POWER_BUTTON_PRESSED,
+ WAKE_RTC_TIMER,
+ WAKE_BATTERY_REACHED_IA_THRESHOLD,
+ WAKE_ERROR = -1,
+};
+
+enum reset_sources {
+ RESET_NOT_APPLICABLE,
+ RESET_OS_INITIATED,
+ RESET_FORCED,
+ RESET_FW_UPDATE,
+ RESET_KERNEL_WATCHDOG,
+ RESET_SECURITY_WATCHDOG,
+ RESET_SECURITY_INITIATED,
+ RESET_EC_WATCHDOG = 8,
+ RESET_PMIC_WATCHDOG,
+ RESET_SHORT_POWER_LOSS = 11,
+ RESET_PLATFORM_SPECIFIC,
+ RESET_UNKNOWN = 0xFF,
+ RESET_ERROR = -1,
+};
+
+enum reset_types {
+ NOT_APPLICABLE,
+ WARM_RESET,
+ COLD_RESET,
+ GLOBAL_RESET = 7
+};
+
+enum wake_sources rsci_get_wake_source(void);
+
+enum reset_sources rsci_get_reset_source(void);
+
+enum reset_types rsci_get_reset_type(void);
+
+UINT32 rsci_get_reset_extra_info(void);
+
+#if DEBUG_MESSAGES
+const CHAR16 *wake_source_string(enum wake_sources ws);
+const CHAR16 *reset_source_string(enum reset_sources rs);
+const CHAR16 *reset_type_string(enum reset_types rt);
+#endif
+
+#endif /* _POWER_H_ */
diff --git a/include/libkernelflinger/protocol.h b/include/libkernelflinger/protocol.h
new file mode 100644
index 00000000..f9550e8c
--- /dev/null
+++ b/include/libkernelflinger/protocol.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __PROTOCOL_H__
+#define __PROTOCOL_H__
+
+#include
+#include
+
+/**
+ * handle_protocol - Query @handle to see if it supports @protocol
+ * @handle: the handle being queried
+ * @protocol: the GUID of the protocol
+ * @interface: used to return the protocol interface
+ *
+ * Query @handle to see if @protocol is supported. If it is supported,
+ * @interface contains the protocol interface.
+ */
+static inline EFI_STATUS
+handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
+{
+ return uefi_call_wrapper(BS->HandleProtocol, 3,
+ handle, protocol, interface);
+}
+
+/**
+ * locate_handle - Search for handles that support @protocol
+ * @type: the search type, which handles are returned
+ * @protocol: the protocol to search by (only valid if @type is ByProtocol)
+ * @key: the search key
+ * @size: on input the size in bytes of @buffer, on output the size of
+ * the returned array or the required size to store the array
+ * in @buffer if it was not large enough
+ * @buffer: buffere where the array of handles is returned
+ */
+static inline EFI_STATUS
+locate_handle(EFI_LOCATE_SEARCH_TYPE type, EFI_GUID *protocol, void *key,
+ UINTN *size, EFI_HANDLE *buffer)
+{
+ return uefi_call_wrapper(BS->LocateHandle, 5, type, protocol,
+ key, size, buffer);
+}
+
+/**
+ * locate_device_path - Locate the @handle to a device on @device_path that
+ * supports the specified protocol.
+ * @protocol: the protocol to search for
+ * @device_path: on input a pointer to a pointer to the device path, on output
+ * the device path pointer is modified to point to the remaining
+ * part of the device path
+ * @handle: pointer to the returned device handle
+ */
+static inline EFI_STATUS
+locate_device_path(EFI_GUID *protocol, EFI_DEVICE_PATH **device_path,
+ EFI_HANDLE *handle)
+{
+ return uefi_call_wrapper(BS->LocateDevicePath, 3, protocol, device_path,
+ handle);
+}
+
+#endif /* __PROTOCOL_H__ */
diff --git a/include/libkernelflinger/rpmb.h b/include/libkernelflinger/rpmb.h
new file mode 100644
index 00000000..f664156b
--- /dev/null
+++ b/include/libkernelflinger/rpmb.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: kwen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _RPMB_H_
+#define _RPMB_H_
+
+#include
+#include "rpmb_storage_common.h"
+
+EFI_STATUS rpmb_init(EFI_HANDLE disk_handle);
+EFI_STATUS get_storage_protocol(void **rpmb_dev, EFI_HANDLE disk_handle);
+EFI_STATUS program_rpmb_key(void *rpmb_dev, const void *key, RPMB_RESPONSE_RESULT *result);
+EFI_STATUS get_storage_partition_num(void *rpmb_dev, UINT8 *current_part);
+EFI_STATUS storage_partition_switch(void *rpmb_dev, UINT8 part);
+EFI_STATUS get_rpmb_counter(void *rpmb_dev, UINT32 *write_counter, const void *key,
+ RPMB_RESPONSE_RESULT *result);
+EFI_STATUS read_rpmb_data(void *rpmb_dev, UINT16 blk_count, UINT16 blk_addr, void *buffer,
+ const void *key, RPMB_RESPONSE_RESULT *result);
+EFI_STATUS write_rpmb_data(void *rpmb_dev, UINT16 blk_count, UINT16 blk_addr, void *buffer,
+ const void *key, RPMB_RESPONSE_RESULT *result);
+EFI_STATUS rpmb_send_request(void *rpmb_dev,
+ rpmb_data_frame *data_frame, UINT8 count, BOOLEAN is_rel_write);
+EFI_STATUS rpmb_get_response(void *rpmb_dev,
+ rpmb_data_frame *data_frame, UINT8 count);
+EFI_STATUS program_rpmb_key_frame(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+EFI_STATUS get_rpmb_counter_frame(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+EFI_STATUS read_rpmb_data_frame(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+EFI_STATUS write_rpmb_data_frame(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+
+
+EFI_STATUS simulate_get_rpmb_counter(UINT32 *write_counter, const void *key,
+ RPMB_RESPONSE_RESULT *result);
+EFI_STATUS simulate_program_rpmb_key(const void *key,
+ RPMB_RESPONSE_RESULT *result);
+EFI_STATUS simulate_read_rpmb_data(UINT32 offset, void *buffer,
+ UINT32 size);
+EFI_STATUS simulate_write_rpmb_data(UINT32 offset, void *buffer,
+ UINT32 size);
+
+#endif /* _RPMB_H_ */
diff --git a/include/libkernelflinger/rpmb_storage.h b/include/libkernelflinger/rpmb_storage.h
new file mode 100644
index 00000000..3b491ad3
--- /dev/null
+++ b/include/libkernelflinger/rpmb_storage.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: genshen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _RPMB_STORAGE_H_
+#define _RPMB_STORAGE_H_
+
+#include "rpmb.h"
+
+#define RPMB_KEY_SIZE 32
+#define RPMB_SEED_SIZE 32
+#define RPMB_NUMBER_KEY 10
+#define MMC_PROD_NAME_WITH_PSN_LEN 15
+#define RPMB_MAX_PARTITION_NUMBER 6
+#define RPMB_MAX_KEY_SIZE 64
+
+typedef struct rpmb_sim_real_storage_interface {
+ BOOLEAN (*is_rpmb_programed)(void);
+ EFI_STATUS (*program_rpmb_key)(UINT8 *key);
+ EFI_STATUS (*rpmb_read_counter)(const void *key, RPMB_RESPONSE_RESULT *result);
+
+ EFI_STATUS (*write_rpmb_device_state)(UINT8 state);
+ EFI_STATUS (*read_rpmb_device_state)(UINT8 *state);
+
+ EFI_STATUS (*write_rpmb_rollback_index)(size_t index, UINT64 in_rollback_index);
+ EFI_STATUS (*read_rpmb_rollback_index)(size_t index, UINT64 *out_rollback_index);
+
+ EFI_STATUS (*write_rpmb_keybox_magic)(UINT16 offset, void *buffer);
+ EFI_STATUS (*read_rpmb_keybox_magic)(UINT16 offset, void *buffer);
+} rpmb_sim_real_storage_interface_t;
+
+EFI_STATUS rpmb_storage_init(void);
+EFI_STATUS get_rpmb_derived_key(OUT UINT8 **d_key, OUT UINT8 *number_d_key);
+EFI_STATUS set_rpmb_derived_key(IN VOID *kbuf, IN size_t kbuf_len, IN size_t num_key);
+void clear_rpmb_key(void);
+void set_rpmb_key(UINT8 *key);
+EFI_STATUS rpmb_key_init(void);
+EFI_STATUS get_rpmb_keys(IN UINT32 num_partition, OUT UINT8 rpmb_key_list[][RPMB_MAX_KEY_SIZE]);
+EFI_STATUS clear_teedata_flag(void);
+EFI_STATUS erase_rpmb_all_blocks(void);
+EFI_STATUS rpmb_read_counter_in_sim_real(const void *key, RPMB_RESPONSE_RESULT *result);
+
+BOOLEAN is_rpmb_programed(void);
+EFI_STATUS program_rpmb_key_in_sim_real(UINT8 *key);
+
+EFI_STATUS write_rpmb_device_state(UINT8 state);
+EFI_STATUS read_rpmb_device_state(UINT8 *state);
+
+EFI_STATUS write_rpmb_rollback_index(size_t index, UINT64 in_rollback_index);
+EFI_STATUS read_rpmb_rollback_index(size_t index, UINT64 *out_rollback_index);
+
+EFI_STATUS write_rpmb_keybox_magic(UINT16 offset, void *buffer);
+EFI_STATUS read_rpmb_keybox_magic(UINT16 offset, void *buffer);
+#endif
diff --git a/include/libkernelflinger/rpmb_storage_common.h b/include/libkernelflinger/rpmb_storage_common.h
new file mode 100644
index 00000000..1c22811b
--- /dev/null
+++ b/include/libkernelflinger/rpmb_storage_common.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2018, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: kwen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _RPMB_STORAGE_COMMON_H
+#define _RPMB_STORAGE_COMMON_H
+
+#include
+
+#define RPMB_PARTITION 3
+#define RPMB_DATA_FRAME_SIZE 512
+#define RPMB_DATA_MAC 32
+#define RPMB_KEY_SIZE 32
+#define RPMB_MAC_SIZE 32
+#define RPMB_ERROR_MASK 0x07
+#define RPMB_NONCE_SIZE 16
+
+#define RPMB_RESPONSE_KEY_WRITE 0x0100
+#define RPMB_RESPONSE_COUNTER_READ 0x0200
+#define RPMB_RESPONSE_AUTH_WRITE 0x0300
+#define RPMB_RESPONSE_AUTH_READ 0x0400
+#define RPMB_RESPONSE_READ_RESULT 0x0500
+
+#define RPMB_REQUEST_KEY_WRITE 0x0001
+#define RPMB_REQUEST_COUNTER_READ 0x0002
+#define RPMB_REQUEST_AUTH_WRITE 0x0003
+#define RPMB_REQUEST_AUTH_READ 0x0004
+#define RPMB_REQUEST_STATUS 0x0005
+
+#define CPU_TO_BE16_SWAP(x) \
+ ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#define CPU_TO_BE32_SWAP(x) \
+ ((((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | \
+ (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24))
+#define BE16_TO_CPU_SWAP(x) \
+ ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#define BE32_TO_CPU_SWAP(x) \
+ ((((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | \
+ (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24))
+
+typedef enum {
+ RPMB_RES_OK,
+ RPMB_RES_GENERAL_FAILURE,
+ RPMB_RES_AUTH_FAILURE,
+ RPMB_RES_COUNTER_FAILURE,
+ RPMB_RES_ADDRESS_FAILURE,
+ RPMB_RES_WRITE_FAILURE,
+ RPMB_RES_READ_FAILURE,
+ RPMB_RES_NO_AUTH_KEY_PROGRAM,
+ RPMB_RES_WRITE_COUNTER_EXPIRED = 0X80,
+} RPMB_RESPONSE_RESULT;
+
+#pragma pack(1)
+typedef struct {
+ UINT8 stuff[196];
+ UINT8 key_mac[32];
+ UINT8 data[256];
+ UINT8 nonce[16];
+ UINT32 write_counter;
+ UINT16 address;
+ UINT16 block_count;
+ UINT16 result;
+ UINT16 req_resp;
+} rpmb_data_frame;
+#pragma pack()
+
+typedef struct rpmb_ops_func {
+ EFI_STATUS (*get_storage_protocol)(void **rpmb_dev, EFI_HANDLE disk_handle);
+ EFI_STATUS (*program_rpmb_key)(void *rpmb_dev,
+ const void *key, RPMB_RESPONSE_RESULT * result);
+ EFI_STATUS (*get_storage_partition_num)(void *rpmb_dev,
+ UINT8 * current_part);
+ EFI_STATUS (*storage_partition_switch)(void *rpmb_dev, UINT8 part);
+ EFI_STATUS (*get_rpmb_counter)(void *rpmb_dev,
+ UINT32 *write_counter, const void *key,
+ RPMB_RESPONSE_RESULT * result);
+
+ EFI_STATUS (*read_rpmb_data)(void *rpmb_dev,
+ UINT16 blk_count, UINT16 blk_addr, void *buffer,
+ const void *key, RPMB_RESPONSE_RESULT * result);
+ EFI_STATUS (*write_rpmb_data)(void *rpmb_dev,
+ UINT16 blk_count, UINT16 blk_addr, void *buffer,
+ const void *key, RPMB_RESPONSE_RESULT * result);
+
+ EFI_STATUS (*rpmb_send_request)(void *rpmb_dev,
+ rpmb_data_frame * data_frame, UINT8 count,
+ BOOLEAN is_rel_write);
+ EFI_STATUS(*rpmb_get_response)(void *rpmb_dev,
+ rpmb_data_frame * data_frame, UINT8 count);
+ EFI_STATUS (*program_rpmb_key_frame)(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+ EFI_STATUS (*get_rpmb_counter_frame)(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+ EFI_STATUS (*read_rpmb_data_frame)(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+ EFI_STATUS (*write_rpmb_data_frame)(void *rpmb_dev, const rpmb_data_frame *data_in_frame, UINT32 in_cnt,
+ rpmb_data_frame *data_out_frame, UINT32 out_cnt);
+
+}rpmb_ops_func_t;
+
+INT32 rpmb_check_mac(const UINT8 *key, rpmb_data_frame *frames, UINT8 cnt);
+INT32 rpmb_calc_hmac_sha256(rpmb_data_frame *frames, UINT8 blocks_cnt,
+ const UINT8 key[], UINT32 key_size,
+ UINT8 mac[], UINT32 mac_size);
+
+#endif /* _RPMB_STORAGE_COMMON_H */
diff --git a/include/libkernelflinger/security.h b/include/libkernelflinger/security.h
new file mode 100644
index 00000000..a27dbe05
--- /dev/null
+++ b/include/libkernelflinger/security.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Matt Wood
+ * Author: Andrew Boie
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+
+#ifndef _SECURITY_H_
+#define _SECURITY_H_
+
+#define BOOT_TARGET_SIZE 32
+#define BOOT_SIGNATURE_MAX_SIZE 4096
+#define ROT_DATA_STRUCT_VERSION2 0x02
+
+#define SETUP_MODE_VAR L"SetupMode"
+#define SECURE_BOOT_VAR L"SecureBoot"
+
+/* Compute sums of the public key value of X509 input CERT */
+EFI_STATUS pub_key_sha256(X509 *cert, UINT8 **hash_p);
+EFI_STATUS pub_key_sha1(X509 *cert, UINT8 **hash_p);
+
+/* Given an Android boot image, test if it is signed with the provided
+ * certificate or the embedded one
+ *
+ * Parameters:
+ * bootimage - data pointer to an Android boot image which may or may not
+ * be signed. This code may seek up to BOOT_SIGNATURE_MAX_SIZE
+ * past the end of the boot image size as reported by its header
+ * to search for the ASN.1 AndroidVerifiedBootSignature message.
+ * der_cert - DER certificate to validate image with
+ * cert_size - Size of DER certificate
+ * target - Pointer to buffer of BOOT_TARGET_SIZE, which will be filled in
+ * with AuthenticatedAttributes 'target' field iff the image is
+ * verified. Caller should only check this on EFI_SUCCESS.
+ * verifier_cert - Return the certificate that validated the boot image
+ *
+ * Return values:
+ * BOOT_STATE_GREEN - Boot image is validated against provided certificate
+ * BOOT_STATE_YELLOW - Boot image is validated against embedded certificate
+ * BOOT_STATE_RED - Boot image is not validated
+ */
+UINT8 verify_android_boot_image(
+ IN VOID *bootimage,
+ IN VOID *der_cert,
+ IN UINTN cert_size,
+ OUT CHAR16 *target,
+ OUT X509 **verifier_cert);
+
+BOOLEAN is_platform_secure_boot_enabled(VOID);
+BOOLEAN is_eom_and_secureboot_enabled(VOID);
+EFI_STATUS set_platform_secure_boot(UINT8 secure);
+EFI_STATUS set_os_secure_boot(BOOLEAN secure);
+
+#ifdef BOOTLOADER_POLICY
+/* Given a PKCS7 (DER encoded), look for the root certificate based on
+ * CERT_SHA256 and verify the PKCS7. On success, EFI_SUCCESS is
+ * return and the PKCS7 payload is returned in DATA as a dynamically
+ * allocated buffer.
+ */
+EFI_STATUS verify_pkcs7(const unsigned char *cert_sha256, UINTN cert_size,
+ const VOID *pkcs7, UINTN pkcs7_size,
+ VOID **data, int *size);
+#endif /* BOOTLOADER_POLICY */
+
+/* Given a X509 certificate, build the following string:
+ * COMMON_NAME:#PUBLIC_KEY_SHA1
+ * Where COMMON_NAME is the certificate issuer CN and PUBLIC_KEY_SHA1
+ * is the X509 certificate public key SHA1 hash.
+ */
+EFI_STATUS get_android_verity_key_id(X509 *cert, char **value);
+
+/* Structure for RoT info (fields defined by Google Keymaster2)
+*/
+struct rot_data_t{
+ /* version 2 for current TEE keymaster2 */
+ UINT32 version;
+ /* 0:unlocked, 1:locked, others not used */
+ UINT32 deviceLocked;
+ /* GREEN:0, YELLOW:1, ORANGE:2, others not used(no RED for TEE) */
+ UINT32 verifiedBootState;
+ /* The current version of the OS as an integer in the format MMmmss,
+ * where MM is a two-digit major version number, mm is a two-digit,
+ * minor version number, and ss is a two-digit sub-minor version number.
+ * For example, version 6.0.1 would be represented as 060001;
+ */
+ UINT32 osVersion;
+ /* The month and year of the last patch as an integer in the format,
+ * YYYYMM, where YYYY is a four-digit year and MM is a two-digit month.
+ * For example, April 2016 would be represented as 201604.
+ */
+ UINT32 patchMonthYear;
+ /* A secure hash (SHA-256 recommended by Google) of the key used to verify the system image
+ * key_size (in bytes) is zero: denotes no key provided by Bootloader. When key_size is
+ * 32, it denotes,key_hash256 is available. Other values not defined now.
+ */
+ UINT32 keySize;
+ UINT8 keyHash256[SHA256_DIGEST_LENGTH];
+} ;
+
+/* Initialize the struct rot_data for startup_information */
+#ifdef USE_AVB
+EFI_STATUS get_rot_data(IN VOID * bootimage, IN UINT8 boot_state,
+ IN const UINT8 *pub_key,
+ IN UINTN pub_key_len,
+ OUT struct rot_data_t *rot_data);
+
+#else
+EFI_STATUS get_rot_data(IN VOID *bootimage, IN UINT8 boot_state, IN X509 *verifier_cert,
+ OUT struct rot_data_t *rot_data);
+#endif
+#endif
diff --git a/include/libkernelflinger/security_interface.h b/include/libkernelflinger/security_interface.h
new file mode 100644
index 00000000..357d6249
--- /dev/null
+++ b/include/libkernelflinger/security_interface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SECURITY_INTERFACE_H_
+#define _SECURITY_INTERFACE_H_
+
+#include
+
+EFI_STATUS set_device_security_info(IN VOID *security_data);
+
+#endif /* _SECURITY_INTERFACE_H_ */
diff --git a/include/libkernelflinger/signature.h b/include/libkernelflinger/signature.h
new file mode 100644
index 00000000..be9ed3c9
--- /dev/null
+++ b/include/libkernelflinger/signature.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _SIGNATURE_H_
+#define _SIGNATURE_H_
+
+#include
+
+#define TARGET_MAX 32
+
+struct algorithm_identifier {
+ int nid;
+ void *parameters;
+ long parameters_len;
+};
+
+struct auth_attributes {
+ char target[TARGET_MAX];
+ long length;
+ const void *data;
+ long data_sz;
+};
+
+struct boot_signature {
+ X509 *certificate;
+ struct algorithm_identifier id;
+ struct auth_attributes attributes;
+ void *signature;
+ long signature_len;
+ long total_size;
+};
+
+struct boot_signature *get_boot_signature(const void *data, long size);
+
+void free_boot_signature(struct boot_signature *bs);
+
+#endif /* _SIGNATURE_H_ */
+
+/* vim: cindent:noexpandtab:softtabstop=8:shiftwidth=8:noshiftround
+ */
+
diff --git a/include/libkernelflinger/slot.h b/include/libkernelflinger/slot.h
new file mode 100644
index 00000000..ece230e1
--- /dev/null
+++ b/include/libkernelflinger/slot.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SLOT_H_
+#define _SLOT_H_
+
+#include
+#include
+
+extern const CHAR16 *SLOT_STORAGE_PART;
+
+EFI_STATUS slot_init(void);
+
+/* Get current suffix directly from misc, used in FASTBOOT mode. */
+EFI_STATUS slot_init_use_misc(void);
+
+/* Return TRUE if slot management is in used, FALSE otherwise. */
+BOOLEAN use_slot(void);
+
+/* Given a partition label BASE, it returns the label of the partition
+ * with the active slot suffix if such a partition exist. If slot AB
+ * management is not in used, it returns BASE. NULL is returned in
+ * case of error. */
+const CHAR16 *slot_label(const CHAR16 *base);
+
+/* Given a partition LABEL, it returns the partition label without the
+ * slot suffix (not necessarly the active slot suffix). If slot
+ * management is not in used, it returns the given partition label.
+ * NULL is returned in case of error. */
+const CHAR16 *slot_base(const CHAR16 *label);
+
+/* Returns the active slot suffix, NULL if none or if slot AB
+ * management is not in used. */
+const char *slot_get_active(void);
+
+/* Sets the slot, associated to SUFFIX, as active. */
+EFI_STATUS slot_set_active(const char *suffix);
+
+/* Sets the active slot cached, associated to SUFFIX, as active.
+ * This function maybe used after some other functions changed the
+ * active slot stored in storage directly, then call this function
+ * to update the active slot in memory cached. */
+void slot_set_active_cached(const char *suffix);
+
+/* Returns the number and the array of slot suffixes. */
+UINTN slot_get_suffixes(char **suffixes_p[]);
+
+/* Returns "yes" if the slot associated to SUFFIX has successfully
+ * booted, "no" otherwise. NULL is returned if SUFFIX is not a valid
+ * slot suffix. */
+const char *slot_get_successful(const char *suffix);
+
+/* Returns "yes" if the slot associated to SUFFIX is unbootable, "no"
+ * otherwise. NULL is returned if SUFFIX is not a valid slot
+ * suffix. */
+const char *slot_get_unbootable(const char *suffix);
+
+/* Returns the number of the retry count remaining of the slot
+ * associated to SUFFIX as a string. NULL is returned if SUFFIX is
+ * not a valid slot suffix. */
+const char *slot_get_retry_count(const char *suffix);
+
+/* Returns TRUE if the active is corrupted from a dm-verity point of
+ * view. FALSE is returned if slot AB management is not in used or if
+ * an error is encountered. */
+BOOLEAN slot_get_verity_corrupted(void);
+
+/* Sets the corrupted flag of the active slot to CORRUPTED.
+ * EFI_SUCCESS is returned on success or if the corrupted flag has
+ * been successfully updated. */
+EFI_STATUS slot_set_verity_corrupted(BOOLEAN eio);
+
+/* Parses the current partition scheme. If slot partitions are found,
+ * slot AB management is enabled, slot AB metadata is initialized and
+ * stored on disk. If no slot partition is found, slot AB management
+ * is disabled and slot AB metadata is erased from the disk. */
+EFI_STATUS slot_reset(void);
+
+/* Stores the slot AB metadata on disk. */
+EFI_STATUS slot_restore(void);
+
+/* Given a boot TARGET, decrements the corresponding tries count if
+ * necessary. */
+EFI_STATUS slot_boot(enum boot_target target);
+
+/* Depending on the boot TARGET, it disables the active slot and
+ * select the next valid slot with the highest priority. */
+EFI_STATUS slot_boot_failed(enum boot_target target);
+
+/* Returns the number of remaining tries for the Android recovery
+ * mode. */
+UINT8 slot_recovery_tries_remaining();
+
+#ifdef USE_SLOT
+extern struct AvbABOps ab_ops;
+#endif
+#endif /* _SLOT_H_ */
diff --git a/include/libkernelflinger/smbios.h b/include/libkernelflinger/smbios.h
new file mode 100644
index 00000000..230f00db
--- /dev/null
+++ b/include/libkernelflinger/smbios.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SMBIOS_H_
+#define _SMBIOS_H_
+
+#define TYPE_BIOS 0
+#define TYPE_PRODUCT 1
+#define TYPE_BOARD 2
+#define TYPE_CHASSIS 3
+
+extern char *SMBIOS_UNDEFINED;
+
+char *smbios_get_string(UINT8 type, UINT8 offset);
+
+#define SMBIOS_GET_STRING(type, field) \
+ smbios_get_string(type, offsetof(SMBIOS_TYPE##type, field))
+
+#endif /* _SMBIOS_H_ */
diff --git a/include/libkernelflinger/sparse_format.h b/include/libkernelflinger/sparse_format.h
new file mode 100644
index 00000000..ebc7ea35
--- /dev/null
+++ b/include/libkernelflinger/sparse_format.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LIBSPARSE_SPARSE_FORMAT_H_
+#define _LIBSPARSE_SPARSE_FORMAT_H_
+
+#include
+
+typedef struct sparse_header {
+ UINT32 magic; /* 0xed26ff3a */
+ UINT16 major_version; /* (0x1) - reject images with higher major versions */
+ UINT16 minor_version; /* (0x0) - allow images with higer minor versions */
+ UINT16 file_hdr_sz; /* 28 bytes for first revision of the file format */
+ UINT16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
+ UINT32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
+ UINT32 total_blks; /* total blocks in the non-sparse output image */
+ UINT32 total_chunks; /* total chunks in the sparse input image */
+ UINT32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+ /* as 0. Standard 802.3 polynomial, use a Public Domain */
+ /* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC 0xed26ff3a
+
+#define CHUNK_TYPE_RAW 0xCAC1
+#define CHUNK_TYPE_FILL 0xCAC2
+#define CHUNK_TYPE_DONT_CARE 0xCAC3
+#define CHUNK_TYPE_CRC32 0xCAC4
+
+typedef struct chunk_header {
+ UINT16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+ UINT16 reserved1;
+ UINT32 chunk_sz; /* in blocks in output image */
+ UINT32 total_sz; /* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill or CRC32 chunk is data.
+ * For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ * For a Fill chunk, it's 4 bytes of the fill data.
+ * For a CRC32 chunk, it's 4 bytes of CRC32
+ */
+
+#endif
diff --git a/include/libkernelflinger/storage.h b/include/libkernelflinger/storage.h
new file mode 100755
index 00000000..771aeaa8
--- /dev/null
+++ b/include/libkernelflinger/storage.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file defines bootlogic data structures, try to keep it without
+ * any external definitions in order to ease export of it.
+ */
+
+#ifndef _STORAGE_H_
+#define _STORAGE_H_
+
+#include
+
+enum storage_type {
+ STORAGE_EMMC,
+ STORAGE_UFS,
+ STORAGE_SDCARD,
+ STORAGE_SATA,
+ STORAGE_NVME,
+ STORAGE_VIRTUAL,
+#ifdef USB_STORAGE
+ STORAGE_USB,
+#endif
+ STORAGE_GENERAL_BLOCK,
+ STORAGE_ALL,
+};
+
+typedef enum {
+ LOGICAL_UNIT_USER,
+ LOGICAL_UNIT_FACTORY,
+} logical_unit_t;
+
+
+/* It is faster to erase multiple block at once */
+#define N_BLOCK (4096)
+
+struct storage {
+ EFI_STATUS (*erase_blocks)(EFI_HANDLE handle, EFI_BLOCK_IO *bio, EFI_LBA start, EFI_LBA end);
+ EFI_STATUS (*check_logical_unit)(EFI_DEVICE_PATH *p, logical_unit_t log_unit);
+ EFI_STATUS (*get_erase_block_size)(EFI_HANDLE handle, UINTN *erase_blk_size);
+ BOOLEAN (*probe)(EFI_DEVICE_PATH *p);
+ const CHAR16 *name;
+};
+
+#define STORAGE(X) storage_##X
+
+EFI_STATUS identify_boot_device(enum storage_type type);
+PCI_DEVICE_PATH *get_boot_device(void);
+const char* get_boot_device_var(void);
+EFI_HANDLE get_boot_device_handle(void);
+EFI_STATUS get_boot_device_type(enum storage_type *type);
+EFI_STATUS storage_set_boot_device(EFI_HANDLE device);
+EFI_STATUS storage_check_logical_unit(EFI_DEVICE_PATH *p, logical_unit_t log_unit);
+EFI_STATUS storage_erase_blocks(EFI_HANDLE handle, EFI_BLOCK_IO *bio, EFI_LBA start, EFI_LBA end);
+EFI_STATUS storage_get_erase_block_size(UINTN *erase_blk_size);
+EFI_STATUS fill_with(EFI_BLOCK_IO *bio, EFI_LBA start, EFI_LBA end,
+ VOID *pattern, UINTN pattern_blocks);
+EFI_STATUS fill_zero(EFI_BLOCK_IO *bio, EFI_LBA start, EFI_LBA end);
+BOOLEAN is_cur_storage_ufs(void);
+EFI_STATUS get_logical_block_size(UINTN *logical_blk_size);
+BOOLEAN is_boot_device_removable(void);
+BOOLEAN is_boot_device_virtual(void);
+
+#endif /* _STORAGE_H_ */
diff --git a/include/libkernelflinger/targets.h b/include/libkernelflinger/targets.h
new file mode 100644
index 00000000..b64786e6
--- /dev/null
+++ b/include/libkernelflinger/targets.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Andrew Boie
+ * Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TARGETS_H_
+#define _TARGETS_H_
+
+#include
+#include
+
+enum boot_target {
+ UNKNOWN_TARGET = -1,
+ NORMAL_BOOT,
+ FASTBOOT,
+ ELK,
+ RECOVERY,
+ CRASHMODE,
+ DNX,
+ ESP_BOOTIMAGE,
+ ESP_EFI_BINARY,
+ MEMORY,
+ CHARGER,
+ POWER_OFF,
+ EXIT_SHELL
+};
+
+#define is_bootimg_target(target) \
+ (target == NORMAL_BOOT || target == CHARGER || target == RECOVERY)
+
+const CHAR16 *boot_target_name(enum boot_target bt);
+const CHAR16 *boot_target_description(enum boot_target bt);
+enum boot_target name_to_boot_target(const CHAR16 *str);
+EFI_STATUS reboot_to_target(enum boot_target bt, EFI_RESET_TYPE type);
+
+#endif /* _TARGETS_H_ */
diff --git a/include/libkernelflinger/text_parser.h b/include/libkernelflinger/text_parser.h
new file mode 100644
index 00000000..4f4fb1b1
--- /dev/null
+++ b/include/libkernelflinger/text_parser.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TEXT_PARSER_H_
+#define _TEXT_PARSER_H_
+
+#include
+#include
+
+void skip_whitespace(char **line);
+EFI_STATUS parse_text_buffer(VOID *data, UINTN size,
+ EFI_STATUS (*parse_line)(char *line, VOID *ctx),
+ VOID *context);
+
+#endif /* _TEXT_PARSER_H_ */
diff --git a/include/libkernelflinger/timer.h b/include/libkernelflinger/timer.h
new file mode 100644
index 00000000..194ccedf
--- /dev/null
+++ b/include/libkernelflinger/timer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include
+#include
+#include "lib.h"
+
+enum TM_POINT {
+ TM_EFI_MAIN = 0,
+ TM_AVB_START,
+ TM_VERIFY_BOOT_DONE,
+ TM_LOAD_TOS_DONE,
+ TM_LAUNCH_TRUSTY_DONE,
+ TM_PROCRSS_TRUSTY_DONE,
+ TM_JMP_KERNEL,
+ TM_POINT_LAST
+};
+
+uint32_t get_cpu_freq(void);
+uint32_t boottime_in_msec(void);
+void set_boottime_stamp(int num);
+void set_efi_enter_point(unsigned int value);
+void construct_stages_boottime(CHAR8 *time_str, size_t buf_len);
+
+#endif
diff --git a/include/libkernelflinger/tpm2_security.h b/include/libkernelflinger/tpm2_security.h
new file mode 100644
index 00000000..25fdf975
--- /dev/null
+++ b/include/libkernelflinger/tpm2_security.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Anisha Kulkarni
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TPM2_SECURITY_H_
+#define _TPM2_SECURITY_H_
+
+#include
+#include
+#include
+
+#define TRUSTY_SEED_SIZE 32
+
+EFI_STATUS tpm2_init(void);
+EFI_STATUS tpm2_end(void);
+
+EFI_STATUS tpm2_fuse_trusty_seed(void);
+EFI_STATUS tpm2_read_trusty_seed(UINT8 seed[TRUSTY_SEED_SIZE]);
+
+EFI_STATUS tpm2_fuse_perm_attr(void *data, uint32_t size);
+
+EFI_STATUS tpm2_fuse_vbmeta_key_hash(void *data, uint32_t size);
+
+EFI_STATUS tpm2_fuse_bootloader_policy(void *data, uint32_t size);
+
+#ifndef USER
+EFI_STATUS tpm2_show_index(UINT32 index, uint8_t *out_buffer, UINTN out_buffer_size);
+EFI_STATUS tpm2_delete_index(UINT32 index);
+#endif // USER
+
+EFI_STATUS tpm2_fuse_lock_owner(void);
+EFI_STATUS tpm2_fuse_provision_seed(void);
+#endif /* _TPM2_SECURITY_H_ */
diff --git a/include/libkernelflinger/trusty_common.h b/include/libkernelflinger/trusty_common.h
new file mode 100644
index 00000000..6f0f8247
--- /dev/null
+++ b/include/libkernelflinger/trusty_common.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TRUSTY_COMMON_H_
+#define _TRUSTY_COMMON_H_
+
+#include "efi.h"
+#include "efilib.h"
+
+EFI_STATUS load_tos_image(OUT VOID **bootimage);
+
+#endif /* _TRUSTY_COMMON_H_ */
diff --git a/include/libkernelflinger/trusty_interface.h b/include/libkernelflinger/trusty_interface.h
new file mode 100644
index 00000000..f2b0f139
--- /dev/null
+++ b/include/libkernelflinger/trusty_interface.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TRUSTY_INTERFACE_H_
+#define _TRUSTY_INTERFACE_H_
+
+#include "efi.h"
+#include "efilib.h"
+#include "vars.h"
+#include
+
+#define LENGTH_TRUSTY_PARAM_STRING 18
+#define TRUSTY_PARAM_STRING "trusty.param_addr="
+
+EFI_STATUS start_trusty(VOID *trusty_image);
+EFI_STATUS set_trusty_param(IN VOID *param_data);
+
+#endif /* _TRUSTY_INTERFACE_H_ */
diff --git a/include/libkernelflinger/uefi_utils.h b/include/libkernelflinger/uefi_utils.h
new file mode 100644
index 00000000..9f75b25e
--- /dev/null
+++ b/include/libkernelflinger/uefi_utils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Sylvain Chouleur
+ * Jeremy Compostella
+ * Jocelyn Falempe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __UEFI_UTILS_H__
+#define __UEFI_UTILS_H__
+
+#include
+#include
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
+
+EFI_STATUS get_esp_fs(EFI_FILE_IO_INTERFACE **esp_fs);
+EFI_STATUS uefi_open_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename, EFI_FILE **file);
+EFI_STATUS uefi_get_file_size(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename, UINTN *size);
+EFI_STATUS uefi_read_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename, void **data, UINTN *size);
+EFI_STATUS uefi_write_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename, void *data, UINTN *size);
+EFI_STATUS uefi_write_file_with_dir(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename, void *data, UINTN size);
+EFI_STATUS uefi_create_dir(EFI_FILE *parent, EFI_FILE **dir, CHAR16 *dirname);
+EFI_STATUS uefi_delete_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename);
+EFI_STATUS find_device_partition(const EFI_GUID *guid, EFI_HANDLE **handles, UINTN *no_handles);
+BOOLEAN uefi_exist_file_root(EFI_FILE_IO_INTERFACE *io, CHAR16 *filename);
+EFI_STATUS uefi_create_directory(EFI_FILE *parent, CHAR16 *dirname);
+EFI_STATUS uefi_create_directory_root(EFI_FILE_IO_INTERFACE *io, CHAR16 *dirname);
+EFI_STATUS uefi_rename_file(EFI_FILE_IO_INTERFACE *io, CHAR16 *oldname, CHAR16 *newname);
+EFI_STATUS verify_image(EFI_HANDLE handle, CHAR16 *path);
+EFI_STATUS uefi_bios_update_capsule(EFI_HANDLE root_dir, CHAR16 *name);
+EFI_STATUS uefi_enter_binary(EFI_HANDLE part_handle, CHAR16 *path,
+ BOOLEAN delete, UINT32 load_options_size, VOID *load_options);
+EFI_STATUS uefi_check_upgrade(EFI_LOADED_IMAGE *loaded_image,
+ CHAR16 *partition, CHAR16 *upgrade_file,
+ CHAR16 *self_path1, CHAR16 *bak_path1, CHAR16 *self_path2, CHAR16 *bak_path2);
+
+#endif /* __UEFI_UTILS_H__ */
diff --git a/include/libkernelflinger/ui.h b/include/libkernelflinger/ui.h
new file mode 100644
index 00000000..64a21c10
--- /dev/null
+++ b/include/libkernelflinger/ui.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _UI_H_
+#define _UI_H_
+
+#include
+#include
+#include "ui.h"
+
+/* Colors */
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_BLACK;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_WHITE;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_LIGHTGRAY;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_LIGHTRED;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_YELLOW;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_RED;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_GREEN;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_HIGHLIGHT;
+extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL COLOR_ORANGE;
+
+/* Image */
+typedef struct image {
+ const char *name;
+ const UINT8 *data;
+ const UINTN size;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *blt;
+ UINTN width;
+ UINTN height;
+} ui_image_t;
+
+EFI_STATUS ui_image_draw(ui_image_t *image, UINTN x, UINTN y);
+EFI_STATUS ui_image_draw_scale(ui_image_t *image, UINTN x,
+ UINTN y, UINTN width, UINTN height);
+ui_image_t *ui_image_get(const char *name);
+
+/* Font */
+typedef struct ui_font {
+ char *name;
+ UINTN width;
+ UINTN height;
+ UINTN cwidth;
+ UINTN cheight;
+ unsigned char *texture;
+} ui_font_t;
+
+EFI_STATUS ui_font_init(void);
+ui_font_t *ui_font_get_default(void);
+ui_font_t *ui_font_get(char *name);
+extern ui_font_t ui_fonts[];
+extern UINTN ui_fonts_nb;
+
+/* Textarea */
+typedef struct textline {
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color;
+ char *str;
+ BOOLEAN bold;
+} ui_textline_t;
+
+typedef struct ui_textarea {
+ UINTN line_nb;
+ UINTN row_nb;
+ ui_textline_t *text;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *bg_color;
+ ui_font_t *font;
+ INTN current;
+ UINTN width;
+ UINTN height;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *blt;
+} ui_textarea_t;
+
+ui_textarea_t *ui_textarea_create(UINTN line_nb, UINTN row_nb, ui_font_t *font,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *bg_color);
+EFI_STATUS ui_textarea_display_text(const ui_textline_t *text, ui_font_t *font,
+ UINTN x, UINTN *y, UINTN width, UINTN height,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *bg_color);
+void ui_textarea_free(ui_textarea_t *textarea);
+void ui_textarea_clear(ui_textarea_t *textarea);
+void ui_textarea_set_line(ui_textarea_t *textarea, UINTN line_nb, char *str,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color, BOOLEAN bold);
+void ui_textarea_set_line_n(ui_textarea_t *textarea, UINTN line_nb, char *str,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color, BOOLEAN bold);
+void ui_textarea_newline(ui_textarea_t *textarea, char *str,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color, BOOLEAN bold);
+void ui_textarea_n(ui_textarea_t *textarea, char *str,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color, BOOLEAN bold);
+EFI_STATUS ui_textarea_draw_scale(ui_textarea_t *textarea, UINTN x, UINTN *y,
+ UINTN width, UINTN height);
+EFI_STATUS ui_textarea_draw(ui_textarea_t *textarea, UINTN x, UINTN y);
+
+/* EFI Scan codes */
+#ifdef USE_POWER_BUTTON
+#define SCAN_POWER CHAR_CARRIAGE_RETURN
+#endif
+
+/* Events */
+typedef enum ui_events {
+ EV_NONE,
+ EV_ANY,
+ EV_UP,
+ EV_DOWN,
+ EV_TIMEOUT,
+#ifdef USE_POWER_BUTTON
+ EV_POWER
+#endif
+} ui_events_t;
+ui_events_t ui_keycode_to_event(UINT16 keycode);
+ui_events_t ui_read_input(void);
+BOOLEAN ui_enforce_key_held(UINT32 milliseconds, ui_events_t event);
+void ui_wait_for_key_release(void);
+ui_events_t ui_wait_for_event(UINTN timeout_secs, ui_events_t expected);
+ui_events_t ui_wait_for_input(UINTN timeout_secs);
+BOOLEAN ui_input_to_bool(UINTN timeout_secs, BOOLEAN timeout_true);
+
+/* Boot menu */
+typedef struct ui_boot_action {
+ const char *img_name;
+ ui_image_t *image;
+ enum boot_target target;
+} ui_boot_action_t;
+typedef struct ui_boot_menu {
+ ui_boot_action_t *actions;
+ UINTN action_nb;
+ UINTN cur;
+ UINTN x;
+ UINTN y;
+ UINTN max_width;
+} ui_boot_menu_t;
+ui_boot_menu_t *ui_boot_menu_create(ui_boot_action_t *actions);
+UINTN ui_boot_menu_draw(ui_boot_menu_t *menu, UINTN x, UINTN *y, UINTN max_width);
+enum boot_target ui_boot_menu_event_handler(ui_boot_menu_t *menu, ui_events_t event);
+void ui_boot_menu_free(ui_boot_menu_t *menu);
+
+/* Confirm UX */
+BOOLEAN ui_confirm(const ui_textline_t *text, UINTN width, UINTN height,
+ UINTN x, UINTN y);
+
+/* Screen / shared */
+EFI_STATUS ui_init(UINTN *width, UINTN *height);
+BOOLEAN ui_is_ready();
+void ui_free(void);
+EFI_STATUS ui_display_vendor_splash(VOID);
+EFI_STATUS ui_fill_area(UINTN x, UINTN y, UINTN width, UINTN height,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color);
+EFI_STATUS ui_clear_area(UINTN x, UINTN y, UINTN width, UINTN height);
+EFI_STATUS ui_clear_screen();
+EFI_STATUS ui_display_texts(const ui_textline_t **texts, UINTN x, UINTN y,
+ UINTN linesarea, UINTN colsarea);
+EFI_STATUS ui_draw_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *blt, UINTN x, UINTN y,
+ UINTN width, UINTN height);
+void ui_print(CHAR16 *fmt, ...);
+void ui_info(CHAR16 *fmt, ...);
+void ui_info_n(CHAR16 *fmt, ...);
+void ui_warning(CHAR16 *fmt, ...);
+void ui_error(CHAR16 *fmt, ...);
+void ui_print_clear(void);
+void ui_get_scaled_dimension(UINTN orig_width, UINTN orig_heigth,
+ UINTN max_width, UINTN max_height,
+ UINTN *width, UINTN *height);
+UINT64 ui_get_blt_size(UINTN width, UINTN height);
+void ui_bilinear_scale(unsigned char *s, unsigned char *d,
+ int sx, int sy, int dx, int dy,
+ int depth);
+
+#endif /* _UI_H_ */
diff --git a/include/libkernelflinger/upng.h b/include/libkernelflinger/upng.h
new file mode 100644
index 00000000..0d9caa9c
--- /dev/null
+++ b/include/libkernelflinger/upng.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _UPNG_H_
+#define _UPNG_H_
+
+#include
+
+EFI_STATUS upng_load(const char *data, UINTN size,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL **blt,
+ UINTN *width, UINTN *height);
+
+#endif /* _UPNG_H_ */
diff --git a/include/libkernelflinger/vars.h b/include/libkernelflinger/vars.h
new file mode 100644
index 00000000..5b9bf21c
--- /dev/null
+++ b/include/libkernelflinger/vars.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Andrew Boie
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _VARS_H_
+#define _VARS_H_
+#include
+#include
+
+/* Gummiboot's loader GUID, for compatibility we honor some of the
+ * same variables */
+extern const EFI_GUID loader_guid;
+
+extern const EFI_GUID fastboot_guid;
+
+#ifdef BOOTLOADER_POLICY_EFI_VAR
+/* FASTBOOT GUID is reserved to internal use only. However, the
+ * following array of EFI variables is the exception and these
+ * variables can be flashed using the flash oemvars fastboot command.
+ * These variables are time-based authenticated EFI variables. */
+extern const CHAR16 *FASTBOOT_SECURED_VARS[];
+extern const UINTN FASTBOOT_SECURED_VARS_SIZE;
+#endif
+
+/* TODO get rid of the rest of these _VAR definitions here and write
+ * accessor functions for them */
+
+#define LOADER_ENTRY_ONESHOT L"LoaderEntryOneShot"
+
+#define SERIAL_PORT_VAR L"SerialPort"
+
+#define SERIAL_NUM_VAR L"SerialNum"
+
+/* EFI variable which stores the max timeout for checking whether the
+ * magic key was pressed at startup */
+#define MAGIC_KEY_TIMEOUT_VAR L"MagicKeyTimeout"
+
+/* EFI variable which stores the time in milliseconds to wait between
+ * two key events for a hold key */
+#define HOLD_KEY_STALL_TIME_VAR L"HoldKeyStallTime"
+
+/* Boot state that we report before exiting boot services, per
+ * Google's verified boot spec */
+#define BOOT_STATE_VAR L"BootState"
+#define BOOT_STATE_GREEN 0
+#define BOOT_STATE_YELLOW 1
+#define BOOT_STATE_ORANGE 2
+#define BOOT_STATE_RED 3
+
+#define OEM_KEY_VAR L"OEMKey"
+
+/* EFI variable to store the kernelflinger logs. */
+#define LOG_VAR L"KernelflingerLogs"
+
+#ifndef USER
+#define CMDLINE_PREPEND_VAR L"PrependCmdline"
+#define CMDLINE_APPEND_VAR L"AppendCmdline"
+#define CMDLINE_REPLACE_VAR L"ReplaceCmdline"
+#endif
+
+#define SERIALNO_MIN_SIZE 6
+#define SERIALNO_MAX_SIZE 20
+
+/* Various interesting partition labels */
+#define BOOT_LABEL L"boot"
+#define ACPI_LABEL L"acpi"
+#define ACPIO_LABEL L"acpio"
+#define RECOVERY_LABEL L"recovery"
+#define MISC_LABEL L"misc"
+#define VENDOR_LABEL L"vendor"
+#define SYSTEM_LABEL L"system"
+#define OEM_LABEL L"oem"
+#define ESP_LABEL L"esp"
+#define BOOTLOADER_LABEL L"bootloader"
+#define BOOTLOADER_A_LABEL BOOTLOADER_LABEL L"_a"
+#define BOOTLOADER_B_LABEL BOOTLOADER_LABEL L"_b"
+#define MULTIBOOT_LABEL L"multiboot"
+#define TOS_LABEL L"tos"
+#define VBMETA_LABEL L"vbmeta"
+#define PRODUCT_LABEL L"product"
+
+/*labels to trigger IFWI self update. Only for ABL*/
+#define IFWI_CAPSULE_UPDATE L"IfwiCapsuleUpdate"
+
+BOOLEAN device_is_unlocked(void);
+BOOLEAN device_is_locked(void);
+BOOLEAN get_off_mode_charge(void);
+EFI_STATUS set_off_mode_charge(BOOLEAN enabled);
+BOOLEAN get_crash_event_menu(void);
+EFI_STATUS set_crash_event_menu(BOOLEAN enabled);
+BOOLEAN get_oemvars_update(void);
+EFI_STATUS set_oemvars_update(BOOLEAN updated);
+BOOLEAN get_slot_fallback(void);
+EFI_STATUS set_slot_fallback(BOOLEAN enabled);
+
+enum device_state {
+ UNKNOWN_STATE = -1,
+ LOCKED = 0,
+ UNLOCKED = 1
+};
+const char *get_current_state_string(void);
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL *get_current_state_color();
+EFI_STATUS set_current_state(enum device_state state);
+enum device_state get_current_state(void);
+EFI_STATUS refresh_current_state(void);
+BOOLEAN device_is_provisioning(void);
+EFI_STATUS get_watchdog_status(UINT8 *counter, EFI_TIME *time);
+EFI_STATUS reset_watchdog_status(VOID);
+EFI_STATUS set_watchdog_counter(UINT8 counter);
+EFI_STATUS set_watchdog_time_reference(EFI_TIME *time);
+UINT8 get_watchdog_counter_max(VOID);
+EFI_STATUS set_watchdog_counter_max(UINT8 max);
+BOOLEAN get_disable_watchdog(void);
+char *get_serial_number(void);
+BOOLEAN get_display_splash(void);
+char *get_property_bootloader(void);
+#ifdef HAL_AUTODETECT
+char *get_property_device(void);
+char *get_property_brand(void);
+char *get_property_name(void);
+char *get_property_model(void);
+#endif
+char *get_device_id(void);
+CHAR16 *boot_state_to_string(UINT8 boot_state);
+#ifndef USER
+EFI_STATUS reprovision_state_vars(VOID);
+EFI_STATUS erase_efivars(VOID);
+#endif
+EFI_STATUS set_reboot_reason(CHAR16 *reboot_reason);
+CHAR16 *get_reboot_reason();
+BOOLEAN is_reboot_reason(CHAR16 *reason);
+VOID del_reboot_reason();
+#ifdef BOOTLOADER_POLICY
+BOOLEAN blpolicy_is_flashed(VOID);
+BOOLEAN device_is_class_A(VOID);
+UINT8 min_boot_state_policy();
+EFI_STATUS get_oak_hash(unsigned char **data_p, UINTN *size);
+#endif // BOOTLOADER_POLICY
+
+#if defined(SECURE_STORAGE_EFIVAR) && defined(USE_AVB)
+EFI_STATUS read_efi_rollback_index(UINTN rollback_index_slot, uint64_t* out_rollback_index);
+EFI_STATUS write_efi_rollback_index(UINTN rollback_index_slot, uint64_t rollback_index);
+#endif
+BOOLEAN is_UEFI(VOID);
+#ifndef USERDEBUG
+#define oem_cert NULL
+#define oem_cert_size 0
+#else
+extern char _binary_oemcert_start;
+extern char _binary_oemcert_end;
+#define oem_cert (&_binary_oemcert_start)
+#define oem_cert_size (&_binary_oemcert_end - &_binary_oemcert_start)
+#endif
+#endif /* _VARS_H_ */
+
diff --git a/include/libkernelflinger/version.h b/include/libkernelflinger/version.h
new file mode 100644
index 00000000..7760eba6
--- /dev/null
+++ b/include/libkernelflinger/version.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Andrew Boie
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef KERNELFLINGER_VERSION_H
+#define KERNELFLINGER_VERSION_H
+
+#define WIDE_STR2(x) L ## x
+#define WIDE_STR(x) WIDE_STR2(x)
+
+#if defined(USER)
+#define BUILD_VARIANT ""
+#elif defined(USERDEBUG)
+#define BUILD_VARIANT "-userdebug"
+#else
+#define BUILD_VARIANT "-eng"
+#endif
+
+#ifdef FASTBOOT_FOR_NON_ANDROID
+#define KERNELFLINGER_VERSION_8 "fastboot-NonAndroid-1.0" BUILD_VARIANT
+#else
+#define KERNELFLINGER_VERSION_8 "kernelflinger-06.04" BUILD_VARIANT
+#endif
+#define KERNELFLINGER_VERSION WIDE_STR(KERNELFLINGER_VERSION_8)
+
+#endif
diff --git a/include/libkernelflinger/watchdog.h b/include/libkernelflinger/watchdog.h
new file mode 100644
index 00000000..83b614f6
--- /dev/null
+++ b/include/libkernelflinger/watchdog.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _WATCHDOG_H_
+#define _WATCHDOG_H_
+
+#include
+
+#define TCO_DEFAULT_TIMEOUT 60
+#define TCO_MIN_TIMEOUT 4
+#define TCO_OPT_DISABLED "iTCO_wdt.force_no_reboot=1"
+
+EFI_STATUS start_watchdog(UINT32 seconds);
+BOOLEAN watchdog_disabled_from_cmdline(CHAR8 *);
+
+#endif /* _WATCHDOG_H_ */
diff --git a/include/libqltipc/libtipc.h b/include/libqltipc/libtipc.h
new file mode 100644
index 00000000..bacc21cc
--- /dev/null
+++ b/include/libqltipc/libtipc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef TRUSTY_LIBTIPC_H_
+#define TRUSTY_LIBTIPC_H_
+
+
+/*
+ * Initialize TIPC library
+ */
+int trusty_ipc_init(void);
+/*
+ * Shutdown TIPC library
+ */
+void trusty_ipc_shutdown(void);
+
+int is_keybox_retrieved(void);
+int set_keybox_provision_magic_data(void);
+
+#endif /* TRUSTY_LIBTIPC_H_ */
diff --git a/include/libtransport/transport.h b/include/libtransport/transport.h
new file mode 100644
index 00000000..3e77cecc
--- /dev/null
+++ b/include/libtransport/transport.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include
+#include
+#include
+
+typedef void (*data_callback_t)(void *buf, unsigned len);
+typedef void (*start_callback_t)(void);
+
+typedef struct transport {
+ const char *name;
+ EFI_STATUS (*start)(start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb);
+ EFI_STATUS (*stop)(void);
+ EFI_STATUS (*run)(void);
+ EFI_STATUS (*read)(void *buf, UINT32 size);
+ EFI_STATUS (*write)(void *buf, UINT32 size);
+} transport_t;
+
+EFI_STATUS transport_register(transport_t *trans, UINTN nb);
+void transport_unregister(void);
+
+EFI_STATUS transport_start(start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb);
+EFI_STATUS transport_stop(void);
+EFI_STATUS transport_run(void);
+EFI_STATUS transport_read(void *buf, UINT32 len);
+EFI_STATUS transport_write(void *buf, UINT32 len);
+
+#endif /* _TRANSPORT_H_ */
diff --git a/installer.c b/installer.c
new file mode 100644
index 00000000..559f2123
--- /dev/null
+++ b/installer.c
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Author: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "lib.h"
+#include "uefi_utils.h"
+#include "protocol.h"
+#include "flash.h"
+#include "gpt.h"
+#include "sparse.h"
+#include "sparse_format.h"
+#include "fastboot.h"
+#include "fastboot_oem.h"
+#include "text_parser.h"
+#include "android.h"
+#include "slot.h"
+
+static BOOLEAN last_cmd_succeeded;
+static fastboot_handle fastboot_flash_cmd;
+static fastboot_handle fastboot_erase_cmd;
+static EFI_FILE_IO_INTERFACE *file_io_interface;
+static data_callback_t fastboot_rx_cb, fastboot_tx_cb;
+static BOOLEAN need_tx_cb;
+static char *fastboot_cmd_buf;
+static UINTN fastboot_cmd_buf_len;
+static char command_buffer[256]; /* Large enough to fit long filename
+ on flash command. */
+static struct download_buffer *dl;
+
+#define inst_perror(ret, x, ...) do { \
+ fastboot_fail(x ": %r", ##__VA_ARGS__, ret); \
+} while (0)
+
+#define MAX_LABEL_LEN 64
+
+static void flush_tx_buffer(void)
+{
+ while (need_tx_cb) {
+ need_tx_cb = FALSE;
+ fastboot_tx_cb(NULL, 0);
+ }
+}
+
+static void do_erase(INTN argc, CHAR8 **argv)
+{
+ fastboot_erase_cmd(argc, argv);
+ flush_tx_buffer();
+}
+
+static EFI_STATUS find_partition(CHAR8 *target)
+{
+ EFI_STATUS ret;
+ CHAR16 *target16;
+ struct gpt_partition_interface gparti;
+
+ target16 = stra_to_str(target);
+ if (!target16) {
+ fastboot_fail("Failed to convert target to CHAR16");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ret = gpt_get_partition_by_label(target16, &gparti, LOGICAL_UNIT_USER);
+ FreePool(target16);
+
+ return ret;
+}
+
+static CHAR8 *get_target(CHAR8 *target)
+{
+ EFI_STATUS ret;
+ CHAR16 *target16;
+ const CHAR16 *label16;
+ static CHAR8 label[MAX_LABEL_LEN];
+ CHAR8 *ret_target = NULL;
+
+ ret = find_partition(target);
+ if (!EFI_ERROR(ret))
+ return target;
+ if (EFI_ERROR(ret) && ret != EFI_NOT_FOUND)
+ return NULL;
+
+ target16 = stra_to_str(target);
+ if (!target16)
+ return NULL;
+
+ label16 = slot_label(target16);
+ if (!label16) {
+ ret_target = target;
+ goto out;
+ }
+
+ if (StrLen(label16) + 1 > sizeof(label)) {
+ fastboot_fail("Label name is too long");
+ goto out;
+ }
+
+ ret = str_to_stra(label, label16, sizeof(label));
+ if (!EFI_ERROR(ret))
+ ret_target = label;
+
+out:
+ if (target16)
+ FreePool(target16);
+
+ return ret_target;
+}
+
+static void installer_erase(INTN argc, CHAR8 **argv)
+{
+ if (argc != 2) {
+ fastboot_fail("Erase command requires exactly 2 arguments");
+ return;
+ }
+
+ argv[1] = get_target(argv[1]);
+ if (!argv[1])
+ return;
+
+ do_erase(argc, argv);
+}
+
+static void installer_flash_buffer(void *data, unsigned size,
+ INTN argc, CHAR8 **argv)
+{
+ void *data_save = dl->data;
+
+ dl->data = data;
+ dl->size = size;
+
+ fastboot_flash_cmd(argc, argv);
+ flush_tx_buffer();
+
+ dl->data = data_save;
+ dl->size = 0;
+}
+
+static EFI_STATUS read_file(EFI_FILE *file, UINTN size, void *data)
+{
+ EFI_STATUS ret;
+ UINTN nsize = size;
+
+ ret = uefi_call_wrapper(file->Read, 3, file, &nsize, data);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to read file");
+ return ret;
+ }
+ if (size != nsize) {
+ fastboot_fail("Failed to read %d bytes (only %d read)",
+ size, nsize);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return ret;
+}
+
+typedef struct flash_buffer {
+ struct sparse_header sph;
+ struct chunk_header skip_ckh;
+ union {
+ struct chunk_header ckh;
+ char data[1];
+ } d;
+ char ckh_data[1];
+} __attribute__((__packed__)) flash_buffer_t;
+
+/*when flash big chunks and in two image should add read_flags*/
+static EFI_STATUS installer_flash_big_chunk_multiple(EFI_FILE **file, UINTN *read_flags,
+ UINTN file_size, UINTN *remaining_data, flash_buffer_t *fb, UINTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret = EFI_INVALID_PARAMETER;
+ UINTN payload_size, read_size, already_read, ckh_blks, data_size;
+ const UINTN MAX_DATA_SIZE = dl->max_size - offsetof(flash_buffer_t, ckh_data);
+ const UINTN MAX_BLKS = MAX_DATA_SIZE / fb->sph.blk_sz;
+ const UINTN HEADER_SIZE = offsetof(flash_buffer_t, d);
+ struct chunk_header *ckh;
+ void *read_ptr;
+
+ ckh = &fb->d.ckh;
+ payload_size = ckh->total_sz - sizeof(*ckh);
+ fb->sph.total_chunks = 2; /* skip and data chunks. */
+
+ for (ckh_blks = ckh->chunk_sz; ckh_blks; ckh_blks -= ckh->chunk_sz) {
+ ckh->chunk_sz = min(MAX_BLKS, ckh_blks);
+ data_size = ckh->chunk_sz * fb->sph.blk_sz;
+ ckh->total_sz = sizeof(*ckh) + data_size;
+ fb->sph.total_blks = fb->skip_ckh.chunk_sz + ckh->chunk_sz;
+ installer_flash_buffer(fb, ckh->total_sz + HEADER_SIZE, argc, argv);
+ if (!last_cmd_succeeded)
+ return EFI_INVALID_PARAMETER;
+
+ payload_size -= data_size;
+ if (!payload_size)
+ break;
+
+ /* Move the incomplete data from the end to the
+ beginning of the buffer. */
+ read_ptr = fb->ckh_data;
+ read_size = min(payload_size, MAX_DATA_SIZE);
+ if (data_size < MAX_DATA_SIZE) {
+ already_read = MAX_DATA_SIZE - data_size;
+ memcpy(read_ptr, fb->d.data + ckh->total_sz, already_read);
+ read_size -= already_read;
+ read_ptr += already_read;
+ if (read_size > file_size) {
+ ret = read_file(file[*read_flags], file_size, read_ptr);
+ if (EFI_ERROR(ret))
+ return ret;
+ read_size -= file_size;
+ read_ptr += file_size;
+ *remaining_data -= file_size;
+ (*read_flags)++;
+ }
+ }
+ ret = read_file(file[*read_flags], read_size, read_ptr);
+ if (EFI_ERROR(ret))
+ return ret;
+ *remaining_data -= read_size;
+
+ fb->skip_ckh.chunk_sz += ckh->chunk_sz;
+ }
+
+ if (payload_size)
+ return EFI_INVALID_PARAMETER;
+
+ return EFI_SUCCESS;
+}
+
+/* This function splits a chunk too large to fit into a
+ dl->max_size buffer into smaller chunks and flash them. */
+static EFI_STATUS installer_flash_big_chunk(EFI_FILE *file, UINTN *remaining_data,
+ flash_buffer_t *fb, UINTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret = EFI_INVALID_PARAMETER;
+ UINTN payload_size, read_size, already_read, ckh_blks, data_size;
+ const UINTN MAX_DATA_SIZE = dl->max_size - offsetof(flash_buffer_t, ckh_data);
+ const UINTN MAX_BLKS = MAX_DATA_SIZE / fb->sph.blk_sz;
+ const UINTN HEADER_SIZE = offsetof(flash_buffer_t, d);
+ struct chunk_header *ckh;
+ void *read_ptr;
+
+ ckh = &fb->d.ckh;
+ payload_size = ckh->total_sz - sizeof(*ckh);
+ fb->sph.total_chunks = 2; /* skip and data chunks. */
+
+ for (ckh_blks = ckh->chunk_sz; ckh_blks; ckh_blks -= ckh->chunk_sz) {
+ ckh->chunk_sz = min(MAX_BLKS, ckh_blks);
+ data_size = ckh->chunk_sz * fb->sph.blk_sz;
+ ckh->total_sz = sizeof(*ckh) + data_size;
+ fb->sph.total_blks = fb->skip_ckh.chunk_sz + ckh->chunk_sz;
+
+ installer_flash_buffer(fb, ckh->total_sz + HEADER_SIZE, argc, argv);
+ if (!last_cmd_succeeded)
+ return EFI_INVALID_PARAMETER;
+
+ payload_size -= data_size;
+ if (!payload_size)
+ break;
+
+ /* Move the incomplete data from the end to the
+ beginning of the buffer. */
+ read_ptr = fb->ckh_data;
+ read_size = min(payload_size, MAX_DATA_SIZE);
+ if (data_size < MAX_DATA_SIZE) {
+ already_read = MAX_DATA_SIZE - data_size;
+ memcpy(read_ptr, fb->d.data + ckh->total_sz, already_read);
+ read_size -= already_read;
+ read_ptr += already_read;
+ }
+
+ ret = read_file(file, read_size, read_ptr);
+ if (EFI_ERROR(ret))
+ return ret;
+ *remaining_data -= read_size;
+
+ fb->skip_ckh.chunk_sz += ckh->chunk_sz;
+ }
+
+ if (payload_size)
+ return EFI_INVALID_PARAMETER;
+
+ return EFI_SUCCESS;
+}
+/*this function splits a huge sparse file and put together the two image*/
+static void installer_split_and_joint_flash(CHAR16 **filename,
+ UINTN *size, UINTN num, UINTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ flash_buffer_t *fb;
+ UINTN read_flags = 0;
+ struct sparse_header sph;
+ struct chunk_header *ckh;
+ UINTN read_size, flash_size, already_read, remaining_data = 0;
+ void *read_ptr;
+ INTN nb_chunks;
+ EFI_FILE *file[num];
+ UINT32 blk_count;
+
+ const UINTN HEADER_SIZE = offsetof(flash_buffer_t, d);
+ const UINTN MAX_DATA_SIZE = dl->max_size - HEADER_SIZE;
+ for (UINTN i = 0; i < num; i++) {
+ remaining_data = remaining_data + size[i];
+ ret = uefi_open_file(file_io_interface, filename[i], &file[i]);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to open %s file", filename[i]);
+ return;
+ }
+ }
+
+ ret = read_file(file[0], sizeof(sph), &sph);
+ if (EFI_ERROR(ret))
+ return;
+ remaining_data -= sizeof(sph);
+ size[read_flags] -= sizeof(sph);
+ if (!is_sparse_image((void *) &sph, sizeof(sph))) {
+ fastboot_fail("sparse file expected");
+ return;
+ }
+ fb = dl->data;
+ memcpy(&fb->sph, &sph, sizeof(sph));
+ /* Sparse skip chunk. */
+ fb->skip_ckh.chunk_type = CHUNK_TYPE_DONT_CARE;
+ fb->skip_ckh.total_sz = sizeof(fb->skip_ckh);
+ nb_chunks = sph.total_chunks;
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ blk_count = 0;
+ while (nb_chunks > 0 && remaining_data > 0) {
+ fb->sph.total_chunks = 1;
+ fb->sph.total_blks = fb->skip_ckh.chunk_sz = blk_count;
+ if (remaining_data < read_size)
+ read_size = remaining_data;
+ /* Read a new piece of the input sparse file. */
+ ret = read_file(file[read_flags], read_size, read_ptr);
+ if (EFI_ERROR(ret))
+ goto exit;
+ remaining_data -= read_size;
+ size[read_flags] -= read_size;
+ /* Process the loaded chunks to build the new header
+ and the skip chunk. */
+ flash_size = HEADER_SIZE;
+ ckh = &fb->d.ckh;
+ while ((void *)ckh + sizeof(*ckh) <= read_ptr + read_size &&
+ (void *)ckh + ckh->total_sz <= read_ptr + read_size) {
+ if (nb_chunks == 0)
+ goto exit;
+ flash_size += ckh->total_sz;
+ fb->sph.total_blks += ckh->chunk_sz;
+ blk_count += ckh->chunk_sz;
+ fb->sph.total_chunks++;
+ nb_chunks--;
+ ckh = (void *)ckh + ckh->total_sz;
+ }
+ /* chunk is too big to fit in the download buffer. */
+ if (flash_size == HEADER_SIZE) {
+ if (ckh->chunk_type != CHUNK_TYPE_RAW ||
+ remaining_data < ckh->total_sz - MAX_DATA_SIZE) {
+ fastboot_fail("Corrupted sparse file");
+ goto exit;
+ }
+
+ blk_count += ckh->chunk_sz;
+ nb_chunks--;
+
+ ret = installer_flash_big_chunk_multiple(file, &read_flags,
+ size[read_flags], &remaining_data, fb, argc, argv);
+ if (EFI_ERROR(ret))
+ goto exit;
+
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ continue;
+ }
+
+ installer_flash_buffer(dl->data, flash_size, argc, argv);
+ if (!last_cmd_succeeded)
+ goto exit;
+ /* Move the incomplete chunk from the end to the
+ beginning of the buffer. */
+
+ if (dl->data + flash_size < read_ptr + read_size) {
+ already_read = read_ptr + read_size - (void *)ckh;
+ memcpy(fb->d.data, ckh, already_read);
+ read_size = MAX_DATA_SIZE - already_read;
+ read_ptr = fb->d.data + already_read;
+
+ } else {
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ }
+ if ((read_size > size[read_flags]) && (read_flags != (num - 1))) {
+ ret = read_file(file[read_flags], size[read_flags], read_ptr);
+ if (EFI_ERROR(ret))
+ goto exit;
+ memcpy(fb->d.data+already_read, read_ptr, size[read_flags]);
+ read_size = read_size - size[read_flags];
+ remaining_data -= size[read_flags];
+ read_ptr = fb->d.data+already_read+size[read_flags];
+ read_flags++;
+ }
+ }
+exit:
+ for (UINTN i = 0; i < num; i++)
+ uefi_call_wrapper(file[i]->Close, 1, file[i]);
+}
+/* This function splits a huge sparse file into smaller ones and flash
+ them. */
+static void installer_split_and_flash(CHAR16 *filename, UINTN size,
+ UINTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ flash_buffer_t *fb;
+ struct sparse_header sph;
+ struct chunk_header *ckh;
+ UINTN read_size, flash_size, already_read, remaining_data = size;
+ void *read_ptr;
+ INTN nb_chunks;
+ EFI_FILE *file;
+ UINT32 blk_count;
+ const UINTN HEADER_SIZE = offsetof(flash_buffer_t, d);
+ const UINTN MAX_DATA_SIZE = dl->max_size - HEADER_SIZE;
+
+ ret = uefi_open_file(file_io_interface, filename, &file);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to open %s file", filename);
+ return;
+ }
+
+ ret = read_file(file, sizeof(sph), &sph);
+ if (EFI_ERROR(ret))
+ return;
+ remaining_data -= sizeof(sph);
+
+ if (!is_sparse_image((void *) &sph, sizeof(sph))) {
+ fastboot_fail("sparse file expected");
+ return;
+ }
+
+ fb = dl->data;
+
+ /* New sparse header. */
+ memcpy(&fb->sph, &sph, sizeof(sph));
+
+ /* Sparse skip chunk. */
+ fb->skip_ckh.chunk_type = CHUNK_TYPE_DONT_CARE;
+ fb->skip_ckh.total_sz = sizeof(fb->skip_ckh);
+
+ nb_chunks = sph.total_chunks;
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ blk_count = 0;
+
+ while (nb_chunks > 0 && remaining_data > 0) {
+ fb->sph.total_chunks = 1;
+ fb->sph.total_blks = fb->skip_ckh.chunk_sz = blk_count;
+
+ if (remaining_data < read_size)
+ read_size = remaining_data;
+
+ /* Read a new piece of the input sparse file. */
+ ret = read_file(file, read_size, read_ptr);
+ if (EFI_ERROR(ret))
+ goto exit;
+ remaining_data -= read_size;
+
+ /* Process the loaded chunks to build the new header
+ and the skip chunk. */
+ flash_size = HEADER_SIZE;
+ ckh = &fb->d.ckh;
+ while ((void *)ckh + sizeof(*ckh) <= read_ptr + read_size &&
+ (void *)ckh + ckh->total_sz <= read_ptr + read_size) {
+ if (nb_chunks == 0) {
+ fastboot_fail("Corrupted sparse file: too many chunks");
+ goto exit;
+ }
+ flash_size += ckh->total_sz;
+ fb->sph.total_blks += ckh->chunk_sz;
+ blk_count += ckh->chunk_sz;
+ fb->sph.total_chunks++;
+ nb_chunks--;
+ ckh = (void *)ckh + ckh->total_sz;
+ }
+
+ /* chunk is too big to fit in the download buffer. */
+ if (flash_size == HEADER_SIZE) {
+ if (ckh->chunk_type != CHUNK_TYPE_RAW ||
+ remaining_data < ckh->total_sz - MAX_DATA_SIZE) {
+ fastboot_fail("Corrupted sparse file");
+ goto exit;
+ }
+
+ blk_count += ckh->chunk_sz;
+ nb_chunks--;
+
+ ret = installer_flash_big_chunk(file, &remaining_data,
+ fb, argc, argv);
+ if (EFI_ERROR(ret))
+ goto exit;
+
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ continue;
+ }
+
+ installer_flash_buffer(dl->data, flash_size, argc, argv);
+ if (!last_cmd_succeeded)
+ goto exit;
+
+ /* Move the incomplete chunk from the end to the
+ beginning of the buffer. */
+ if (dl->data + flash_size < read_ptr + read_size) {
+ already_read = read_ptr + read_size - (void *)ckh;
+ memcpy(fb->d.data, ckh, already_read);
+ read_size = MAX_DATA_SIZE - already_read;
+ read_ptr = fb->d.data + already_read;
+ } else {
+ read_size = MAX_DATA_SIZE;
+ read_ptr = fb->d.data;
+ }
+ }
+
+exit:
+ uefi_call_wrapper(file->Close, 1, file);
+}
+
+static void installer_flash_cmd(INTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ CHAR16 *filename;
+ INTN num = argc - 2;
+ CHAR16 *numname[num];
+ void *data;
+ UINTN size;
+ UINTN numsize[num];
+ if (argc < 3) {
+ fastboot_fail("Flash command requires exactly more then 3 arguments");
+ return;
+ }
+ if (argc > 4) {
+ argc = 2;
+ for (int i = 0; i < num; i++) {
+ numname[i] = stra_to_str(argv[i+2]);
+ if (!numname[i]) {
+ fastboot_fail("Failed to convert CHAR8 numname to CHAR16");
+ return;
+ }
+ ret = uefi_get_file_size(file_io_interface, numname[i], &numsize[i]);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to get %s file size", numname[i]);
+ goto exit;
+ }
+ }
+ if (get_current_state() == LOCKED) {
+ error(L"Installer: Flash %a is prohibited in %a state.", argv[1],
+ get_current_state_string());
+ fastboot_fail("Installer: Prohibited command in %a state.",
+ get_current_state_string());
+ return;
+ }
+ argv[1] = get_target(argv[1]);
+ if (!argv[1])
+ goto exit;
+
+ ret = find_partition(argv[1]);
+ switch (ret) {
+ case EFI_SUCCESS:
+ do_erase(argc, argv);
+ if (!last_cmd_succeeded)
+ goto exit;
+ break;
+ case EFI_NOT_FOUND:
+ break;
+ default:
+ inst_perror(ret, "Failed to get partition information");
+ goto exit;
+ }
+
+ installer_split_and_joint_flash(numname, numsize, num, argc, argv);
+ } else {
+ /* The fastboot flash command does not want the file parameter. */
+ argc--;
+
+ filename = stra_to_str(argv[2]);
+ if (!filename) {
+ fastboot_fail("Failed to convert CHAR8 filename to CHAR16");
+ return;
+ }
+ if (get_current_state() == LOCKED) {
+ error(L"Installer: Flash %a is prohibited in %a state.", argv[1],
+ get_current_state_string());
+ fastboot_fail("Installer: Prohibited command in %a state.",
+ get_current_state_string());
+ return;
+ }
+ ret = uefi_get_file_size(file_io_interface, filename, &size);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to get %s file size", filename);
+ goto exit;
+ }
+
+ argv[1] = get_target(argv[1]);
+ if (!argv[1])
+ goto exit;
+
+ ret = find_partition(argv[1]);
+ switch (ret) {
+ case EFI_SUCCESS:
+ do_erase(argc, argv);
+ if (!last_cmd_succeeded)
+ goto exit;
+ break;
+ case EFI_NOT_FOUND:
+ break;
+ default:
+ inst_perror(ret, "Failed to get partition information");
+ goto exit;
+ }
+
+ if (size > dl->max_size) {
+ installer_split_and_flash(filename, size, argc, argv);
+ goto exit;
+ }
+
+ ret = uefi_read_file(file_io_interface, filename, &data, &size);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Unable to read file %s", filename);
+ goto exit;
+ }
+
+ installer_flash_buffer(data, size, argc, argv);
+ FreePool(data);
+ }
+exit:
+ if (num == 1) {
+ FreePool(filename);
+ } else {
+ for (INTN i = 0; i < num; i++)
+ FreePool(numname[i]);
+ }
+}
+
+static CHAR16 *get_format_image_filename(CHAR8 *label)
+{
+ CHAR8 *filename;
+ CHAR16 *filename16;
+ UINTN label_length;
+
+ if (!strcmp(label, (CHAR8 *)"data"))
+ label = (CHAR8 *)"userdata";
+
+ label_length = strlena(label);
+ filename = AllocateZeroPool(label_length + 5);
+ if (!filename) {
+ fastboot_fail("Unable to allocate CHAR8 filename buffer");
+ return NULL;
+ }
+ memcpy(filename, label, label_length);
+ memcpy(filename + label_length, ".img", 4);
+ filename16 = stra_to_str(filename);
+ FreePool(filename);
+ if (!filename16) {
+ fastboot_fail("Unable to allocate CHAR16 filename buffer");
+ return NULL;
+ }
+
+ return filename16;
+}
+
+/* Simulate the fastboot host format command:
+ 1. get a filesystem image from a file;
+ 2. erase the partition;
+ 3. flash the filesystem image; */
+static void installer_format(INTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ void *data = NULL;
+ UINTN size;
+ CHAR16 *filename;
+
+ if (argc != 2) {
+ fastboot_fail("Format command requires exactly 2 arguments");
+ return;
+ }
+
+ filename = get_format_image_filename(argv[1]);
+ if (!filename)
+ return;
+
+ ret = uefi_read_file(file_io_interface, filename, &data, &size);
+ if (ret == EFI_NOT_FOUND && !StrCmp(L"userdata.img", filename)) {
+ fastboot_info("userdata.img is missing, cannot format %a", argv[1]);
+ fastboot_info("Android fs_mgr will manage this");
+ } else if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Unable to read file %s", filename);
+ goto free_filename;
+ }
+
+ argv[1] = get_target(argv[1]);
+ if (!argv[1])
+ goto free_data;
+
+ do_erase(argc, argv);
+ if (!last_cmd_succeeded)
+ goto free_data;
+
+ if (data)
+ installer_flash_buffer(data, size, argc, argv);
+
+free_data:
+ FreePool(data);
+free_filename:
+ FreePool(filename);
+}
+
+static void installer_boot(INTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ VOID *bootimage;
+ UINTN size;
+ CHAR16 *filename;
+
+ if (argc != 2) {
+ fastboot_fail("boot command takes one parameter");
+ return;
+ }
+
+ filename = stra_to_str((CHAR8 *)argv[1]);
+ if (!filename) {
+ fastboot_fail("Failed to convert filename to CHAR16");
+ return;
+ }
+
+ ret = uefi_read_file(file_io_interface, filename, &bootimage, &size);
+ FreePool(filename);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to read %a file", argv[1]);
+ return;
+ }
+
+ ret = android_image_start_buffer(g_parent_image, bootimage,
+ NORMAL_BOOT, BOOT_STATE_ORANGE, NULL,
+ NULL, NULL);
+ if (EFI_ERROR(ret))
+ inst_perror(ret, "Failed to start %s image", filename);
+ else
+ fastboot_okay("");
+}
+
+static struct command {
+ BOOLEAN optional;
+ char *cmd;
+} *commands;
+static UINTN command_nb;
+static UINTN current_command;
+
+static void free_commands(void)
+{
+ UINTN i;
+
+ if (!commands)
+ return;
+
+ for (i = 0; i < command_nb; i++)
+ if (commands[i].cmd)
+ FreePool(commands[i].cmd);
+
+ FreePool(commands);
+ commands = NULL;
+ command_nb = 0;
+ current_command = 0;
+}
+
+static EFI_STATUS create_new_command(struct command *command, char *str)
+{
+ char *cmd = str;
+
+ command->optional = FALSE;
+
+ if (*str == '[') {
+ str++;
+ cmd = (char *)strchr((CHAR8 *)str, ']');
+ if (!cmd)
+ return EFI_INVALID_PARAMETER;
+ *cmd++ = '\0';
+
+ while (*str) {
+ switch (*str++) {
+ case 'o':
+ command->optional = TRUE;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ while (*cmd && isspace(*cmd))
+ cmd++;
+ if (!*cmd)
+ return EFI_INVALID_PARAMETER;
+ }
+
+ command->cmd = strdup(cmd);
+ if (!command->cmd)
+ return EFI_OUT_OF_RESOURCES;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS store_command(char *command, VOID *context _unused)
+{
+ EFI_STATUS ret;
+ struct command *new_commands;
+
+ new_commands = AllocatePool((command_nb + 1) * sizeof(*new_commands));
+ if (!new_commands) {
+ free_commands();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memcpy(new_commands, commands, command_nb * sizeof(*commands));
+ ret = create_new_command(&new_commands[command_nb], command);
+ if (EFI_ERROR(ret)) {
+ free_commands();
+ return ret;
+ }
+ if (commands)
+ FreePool(commands);
+ commands = new_commands;
+ command_nb++;
+
+ return EFI_SUCCESS;
+}
+
+static char *next_command()
+{
+ if (command_nb == current_command) {
+ free_commands();
+ return NULL;
+ }
+
+ return commands[current_command++].cmd;
+}
+
+static void batch(INTN argc, CHAR8 **argv)
+{
+ EFI_STATUS ret;
+ void *data;
+ UINTN size;
+ CHAR16 *filename;
+
+ if (argc != 2) {
+ fastboot_fail("Batch command takes one parameter");
+ return;
+ }
+
+ filename = stra_to_str(argv[1]);
+ if (!filename) {
+ fastboot_fail("Failed to convert CHAR8 filename to CHAR16");
+ return;
+ }
+
+ ret = uefi_read_file(file_io_interface, filename, &data, &size);
+ if (EFI_ERROR(ret)) {
+ inst_perror(ret, "Failed to read %s file", filename);
+ FreePool(filename);
+ return;
+ }
+ FreePool(filename);
+
+ ret = parse_text_buffer(data, size, store_command, NULL);
+ FreePool(data);
+ if (EFI_ERROR(ret))
+ inst_perror(ret, "Failed to parse batch file");
+ else
+ fastboot_okay("");
+}
+
+static CHAR8 *build_default_options()
+{
+ static CHAR8 options[64];
+ const char cmd_prefix[] = "--batch installer";
+ const char file_suffix[] = ".cmd";
+ char *str;
+
+ if (*options)
+ return options;
+
+ memcpy(options, cmd_prefix, sizeof(cmd_prefix) - 1);
+ str = (char *)options + strlen(options);
+
+#ifdef HAL_AUTODETECT
+ char *device = get_property_device();
+ if (device) {
+ *str++ = '_';
+ while (*device)
+ *str++ = *device++;
+ }
+#endif
+
+ memcpy(str, file_suffix, sizeof(file_suffix) - 1);
+
+ return options;
+}
+
+static void usage(__attribute__((__unused__)) INTN argc,
+ __attribute__((__unused__)) CHAR8 **argv)
+{
+ Print(L"Usage: installer [OPTIONS | COMMANDS]\n");
+ Print(L" installer is an EFI application acting like the fastboot command.\n\n");
+ Print(L" COMMANDS fastboot commands (cf. the fastboot manual page)\n");
+ Print(L" --help, -h print this help and exit\n");
+ Print(L" --version, -v print Installer version and exit\n");
+ Print(L" --batch, -b FILE run all the fastboot commands of FILE\n");
+ Print(L"If no option is provided, the installer assumes '%a'\n", build_default_options());
+ Print(L"Note: 'update', 'flash-raw' and 'flashall' commands are NOT supported\n");
+
+ fastboot_okay("");
+}
+
+static void version(__attribute__((__unused__)) INTN argc,
+ __attribute__((__unused__)) CHAR8 **argv)
+{
+ Print(L"%s\n", KERNELFLINGER_VERSION);
+
+ fastboot_okay("");
+}
+
+static void unsupported_cmd(__attribute__((__unused__)) INTN argc,
+ CHAR8 **argv)
+{
+ fastboot_fail("installer does not the support the '%a' command", argv[0]);
+}
+
+static struct replacements {
+ struct fastboot_cmd cmd;
+ fastboot_handle *save_handle;
+ const char *equ_name;
+} REPLACEMENTS[] = {
+ /* Fastboot replacements. */
+ { .cmd = { .name = "flash", .handle = installer_flash_cmd },
+ .save_handle = &fastboot_flash_cmd },
+ { .cmd = { .name = "erase", .handle = installer_erase },
+ .save_handle = &fastboot_erase_cmd },
+ { .cmd = { .name = "format", .handle = installer_format } },
+ { .cmd = { .name = "boot", .handle = installer_boot } },
+ /* Equivalent commands. */
+ { .cmd = { .name = "--set-active" }, .equ_name = "set_active" },
+ /* Unsupported commands. */
+ { .cmd = { "update", LOCKED, unsupported_cmd } },
+ { .cmd = { "flashall", LOCKED, unsupported_cmd } },
+ { .cmd = { "devices", LOCKED, unsupported_cmd } },
+ { .cmd = { "download", LOCKED, unsupported_cmd } },
+ /* Installer specific commands. */
+ { .cmd = { "--help", LOCKED, usage } },
+ { .cmd = { "-h", LOCKED, usage } },
+ { .cmd = { "--version", LOCKED, version } },
+ { .cmd = { "-v", LOCKED, version } },
+ { .cmd = { "--batch", LOCKED, batch } },
+ { .cmd = { "-b", LOCKED, batch } }
+};
+
+static EFI_STATUS installer_replace_functions(void)
+{
+ EFI_STATUS ret;
+ struct fastboot_cmd *cmd;
+ UINTN i;
+
+ for (i = 0; i < ARRAY_SIZE(REPLACEMENTS); i++) {
+ cmd = fastboot_get_root_cmd(REPLACEMENTS[i].cmd.name);
+
+ if (cmd && REPLACEMENTS[i].save_handle)
+ *(REPLACEMENTS[i].save_handle) = cmd->handle;
+
+ if (cmd && REPLACEMENTS[i].cmd.handle)
+ cmd->handle = REPLACEMENTS[i].cmd.handle;
+
+ if (!cmd && REPLACEMENTS[i].cmd.handle) {
+ ret = fastboot_register(&REPLACEMENTS[i].cmd);
+ if (EFI_ERROR(ret))
+ return ret;
+ continue;
+ }
+
+ if (REPLACEMENTS[i].equ_name) {
+ cmd = fastboot_get_root_cmd(REPLACEMENTS[i].equ_name);
+ if (!cmd)
+ return EFI_INVALID_PARAMETER;
+
+ REPLACEMENTS[i].cmd.min_state = cmd->min_state;
+ REPLACEMENTS[i].cmd.handle = cmd->handle;
+ ret = fastboot_register(&REPLACEMENTS[i].cmd);
+ if (EFI_ERROR(ret))
+ return ret;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
+{
+ EFI_STATUS ret;
+ EFI_LOADED_IMAGE *loaded_img = NULL;
+ CHAR8 *options, *buf;
+ UINTN i;
+ void *bootimage;
+ void *efiimage;
+ UINTN imagesize;
+ enum boot_target target;
+
+ InitializeLib(image, _table);
+ g_parent_image = image;
+
+ ret = handle_protocol(image, &LoadedImageProtocol, (void **)&loaded_img);
+ if (ret != EFI_SUCCESS) {
+ efi_perror(ret, L"LoadedImageProtocol error");
+ return ret;
+ }
+
+ /* Initialize File IO interface. */
+ ret = uefi_call_wrapper(BS->HandleProtocol, 3, loaded_img->DeviceHandle,
+ &FileSystemProtocol, (void *)&file_io_interface);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get FileSystemProtocol");
+ return ret;
+ }
+
+ /* Prepare parameters. */
+ UINTN size = StrLen(loaded_img->LoadOptions) + 1;
+ buf = options = AllocatePool(size);
+ if (!options) {
+ error(L"Unable to allocate buffer for parameters");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ str_to_stra(options, loaded_img->LoadOptions, size);
+ /* Snip control and space characters. */
+ for (i = size - 1; options[i] <= ' '; i--)
+ options[i] = '\0';
+ /* Drop the first parameter. */
+ options = strchr(options, ' ');
+ if (options)
+ skip_whitespace((char **)&options);
+
+ if (!options || *options == '\0')
+ options = build_default_options();
+ store_command((char *)options, NULL);
+
+ /* Initialize slot management. */
+ ret = slot_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Slot management initialization failed");
+ goto exit;
+ }
+
+ /* Run the fastboot library. */
+ ret = fastboot_start(&bootimage, &efiimage, &imagesize, &target);
+ if (EFI_ERROR(ret))
+ goto exit;
+
+ if (target != UNKNOWN_TARGET)
+ reboot_to_target(target, EfiResetCold);
+
+exit:
+ FreePool(buf);
+ if (EFI_ERROR(ret))
+ return ret;
+ return last_cmd_succeeded ? EFI_SUCCESS : EFI_INVALID_PARAMETER;
+}
+
+/* Installer transport abstraction. */
+EFI_STATUS installer_transport_start(start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb)
+{
+ EFI_STATUS ret;
+ ret = fastboot_set_command_buffer(command_buffer,
+ sizeof(command_buffer));
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to set fastboot command buffer");
+ return ret;
+ }
+
+ fastboot_tx_cb = tx_cb;
+ fastboot_rx_cb = rx_cb;
+ start_cb();
+
+ if (!fastboot_cmd_buf)
+ return EFI_INVALID_PARAMETER;
+
+ dl = fastboot_download_buffer();
+ if (!dl || !dl->data || !dl->max_size)
+ return EFI_NOT_READY;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS installer_transport_stop(void)
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS installer_transport_run(void)
+{
+ static BOOLEAN initialized = FALSE;
+ EFI_STATUS ret;
+ char *cmd;
+ UINTN cmd_len;
+
+ if (!initialized) {
+ ret = installer_replace_functions();
+ if (EFI_ERROR(ret))
+ return ret;
+ if (!fastboot_flash_cmd) {
+ fastboot_fail("Failed to get the flash handle");
+ return ret;
+ }
+ initialized = TRUE;
+ }
+
+ if (current_command > 0) {
+ flush_tx_buffer();
+ if (last_cmd_succeeded)
+ Print(L"Command successfully executed\n");
+ else {
+ if (!commands[current_command - 1].optional)
+ goto stop;
+ Print(L"Command failed but is optional\n");
+ }
+ }
+
+ cmd = next_command();
+ if (!cmd)
+ goto stop;
+
+ cmd_len = strlena((CHAR8 *)cmd);
+ if (cmd_len > fastboot_cmd_buf_len) {
+ inst_perror(EFI_BUFFER_TOO_SMALL,
+ "command too long for fastboot command buffer");
+ goto stop;
+ }
+
+ memcpy(fastboot_cmd_buf, cmd, cmd_len);
+
+ Print(L"Starting command: '%a'\n", cmd);
+ fastboot_rx_cb(fastboot_cmd_buf, cmd_len);
+
+ return EFI_SUCCESS;
+
+stop:
+ fastboot_stop(NULL, NULL, 0, EXIT_SHELL);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS installer_transport_read(void *buf, UINT32 size)
+{
+ fastboot_cmd_buf = buf;
+ fastboot_cmd_buf_len = size;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS installer_transport_write(void *buf, UINT32 size)
+{
+#define PREFIX_LEN 4
+
+ if (size < PREFIX_LEN)
+ return EFI_SUCCESS;
+
+ if (!memcmp((CHAR8 *)"INFO", buf, PREFIX_LEN)) {
+ Print(L"(bootloader) %a\n", buf + PREFIX_LEN);
+ need_tx_cb = TRUE;
+ } if (!memcmp((CHAR8 *)"OKAY", buf, PREFIX_LEN)) {
+ if (((char *)buf)[PREFIX_LEN] != '\0')
+ Print(L"%a\n", buf + PREFIX_LEN);
+ last_cmd_succeeded = TRUE;
+ fastboot_tx_cb(NULL, 0);
+ } else if (!memcmp((CHAR8 *)"FAIL", buf, PREFIX_LEN)) {
+ error(L"%a", buf + PREFIX_LEN);
+ last_cmd_succeeded = FALSE;
+ fastboot_tx_cb(NULL, 0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+static transport_t INSTALLER_TRANSPORT[] = {
+ {
+ .name = "Installer for fastboot",
+ .start = installer_transport_start,
+ .stop = installer_transport_stop,
+ .run = installer_transport_run,
+ .read = installer_transport_read,
+ .write = installer_transport_write
+ }
+};
+
+EFI_STATUS fastboot_transport_register(void)
+{
+ return transport_register(INSTALLER_TRANSPORT,
+ ARRAY_SIZE(INSTALLER_TRANSPORT));
+}
+
+void fastboot_transport_unregister(void)
+{
+ transport_unregister();
+}
+
+/* UI wrapper functions. */
+void fastboot_ui_destroy(void)
+{
+}
+
+void fastboot_ui_refresh(void)
+{
+}
+
+EFI_STATUS fastboot_ui_init(void)
+{
+ return EFI_SUCCESS;
+}
+
+enum boot_target fastboot_ui_event_handler()
+{
+ return UNKNOWN_TARGET;
+}
+
+/* Installer does not support UI. It is intended to be used in
+ factory or for engineering purpose only. */
+BOOLEAN fastboot_ui_confirm_for_state(__attribute__((__unused__)) enum device_state target)
+{
+ return TRUE;
+}
diff --git a/kernelflinger.c b/kernelflinger.c
index d1491ebf..e0076348 100644
--- a/kernelflinger.c
+++ b/kernelflinger.c
@@ -35,685 +35,1464 @@
#include
#include
-#include "kernelflinger.h"
+#include
+
+#include
+
+#include "vars.h"
#include "lib.h"
#include "security.h"
#include "android.h"
#include "ux.h"
#include "options.h"
+#include "power.h"
+#include "targets.h"
+#include "unittest.h"
+#include "em.h"
+#include "storage.h"
+#include "version.h"
+#include "timer.h"
+#ifdef HAL_AUTODETECT
+#include "blobstore.h"
+#endif
+#include "oemvars.h"
+#include "slot.h"
+#ifdef RPMB_STORAGE
+#include "rpmb.h"
+#include "rpmb_storage.h"
+#endif
+#ifdef USE_TRUSTY
+#include "trusty_interface.h"
+#include "trusty_common.h"
+#endif
+#include "gpt.h"
+#include "protocol.h"
+#include "uefi_utils.h"
+#include "security_interface.h"
+#ifdef USE_TPM
+#include "tpm2_security.h"
+#endif
-/* GUIDs for various interesting Android partitions */
-static const EFI_GUID fastboot_ptn_guid = { 0x767941d0, 0x2085, 0x11e3,
- {0xad, 0x3b, 0x6c, 0xfd, 0xb9, 0x47, 0x11, 0xe9 } };
-static const EFI_GUID boot_ptn_guid = { 0x49a4d17f, 0x93a3, 0x45c1,
- {0xa0, 0xde, 0xf5, 0x0b, 0x2e, 0xbe, 0x25, 0x99 } };
-static const EFI_GUID recovery_ptn_guid = { 0x4177c722, 0x9e92, 0x4aab,
- {0x86, 0x44, 0x43, 0x50, 0x2b, 0xfd, 0x55, 0x06 } };
-static const EFI_GUID misc_ptn_guid = { 0xef32a33b, 0xa409, 0x486c,
- {0x91, 0x41, 0x9f, 0xfb, 0x71, 0x1f, 0x62, 0x66 } };
-
-/* Gummiboot's GUID, included here as we also honor LoaderEntryOneShot */
-const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf,
- {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} };
-
-#define LOADER_ENTRY_ONESHOT L"LoaderEntryOneShot"
-/* Report bootloader version */
-#define LOADER_VERSION_VAR L"LoaderVersion"
-
-/* For reading EFI globals */
-static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
-
-#define SECURE_BOOT_VAR L"SecureBoot"
-
-/* GUID for communicating with Fastboot */
-const EFI_GUID fastboot_guid = { 0x1ac80a82, 0x4f0c, 0x456b,
- {0x9a, 0x99, 0xde, 0xbe, 0xb4, 0x31, 0xfc, 0xc1} };
-
-/* Current device state, set by Fastboot */
-#define OEM_LOCK_VAR L"OEMLock"
-#define OEM_LOCK_UNLOCKED (1 << 0)
-#define OEM_LOCK_VERIFIED (1 << 1)
-
-/* Boot state that we report before exiting boot services, per
- * Google's verified boot spec */
-#define BOOT_STATE_VAR L"BootState"
-#define BOOT_STATE_GREEN 0
-#define BOOT_STATE_YELLOW 1
-#define BOOT_STATE_ORANGE 2
-#define BOOT_STATE_RED 3
-
-/* EFI Variable to store user-supplied key store binary data */
-#define KEYSTORE_VAR L"KeyStore"
-
-
-
-enum boot_target {
- NORMAL_BOOT,
- RECOVERY,
- FASTBOOT,
- ESP_BOOTIMAGE,
- ESP_EFI_BINARY,
- MEMORY
-};
-
-/* Max wait time for console reset in units of tenths of a second.
- * You want this value as small as possible as this is added to
- * the boot time for EVERY boot */
-#define EFI_RESET_WAIT_TENTH_SECS 2
+/* Ensure this is embedded in the EFI binary somewhere */
+static const CHAR16 __attribute__((used)) magic[] = L"### kernelflinger ###";
-/* Interval to check on startup for initial press of magic key */
-#define DETECT_KEY_STALL_TIME (100 * 1000)
+/* Default max wait time for console reset in units of milliseconds if no EFI
+ * variable is set for this platform.
+ * You want this value as small as possible as this is added to
+ * the boot time for EVERY boot
+ */
+#define EFI_RESET_WAIT_MS 200
-/* Time between calls to ReadKeyStroke to check if it is being actively held
- * Smaller stall values seem to result in false reporting of no key pressed
- * on several devices */
-#define HOLD_KEY_STALL_TIME (500 * 1000)
+/* Interval in ms to check on startup for initial press of magic key */
+#define DETECT_KEY_STALL_TIME_MS 1
-/* How long magic key should be held to force Fastboot mode */
-#define FASTBOOT_HOLD_DELAY (4 * 1000 * 1000)
+/* How long (in milliseconds) magic key should be held to force
+ * Fastboot mode
+ */
+#define FASTBOOT_HOLD_DELAY (2 * 1000)
-/* If we find this in the root of the EFI system partition, boot it. Used
- * for bootable USB media */
-#define MAGIC_ESP_BOOTIMAGE L"\\espboot.img"
+/* Magic key to enter fastboot mode or revovery console */
+#define MAGIC_KEY EV_DOWN
-extern VOID *oem_keystore;
-extern UINTN oem_keystore_size;
+/* If we find this in the root of the EFI system partition, unconditionally
+ * enter Fastboot mode
+ */
+#define FASTBOOT_SENTINEL L"\\force_fastboot"
+
+/* BIOS Capsule update file */
+#define FWUPDATE_FILE L"\\BIOSUPDATE.fv"
+
+#define KFSELF_FILE L"\\EFI\\BOOT\\kernelflinger.efi"
+#define KFUPDATE_FILE L"\\EFI\\BOOT\\kernelflinger_new.efi"
+#define KFBACKUP_FILE L"\\EFI\\BOOT\\kernelflinger_bak.efi"
+
+#ifndef ARCH_X86_64
+#define BOOTLOADER_FILE L"\\EFI\\BOOT\\bootia32.efi"
+#define BOOTLOADER_FILE_BAK L"\\EFI\\BOOT\\bootia32_bak.efi"
+#else
+#define BOOTLOADER_FILE L"\\EFI\\BOOT\\bootx64.efi"
+#define BOOTLOADER_FILE_BAK L"\\EFI\\BOOT\\bootx64_bak.efi"
+#endif // ARCH_X86_64
+
+/* Crash event menu settings:
+ * Maximum time between the first and the last watchdog reset. If the
+ * current difference exceeds this constant, the watchdog counter is
+ * reset to zero.
+ */
+#define WATCHDOG_DELAY (10 * 60)
-extern VOID *oem_key;
-extern UINTN oem_key_size;
+#ifdef USE_TRUSTY
+struct rot_data_t g_rot_data = {0};
+#endif
-static EFI_HANDLE g_parent_image;
static EFI_HANDLE g_disk_device;
static EFI_LOADED_IMAGE *g_loaded_image;
+static VOID die(VOID) __attribute__ ((noreturn));
#if DEBUG_MESSAGES
-static CHAR16 *boot_target_to_string(enum boot_target bt)
+static VOID print_rsci_values(VOID)
{
- switch (bt) {
- case NORMAL_BOOT:
- return L"boot";
- case RECOVERY:
- return L"recovery";
- case FASTBOOT:
- return L"fastboot";
- case ESP_BOOTIMAGE:
- return L"ESP bootimage";
- case ESP_EFI_BINARY:
- return L"ESP efi binary";
- case MEMORY:
- return L"RAM bootimage";
- default:
- return L"unknown";
- }
+ enum wake_sources raw_wake_source = rsci_get_wake_source();
+ enum reset_sources raw_reset_source = rsci_get_reset_source();
+ enum reset_types raw_reset_type = rsci_get_reset_type();
+
+ debug(L"wake_source = %s (0x%02hhx)",
+ wake_source_string(raw_wake_source),
+ raw_wake_source);
+ debug(L"reset_source = %s (0x%02hhx)",
+ reset_source_string(raw_reset_source),
+ raw_reset_source);
+ debug(L"reset_type = %s (0x%02hhx)",
+ reset_type_string(raw_reset_type),
+ raw_reset_type);
+ if (raw_reset_source == RESET_PLATFORM_SPECIFIC)
+ debug(L"reset_extra_info = 0x%08hhx", rsci_get_reset_extra_info());
}
+#endif
-static CHAR16 *boot_state_to_string(UINT8 boot_state)
+static enum boot_target check_fastboot_sentinel(VOID)
{
- switch (boot_state) {
- case BOOT_STATE_GREEN:
- return L"GREEN";
- case BOOT_STATE_YELLOW:
- return L"YELLOW";
- case BOOT_STATE_ORANGE:
- return L"ORANGE";
- case BOOT_STATE_RED:
- return L"RED";
- default:
- return L"UNKNOWN";
- }
+ debug(L"checking ESP for %s", FASTBOOT_SENTINEL);
+ if (file_exists(g_disk_device, FASTBOOT_SENTINEL))
+ return FASTBOOT;
+ return NORMAL_BOOT;
}
-#endif
-static BOOLEAN is_efi_secure_boot_enabled(VOID)
+static enum boot_target check_magic_key(VOID)
{
- UINT8 sb;
-
- if (EFI_ERROR(get_efi_variable_byte(&global_guid, SECURE_BOOT_VAR,
- &sb)))
- return FALSE;
- return sb != 0;
+ unsigned long i;
+ EFI_STATUS ret = EFI_NOT_READY;
+ EFI_INPUT_KEY key;
+ unsigned long wait_ms = EFI_RESET_WAIT_MS;
+
+ /* Some systems require a short stall before we can be sure there
+ * wasn't a keypress at boot. Read the EFI variable which determines
+ * that time for this platform
+ */
+ ret = get_efi_variable_long_from_str8(&loader_guid,
+ MAGIC_KEY_TIMEOUT_VAR,
+ &wait_ms);
+ if (EFI_ERROR(ret)) {
+ debug(L"Couldn't read timeout variable; assuming default");
+ } else {
+ if (wait_ms > 1000) {
+ debug(L"pathological magic key timeout, use default");
+ wait_ms = EFI_RESET_WAIT_MS;
+ }
+ }
+
+ debug(L"Reset wait time: %d", wait_ms);
+
+ /* Check for 'magic' key. Some BIOSes are flaky about this
+ * so wait for the ConIn to be ready after reset
+ */
+ for (i = 0; i <= wait_ms; i += DETECT_KEY_STALL_TIME_MS) {
+ ret = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
+ ST->ConIn, &key);
+ if (ret == EFI_SUCCESS || i == wait_ms)
+ break;
+ uefi_call_wrapper(BS->Stall, 1, DETECT_KEY_STALL_TIME_MS * 1000);
+ }
+
+ if (EFI_ERROR(ret))
+ return NORMAL_BOOT;
+
+ debug(L"ReadKeyStroke: (%d tries) %d %d", i, key.ScanCode, key.UnicodeChar);
+ if (ui_keycode_to_event(key.ScanCode) != MAGIC_KEY)
+ return NORMAL_BOOT;
+
+ if (ui_enforce_key_held(FASTBOOT_HOLD_DELAY, MAGIC_KEY))
+ return FASTBOOT;
+
+ return NORMAL_BOOT;
}
-static BOOLEAN is_device_locked_or_verified(VOID)
+static enum boot_target check_bcb(CHAR16 **target_path, BOOLEAN *oneshot)
{
- UINT8 ds;
-
- /* If we can't read the state, be safe and assume locked */
- if (EFI_ERROR(get_efi_variable_byte(&fastboot_guid, OEM_LOCK_VAR,
- &ds)))
- return TRUE;
-
- if (ds & OEM_LOCK_VERIFIED)
- return TRUE;
+ EFI_STATUS ret;
+ struct bootloader_message bcb;
+ CHAR16 *target = NULL;
+ enum boot_target t;
+ CHAR8 *bcb_cmd;
+ BOOLEAN dirty;
+
+ *oneshot = FALSE;
+ *target_path = NULL;
+
+ ret = read_bcb(MISC_LABEL, &bcb);
+ if (EFI_ERROR(ret)) {
+ error(L"Unable to read BCB");
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ dirty = bcb.status[0] != '\0';
+ /* We own the status field; clear it in case there is any stale data */
+ bcb.status[0] = '\0';
+ bcb_cmd = (CHAR8 *)bcb.command;
+ if (!strncmpa(bcb_cmd, (CHAR8 *)"boot-", 5)) {
+ target = stra_to_str(bcb_cmd + 5);
+ debug(L"BCB boot target: '%s'", target);
+ } else if (!strncmpa(bcb_cmd, (CHAR8 *)"bootonce-", 9)) {
+ target = stra_to_str(bcb_cmd + 9);
+ bcb_cmd[0] = '\0';
+ dirty = TRUE;
+ debug(L"BCB oneshot boot target: '%s'", target);
+ *oneshot = TRUE;
+ }
+
+ if (dirty) {
+ ret = write_bcb(MISC_LABEL, &bcb);
+ if (EFI_ERROR(ret))
+ error(L"Unable to update BCB contents!");
+ }
+
+ if (!target) {
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ if (target[0] == L'\\') {
+ UINTN len;
+
+ if (!file_exists(g_disk_device, target)) {
+ error(L"Specified BCB file '%s' doesn't exist",
+ target);
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ len = StrLen(target);
+ if (len > 4) {
+ *target_path = StrDuplicate(target);
+ if (!StrCmp(target + (len - 4), L".efi") ||
+ !StrCmp(target + (len - 4), L".EFI")) {
+ t = ESP_EFI_BINARY;
+ } else {
+ t = ESP_BOOTIMAGE;
+ }
+ goto out;
+ }
+ error(L"BCB file '%s' appears to be malformed", target);
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ t = name_to_boot_target(target);
+ if (t != UNKNOWN_TARGET)
+ goto out;
+
+ error(L"Unknown boot target in BCB: '%s'", target);
+ t = NORMAL_BOOT;
- if (ds & OEM_LOCK_UNLOCKED)
- return FALSE;
-
- return TRUE;
-}
-
-/* If a user-provided keystore is present it must be selected for later.
- * If no user-provided keystore is present then the original factory
- * keystore must be selected instead. Selection of a keystore is
- * independent of validation of that keystore. */
-static VOID select_keystore(VOID **keystore, UINTN *size)
-{
- if (EFI_ERROR(get_efi_variable(&fastboot_guid, KEYSTORE_VAR,
- size, keystore)) ||
- *size == 0) {
- *keystore = oem_keystore;
- *size = oem_keystore_size;
- }
+out:
+ FreePool(target);
+ return t;
}
-static enum boot_target check_esp_bootimage(VOID)
+static enum boot_target check_loader_entry_one_shot(VOID)
{
- debug("checking ESP for %s", MAGIC_ESP_BOOTIMAGE);
- if (file_exists(g_disk_device, MAGIC_ESP_BOOTIMAGE))
- return ESP_BOOTIMAGE;
- return NORMAL_BOOT;
+ EFI_STATUS ret;
+ CHAR16 *target;
+ enum boot_target bt;
+
+ debug(L"checking %s", LOADER_ENTRY_ONESHOT);
+ target = get_efi_variable_str(&loader_guid, LOADER_ENTRY_ONESHOT);
+
+ del_efi_variable(&loader_guid, LOADER_ENTRY_ONESHOT);
+
+ if (!target)
+ return NORMAL_BOOT;
+
+ debug(L"target = %s", target);
+ bt = name_to_boot_target(target);
+ if (bt == UNKNOWN_TARGET) {
+ if (!StrCmp(target, L"dm-verity device corrupted")) {
+ debug(L"Reboot was triggered by dm-verity module because partition is corrupted");
+ ret = slot_set_verity_corrupted(TRUE);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to set the active slot verity eio flag");
+ } else
+ error(L"Unknown oneshot boot target: '%s'", target);
+ bt = NORMAL_BOOT;
+ } else if (bt == CHARGER && !get_off_mode_charge()) {
+ debug(L"Off mode charge is not set, powering off.");
+ bt = POWER_OFF;
+ }
+
+ FreePool(target);
+ return bt;
}
-
-static enum boot_target check_magic_key(VOID)
+static BOOLEAN reset_is_due_to_watchdog_or_panic(void)
{
- int i;
- EFI_STATUS ret;
- EFI_INPUT_KEY key;
-
- debug("checking for magic key");
- uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
-
- /* Check for 'magic' key. Some BIOSes are flaky about this
- * so wait for the ConIn to be ready after reset */
- for (i = 0; i < EFI_RESET_WAIT_TENTH_SECS; i++) {
- ret = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
- ST->ConIn, &key);
- if (ret == EFI_SUCCESS)
- break;
- uefi_call_wrapper(BS->Stall, 1, DETECT_KEY_STALL_TIME);
- }
-
- if (EFI_ERROR(ret))
- return NORMAL_BOOT;
-
- debug("ReadKeyStroke: (%d tries) %d %d", i, key.ScanCode, key.UnicodeChar);
-
- Print(L"Continue holding key for %d seconds to force Fastboot mode.\n",
- FASTBOOT_HOLD_DELAY / 1000000);
- Print(L"Release key now to load Recovery Console.");
-
- for (i = 0; i < (FASTBOOT_HOLD_DELAY / HOLD_KEY_STALL_TIME); i++) {
- uefi_call_wrapper(BS->Stall, 1, HOLD_KEY_STALL_TIME);
-
- ret = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
- ST->ConIn, &key);
- if (ret != EFI_SUCCESS) {
- debug("err=%r", ret);
- break;
- }
- Print(L".");
- }
- Print(L"\n");
-
- if (ret == EFI_SUCCESS)
- return FASTBOOT;
- else
- return RECOVERY;
+ static enum reset_sources WATCHDOG_RESET_SOURCES[] = {
+ RESET_KERNEL_WATCHDOG,
+ RESET_SECURITY_WATCHDOG,
+ RESET_PMIC_WATCHDOG,
+ RESET_EC_WATCHDOG
+ };
+ enum reset_sources reset_source;
+ UINTN i;
+
+ reset_source = rsci_get_reset_source();
+ for (i = 0; i < ARRAY_SIZE(WATCHDOG_RESET_SOURCES); i++)
+ if (reset_source == WATCHDOG_RESET_SOURCES[i]) {
+ debug(L"Watchdog reset source = %d", reset_source);
+ return TRUE;
+ }
+
+ return is_reboot_reason(L"kernel_panic") ||
+ is_reboot_reason(L"watchdog");
}
-
-static enum boot_target check_bcb(CHAR16 **target_path, BOOLEAN *oneshot)
+/* If more than get_watchdog_counter_max() watchdog (or kernel panic)
+ * resets in a row happened in less than WATCHDOG_DELAY seconds, the
+ * crash event menu is displayed. This menu informs the user of the
+ * situation and let him choose which boot target he wants.
+ */
+static enum boot_target check_watchdog(VOID)
{
- EFI_STATUS ret;
- struct bootloader_message bcb;
- CHAR16 *target = NULL;
- enum boot_target t;
-
- debug("checking bootloader control block");
- *oneshot = FALSE;
- *target_path = NULL;
-
- ret = read_bcb(&misc_ptn_guid, &bcb);
- if (EFI_ERROR(ret)) {
- Print(L"Unable to read BCB\n");
- t = NORMAL_BOOT;
- goto out;
- }
-
- /* We own the status field; clear it in case there is any stale data */
- bcb.status[0] = '\0';
-
- if (!strncmpa(bcb.command, (CHAR8 *)"boot-", 5)) {
- target = stra_to_str(bcb.command + 5);
- debug("BCB boot target: '%s'", target);
- } else if (!strncmpa(bcb.command, (CHAR8 *)"bootonce-", 9)) {
- target = stra_to_str(bcb.command + 9);
- bcb.command[0] = '\0';
- debug("BCB oneshot boot target: '%s'", target);
- *oneshot = TRUE;
- }
-
- ret = write_bcb(&misc_ptn_guid, &bcb);
- if (EFI_ERROR(ret))
- Print(L"Unable to update BCB contents!\n");
-
- if (!target) {
- t = NORMAL_BOOT;
- goto out;
- }
-
- if (target[0] == L'\\') {
- UINTN len;
-
- if (!file_exists(g_disk_device, target)) {
- Print(L"Specified BCB file '%s' doesn't exist\n",
- target);
- t = NORMAL_BOOT;
- goto out;
- }
-
- len = StrLen(target);
- if (len > 4) {
- *target_path = StrDuplicate(target);
- if (!StrCmp(target + (len - 4), L".efi") ||
- !StrCmp(target + (len - 4), L".EFI")) {
- t = ESP_EFI_BINARY;
- } else {
- t = ESP_BOOTIMAGE;
- }
- goto out;
- }
- Print(L"BCB file '%s' appears to be malformed\n", target);
- t = NORMAL_BOOT;
- goto out;
- }
+ EFI_STATUS ret;
+ UINT8 counter;
+ EFI_TIME time_ref, now;
+
+ if (!get_crash_event_menu())
+ return NORMAL_BOOT;
+
+ ret = get_watchdog_status(&counter, &time_ref);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the watchdog status");
+ return NORMAL_BOOT;
+ }
+
+ if (!reset_is_due_to_watchdog_or_panic()) {
+ if (counter != 0) {
+ ret = reset_watchdog_status();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to reset the watchdog status");
+ goto error;
+ }
+ }
+ return NORMAL_BOOT;
+ }
+
+#ifdef USER
+ if (is_reboot_reason(L"shutdown")) {
+ del_reboot_reason();
+ return POWER_OFF;
+ }
+#endif
- if (!StrCmp(target, L"fastboot") || !StrCmp(target, L"bootloader")) {
- t = FASTBOOT;
- goto out;
- }
+ ret = uefi_call_wrapper(RT->GetTime, 2, &now, NULL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the current time");
+ goto error;
+ }
+
+ if (counter > 0) {
+ if (efi_time_to_ctime(&now) < efi_time_to_ctime(&time_ref) ||
+ efi_time_to_ctime(&now) - efi_time_to_ctime(&time_ref) > WATCHDOG_DELAY)
+ counter = 0;
+ }
+
+ if (counter == 0) {
+ time_ref = now;
+ ret = set_watchdog_time_reference(&now);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to set the watchdog time reference");
+ goto error;
+ }
+ }
+
+ counter++;
+ debug(L"Incrementing watchdog counter (%d)", counter);
+
+ if (counter <= get_watchdog_counter_max()) {
+ ret = set_watchdog_counter(counter);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to set the watchdog counter");
+ goto error;
+ }
+
+ ret = reset_watchdog_status();
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to reset the watchdog status");
+
+#ifdef USE_UI
+ return ux_prompt_user_for_boot_target(CRASH_EVENT_CODE);
+#else
+ debug(L"NO_UI,CRASH_EVENT,rebooting");
+ return NORMAL_BOOT;
+#endif
- if (!StrCmp(target, L"recovery")) {
- t = RECOVERY;
- goto out;
- }
+error:
+ return NORMAL_BOOT;
+}
- Print(L"Unknown boot target in BCB: '%s'\n", target);
- t = NORMAL_BOOT;
+static enum boot_target check_command_line(VOID)
+{
+ UINTN argc, pos;
+ CHAR16 **argv;
+ enum boot_target bt;
+
+ bt = NORMAL_BOOT;
+
+ if (EFI_ERROR(get_argv(g_loaded_image, &argc, &argv)))
+ return NORMAL_BOOT;
+
+ for (pos = 0; pos < argc; pos++) {
+ debug(L"Argument %d: %s", pos, argv[pos]);
+
+ if (!StrCmp(argv[pos], L"-f")) {
+ bt = FASTBOOT;
+ continue;
+ }
+#ifndef USER
+ if (!StrCmp(argv[pos], L"-U")) {
+ pos++;
+ unittest_main(pos >= argc ? NULL : argv[pos]);
+ FreePool(argv);
+ return EXIT_SHELL;
+ }
+#endif
+ if (!StrCmp(argv[pos], L"-a")) {
+ pos++;
+ if (pos >= argc) {
+ error(L"-a requires a memory address");
+ goto out;
+ }
+
+ /* For compatibility...just ignore the supplied address
+ * and enter Fastboot mode
+ */
+ bt = FASTBOOT;
+ continue;
+ }
+
+ /* If we get here the argument isn't recognized */
+ if (pos == 0) {
+ /* EFI is inconsistent and only seems to populate the image
+ * name as argv[0] when called from a shell. Do nothing.
+ */
+ continue;
+ } else {
+ error(L"unexpected argument %s", argv[pos]);
+ goto out;
+ }
+ }
out:
- FreePool(target);
- return t;
+ FreePool(argv);
+ return bt;
}
-
-static enum boot_target check_loader_entry_one_shot(VOID)
+static enum boot_target check_battery_inserted(void)
{
- CHAR16 *target;
- enum boot_target ret;
-
- debug("checking %s", LOADER_ENTRY_ONESHOT);
- target = get_efi_variable_str(&loader_guid, LOADER_ENTRY_ONESHOT);
-
- set_efi_variable(&loader_guid, LOADER_ENTRY_ONESHOT, 0, NULL,
- TRUE, TRUE);
-
- if (!target) {
- ret = NORMAL_BOOT;
- } else if (!StrCmp(target, L"fastboot") || !StrCmp(target, L"bootloader")) {
- ret = FASTBOOT;
- } else if (!StrCmp(target, L"recovery")) {
- ret = RECOVERY;
- } else {
- Print(L"Unknown oneshot boot target: '%s'\n", target);
- ret = NORMAL_BOOT;
- }
-
- FreePool(target);
- return ret;
-}
+ enum wake_sources wake_source;
+ if (!get_off_mode_charge())
+ return NORMAL_BOOT;
-static enum boot_target check_command_line(VOID **address)
-{
- UINTN argc, pos;
- CHAR16 **argv;
- enum boot_target bt;
+ wake_source = rsci_get_wake_source();
+ if (wake_source == WAKE_BATTERY_INSERTED)
+ return POWER_OFF;
- *address = NULL;
- bt = NORMAL_BOOT;
+ return NORMAL_BOOT;
+}
- debug("checking loader command line");
+static enum boot_target check_charge_mode(void)
+{
+ enum wake_sources wake_source;
- if (EFI_ERROR(get_argv(g_loaded_image, &argc, &argv)))
- return NORMAL_BOOT;
+ if (!get_off_mode_charge())
+ return NORMAL_BOOT;
- for (pos = 0; pos < argc; pos++) {
- debug("Argument %d: %s", pos, argv[pos]);
+ wake_source = rsci_get_wake_source();
+ if ((wake_source == WAKE_USB_CHARGER_INSERTED) ||
+ (wake_source == WAKE_ACDC_CHARGER_INSERTED)) {
+ debug(L"Wake source = %d", wake_source);
+ return CHARGER;
+ }
- if (!StrCmp(argv[pos], L"-a")) {
- pos++;
- if (pos >= argc) {
- Print(L"-a requires a memory address\n");
- goto out;
- }
+ return NORMAL_BOOT;
+}
- *address = (VOID *)strtoul(argv[pos], NULL, 0);
- bt = MEMORY;
- continue;
- }
+enum boot_target check_battery(void)
+{
+ if (!get_off_mode_charge())
+ return NORMAL_BOOT;
- /* If we get here the argument isn't recognized */
- if (pos == 0) {
- /* EFI is inconsistent and only seems to populate the image
- * name as argv[0] when called from a shell. Do nothing. */
- continue;
- } else {
- Print(L"unexpected argument %s\n", argv[pos]);
- goto out;
- }
- }
+ if (is_battery_below_boot_OS_threshold()) {
+ BOOLEAN charger_plugged = is_charger_plugged_in();
-out:
- FreePool(argv);
- return bt;
-}
+ debug(L"Battery is below boot OS threshold");
+ debug(L"Charger is%s plugged", charger_plugged ? L"" : L" not");
+ return charger_plugged ? CHARGER : POWER_OFF;
+ }
+ return NORMAL_BOOT;
+}
/* Policy:
- * 1. Check if the "-a xxxxxxxxx" command line was passed in, if so load an
+ * 1. Check if we had multiple watchdog reported in a short period of
+ * time. If so, let the user choose the boot target.
+ * 2. Check if the "-a xxxxxxxxx" command line was passed in, if so load an
* android boot image from RAM at that location.
- * 2. Check if "espboot.img" is in the root of the EFI System Partition. If so,
- * boot that, skipping all other logic. Used only for bootable USB media.
- * 3. Check for "magic key" being held. Short press loads Recovery. Long press
+ * 3. Check if the fastboot sentinel file \force_fastboot is present, and if
+ * so, force fastboot mode. Use in bootable media.
+ * 4. Check for "magic key" being held. Short press loads Recovery. Long press
* loads Fastboot.
- * 4. Check bootloader control block for a boot target, which could be
+ * 5. Check if wake source is battery inserted, if so power off
+ * 6. Check bootloader control block for a boot target, which could be
* the name of a boot image that we know how to read from a partition,
* or a boot image file in the ESP. BCB can specify oneshot or persistent
* targets.
- * 5. Check LoaderEntryOneShot for a boot target */
-static enum boot_target choose_boot_target(VOID **target_address,
- CHAR16 **target_path, BOOLEAN *oneshot)
+ * 7. Check LoaderEntryOneShot for a boot target
+ * 8. Check if we should go into charge mode or normal boot
+ *
+ * target_path - If ESP_EFI_BINARY or ESP_BOOTIMAGE returned, path to the
+ * image on the EFI System Partition
+ * oneshot - Whether this is a one-shot boot, indicating that the image at
+ * target_path should be deleted before chainloading
+ *
+ */
+static enum boot_target choose_boot_target(CHAR16 **target_path, BOOLEAN *oneshot)
{
- enum boot_target ret;
+ enum boot_target ret;
- *target_path = NULL;
- *target_address = NULL;
- *oneshot = TRUE;
+ *target_path = NULL;
+ *oneshot = TRUE;
- ret = check_command_line(target_address);
- if (ret != NORMAL_BOOT)
- return ret;
-
- ret = check_esp_bootimage();
- if (ret != NORMAL_BOOT) {
- *oneshot = FALSE;
- *target_path = StrDuplicate(MAGIC_ESP_BOOTIMAGE);
- return ret;
- }
+#if DEBUG_MESSAGES
+ print_rsci_values();
+#endif
+ debug(L"Bootlogic: Choosing boot target");
+
+ debug(L"Bootlogic: Check osloader command line...");
+ ret = check_command_line();
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check fastboot sentinel...");
+ ret = check_fastboot_sentinel();
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check magic key...");
+ ret = check_magic_key();
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check watchdog...");
+ ret = check_watchdog();
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check battery insertion...");
+ ret = check_battery_inserted();
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check BCB...");
+ ret = check_bcb(target_path, oneshot);
+ if (ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check reboot target...");
+ ret = check_loader_entry_one_shot();
+ if (ret != DNX && ret != NORMAL_BOOT)
+ goto out;
+
+ debug(L"Bootlogic: Check battery level...");
+ ret = check_battery();
+
+#ifdef USE_UI
+ if (ret == POWER_OFF)
+ ux_display_low_battery(3);
+#else
+ if (ret == POWER_OFF)
+ debug(L"NO_UI: low battery");
+#endif
+ if (ret != NORMAL_BOOT)
+ goto out;
- ret = check_magic_key();
- if (ret != NORMAL_BOOT)
- return ret;
+ debug(L"Bootlogic: Check charger insertion...");
+ ret = check_charge_mode();
- ret = check_bcb(target_path, oneshot);
- if (ret != NORMAL_BOOT)
- return ret;
+out:
+ debug(L"Bootlogic: selected '%s'", boot_target_description(ret));
+ return ret;
+}
- return check_loader_entry_one_shot();
+#ifdef USE_AVB
+/* Use AVB load and verify a boot image into RAM.
+ *
+ * boot_target - Boot image to load. Values supported are NORMAL_BOOT, RECOVERY,
+ * and ESP_BOOTIMAGE (for 'fastboot boot')
+ * target_path - Path to load boot image from for ESP_BOOTIMAGE case, ignored
+ * otherwise.
+ * bootimage - Returned allocated pointer value for the loaded boot image.
+ * oneshot - For ESP_BOOTIMAGE case, flag indicating that the image should
+ * be deleted.
+ * boot_state - The boot state, maybe changed according the load and verify result.
+ *
+ * Return values:
+ * EFI_INVALID_PARAMETER - Unsupported boot target type, key is not well-formed,
+ * or loaded boot image was missing or corrupt
+ * EFI_ACCESS_DENIED - Validation failed against OEM or embedded certificate,
+ * boot image still usable
+ */
+static EFI_STATUS avb_load_verify_boot_image(
+ IN enum boot_target boot_target,
+ IN CHAR16 *target_path,
+ OUT VOID **bootimage,
+ IN BOOLEAN oneshot,
+ UINT8 *boot_state,
+ AvbSlotVerifyData **slot_data)
+{
+ EFI_STATUS ret;
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ case CHARGER:
+ ret = android_image_load_partition_avb_ab("boot", bootimage, boot_state, slot_data);
+ break;
+ case RECOVERY:
+ if (recovery_in_boot_partition()) {
+ ret = avb_load_verify_boot_image(NORMAL_BOOT, target_path, bootimage, oneshot, boot_state, slot_data);
+ break;
+ }
+#if !defined(USE_AVB)
+ /* Tries count is handled by avb_ab_flow when AVB is enabled. */
+ if (use_slot() && !slot_recovery_tries_remaining()) {
+ ret = EFI_NOT_FOUND;
+ break;
+ }
+#endif
+ ret = android_image_load_partition_avb("recovery", bootimage, boot_state, slot_data);
+ break;
+ case ESP_BOOTIMAGE:
+ /* "fastboot boot" case */
+ ret = android_image_load_file(g_disk_device, target_path, oneshot,
+ bootimage);
+ break;
+ default:
+ *bootimage = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EFI_ERROR(ret))
+ debug(L"boot image loaded");
+
+ return ret;
}
+#else // USE_AVB == false
+
+/* Validate an image.
+ *
+ * Parameters:
+ * boot_target - Boot image to load. Values supported are NORMAL_BOOT,
+ * RECOVERY, and ESP_BOOTIMAGE (for 'fastboot boot')
+ * bootimage - Bootimage to validate
+ * verifier_cert - Return the certificate that validated the boot image
+ *
+ * Return values:
+ * BOOT_STATE_GREEN - Boot image is valid against provided certificate
+ * BOOT_STATE_YELLOW - Boot image is valid against embedded certificate
+ * BOOT_STATE_RED - Boot image is not valid
+ */
+static UINT8 validate_bootimage(
+ IN enum boot_target boot_target,
+ IN VOID *bootimage,
+ X509 **verifier_cert)
+{
+ CHAR16 target[BOOT_TARGET_SIZE];
+ CHAR16 *expected;
+ CHAR16 *expected2 = NULL;
+ UINT8 boot_state;
+
+ boot_state = verify_android_boot_image(bootimage, oem_cert,
+ oem_cert_size, target,
+ verifier_cert);
+
+ if (boot_state == BOOT_STATE_RED) {
+ debug(L"boot image doesn't verify");
+ return boot_state;
+ }
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ expected = L"/boot";
+ /* in case of multistage ota */
+ expected2 = L"/recovery";
+ break;
+ case CHARGER:
+ expected = L"/boot";
+ break;
+ case RECOVERY:
+ if (recovery_in_boot_partition())
+ expected = L"/boot";
+ else
+ expected = L"/recovery";
+ break;
+ case ESP_BOOTIMAGE:
+ /* "live" bootable image */
+ expected = L"/boot";
+ break;
+ default:
+ expected = NULL;
+ }
+
+ if ((!expected || StrCmp(expected, target)) &&
+ (!expected2 || StrCmp(expected2, target))) {
+ debug(L"boot image has unexpected target name");
+ return BOOT_STATE_RED;
+ }
+
+ return boot_state;
+}
+/* Load a boot image into RAM.
+ *
+ * boot_target - Boot image to load. Values supported are NORMAL_BOOT, RECOVERY,
+ * and ESP_BOOTIMAGE (for 'fastboot boot')
+ * target_path - Path to load boot image from for ESP_BOOTIMAGE case, ignored
+ * otherwise.
+ * bootimage - Returned allocated pointer value for the loaded boot image.
+ * oneshot - For ESP_BOOTIMAGE case, flag indicating that the image should
+ * be deleted.
+ *
+ * Return values:
+ * EFI_INVALID_PARAMETER - Unsupported boot target type, key is not well-formed,
+ * or loaded boot image was missing or corrupt
+ * EFI_ACCESS_DENIED - Validation failed against OEM or embedded certificate,
+ * boot image still usable
+ */
static EFI_STATUS load_boot_image(
- IN enum boot_target boot_target,
- IN VOID *keystore,
- IN UINTN keystore_size,
- IN CHAR16 *target_path,
- IN VOID *mem_address,
- OUT VOID **bootimage,
- IN BOOLEAN oneshot)
+ IN enum boot_target boot_target,
+ IN CHAR16 *target_path,
+ OUT VOID **bootimage,
+ IN BOOLEAN oneshot)
{
- CHAR16 target[BOOT_TARGET_SIZE];
- EFI_STATUS ret;
-
- switch (boot_target) {
- case NORMAL_BOOT:
- ret = android_image_load_partition(&boot_ptn_guid, bootimage);
- break;
- case RECOVERY:
- ret = android_image_load_partition(&recovery_ptn_guid, bootimage);
- break;
- case FASTBOOT:
- ret = android_image_load_partition(&fastboot_ptn_guid, bootimage);
- break;
- case ESP_BOOTIMAGE:
- ret = android_image_load_file(g_disk_device, target_path, oneshot,
- bootimage);
- break;
- case MEMORY:
- *bootimage = mem_address;
- ret = EFI_SUCCESS;
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
-
- if (EFI_ERROR(ret))
- return ret;
-
- debug("boot image loaded");
- if (keystore) {
- CHAR16 *expected;
-
- ret = verify_android_boot_image(*bootimage, keystore,
- keystore_size, target);
- if (EFI_ERROR(ret) && keystore != oem_keystore) {
- debug("selected keystore doesn't verify, try OEM key\n");
- ret = verify_android_boot_image(*bootimage,
- oem_keystore, oem_keystore_size,
- target);
- }
+ EFI_STATUS ret;
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ case CHARGER:
+ ret = EFI_NOT_FOUND;
+ if (use_slot() && !slot_get_active())
+ break;
+ do {
+ const CHAR16 *label = slot_label(BOOT_LABEL);
+
+ ret = android_image_load_partition(label, bootimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to load boot image from %s partition",
+ label);
+ if (use_slot())
+ slot_boot_failed(boot_target);
+ }
+ } while (EFI_ERROR(ret) && slot_get_active());
+ break;
+ case RECOVERY:
+ if (recovery_in_boot_partition()) {
+ ret = load_boot_image(NORMAL_BOOT, target_path, bootimage, oneshot);
+ break;
+ }
+
+ if (use_slot() && !slot_recovery_tries_remaining()) {
+ ret = EFI_NOT_FOUND;
+ break;
+ }
+
+ ret = android_image_load_partition(RECOVERY_LABEL, bootimage);
+ break;
+ case ESP_BOOTIMAGE:
+ /* "fastboot boot" case */
+ ret = android_image_load_file(g_disk_device, target_path, oneshot,
+ bootimage);
+ break;
+ default:
+ *bootimage = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EFI_ERROR(ret))
+ debug(L"boot image loaded");
+
+ return ret;
+}
+#endif
- if (EFI_ERROR(ret)) {
- debug("boot image doesn't verify");
- goto out;
- }
+#define OEMVARS_MAGIC "#OEMVARS\n"
+#define OEMVARS_MAGIC_SZ 9
- switch (boot_target) {
- case NORMAL_BOOT:
- expected = L"boot";
- break;
- case FASTBOOT:
- case MEMORY:
- expected = L"fastboot";
- break;
- case RECOVERY:
- expected = L"recovery";
- break;
- default:
- expected = NULL;
- }
+static EFI_STATUS set_image_oemvars_nocheck(VOID *bootimage,
+ const EFI_GUID *restricted_guid)
+{
+ VOID *oemvars;
+ UINT32 osz;
+ EFI_STATUS ret;
+
+ ret = get_bootimage_2nd(bootimage, &oemvars, &osz);
+ if (ret == EFI_SUCCESS && osz > OEMVARS_MAGIC_SZ &&
+ !memcmp(oemvars, OEMVARS_MAGIC, OEMVARS_MAGIC_SZ)) {
+ debug(L"secondstage contains raw oemvars");
+ return flash_oemvars_silent_write_error((CHAR8 *)oemvars + OEMVARS_MAGIC_SZ,
+ osz - OEMVARS_MAGIC_SZ,
+ restricted_guid);
+ }
+
+#ifdef HAL_AUTODETECT
+ ret = get_bootimage_blob(bootimage, BLOB_TYPE_OEMVARS, &oemvars, &osz);
+ if (EFI_ERROR(ret)) {
+ if (ret == EFI_UNSUPPORTED || ret == EFI_NOT_FOUND) {
+ debug(L"No blobstore in this boot image");
+ return EFI_SUCCESS;
+ }
+ return ret;
+ }
+
+ return flash_oemvars_silent_write_error(oemvars, osz, restricted_guid);
+#else
+ return EFI_NOT_FOUND;
+#endif
+}
+
+static EFI_STATUS set_image_oemvars(VOID *bootimage)
+{
+ if (!get_oemvars_update()) {
+ debug(L"OEM vars should be up-to-date");
+ return EFI_SUCCESS;
+ }
+ debug(L"OEM vars may need to be updated");
+ set_oemvars_update(FALSE);
+
+ return set_image_oemvars_nocheck(bootimage, NULL);
+}
+
+static EFI_STATUS load_image(VOID *bootimage, UINT8 boot_state,
+ enum boot_target boot_target,
+#ifdef USE_AVB
+ AvbSlotVerifyData *slot_data
+#else
+ X509 *verifier_cert
+#endif
+ )
+{
+ EFI_STATUS ret;
+#ifdef USE_TRUSTY
+ VOID *tosimage = NULL;
+#endif
+#ifdef USER
+ /* per bootloaderequirements.pdf */
+ if (boot_state == BOOT_STATE_ORANGE) {
+ ret = android_clear_memory();
+ if (EFI_ERROR(ret)) {
+ error(L"Failed to clear memory. Load image aborted.");
+ return ret;
+ }
+ }
+#endif
+
+ set_efi_variable(&fastboot_guid, BOOT_STATE_VAR, sizeof(boot_state),
+ &boot_state, FALSE, TRUE);
+
+#ifdef OS_SECURE_BOOT
+ ret = set_os_secure_boot(boot_state == BOOT_STATE_GREEN);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to set os secure boot");
+#endif
+
+ /* install acpi tables before starting trusty */
+ ret = setup_acpi_table(bootimage, boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"setup_acpi_table");
+ return ret;
+ }
+
+#ifdef USE_TRUSTY
+ if (is_bootimg_target(boot_target)) {
+
+ if (boot_state == BOOT_STATE_RED) {
+#ifndef USERDEBUG
+ debug(L"Red state: start trusty anyway as ENG build");
+#else
+ debug(L"Red state: invalid boot image.Unable to start trusty. Stop");
+ die();
+#endif
+ }
+ debug(L"loading trusty");
+ ret = load_tos_image(&tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Load tos image failed");
+ die();
+ }
+#ifdef USE_AVB
+ const UINT8 *vbmeta_pub_key;
+ UINTN vbmeta_pub_key_len;
+
+ if (slot_data != NULL) {
+ ret = avb_vbmeta_image_verify(slot_data->vbmeta_images[0].vbmeta_data,
+ slot_data->vbmeta_images[0].vbmeta_size,
+ &vbmeta_pub_key,
+ &vbmeta_pub_key_len);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the vbmeta_pub_key");
+ die();
+ }
- /* XXX do we need to enforce this? can't cover the ESP case */
- if (StrCmp(expected, target)) {
- debug("boot image has unexpected target name");
- // ret = EFI_ACCESS_DENIED;
+ ret = get_rot_data(bootimage, boot_state,
+ vbmeta_pub_key, vbmeta_pub_key_len, &g_rot_data);
}
- }
+#else
+ ret = get_rot_data(bootimage, boot_state, verifier_cert, &g_rot_data);
+#endif
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Unable to get the root of trust data for trusty");
+ die();
+ }
+
+ set_boottime_stamp(TM_LOAD_TOS_DONE);
+ ret = start_trusty(tosimage);
+ if (EFI_ERROR(ret)) {
+#ifndef BUILD_ANDROID_THINGS
+ efi_perror(ret, L"Unable to start trusty; stop.");
+ die();
+#else
+ efi_perror(ret, L"Unable to start trusty");
+ efi_perror(ret, L"Continue to boot");
+#endif
+ }
+ set_boottime_stamp(TM_PROCRSS_TRUSTY_DONE);
+ }
+#endif
-out:
- if (EFI_ERROR(ret) && *bootimage != mem_address)
- FreePool(bootimage);
+#if !defined(USE_AVB)
+ ret = slot_boot(boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to write slot boot");
+ return ret;
+ }
+#endif
+
+#ifdef USE_TPM
+ // Make sure the TPM2 is ended
+ tpm2_end();
+#endif
+
+ debug(L"chainloading boot image, boot state is %s",
+ boot_state_to_string(boot_state));
+ ret = android_image_start_buffer(g_parent_image, bootimage,
+ boot_target, boot_state, NULL,
+#ifdef USE_AVB
+ slot_data,
+#else
+ verifier_cert,
+#endif
+ NULL);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Couldn't load Boot image");
+
+ ret = slot_boot_failed(boot_target);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to write slot failure");
- return ret;
+ return ret;
}
+static VOID die(VOID)
+{
+ /* Allow plenty of time for the error to be visible before the
+ * screen goes blank
+ */
+ pause(30);
+ halt_system();
+}
+
+static VOID enter_fastboot_mode(UINT8 boot_state)
+ __attribute__ ((noreturn));
-static EFI_STATUS enter_efi_binary(CHAR16 *path, BOOLEAN delete)
+static VOID enter_fastboot_mode(UINT8 boot_state)
{
- EFI_DEVICE_PATH *edp;
- EFI_STATUS ret;
- EFI_HANDLE image;
-
- edp = FileDevicePath(g_disk_device, path);
- if (!edp) {
- Print(L"Couldn't generate a path\n");
- return EFI_INVALID_PARAMETER;
- }
-
- ret = uefi_call_wrapper(BS->LoadImage, 6, FALSE, g_parent_image,
- edp, NULL, 0, &image);
- if (EFI_ERROR(ret)) {
- efi_perror(ret, L"BS->LoadImage '%s'", path);
- } else {
- if (delete) {
- ret = file_delete(g_disk_device, path);
- if (EFI_ERROR(ret))
- efi_perror(ret, "Couldn't delete %s", path);
- }
- ret = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL);
- uefi_call_wrapper(BS->UnloadImage, 1, image);
- }
- FreePool(edp);
- return ret;
+ EFI_STATUS ret = EFI_SUCCESS;
+ enum boot_target target;
+ EFI_HANDLE image;
+ void *efiimage = NULL;
+ UINTN imagesize;
+ VOID *bootimage;
+ VOID *bootimage_p;
+ AvbSlotVerifyData *slot_data;
+
+ set_efi_variable(&fastboot_guid, BOOT_STATE_VAR, sizeof(boot_state),
+ &boot_state, FALSE, TRUE);
+ set_oemvars_update(TRUE);
+
+ for (;;) {
+ target = UNKNOWN_TARGET;
+
+ ret = fastboot_start(&bootimage, &efiimage, &imagesize, &target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Fastboot mode failed");
+ break;
+ }
+
+ if (bootimage) {
+ /* 'fastboot boot' case, only allowed on unlocked devices.
+ * check just to make sure
+ */
+ /* in 'fastboot boot' case, pass 'NULL' as the last parameter
+ * of load_image will lost vbmeta options which should be
+ * passed to kernel as kernel parameters. Fill a temporay
+ * slot data here.
+ */
+ if (device_is_unlocked()) {
+ ret = android_image_load_partition_avb_ab(NULL,
+ &bootimage_p, &boot_state, &slot_data);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Fastboot mode fail to load slot data");
+ set_image_oemvars_nocheck(bootimage, NULL);
+ load_image(bootimage, BOOT_STATE_ORANGE, MEMORY, slot_data);
+ }
+ FreePool(bootimage);
+ bootimage = NULL;
+ continue;
+ }
+
+ if (efiimage) {
+ ret = uefi_call_wrapper(BS->LoadImage, 6, FALSE, g_parent_image,
+ NULL, efiimage, imagesize, &image);
+ FreePool(efiimage);
+ efiimage = NULL;
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Unable to load the received EFI image");
+ continue;
+ }
+ ret = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Unable to start the received EFI image");
+
+ uefi_call_wrapper(BS->UnloadImage, 1, image);
+ continue;
+ }
+
+ /* Offer a fast path between crashmode and fastboot
+ * mode to keep the RAM state.
+ */
+ if (target == CRASHMODE) {
+#ifdef USE_UI
+ target = ux_prompt_user_for_boot_target(NO_ERROR_CODE);
+ if (target == FASTBOOT)
+ continue;
+#else
+ debug(L"NO_UI,only support fastboot");
+ target = FASTBOOT;
+ continue;
+#endif
+ }
+
+ if (target != UNKNOWN_TARGET)
+ reboot_to_target(target, EfiResetCold);
+ }
+
+ die();
+}
+static void bootloader_recover_mode(UINT8 boot_state)
+{
+ enum boot_target target;
+
+#ifdef USE_UI
+ target = ux_prompt_user_for_boot_target(NOT_BOOTABLE_CODE);
+ if (target == FASTBOOT)
+ enter_fastboot_mode(boot_state);
+#else
+ debug(L"NO_UI,rebooting,boot_state: %d", boot_state);
+ target = NORMAL_BOOT;
+#endif
+ reboot_to_target(target, EfiResetCold);
+ die();
}
+static VOID boot_error(enum ux_error_code error_code, UINT8 boot_state,
+ UINT8 *hash, UINTN hash_size)
+{
+ BOOLEAN power_off = FALSE;
+ enum boot_target bt;
+ return; //hacked only for demo to skip warning
+ if (boot_state > min_boot_state()) {
+ power_off = TRUE;
+
+#ifndef USER
+#ifdef NO_DEVICE_UNLOCK
+ error(L"NO_DEVICE_UNLOCK set, device should power off");
+ error(L"Not a user build, continue anyway");
+ power_off = FALSE;
+#endif
+#endif
+ }
+#ifdef USE_UI
+ //bt = ux_prompt_user(error_code, power_off, boot_state, hash, hash_size);
+
+ if (bt == CRASHMODE) {
+ debug(L"Rebooting to bootloader recover mode");
+ bootloader_recover_mode(boot_state);
+ }
+#else
+ debug(L"NO_UI,%d %d %d", error_code, hash, hash_size);
+ if (power_off)
+ bt = POWER_OFF;
+ else
+ bt = NORMAL_BOOT;
+#endif
+ if (power_off || bt == POWER_OFF)
+ halt_system();
+}
+
+#ifdef BOOTLOADER_POLICY_EFI_VAR
+/* Flash the OEMVARS that include the bootloader policy. */
+static void flash_bootloader_policy(__attribute__((__unused__)) UINT8 boot_state)
+{
+ VOID *bootimage = NULL;
+ EFI_STATUS ret;
+
+#ifdef USE_AVB
+ UINT8 new_boot_state = boot_state;
+ AvbSlotVerifyData *slot_data;
+
+ debug(L"Loading bootloader policy using AVB");
+ ret = avb_load_verify_boot_image(NORMAL_BOOT, NULL, &bootimage, FALSE, &new_boot_state, &slot_data);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to load the boot image using AVB to get bootloader policy");
+ goto out;
+ }
+#else
+ UINT8 verify_state;
+
+ debug(L"Loading bootloader policy");
+ ret = load_boot_image(NORMAL_BOOT, NULL, &bootimage, FALSE);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to load the boot image to get bootloader policy");
+ return;
+ }
+
+ verify_state = validate_bootimage(NORMAL_BOOT, bootimage, NULL);
+ if (EFI_ERROR(ret) || verify_state != BOOT_STATE_GREEN) {
+ efi_perror(ret, L"Failed to verify the boot image to get bootloader policy");
+ goto out;
+ }
+#endif
+ /* The bootloader policy EFI variables are using the
+ * FASTBOOT_GUID.
+ */
+ set_image_oemvars_nocheck(bootimage, &fastboot_guid);
+
+ /* It might not be an error. Some devices have a buggy BIOS
+ * that does not allowed secured EFI variables to be
+ * flashed.
+ */
+ if (!blpolicy_is_flashed())
+ debug(L"Bootloader Policy EFI variables are not flashed");
+out:
+#ifdef USE_AVB
+ if (slot_data != NULL)
+ avb_slot_verify_data_free(slot_data);
+#else
+ if (bootimage != NULL)
+ FreePool(bootimage);
+#endif
+}
+#endif
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table)
{
- EFI_STATUS ret;
- CHAR16 *target_path = NULL;
- VOID *target_address = NULL;
- VOID *bootimage = NULL;
- BOOLEAN oneshot = FALSE;
- VOID *selected_keystore;
- UINTN selected_keystore_size;
- enum boot_target boot_target = NORMAL_BOOT;
- UINT8 boot_state = BOOT_STATE_GREEN;
- CHAR16 *loader_version = KERNELFLINGER_VERSION;
-
- /* gnu-efi initialization */
- InitializeLib(image, sys_table);
-
- debug("%s", loader_version);
- set_efi_variable_str(&loader_guid, LOADER_VERSION_VAR,
- FALSE, TRUE, loader_version);
-
- /* populate globals */
- g_parent_image = image;
- ret = uefi_call_wrapper(BS->OpenProtocol, 6, image,
- &LoadedImageProtocol, (VOID **)&g_loaded_image,
- image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (EFI_ERROR(ret)) {
- efi_perror(ret, L"OpenProtocol: LoadedImageProtocol");
- return ret;
- }
- g_disk_device = g_loaded_image->DeviceHandle;
-
- debug("choosing a boot target");
- boot_target = choose_boot_target(&target_address, &target_path,
- &oneshot);
-
- if (boot_target == ESP_EFI_BINARY) {
- debug("entering EFI binary");
- /* special handling, security taken care of by EFI BIOS */
- ret = enter_efi_binary(target_path, oneshot);
- if (EFI_ERROR(ret)) {
- efi_perror(ret, L"EFI Application exited abnormally");
- pause(3);
- }
- FreePool(target_path);
- reboot();
- }
-
- debug("selected '%s'", boot_target_to_string(boot_target));
-
- debug("checking device state");
- /* select the keystore to use for verification based on some
- * security checks and user input. If not everything checks out,
- * the user may be prompted whether they want to continue booting
- * or enter the Recovery Console (unverified) */
- if (!is_efi_secure_boot_enabled() || !is_device_locked_or_verified()) {
- boot_state = BOOT_STATE_ORANGE;
- debug("Device is unlocked or secure boot disabled");
- selected_keystore = NULL;
- selected_keystore_size = 0;
-
- /* XXX cache this decision? */
- if (!prompt_user_device_unlocked()) {
- boot_state = BOOT_STATE_RED;
- boot_target = RECOVERY;
- }
- } else {
- debug("examining keystore");
- UINT8 hash[KEYSTORE_HASH_SIZE];
- select_keystore(&selected_keystore, &selected_keystore_size);
- if (!verify_android_keystore(selected_keystore,
- selected_keystore_size,
- oem_key, oem_key_size, hash)) {
- debug("keystore not validated");
- boot_state = BOOT_STATE_YELLOW;
-
- /* XXX cache this decision? */
- if (!prompt_user_keystore_unverified(hash)) {
- selected_keystore = NULL;
- boot_state = BOOT_STATE_RED;
- boot_target = RECOVERY;
- }
- }
- }
-
- while (1) {
- if (bootimage && bootimage != target_address)
- FreePool(bootimage);
-
- debug("loading boot image");
- ret = load_boot_image(boot_target, selected_keystore,
- selected_keystore_size, target_path,
- target_address, &bootimage, oneshot);
- FreePool(target_path);
- target_path = NULL;
-
- if (EFI_ERROR(ret)) {
- debug("couldn't load boot image: %r", ret);
- if (ret == EFI_ACCESS_DENIED)
- boot_state = BOOT_STATE_RED;
-
- /* Recovery itself is unverified. Give up. */
- if (boot_target == RECOVERY) {
- debug("recovery image is bad");
- warn_user_unverified_recovery();
- halt_system();
- return ret;
- }
+ EFI_STATUS ret;
+ CHAR16 *target_path = NULL;
+ VOID *bootimage = NULL;
+ BOOLEAN oneshot = FALSE;
+ BOOLEAN lock_prompted = FALSE;
+ enum boot_target boot_target = NORMAL_BOOT;
+ UINT8 boot_state = BOOT_STATE_GREEN;
+#ifndef USE_AVB
+ UINT8 *hash = NULL;
+ X509 *verifier_cert = NULL;
+#else
+ AvbSlotVerifyData *slot_data = NULL;
+#endif
- if (!prompt_user_bootimage_unverified())
- halt_system();
+ set_boottime_stamp(TM_EFI_MAIN);
+ /* gnu-efi initialization */
+ InitializeLib(image, sys_table);
- /* Fall back to loading Recovery Console */
- debug("fall back to recovery console");
- boot_target = RECOVERY;
- continue;
- }
+#ifdef COUNTDOWN
+ ux_display_countdown();
+#endif
- /* Image loaded and if we have a keystore, verified */
- break;
- }
+#ifdef USE_UI
+ //ux_display_vendor_splash();
+#endif
+
+ debug(KERNELFLINGER_VERSION);
+
+ /* populate globals */
+ g_parent_image = image;
+ ret = uefi_call_wrapper(BS->OpenProtocol, 6, image,
+ &LoadedImageProtocol, (VOID **)&g_loaded_image,
+ image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"OpenProtocol: LoadedImageProtocol");
+ return ret;
+ }
+ g_disk_device = g_loaded_image->DeviceHandle;
+
+ /* loaded from mass storage (not DnX) */
+ if (g_disk_device) {
+ ret = storage_set_boot_device(g_disk_device);
+ if (EFI_ERROR(ret))
+ error(L"Failed to set boot device");
+ }
+
+ // Set the boot device now
+ if (!get_boot_device_handle()) {
+ if (!get_boot_device()) {
+ // Get boot device failed
+ error(L"Failed to find boot device");
+ return EFI_NO_MEDIA;
+ }
+ }
+
+ uefi_bios_update_capsule(g_disk_device, FWUPDATE_FILE);
+
+ uefi_check_upgrade(g_loaded_image, BOOTLOADER_LABEL, KFUPDATE_FILE,
+ BOOTLOADER_FILE, BOOTLOADER_FILE_BAK, KFSELF_FILE, KFBACKUP_FILE);
+
+#ifdef USE_TPM
+ if (!is_boot_device_removable()) {
+ ret = tpm2_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init TPM, enter fastboot mode");
+ boot_target = FASTBOOT;
+ }
+ }
+#endif
+
+ ret = set_device_security_info(NULL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init security info, enter fastboot mode");
+ boot_target = FASTBOOT;
+ }
+
+#ifdef RPMB_STORAGE
+ // Init the rpmb
+ ret = rpmb_storage_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init RPMB, enter fastboot mode");
+ boot_target = FASTBOOT;
+ }
+#endif // RPMB_STORAGE
+
+ ret = slot_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Slot management initialization failed");
+ return ret;
+ }
+
+ /* No UX prompts before this point, do not want to interfere
+ * with magic key detection
+ */
+ if (boot_target == NORMAL_BOOT)
+ boot_target = choose_boot_target(&target_path, &oneshot);
+ if (boot_target == EXIT_SHELL)
+ return EFI_SUCCESS;
+ if (boot_target == CRASHMODE) {
+#if 0//def USE_UI
+ boot_target = ux_prompt_user_for_boot_target(NO_ERROR_CODE);
+ if (boot_target != FASTBOOT)
+ reboot_to_target(boot_target, EfiResetCold);
+#else
+ debug(L"NO_UI,only support fastboot");
+ reboot_to_target(FASTBOOT, EfiResetCold);
+#endif
+ }
+
+#ifdef RPMB_STORAGE
+ if (boot_target != CRASHMODE) {
+ ret = rpmb_key_init();
+ if (EFI_ERROR(ret)) {
+ error(L"RPMB key init failure for osloader");
+ boot_target = FASTBOOT;
+ }
+ }
+#endif
+
+ if (boot_target == POWER_OFF)
+ halt_system();
- set_efi_variable(&fastboot_guid, BOOT_STATE_VAR, sizeof(boot_state),
- &boot_state, FALSE, TRUE);
+#if 0//def USE_UI
+ if (boot_target == CHARGER)
+ ux_display_empty_battery();
+#else
+ debug(L"NO_UI,empty battery");
+#endif
- debug("chainloading boot image, boot state is %s", boot_state_to_string(boot_state));
- debug_pause(5);
- return android_image_start_buffer(g_parent_image, bootimage,
- boot_target == NORMAL_BOOT, NULL);
+ if (boot_target == DNX || boot_target == CRASHMODE)
+ reboot_to_target(boot_target, EfiResetCold);
+
+#ifdef USERDEBUG
+ debug(L"checking device state");
+
+ if (!is_platform_secure_boot_enabled() && !device_is_provisioning()) {
+ debug(L"uefi secure boot is disabled");
+ boot_state = BOOT_STATE_ORANGE;
+ lock_prompted = TRUE;
+
+ /* Need to warn early, before we even enter Fastboot
+ * or run EFI binaries. Set lock_prompted to true so
+ * we don't ask again later
+ */
+ boot_error(SECURE_BOOT_CODE, boot_state, NULL, 0);
+ } else if (device_is_unlocked()) {
+ boot_state = BOOT_STATE_ORANGE;
+ debug(L"Device is unlocked");
+ }
+
+#ifdef USER
+ if (device_is_provisioning()) {
+ debug(L"device is provisioning, force Fastboot mode");
+ enter_fastboot_mode(boot_state);
+ }
+#endif
+#else /* !USERDEBUG */
+ /* Make sure it's abundantly clear! */
+ error(L"INSECURE BOOTLOADER - SYSTEM SECURITY IN RED STATE");
+ pause(1);
+ boot_state = BOOT_STATE_RED;
+#endif
+
+ /* EFI binaries are validated by the BIOS */
+ if (boot_target == ESP_EFI_BINARY) {
+ debug(L"entering EFI binary");
+ if (!target_path)
+ return EFI_INVALID_PARAMETER;
+ ret = uefi_enter_binary(g_disk_device, target_path, oneshot, 0, NULL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"EFI Application exited abnormally");
+ pause(3);
+ }
+ FreePool(target_path);
+ reboot(NULL, EfiResetCold);
+ }
+
+#ifdef BOOTLOADER_POLICY_EFI_VAR
+ /* Ensure that the bootloader policy is set. */
+ if (!device_is_provisioning() && !blpolicy_is_flashed())
+ flash_bootloader_policy(boot_state);
+#endif
+
+ if (boot_target == FASTBOOT) {
+ debug(L"entering Fastboot mode");
+ enter_fastboot_mode(boot_state);
+ }
+
+ /* If the device is unlocked the only way to re-lock it is
+ * via fastboot. Skip this UX if we already prompted earlier
+ * about EFI secure boot being turned off
+ */
+ if (boot_state == BOOT_STATE_ORANGE && !lock_prompted)
+ boot_error(DEVICE_UNLOCKED_CODE, boot_state, NULL, 0);
+
+ debug(L"Loading boot image");
+
+ set_boottime_stamp(TM_AVB_START);
+#ifdef USE_AVB
+ ret = avb_load_verify_boot_image(boot_target, target_path, &bootimage, oneshot, &boot_state, &slot_data);
+#else
+ ret = load_boot_image(boot_target, target_path, &bootimage, oneshot);
+ FreePool(target_path);
+ if (EFI_ERROR(ret)) {
+ debug(L"issue loading boot image: %r", ret);
+ boot_state = BOOT_STATE_RED;
+ } else if (boot_state != BOOT_STATE_ORANGE) {
+ debug(L"Validating boot image");
+ boot_state = validate_bootimage(boot_target, bootimage,
+ &verifier_cert);
+ }
+
+ if (boot_state == BOOT_STATE_YELLOW) {
+ ret = pub_key_sha256(verifier_cert, &hash);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to compute pub key hash");
+ boot_error(BOOTIMAGE_UNTRUSTED_CODE, boot_state, hash,
+ SHA256_DIGEST_LENGTH);
+ }
+#endif
+ set_boottime_stamp(TM_VERIFY_BOOT_DONE);
+
+ if (boot_state == BOOT_STATE_RED) {
+ if (boot_target == RECOVERY)
+ boot_error(BAD_RECOVERY_CODE, boot_state, NULL, 0);
+ else
+ boot_error(RED_STATE_CODE, boot_state, NULL, 0);
+ }
+
+ switch (boot_target) {
+ case RECOVERY:
+ case ESP_BOOTIMAGE:
+ /* We're either about to do an OTA update, or doing a one-shot
+ * boot into an alternate boot image from 'fastboot boot'.
+ * Load the OEM vars in this new boot image, but ensure that
+ * we'll read them again on the next normal boot
+ */
+ set_image_oemvars_nocheck(bootimage, NULL);
+ set_oemvars_update(TRUE);
+ break;
+ case NORMAL_BOOT:
+ case CHARGER:
+ set_image_oemvars(bootimage);
+ break;
+ default:
+ break;
+ }
+
+ ret = load_image(bootimage, boot_state, boot_target,
+#ifdef USE_AVB
+ slot_data
+#else
+ verifier_cert
+#endif
+ );
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to start boot image");
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ case CHARGER:
+ if (slot_get_active())
+ reboot_to_target(boot_target, EfiResetCold);
+ break;
+ case RECOVERY:
+ if (recovery_in_boot_partition()) {
+ if (slot_get_active())
+ reboot_to_target(boot_target, EfiResetCold);
+ }
+#if !defined(USE_AVB)
+ else if (slot_recovery_tries_remaining())
+ reboot_to_target(boot_target, EfiResetCold);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ bootloader_recover_mode(boot_state);
+
+ return EFI_INVALID_PARAMETER;
}
-/* vim: softtabstop=8:shiftwidth=8:expandtab
+/* vim: tabstop=8:shiftwidth=8
*/
-
diff --git a/kernelflinger.h b/kernelflinger.h
deleted file mode 100644
index c5ed796c..00000000
--- a/kernelflinger.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _DUMMYBOOT_H_
-#define _DUMMYBOOT_H_
-
-#include
-#include
-#include
-
-#include "lib.h"
-
-#define DEBUG_MESSAGES 1
-
-#if DEBUG_MESSAGES
-#define debug(fmt, ...) do { \
- Print(L##fmt L"\n", ##__VA_ARGS__); \
-} while(0)
-
-#define debug_pause(x) pause(x)
-#else
-#define debug(fmt, ...) (void)0
-#define debug_pause(x) (void)(x)
-#endif
-
-#define efi_perror(ret, x, ...) Print(x L": %r", ##__VA_ARGS__, ret)
-
-#define KERNELFLINGER_VERSION L"kernelflinger-00.01"
-
-#define _unused __attribute__((unused))
-
-extern const EFI_GUID fastboot_guid;
-
-#endif
diff --git a/kf4abl.c b/kf4abl.c
new file mode 100644
index 00000000..0c5040f5
--- /dev/null
+++ b/kf4abl.c
@@ -0,0 +1,1215 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#ifdef CRASHMODE_USE_ADB
+#include
+#endif
+#include
+
+#include "options.h"
+#if defined(IOC_USE_SLCAN) || defined(IOC_USE_CBC)
+#include "ioc_can.h"
+#endif
+#include "android.h"
+#include "slot.h"
+#include "timer.h"
+#ifdef USE_AVB
+#include "avb_init.h"
+#include "libavb/libavb.h"
+#include "libavb/uefi_avb_ops.h"
+#include "libavb_ab/libavb_ab.h"
+#endif
+#include "security.h"
+#include "security_interface.h"
+#ifdef RPMB_STORAGE
+#include
+#include "rpmb.h"
+#include "rpmb_storage.h"
+#endif
+#ifdef USE_TRUSTY
+#include "trusty_interface.h"
+#include "trusty_common.h"
+#endif
+#include "storage.h"
+#include "acpi.h"
+#include "ux.h"
+
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t patch_M:4;
+ uint32_t patch_Y:7;
+ uint32_t version_C:7;
+ uint32_t version_B:7;
+ uint32_t version_A:7;
+ };
+} os_version_t;
+
+#define MAX_CMD_BUF 0x1000
+static CHAR8 cmd_buf[MAX_CMD_BUF];
+struct rot_data_t g_rot_data = {0};
+
+#ifdef CRASHMODE_USE_ADB
+static EFI_STATUS enter_crashmode(enum boot_target *target)
+{
+ EFI_STATUS ret;
+
+#ifdef USER
+#error "adb in crashmode MUST be disabled on a USER build"
+#endif
+
+ ret = adb_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to initialize adb");
+ return ret;
+ }
+
+ debug(L"adb implementation is initialized");
+ for (;;) {
+ ret = adb_run();
+ if (EFI_ERROR(ret))
+ break;
+
+ *target = adb_get_boot_target();
+ if (*target != UNKNOWN_TARGET)
+ break;
+ }
+ adb_exit();
+
+ return ret;
+}
+#endif
+#ifndef __FORCE_FASTBOOT
+static enum boot_target check_bcb(CHAR16 **target_path, BOOLEAN *oneshot)
+{
+ EFI_STATUS ret;
+ struct bootloader_message bcb;
+ CHAR16 *target = NULL;
+ enum boot_target t;
+ CHAR8 *bcb_cmd;
+ BOOLEAN dirty;
+
+ *oneshot = FALSE;
+ *target_path = NULL;
+
+ ret = read_bcb(MISC_LABEL, &bcb);
+ if (EFI_ERROR(ret)) {
+ error(L"Unable to read BCB");
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ dirty = bcb.status[0] != '\0';
+ /* We own the status field; clear it in case there is any stale data */
+ bcb.status[0] = '\0';
+ bcb_cmd = (CHAR8 *)bcb.command;
+ if (!strncmpa(bcb_cmd, (CHAR8 *)"boot-", 5)) {
+ target = stra_to_str(bcb_cmd + 5);
+ debug(L"BCB boot target: '%s'", target);
+ } else if (!strncmpa(bcb_cmd, (CHAR8 *)"bootonce-", 9)) {
+ target = stra_to_str(bcb_cmd + 9);
+ bcb_cmd[0] = '\0';
+ dirty = TRUE;
+ debug(L"BCB oneshot boot target: '%s'", target);
+ *oneshot = TRUE;
+ }
+
+ if (dirty) {
+ ret = write_bcb(MISC_LABEL, &bcb);
+ if (EFI_ERROR(ret))
+ error(L"Unable to update BCB contents!");
+ }
+
+ if (!target) {
+ t = NORMAL_BOOT;
+ goto out;
+ }
+
+ t = name_to_boot_target(target);
+ if (t != UNKNOWN_TARGET && t != CHARGER)
+ goto out;
+
+ error(L"Unknown/Unsupported boot target in BCB: '%s'", target);
+ t = NORMAL_BOOT;
+
+out:
+ FreePool(target);
+ return t;
+}
+#endif
+
+static EFI_STATUS process_bootimage(void *bootimage, UINTN imagesize)
+{
+ EFI_STATUS ret;
+ void* param = NULL;
+ UINT8 boot_state = BOOT_STATE_GREEN;
+ enum boot_target target = NORMAL_BOOT;
+
+ if (!bootimage)
+ return EFI_SUCCESS;
+
+#ifndef __FORCE_FASTBOOT
+#ifdef USE_AVB
+ AvbOps *ops;
+ AvbPartitionData *acpi;
+ AvbSlotVerifyData *slot_data = NULL;
+#ifndef USE_SLOT
+ const char *slot_suffix = "";
+ AvbSlotVerifyResult verify_result;
+#else
+ AvbABFlowResult flow_result;
+#endif
+
+ const char *requested_partitions[] = {"boot",
+#ifdef USE_ACPI
+ "acpi",
+#endif
+#ifdef USE_ACPIO
+ "acpio",
+#endif
+ NULL};
+ VOID *acpiimage = NULL;
+ bool allow_verification_error = FALSE;
+ AvbSlotVerifyFlags flags;
+
+#ifdef USE_TRUSTY
+ const uint8_t *vbmeta_pub_key;
+ UINTN vbmeta_pub_key_len;
+ VOID *tosimage = NULL;
+#endif
+ debug(L"Processing boot image");
+
+ ops = avb_init();
+ if (ops) {
+ if (ops->read_is_device_unlocked(ops, &allow_verification_error) != AVB_IO_RESULT_OK) {
+ avb_fatal("Error determining whether device is unlocked.\n");
+ return EFI_ABORTED;
+ }
+ } else {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ flags = AVB_SLOT_VERIFY_FLAGS_NONE;
+ if (allow_verification_error) {
+ flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
+ }
+
+#ifdef USE_SLOT
+ flow_result = avb_ab_flow(&ab_ops, requested_partitions, flags, AVB_HASHTREE_ERROR_MODE_RESTART, &slot_data);
+ ret = get_avb_flow_result(slot_data,
+ allow_verification_error,
+ flow_result,
+ &boot_state);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get avb slot a/b flow result for boot");
+ goto fail;
+ }
+ slot_set_active_cached(slot_data->ab_suffix);
+#else
+ verify_result = avb_slot_verify(ops,
+ requested_partitions,
+ slot_suffix,
+ flags,
+ AVB_HASHTREE_ERROR_MODE_RESTART,
+ &slot_data);
+ ret = get_avb_result(slot_data,
+ allow_verification_error,
+ verify_result,
+ &boot_state);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get avb result for boot");
+ goto fail;
+ }
+#endif
+ param = slot_data;
+ for (int i = 1; requested_partitions[i] != NULL; i++) {
+ acpi = &slot_data->loaded_partitions[i];
+ acpiimage = acpi->data;
+ ret = install_acpi_table_from_partitions(acpiimage,
+ acpi->partition_name,
+ NORMAL_BOOT);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to install acpi table from %a image",
+ acpi->partition_name);
+ goto fail;
+ }
+ }
+
+ set_boottime_stamp(TM_VERIFY_BOOT_DONE);
+#ifdef USE_TRUSTY
+ ret = avb_vbmeta_image_verify(slot_data->vbmeta_images[0].vbmeta_data,
+ slot_data->vbmeta_images[0].vbmeta_size,
+ &vbmeta_pub_key,
+ &vbmeta_pub_key_len);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the vbmeta_pub_key");
+ goto fail;
+ }
+
+ ret = get_rot_data(bootimage, boot_state, vbmeta_pub_key, vbmeta_pub_key_len, &g_rot_data);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init rot params");
+ goto fail;
+ }
+
+ ret = load_tos_image(&tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Load tos image failed");
+ goto fail;
+ }
+ set_boottime_stamp(TM_LOAD_TOS_DONE);
+ ret = start_trusty(tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Unable to start trusty: stop");
+ goto fail;
+ }
+ set_boottime_stamp(TM_PROCRSS_TRUSTY_DONE);
+#endif //USE_TRUSTY
+fail:
+#endif //USE_AVB
+#else
+ //Fastboot stored in the SPI gets the capability to load an image
+ //(fastboot boot) using the RAMDISK and nothing from the eMMC
+ target = MEMORY;
+#endif //__FORCE_FASTBOOT
+ /* 'fastboot boot' case, only allowed on unlocked devices.*/
+ if (device_is_unlocked()) {
+ UINT32 crc;
+
+ ret = uefi_call_wrapper(BS->CalculateCrc32, 3, bootimage, imagesize, &crc);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"CalculateCrc32 failed");
+ return ret;
+ }
+
+ ret = android_image_start_buffer(NULL, bootimage,
+ target, boot_state, NULL,
+ param, (const CHAR8 *)cmd_buf);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Couldn't load Boot image");
+ return ret;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS enter_fastboot_mode(enum boot_target *target)
+{
+ EFI_STATUS ret;
+ void *efiimage, *bootimage;
+ UINTN imagesize;
+
+#if defined(IOC_USE_SLCAN) || defined(IOC_USE_CBC)
+ ret = notify_ioc_ready();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"notify ioc ready failed");
+ }
+#endif
+
+ /* Handle corner case that EOP not send before ABL jump to fastboot, will force EOP send.*/
+ heci_end_of_post();
+
+ for (;;) {
+ *target = UNKNOWN_TARGET;
+ bootimage = NULL;
+ efiimage = NULL;
+
+ ret = fastboot_start(&bootimage, &efiimage, &imagesize, target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Fastboot mode failed");
+ break;
+ }
+
+ ret = process_bootimage(bootimage, imagesize);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Process bootimage failed");
+ if (bootimage) {
+ FreePool(bootimage);
+ bootimage = NULL;
+ }
+ break;
+ }
+
+ if (*target == UNKNOWN_TARGET)
+ continue;
+
+ if (*target == CRASHMODE)
+ break;
+
+ reboot_to_target(*target, EfiResetCold);
+ }
+
+ return ret;
+}
+
+/*
+ * Boot mode field definitions.
+ */
+static union bootMode
+{
+ UINT16 _bits;
+ struct {
+ UINT16 target : 5; /* [4:0] */
+ UINT16 do_mrc_training : 1; /* [5] */
+ UINT16 do_save_mrc_data : 1; /* [6] */
+ UINT16 do_flash_update : 1; /* [7] */
+ UINT16 silent : 1; /* [8] */
+ UINT16 _reserved : 1; /* [9] */
+ UINT16 action : 2; /* [11:10] 0:boot,1:CLI,2:halt,3:reset */
+ UINT16 dipsw : 4; /* [15:12] */
+ };
+} bootMode;
+
+static enum boot_target check_command_line(EFI_HANDLE image, CHAR8 *cmd_buf, UINTN max_cmd_size)
+{
+ EFI_STATUS ret;
+ enum boot_target target = FASTBOOT;
+ static EFI_LOADED_IMAGE *limg;
+ UINTN argc, i, j;
+ CHAR16 **argv;
+ UINTN cmd_len = 0;
+ CHAR8 arg8[256] = "";
+ UINTN arglen;
+#if defined(USE_TRUSTY) || defined(RPMB_STORAGE)
+ UINTN num;
+#endif
+
+ enum CmdType
+ {
+ RESET,
+ BOOT_TARGET,
+ BOOT,
+ TRUSTY_PARAM,
+ SECUREBOOT,
+ BOOTVERSION,
+ SERIALNO,
+ DEV_SEC_INFO,
+ IMAGE_BOOT_PARAMS_ADDR,
+ FIRMWARE_BOOTTIME,
+ BOOTREASON
+ };
+
+ struct Cmdline
+ {
+ CHAR8 *name;
+ UINTN length;
+ enum CmdType type;
+ };
+
+ struct Cmdline CmdlineArray[] = {
+ {
+ (CHAR8 *)"ABL.reset=",
+ strlen((CHAR8 *)"ABL.reset="),
+ RESET
+ },
+ {
+ (CHAR8 *)"ABL.boot_target=",
+ strlen((CHAR8 *)"ABL.boot_target="),
+ BOOT_TARGET
+ },
+ {
+ (CHAR8 *)"ABL.boot=",
+ strlen((CHAR8 *)"ABL.boot="),
+ BOOT
+ },
+ {
+ (CHAR8 *)"trusty.param_addr=",
+ strlen((CHAR8 *)"trusty.param_addr="),
+ TRUSTY_PARAM
+ },
+ {
+ (CHAR8 *)"ABL.secureboot=",
+ strlen((CHAR8 *)"ABL.secureboot="),
+ SECUREBOOT
+ },
+ {
+ (CHAR8 *)"androidboot.bootloader=",
+ strlen((CHAR8 *)"androidboot.bootloader="),
+ BOOTVERSION
+ },
+ {
+ (CHAR8 *)"androidboot.bootreason=",
+ strlen((CHAR8 *)"androidboot.bootreason="),
+ BOOTREASON
+ },
+ {
+ (CHAR8 *)"androidboot.serialno=",
+ strlen((CHAR8 *)"androidboot.serialno="),
+ SERIALNO
+ },
+ {
+ (CHAR8 *)"dev_sec_info.param_addr=",
+ strlen((CHAR8 *)"dev_sec_info.param_addr="),
+ DEV_SEC_INFO
+ },
+ {
+ (CHAR8 *)"ImageBootParamsAddr=",
+ strlen((CHAR8 *)"ImageBootParamsAddr="),
+ IMAGE_BOOT_PARAMS_ADDR
+ },
+ {
+ (CHAR8 *)"fw_boottsc=",
+ strlen("fw_boottsc="),
+ FIRMWARE_BOOTTIME
+ }
+ };
+
+ CHAR8 *nptr = NULL;
+ ret = uefi_call_wrapper(BS->OpenProtocol, 6, image,
+ &LoadedImageProtocol, (VOID **)&limg,
+ image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to open LoadedImageProtocol");
+ return FASTBOOT;
+ }
+
+ ret = get_argv(limg, &argc, &argv);
+ if (EFI_ERROR(ret))
+ return FASTBOOT;
+
+ cmd_buf[0] = 0;
+
+ for (i = 0; i < argc; i++) {
+ debug(L" abl cmd %02d: %s", i, argv[i]);
+ arglen = StrLen(argv[i]);
+
+ if (arglen > (int)sizeof(arg8) - 2)
+ arglen = sizeof(arg8) - 2;
+ debug(L" abl cmd %02d length: %d", i, arglen);
+
+ ret = str_to_stra((CHAR8 *)arg8, argv[i], arglen + 1);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Non-ascii characters in command line");
+ return FASTBOOT;
+ }
+
+ if (cmd_len + arglen + 1 < max_cmd_size) {
+ for (j = 0; j < sizeof(CmdlineArray)/sizeof(CmdlineArray[0]); j++) {
+ if((arglen >= CmdlineArray[j].length) && !strncmp(arg8, CmdlineArray[j].name, CmdlineArray[j].length))
+ break;
+ }
+
+ if (j < sizeof(CmdlineArray)/sizeof(CmdlineArray[0])) {
+ switch(CmdlineArray[j].type) {
+ /* Parse "ABL.reset=xxx" */
+ case RESET:
+ set_reboot_reason(argv[i] + CmdlineArray[j].length);
+ continue;
+
+ /* Parse "ABL.boot_target=xxxx" */
+ case BOOT_TARGET:
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ /* Only handle CRASHMODE case, other mode should be decided by "ABL.boot". */
+ if (!strcmp(nptr, (CHAR8 *)"CRASHMODE")) {
+ target = CRASHMODE;
+ goto out;
+ }
+ continue;
+
+ /* Parse "ABL.boot=xx" */
+ case BOOT:
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ bootMode._bits = (UINT16)strtoul((char *)nptr, 0, 16);
+ target = bootMode.target;
+ break;
+#ifdef USE_TRUSTY
+ /* Parse "trusty.param_addr=xxxxx" */
+ case TRUSTY_PARAM:
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ num = strtoul((char *)nptr, 0, 16);
+ debug(L"Parsed trusty param addr is 0x%x", num);
+ set_trusty_param((VOID *)num);
+ continue;
+#endif //USE_TRUSTY
+#ifdef RPMB_STORAGE
+ /* Parse "Add legacy DEV_SEC_INFO parameter for backward compatible to ABL usage" */
+ case DEV_SEC_INFO:
+ case IMAGE_BOOT_PARAMS_ADDR:
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ num = strtoul((char *)nptr, 0, 16);
+ debug(L"Parsed device security information addr is 0x%x", num);
+ set_device_security_info((VOID *)num);
+ continue;
+#endif //RPMB_STORAGE
+ /* Parse "ABL.secureboot=x" */
+ case SECUREBOOT: {
+ UINT8 val;
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ val = (UINT8)strtoul((char *)nptr, 0, 10);
+ ret = set_platform_secure_boot(val);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to set secure boot");
+ break;
+ }
+ /* Parse "fw_boottsc=xxxxx" */
+ case FIRMWARE_BOOTTIME: {
+ UINT64 VALUE;
+ UINT32 cpu_khz;
+ nptr = (CHAR8 *)(arg8 + CmdlineArray[j].length);
+ VALUE = (UINT64)strtoull((char *)nptr, 0, 10);
+ cpu_khz = get_cpu_freq() * 1000;
+ //EFI_ENTER_POINT boot time is recorded in ms
+ set_efi_enter_point(VALUE /cpu_khz);
+ continue;
+ }
+
+ /* Parse "android.bootloader=xxxxx" */
+ case BOOTVERSION:
+ continue;
+
+ /* Parse "android.serialno=xxxxx " */
+ case SERIALNO:
+ continue;
+
+ /* Parse "androidboot.bootreason=xxxxx " */
+ case BOOTREASON:
+ continue;
+
+ default:
+ continue;
+ }
+ }
+
+ if (cmd_buf[0] != 0) {
+ strncpy((CHAR8 *)(cmd_buf + cmd_len), (const CHAR8 *)" ", 1);
+ cmd_len++;
+ }
+
+ strncpy((CHAR8 *)(cmd_buf + cmd_len), (const CHAR8 *)arg8, arglen);
+ cmd_len += arglen;
+ }
+ }
+
+out:
+ debug(L"boot target: %d", target);
+ FreePool(argv);
+ return target;
+}
+
+#ifndef USE_AVB
+/* Load a boot image into RAM.
+ *
+ * boot_target - Boot image to load. Values supported are NORMAL_BOOT, RECOVERY,
+ * and ESP_BOOTIMAGE (for 'fastboot boot')
+ * target_path - Path to load boot image from for ESP_BOOTIMAGE case, ignored
+ * otherwise.
+ * bootimage - Returned allocated pointer value for the loaded boot image.
+ * oneshot - For ESP_BOOTIMAGE case, flag indicating that the image should
+ * be deleted.
+ *
+ * Return values:
+ * EFI_INVALID_PARAMETER - Unsupported boot target type, key is not well-formed,
+ * or loaded boot image was missing or corrupt
+ * EFI_ACCESS_DENIED - Validation failed against OEM or embedded certificate,
+ * boot image still usable
+ */
+static EFI_STATUS load_boot_image(
+ IN enum boot_target boot_target,
+ IN CHAR16 *target_path,
+ OUT VOID **bootimage,
+ IN BOOLEAN oneshot)
+{
+ EFI_STATUS ret;
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ ret = EFI_NOT_FOUND;
+ if (use_slot() && !slot_get_active())
+ break;
+ do {
+ const CHAR16 *label = slot_label(BOOT_LABEL);
+ ret = android_image_load_partition(label, bootimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to load boot image from %s partition",
+ label);
+ if (use_slot())
+ slot_boot_failed(boot_target);
+ }
+ } while (EFI_ERROR(ret) && slot_get_active());
+ break;
+
+ case RECOVERY:
+ if (recovery_in_boot_partition()) {
+ ret = load_boot_image(NORMAL_BOOT, target_path, bootimage, oneshot);
+ break;
+ }
+ if (use_slot() && !slot_recovery_tries_remaining()) {
+ ret = EFI_NOT_FOUND;
+ break;
+ }
+ ret = android_image_load_partition(RECOVERY_LABEL, bootimage);
+ break;
+ default:
+ *bootimage = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EFI_ERROR(ret))
+ debug(L"boot image loaded");
+
+ return ret;
+}
+#endif
+
+
+#ifdef USE_AVB
+static EFI_STATUS start_boot_image(VOID *bootimage, UINT8 boot_state,
+ enum boot_target boot_target,
+ AvbSlotVerifyData *slot_data,
+ CHAR8 *abl_cmd_line)
+#else
+static EFI_STATUS start_boot_image(VOID *bootimage, UINT8 boot_state,
+ enum boot_target boot_target,
+ X509 *verifier_cert,
+ CHAR8 *abl_cmd_line)
+#endif
+{
+ EFI_STATUS ret;
+#ifdef USER
+ /* per bootloaderequirements.pdf */
+ if (boot_state == BOOT_STATE_ORANGE) {
+ ret = android_clear_memory();
+ if (EFI_ERROR(ret)) {
+ error(L"Failed to clear memory. Load image aborted.");
+ return ret;
+ }
+ }
+#endif
+
+#ifdef USER
+ if (boot_state == BOOT_STATE_RED) {
+ if (is_platform_secure_boot_enabled()) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+#endif
+
+ set_efi_variable(&fastboot_guid, BOOT_STATE_VAR, sizeof(boot_state),
+ &boot_state, FALSE, TRUE);
+
+#ifdef OS_SECURE_BOOT
+ ret = set_os_secure_boot(boot_state == BOOT_STATE_GREEN);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to set os secure boot");
+#endif
+
+ if (!use_slot()) {
+ ret = slot_boot(boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to write slot boot");
+ return ret;
+ }
+ }
+
+ debug(L"chainloading boot image, boot state is %s\n",
+ boot_state_to_string(boot_state));
+#ifdef USE_AVB
+ ret = android_image_start_buffer(NULL, bootimage,
+ boot_target, boot_state, NULL,
+ slot_data, (const CHAR8 *)abl_cmd_line);
+#else
+ ret = android_image_start_buffer(NULL, bootimage,
+ boot_target, boot_state, NULL,
+ verifier_cert, (const CHAR8 *)abl_cmd_line);
+#endif
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Couldn't load Boot image");
+
+ ret = slot_boot_failed(boot_target);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to write slot failure");
+
+ return ret;
+}
+
+#ifndef USE_AVB
+/* Validate an image.
+ *
+ * Parameters:
+ * boot_target - Boot image to load. Values supported are NORMAL_BOOT,
+ * RECOVERY, and ESP_BOOTIMAGE (for 'fastboot boot')
+ * bootimage - Bootimage to validate
+ * verifier_cert - Return the certificate that validated the boot image
+ *
+ * Return values:
+ * BOOT_STATE_GREEN - Boot image is valid against provided certificate
+ * BOOT_STATE_YELLOW - Boot image is valid against embedded certificate
+ * BOOT_STATE_RED - Boot image is not valid
+ */
+static UINT8 validate_bootimage(
+ IN enum boot_target boot_target,
+ IN VOID *bootimage,
+ OUT X509 **verifier_cert)
+{
+ CHAR16 target[BOOT_TARGET_SIZE];
+ CHAR16 *expected;
+ CHAR16 *expected2 = NULL;
+ UINT8 boot_state;
+
+ boot_state = verify_android_boot_image(bootimage, oem_cert,
+ oem_cert_size, target,
+ verifier_cert);
+
+ if (boot_state == BOOT_STATE_RED) {
+ error(L"boot image doesn't verify");
+ return boot_state;
+ }
+
+ switch (boot_target) {
+ case NORMAL_BOOT:
+ expected = L"/boot";
+ /* in case of multistage ota */
+ expected2 = L"/recovery";
+ break;
+ case RECOVERY:
+ if (recovery_in_boot_partition())
+ expected = L"/boot";
+ else
+ expected = L"/recovery";
+ break;
+ default:
+ expected = NULL;
+ }
+
+ if ((!expected || StrCmp(expected, target)) &&
+ (!expected2 || StrCmp(expected2, target))) {
+ error(L"boot image has unexpected target name");
+ return BOOT_STATE_RED;
+ }
+
+ return boot_state;
+}
+#endif
+
+#ifdef USE_AVB
+EFI_STATUS avb_boot_android(enum boot_target boot_target, CHAR8 *abl_cmd_line)
+{
+ AvbOps *ops;
+ AvbPartitionData *boot, *acpi;
+ AvbSlotVerifyData *slot_data = NULL;
+#ifndef USE_SLOT
+ const char *slot_suffix = "";
+ AvbSlotVerifyResult verify_result;
+#else
+ AvbABFlowResult flow_result;
+#endif
+ const char *requested_partitions[] = {"boot",
+#ifdef USE_ACPI
+ "acpi",
+#endif
+#ifdef USE_ACPIO
+ "acpio",
+#endif
+ NULL};
+ EFI_STATUS ret;
+ VOID *bootimage = NULL, *acpiimage = NULL;
+ UINT8 boot_state = BOOT_STATE_GREEN;
+ bool allow_verification_error = FALSE;
+ AvbSlotVerifyFlags flags;
+ const uint8_t *vbmeta_pub_key;
+ UINTN vbmeta_pub_key_len;
+
+ debug(L"Loading boot image");
+ if (!use_slot()) {
+ if (boot_target == RECOVERY) {
+ requested_partitions[0] = "recovery";
+ }
+ }
+
+ ops = avb_init();
+ if (ops) {
+ if (ops->read_is_device_unlocked(ops, &allow_verification_error) != AVB_IO_RESULT_OK) {
+ avb_fatal("Error determining whether device is unlocked.\n");
+ return EFI_ABORTED;
+ }
+ } else {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ flags = AVB_SLOT_VERIFY_FLAGS_NONE;
+ if (allow_verification_error) {
+ flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
+ }
+
+#ifdef USE_SLOT
+ flow_result = avb_ab_flow(&ab_ops, requested_partitions, flags, AVB_HASHTREE_ERROR_MODE_RESTART, &slot_data);
+ ret = get_avb_flow_result(slot_data,
+ allow_verification_error,
+ flow_result,
+ &boot_state);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get avb slot a/b flow result for boot");
+ goto fail;
+ }
+ slot_set_active_cached(slot_data->ab_suffix);
+
+ if (slot_data->ab_suffix) {
+ CHAR8 *capsule_buf;
+ UINTN capsule_buf_len = 0;
+ CHAR16 *AB_SUFFIX = NULL;
+ CHAR16 *ABL_AB_SUFFIX = NULL;
+
+ AB_SUFFIX = stra_to_str((const CHAR8 *)slot_data->ab_suffix);
+ if (!AB_SUFFIX) {
+ error(L"Cannot get a valid AVB flow suffix: %s", slot_data->ab_suffix);
+ goto fail;
+ }
+ ABL_AB_SUFFIX = stra_to_str((const CHAR8 *)abl_cmd_line);
+ if (!ABL_AB_SUFFIX) {
+ error(L"Cannot get a valid ABL suffix: %s", abl_cmd_line);
+ goto fail;
+ }
+ if (!(StrStr(ABL_AB_SUFFIX, L"ABL.suffix"))) {
+ debug(L"ABL.suffix is null");
+ } else if (!(StrCmp(AB_SUFFIX, L"_a")) && (!(StrStr(ABL_AB_SUFFIX, L"ABL.suffix=0")))) {
+ capsule_buf = (CHAR8 *)"m1:@0";
+ capsule_buf_len = strlen(capsule_buf);
+ } else if (!(StrCmp(AB_SUFFIX, L"_b")) && (!(StrStr(ABL_AB_SUFFIX, L"ABL.suffix=1")))) {
+ capsule_buf = (CHAR8 *)"m2:@0";
+ capsule_buf_len = strlen(capsule_buf);
+ }
+
+ if (capsule_buf_len != 0 ) {
+ error(L"Avb flow suffix %a doesn't equal to ABL suffix, reboot and update ABL.", slot_data->ab_suffix);
+ ret = set_efi_variable(&loader_guid, IFWI_CAPSULE_UPDATE, capsule_buf_len + 1,
+ capsule_buf, TRUE, TRUE);
+ if (EFI_ERROR(ret)) {
+ error(L"Unable to set slot %a into %a", slot_data->ab_suffix, IFWI_CAPSULE_UPDATE);
+ goto fail;
+ }
+ reboot_to_target(NORMAL_BOOT, EfiResetCold);
+ }
+ }
+#else
+ verify_result = avb_slot_verify(ops,
+ requested_partitions,
+ slot_suffix,
+ flags,
+ AVB_HASHTREE_ERROR_MODE_RESTART,
+ &slot_data);
+ ret = get_avb_result(slot_data,
+ allow_verification_error,
+ verify_result,
+ &boot_state);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get avb result for boot");
+ goto fail;
+ }
+#endif
+
+ boot = &slot_data->loaded_partitions[0];
+ bootimage = boot->data;
+
+ for (int i = 1; requested_partitions[i] != NULL; i++) {
+ acpi = &slot_data->loaded_partitions[i];
+ acpiimage = acpi->data;
+ ret = install_acpi_table_from_partitions(acpiimage,
+ acpi->partition_name,
+ boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to install acpi table from %a image",
+ acpi->partition_name);
+ goto fail;
+ }
+ }
+
+ ret = avb_vbmeta_image_verify(slot_data->vbmeta_images[0].vbmeta_data,
+ slot_data->vbmeta_images[0].vbmeta_size,
+ &vbmeta_pub_key,
+ &vbmeta_pub_key_len);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the vbmeta_pub_key");
+ goto fail;
+ }
+
+ ret = get_rot_data(bootimage, boot_state, vbmeta_pub_key, vbmeta_pub_key_len, &g_rot_data);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init rot params");
+ goto fail;
+ }
+
+ set_boottime_stamp(TM_VERIFY_BOOT_DONE);
+
+ /* install acpi tables before starting trusty */
+ ret = setup_acpi_table(bootimage, boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"setup_acpi_table");
+ return ret;
+ }
+
+#ifdef USE_TRUSTY
+ if (boot_target == NORMAL_BOOT) {
+ VOID *tosimage = NULL;
+ ret = load_tos_image(&tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Load tos image failed");
+ goto fail;
+ }
+ set_boottime_stamp(TM_LOAD_TOS_DONE);
+ ret = start_trusty(tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Unable to start trusty: stop");
+ goto fail;
+ }
+ set_boottime_stamp(TM_PROCRSS_TRUSTY_DONE);
+ }
+#endif
+
+ if (boot_state == BOOT_STATE_GREEN) {
+ avb_update_stored_rollback_indexes_for_slot(ops, slot_data);
+ }
+
+ ret = start_boot_image(bootimage, boot_state, boot_target, slot_data, abl_cmd_line);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to start boot image");
+ goto fail;
+ }
+
+fail:
+ if (slot_data)
+ avb_slot_verify_data_free(slot_data);
+
+ return ret;
+}
+#endif
+
+#ifndef USE_AVB
+EFI_STATUS boot_android(enum boot_target boot_target, CHAR8 *abl_cmd_line)
+{
+ EFI_STATUS ret;
+ CHAR16 *target_path = NULL;
+ VOID *bootimage = NULL;
+ BOOLEAN oneshot = FALSE;
+ UINT8 boot_state = BOOT_STATE_GREEN;
+ X509 *verifier_cert = NULL;
+ const char *acpi_part_names[] = {
+#ifdef USE_ACPI
+ "acpi",
+#endif
+#ifdef USE_ACPIO
+ "acpio",
+#endif
+ NULL};
+
+ for (int i = 0; acpi_part_names[i] != NULL; i++) {
+ ret = install_acpi_table_from_partitions(NULL, acpi_part_names[i],
+ boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to install acpi table from %a image",
+ acpi_part_names[i]);
+ return ret;
+ }
+ }
+
+ debug(L"Loading boot image");
+ ret = load_boot_image(boot_target, target_path, &bootimage, oneshot);
+ FreePool(target_path);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to load boot image");
+ return ret;
+ }
+ boot_state = validate_bootimage(boot_target, bootimage, &verifier_cert);
+
+ /* keymaster interface always use the g_rot_data as its input param */
+ ret = get_rot_data(bootimage, boot_state, verifier_cert, &g_rot_data);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to init rot params");
+ goto exit;
+ }
+ set_boottime_stamp(TM_VERIFY_BOOT_DONE);
+
+ /* install acpi tables before starting trusty */
+ ret = setup_acpi_table(bootimage, boot_target);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"setup_acpi_table");
+ return ret;
+ }
+
+#ifdef USE_TRUSTY
+ if (boot_target == NORMAL_BOOT) {
+ VOID *tosimage = NULL;
+ ret = load_tos_image(&tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Load tos image failed");
+ goto exit;
+ }
+ set_boottime_stamp(TM_LOAD_TOS_DONE);
+ ret = start_trusty(tosimage);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Unable to start trusty: stop");
+ goto exit;
+ }
+ set_boottime_stamp(TM_PROCRSS_TRUSTY_DONE);
+ }
+#endif
+
+ ret = start_boot_image(bootimage, boot_state, boot_target, verifier_cert, abl_cmd_line);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to start boot image");
+ goto exit;
+ }
+
+ ret = EFI_INVALID_PARAMETER;
+exit:
+ return ret;
+}
+#endif
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table)
+{
+ enum boot_target target;
+ EFI_STATUS ret;
+
+#ifndef __FORCE_FASTBOOT
+ BOOLEAN oneshot = FALSE;
+ CHAR16 *target_path = NULL;
+ enum boot_target bcb_target;
+#endif
+
+ set_boottime_stamp(TM_EFI_MAIN);
+ InitializeLib(image, sys_table);
+
+#ifdef USE_UI
+ ux_display_vendor_splash();
+#endif
+
+ target = check_command_line(image, cmd_buf, sizeof(cmd_buf) - 1);
+ if (!get_boot_device()) {
+ // Get boot device failed
+ error(L"Failed to find boot device");
+ return EFI_NO_MEDIA;
+ }
+
+#ifdef RPMB_STORAGE
+ rpmb_storage_init();
+#endif
+
+ ret = slot_init();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Slot management initialization failed");
+ return ret;
+ }
+
+#ifndef __FORCE_FASTBOOT
+ debug(L"Before Check BCB target is %d", target);
+ bcb_target = check_bcb(&target_path, &oneshot);
+ debug(L"BCB target is %d", bcb_target);
+ if (bcb_target == RECOVERY) {
+#ifdef USE_TRUSTY
+ if (target == NORMAL_BOOT) {
+ /* in this case, evmm has been launched, reboot so
+ * bootloader will boot to recovery mode without launch evmm.
+ */
+ error(L"need reboot to RECOVERY mode!");
+ reboot_to_target(RECOVERY, EfiResetCold);
+ }
+#endif
+ target = bcb_target;
+ }
+ debug(L"After Check BCB target is %d", target);
+#endif
+
+ debug(L"target=%d", target);
+
+#ifdef RPMB_STORAGE
+ if (target != CRASHMODE) {
+ ret = rpmb_key_init();
+ if (EFI_ERROR(ret))
+ error(L"rpmb key init failure for osloader");
+ }
+#endif
+
+#ifdef __FORCE_FASTBOOT
+ ret = slot_init_use_misc();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Slot management initialization failed by misc");
+ return ret;
+ }
+
+ for (;;) {
+#ifdef CRASHMODE_USE_ADB
+ if (target == CRASHMODE) {
+ log(L"Enter crash mode ...\n");
+ enter_crashmode(&target);
+ continue;
+ }
+#endif
+ log(L"Enter fastboot mode ...\n");
+ enter_fastboot_mode(&target);
+ }
+#else
+ if (target == FASTBOOT) {
+ ret = slot_init_use_misc();
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Slot management initialization failed by misc");
+ return ret;
+ }
+ }
+
+ for (;;) {
+ switch (target) {
+ case NORMAL_BOOT:
+ case RECOVERY:
+ set_boottime_stamp(TM_AVB_START);
+#ifdef USE_AVB
+ ret = avb_boot_android(target, cmd_buf);
+#else
+ ret = boot_android(target, cmd_buf);
+#endif
+ if (EFI_ERROR(ret))
+ target = FASTBOOT;
+ break;
+ case UNKNOWN_TARGET:
+#ifndef CRASHMODE_USE_ADB
+ case CRASHMODE:
+#endif
+ case FASTBOOT:
+ enter_fastboot_mode(&target);
+ break;
+#ifdef CRASHMODE_USE_ADB
+ case CRASHMODE:
+ enter_crashmode(&target);
+ break;
+#endif
+ default:
+ reboot_to_target(target, EfiResetCold);
+ }
+ }
+#endif
+ return EFI_SUCCESS;
+}
diff --git a/lib.c b/lib.c
deleted file mode 100644
index 2a9ab020..00000000
--- a/lib.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (c) 2013, Intel Corporation
- * All rights reserved.
- *
- * Author: Andrew Boie
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include
-#include
-
-#include "lib.h"
-#include "kernelflinger.h"
-
-CHAR16 *stra_to_str(CHAR8 *stra)
-{
- UINTN len, i;
- CHAR16 *str;
-
- len = strlena(stra);
- str = AllocatePool((len + 1) * sizeof(CHAR16));
-
- if (!str)
- return NULL;
- for (i = 0; i < len; i++)
- str[i] = (CHAR16)stra[i];
- str[i] = 0;
- return str;
-}
-
-
-EFI_STATUS get_efi_variable(const EFI_GUID *guid, CHAR16 *key,
- UINTN *size_p, VOID **data_p)
-{
- VOID *data;
- UINTN size;
- EFI_STATUS ret;
-
- size = EFI_MAXIMUM_VARIABLE_SIZE;
- data = AllocatePool(size);
- if (!data)
- return EFI_OUT_OF_RESOURCES;
-
- ret = uefi_call_wrapper(RT->GetVariable, 5, key, (EFI_GUID *)guid,
- NULL, &size, data);
-
- if (EFI_ERROR(ret)) {
- FreePool(data);
- return ret;
- }
-
- if (size_p)
- *size_p = size;
- *data_p = data;
-
- return EFI_SUCCESS;
-}
-
-
-CHAR16 *get_efi_variable_str(const EFI_GUID *guid, CHAR16 *key)
-{
- CHAR16 *data;
- EFI_STATUS ret;
- UINTN size;
-
- ret = get_efi_variable(guid, key, &size, (VOID **)&data);
- if (EFI_ERROR(ret))
- return NULL;
-
- if (!size) {
- FreePool(data);
- return NULL;
- }
-
- return data;
-}
-
-
-EFI_STATUS get_efi_variable_byte(const EFI_GUID *guid, CHAR16 *key, UINT8 *byte)
-{
- CHAR16 *data;
- EFI_STATUS ret;
- UINTN size;
-
- ret = get_efi_variable(guid, key, &size, (VOID **)&data);
- if (EFI_ERROR(ret))
- return ret;
-
- if (!size) {
- FreePool(data);
- return EFI_NOT_FOUND;
- }
-
- *byte = data[0];
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS set_efi_variable(const EFI_GUID *guid, CHAR16 *key,
- UINTN size, VOID *data, BOOLEAN nonvol, BOOLEAN runtime)
-{
- UINT32 flags = EFI_VARIABLE_BOOTSERVICE_ACCESS;
-
- if (nonvol)
- flags |= EFI_VARIABLE_NON_VOLATILE;
- if (runtime)
- flags |= EFI_VARIABLE_RUNTIME_ACCESS;
-
- return uefi_call_wrapper(RT->SetVariable, 5, key, (EFI_GUID *)guid, flags,
- size, data);
-}
-
-
-EFI_STATUS set_efi_variable_str(const EFI_GUID *guid, CHAR16 *key,
- BOOLEAN nonvol, BOOLEAN runtime, CHAR16 *val)
-{
- return set_efi_variable(guid, key, val ? (StrLen(val) + 1) : 0,
- val, nonvol, runtime);
-}
-
-
-EFI_STATUS file_delete(IN EFI_HANDLE disk, IN const CHAR16 *name)
-{
- EFI_STATUS ret;
- EFI_FILE *file;
- EFI_FILE *root_dir;
-
- root_dir = LibOpenRoot(disk);
- if (!root_dir)
- return EFI_LOAD_ERROR;
-
- ret = uefi_call_wrapper(root_dir->Open, 5, root_dir, &file,
- (CHAR16 *)name, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
- if (EFI_ERROR(ret)) {
- efi_perror(ret, L"Couldn't open the file in order to delete");
- goto out;
- }
- ret = uefi_call_wrapper(file->Delete, 1, file);
- if (EFI_ERROR(ret)) {
- efi_perror(ret, L"Couldn't delete source file");
- goto out;
- }
-out:
- uefi_call_wrapper(root_dir->Close, 1, root_dir);
- return ret;
-}
-
-
-BOOLEAN file_exists(IN EFI_HANDLE disk, IN const CHAR16 *path)
-{
- EFI_FILE *root_dir;
- EFI_FILE *file;
- EFI_STATUS ret;
- BOOLEAN exists = TRUE;
-
- root_dir = LibOpenRoot(disk);
- if (!root_dir)
- return FALSE;
-
- ret = uefi_call_wrapper(root_dir->Open, 5, root_dir, &file,
- (CHAR16 *)path, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR(ret)) {
- exists = FALSE;
- } else {
- uefi_call_wrapper(file->Close, 1, file);
- }
-
- uefi_call_wrapper(root_dir->Close, 1, root_dir);
- return exists;
-}
-
-
-UINTN memcmp(const VOID *ptr1, const VOID *ptr2, UINTN num)
-{
- CHAR8 *buf1 = (CHAR8 *) ptr1;
- CHAR8 *buf2 = (CHAR8 *) ptr2;
- if (!ptr1 || !ptr2 || !num)
- return -1;
- while (num-- > 0){
- if (*buf1++ != *buf2++)
- return -1;
- }
- return 0;
-}
-
-
-VOID StrNCpy(OUT CHAR16 *dest, IN const CHAR16 *src, UINT32 n)
-{
- UINT32 i;
-
- for (i = 0; i < n && src[i] != 0; i++)
- dest[i] = src[i];
- for ( ; i < n; i++)
- dest[i] = 0;
-}
-
-
-UINT8 getdigit(IN CHAR16 *str)
-{
- CHAR16 bytestr[3];
- bytestr[2] = 0;
- StrNCpy(bytestr, str, 2);
- return (UINT8)xtoi(bytestr);
-}
-
-
-EFI_STATUS string_to_guid(
- IN CHAR16 *in_guid_str,
- OUT EFI_GUID *guid)
-{
- CHAR16 gstr[37];
- int i;
-
- StrNCpy(gstr, in_guid_str, 36);
- gstr[36] = 0;
- gstr[8] = 0;
- gstr[13] = 0;
- gstr[18] = 0;
- guid->Data1 = (UINT32)xtoi(gstr);
- guid->Data2 = (UINT16)xtoi(&gstr[9]);
- guid->Data3 = (UINT16)xtoi(&gstr[14]);
-
- guid->Data4[0] = getdigit(&gstr[19]);
- guid->Data4[1] = getdigit(&gstr[21]);
- for (i = 0; i < 6; i++)
- guid->Data4[i + 2] = getdigit(&gstr[24 + (i * 2)]);
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS str_to_stra(CHAR8 *dst, CHAR16 *src, UINTN len)
-{
- UINTN i;
-
- /* This is NOT how to do UTF16 to UTF8 conversion. For now we're just
- * going to hope that nobody's putting non-ASCII characters in
- * the source string! We'll at least abort with an error
- * if we see any funny stuff */
- for (i = 0; i < len; i++) {
- if (src[i] > 0x7F)
- return EFI_INVALID_PARAMETER;
-
- dst[i] = (CHAR8)src[i];
- if (!src[i])
- break;
- }
- dst[len - 1] = '\0';
- return EFI_SUCCESS;
-}
-
-
-VOID memset(VOID *dst, CHAR8 ch, UINTN size)
-{
- UINTN i;
- CHAR8 *p = (CHAR8 *)dst;
-
- for (i = 0; i < size; i++)
- p[i] = ch;
-}
-
-
-VOID memcpy(VOID *dst, const VOID *src, UINTN size)
-{
- UINTN i;
- CHAR8 *d = (CHAR8 *)dst;
- const CHAR8 *s = (const CHAR8 *)src;
-
- for (i = 0; i < size; i++)
- *d++ = *s++;
-}
-
-
-/*
- * Parameters Passed : character : char to be converted to int
- * base : the base of convertion ( hex, dec etc)
- *
- * Returns : value : character after conversion to int
- *
- * This function converts character to integer.
- */
-static INTN to_digit(CHAR16 character, UINTN base)
-{
- UINTN value = -1;
-
- if (character >= '0' && character <= '9')
- value = character - '0';
- else if (character >= 'a' && character <= 'z')
- value = 0xA + character - 'a';
- else if (character >= 'A' && character <= 'Z')
- value = 0xA + character - 'A';
-
- return value < base ? (INTN)value : -1;
-}
-
-
-/*
- * Parameters Passed : nptr : Pointer to the string to be converted to int
- * base : the base of convertion ( hex, dec etc)
- * endptr: Reference to the next character after the converted string
- * Returns : value : coverted unsigned long int
- *
- * This function converts String to unsigned long int.
- */
-UINTN strtoul(const CHAR16 *nptr, CHAR16 **endptr, UINTN base)
-{
- UINTN value = 0;
-
- if (!nptr)
- goto out;
-
- if ((base == 0 || base == 16) &&
- (StrLen(nptr) > 2 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X'))) {
- nptr += 2;
- base = 16;
- }
-
- if (base == 0)
- base = 10;
-
- for (; *nptr != '\0' ; nptr++) {
- INTN t = to_digit(*nptr, base);
- if (t == -1)
- goto out;
- value = (value * base) + t;
- }
-
-out:
- if (endptr)
- *endptr = (CHAR16 *)nptr;
- return value;
-}
-
-
-VOID pause(UINTN seconds)
-{
- uefi_call_wrapper(BS->Stall, 1, seconds * 1000000);
-}
-
-
-EFI_STATUS halt_system(VOID)
-{
- return uefi_call_wrapper(RT->ResetSystem, 4, EfiResetShutdown, EFI_SUCCESS,
- 0, NULL);
-}
-
-
-EFI_STATUS reboot(VOID)
-{
- return uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS,
- 0, NULL);
-}
-
-/* vim: softtabstop=8:shiftwidth=8:expandtab
- */
-
diff --git a/libadb/Android.mk b/libadb/Android.mk
new file mode 100644
index 00000000..1a45db88
--- /dev/null
+++ b/libadb/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libadb-$(TARGET_BUILD_VARIANT)
+LOCAL_CFLAGS := $(KERNELFLINGER_CFLAGS)
+LOCAL_STATIC_LIBRARIES := \
+ $(KERNELFLINGER_STATIC_LIBRARIES) \
+ libefiusb-$(TARGET_BUILD_VARIANT) \
+ libefitcp-$(TARGET_BUILD_VARIANT) \
+ libtransport-$(TARGET_BUILD_VARIANT) \
+ libkernelflinger-$(TARGET_BUILD_VARIANT)
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include/libadb
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include/libadb
+LOCAL_SRC_FILES := \
+ adb.c \
+ adb_socket.c \
+ reboot_service.c \
+ sync_service.c \
+ reader.c
+
+include $(BUILD_EFI_STATIC_LIBRARY)
diff --git a/libadb/adb.c b/libadb/adb.c
new file mode 100644
index 00000000..90e05752
--- /dev/null
+++ b/libadb/adb.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "adb.h"
+#include "adb_socket.h"
+#include "service.h"
+
+/* USB configuration */
+#define ADB_IF_SUBCLASS 0x42
+#define ADB_IF_PROTOCOL 0x01
+#define STR_CONFIGURATION L"ADB"
+#define STR_INTERFACE L"ADB Interface"
+
+/* TCP configuration */
+#define TCP_PORT 5555
+
+/* Protocol definitions */
+#define ADB_VERSION 0x01000000
+#define SYSTEM_TYPE "bootloader"
+
+/* Internal data */
+typedef enum adb_state {
+ ADB_READ_MSG,
+ ADB_READ_MSG_PAYLOAD,
+ ADB_PROCESS_MSG
+} adb_state_t;
+
+static service_t *SERVICES[] = { &reboot_service, &sync_service };
+static adb_state_t adb_state;
+static adb_pkt_t adb_pkt_in;
+/* This buffer size is set to the minimum to avoid the waste of memory
+ * resource. If new adb commands support is added that requires a
+ * bigger input buffer, feel free to increase this size. */
+unsigned char in_buf[ADB_MIN_PAYLOAD];
+
+UINT32 adb_max_payload;
+
+static UINT32 adb_pkt_sum(adb_pkt_t *pkt)
+{
+ UINTN count, sum;
+ unsigned char *cur = pkt->data;
+
+ for (sum = 0, count = pkt->msg.data_length; count; count--)
+ sum += *cur++;
+
+ return sum;
+}
+
+static adb_pkt_t *delayed_pkt_data;
+EFI_STATUS adb_send_pkt(adb_pkt_t *pkt, UINT32 command, UINT32 arg0, UINT32 arg1)
+{
+ EFI_STATUS ret;
+
+ pkt->msg.command = command;
+ pkt->msg.arg0 = arg0;
+ pkt->msg.arg1 = arg1;
+
+ pkt->msg.magic = pkt->msg.command ^ 0xFFFFFFFF;
+ pkt->msg.data_check = adb_pkt_sum(pkt);
+
+ /* Some transport layer (USB in particular) might not support
+ several writes in raw. Wait for the TX event to send the
+ payload. Prepare the delayed packet before we send the
+ first one because some transport implementation trig the TX
+ even (TCP in particular) before the first transport_write()
+ returns. */
+ if (pkt->msg.data_length)
+ delayed_pkt_data = pkt;
+
+ ret = transport_write(&pkt->msg, sizeof(pkt->msg));
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to send adb msg");
+
+ return ret;
+}
+
+static void adb_read_msg(void)
+{
+ EFI_STATUS ret;
+
+ adb_state = ADB_READ_MSG;
+ ret = transport_read(&adb_pkt_in.msg, sizeof(adb_pkt_in.msg));
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"transport_read failed for next adb message");
+}
+
+static void adb_read_msg_payload()
+{
+ EFI_STATUS ret;
+
+ adb_state = ADB_READ_MSG_PAYLOAD;
+ ret = transport_read(adb_pkt_in.data, adb_pkt_in.msg.data_length);
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"transport_read failed for adb message payload");
+
+}
+
+/* ADB commands */
+static void cmd_unsupported(adb_pkt_t *pkt)
+{
+ char cmd[5] = { '\0', '\0', '\0', '\0', '\0' };
+ *(UINT32 *)cmd = pkt->msg.command;
+ *(UINT32 *)cmd = MKID(cmd[0], cmd[1], cmd[2], cmd[3]);
+
+ error(L"'%a' adb message is not supported", cmd);
+}
+
+static void cmd_connect(adb_pkt_t *pkt)
+{
+ EFI_STATUS ret;
+ static adb_pkt_t out_pkt;
+
+ if (pkt->msg.arg0 != ADB_VERSION) {
+ error(L"Unsupported adb version 0x%08x", pkt->msg.arg0);
+ return;
+ }
+
+ adb_max_payload = min((UINT32)ADB_MAX_PAYLOAD, pkt->msg.arg1);
+ debug(L"Negociated payload size is %d bytes", adb_max_payload);
+
+ out_pkt.data = (unsigned char *)SYSTEM_TYPE "::";
+ out_pkt.msg.data_length = strlen(out_pkt.data);
+
+ ret = adb_send_pkt(&out_pkt, pkt->msg.command, pkt->msg.arg0,
+ adb_max_payload);
+ if (EFI_ERROR(ret))
+ error(L"Failed to send connection packet");
+}
+
+static void cmd_open(adb_pkt_t *pkt)
+{
+ char *name = (char *)pkt->data;
+ char *arg = name;
+ service_t *srv = NULL;
+ UINTN i;
+
+ if (!pkt->msg.data_length) {
+ error(L"Received OPEN packet without any data");
+ return;
+ }
+
+ while (*arg != ':' && *arg != '\0')
+ arg++;
+ if (*arg == ':')
+ *arg++ = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(SERVICES); i++)
+ if (!strcmp((CHAR8 *)name, (CHAR8 *)SERVICES[i]->name)) {
+ srv = SERVICES[i];
+ break;
+ }
+
+ asock_open(pkt->msg.arg0, srv, arg);
+}
+
+static void cmd_okay(adb_pkt_t *pkt)
+{
+ asock_okay(asock_find(pkt->msg.arg1, pkt->msg.arg0));
+}
+
+static void cmd_close(adb_pkt_t *pkt)
+{
+ asock_close(asock_find(pkt->msg.arg1, pkt->msg.arg0));
+}
+
+static void cmd_write(adb_pkt_t *pkt)
+{
+ asock_read(asock_find(pkt->msg.arg1, pkt->msg.arg0),
+ pkt->data, pkt->msg.data_length);
+}
+
+typedef struct adb_handler {
+ UINT32 command;
+ void (*fun)(adb_pkt_t *);
+} adb_handler_t;
+
+static adb_handler_t HANDLERS[] = {
+ { A_SYNC, cmd_unsupported },
+ { A_CNXN, cmd_connect },
+ { A_OPEN, cmd_open },
+ { A_OKAY, cmd_okay },
+ { A_CLSE, cmd_close },
+ { A_WRTE, cmd_write },
+ { A_AUTH, cmd_unsupported }
+};
+
+static adb_handler_t *get_handler(adb_msg_t *msg)
+{
+ UINTN i;
+
+ for (i = 0; i < ARRAY_SIZE(HANDLERS); i++)
+ if (HANDLERS[i].command == msg->command)
+ return &HANDLERS[i];
+
+ return NULL;
+}
+
+static void process_msg(void)
+{
+ adb_handler_t *handler;
+
+ if (adb_state != ADB_PROCESS_MSG)
+ return;
+
+ handler = get_handler(&adb_pkt_in.msg);
+ if (!handler)
+ error(L"Unknown command");
+ else
+ handler->fun(&adb_pkt_in);
+
+ adb_read_msg();
+}
+
+static void adb_process_rx(void *buf, unsigned len)
+{
+ adb_msg_t *msg;
+
+ switch (adb_state) {
+ case ADB_READ_MSG:
+ if (buf != &adb_pkt_in || len != sizeof(adb_pkt_in.msg)) {
+ error(L"Invalid adb packet buffer reference");
+ return;
+ }
+
+ msg = (adb_msg_t *)buf;
+ if (msg->magic != (msg->command ^ 0xFFFFFFFF)) {
+ error(L"Bad magic");
+ return;
+ }
+
+ if (msg->data_length > sizeof(in_buf)) {
+ error(L"internal read buffer is too small");
+ return;
+ }
+
+ if (msg->data_length) {
+ adb_read_msg_payload();
+ return;
+ }
+
+ /* Fastpath for OKAY message for performance purposes. */
+ if (msg->command == A_OKAY) {
+ cmd_okay(&adb_pkt_in);
+ adb_read_msg();
+ return;
+ }
+
+ adb_state = ADB_PROCESS_MSG;
+ break;
+
+ case ADB_READ_MSG_PAYLOAD:
+ if (buf != adb_pkt_in.data) {
+ error(L"Invalid adb payload buffer reference");
+ return;
+ }
+
+ if (len != adb_pkt_in.msg.data_length) {
+ error(L"Received 0x%x bytes payload instead of 0x%x bytes",
+ len, adb_pkt_in.msg.data_length);
+ return;
+ }
+
+ if (adb_pkt_in.msg.data_check != adb_pkt_sum(&adb_pkt_in)) {
+ error(L"Corrupted data detected");
+ return;
+ }
+
+ adb_state = ADB_PROCESS_MSG;
+ break;
+
+ default:
+ error(L"Inconsistent 0x%x adb state", adb_state);
+ }
+}
+
+static void adb_process_tx(__attribute__((__unused__)) void *buf,
+ __attribute__((__unused__)) unsigned len)
+{
+ EFI_STATUS ret;
+
+ if (!delayed_pkt_data)
+ return;
+
+ ret = transport_write(delayed_pkt_data->data, delayed_pkt_data->msg.data_length);
+ delayed_pkt_data = NULL;
+ if (EFI_ERROR(ret))
+ efi_perror(ret, L"Failed to send adb payload");
+}
+
+static enum boot_target exit_bt;
+
+enum boot_target adb_get_boot_target(void)
+{
+ return exit_bt;
+}
+
+void adb_set_boot_target(enum boot_target bt)
+{
+ exit_bt = bt;
+}
+
+static EFI_STATUS adb_usb_start(start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb)
+{
+ return usb_start(ADB_IF_SUBCLASS, ADB_IF_PROTOCOL,
+ STR_CONFIGURATION, STR_INTERFACE,
+ start_cb, rx_cb, tx_cb);
+}
+
+static void print_tcpip_information(EFI_IPv4_ADDRESS *address)
+{
+#define TCPIP_INFO_FMT L"ADB is listening on TCP %d.%d.%d.%d:%d"
+
+ ui_print(TCPIP_INFO_FMT, address->Addr[0], address->Addr[1],
+ address->Addr[2], address->Addr[3], TCP_PORT);
+ debug(TCPIP_INFO_FMT, address->Addr[0], address->Addr[1],
+ address->Addr[2], address->Addr[3], TCP_PORT);
+}
+
+static EFI_STATUS adb_tcp_start(start_callback_t start_cb,
+ data_callback_t rx_cb,
+ data_callback_t tx_cb)
+{
+ EFI_STATUS ret;
+ EFI_IPv4_ADDRESS station_address;
+
+ ret = tcp_start(TCP_PORT, start_cb, rx_cb, tx_cb,
+ &station_address);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ print_tcpip_information(&station_address);
+
+ return EFI_SUCCESS;
+}
+
+static transport_t ADB_TRANSPORT[] = {
+ {
+ .name = "USB for adb",
+ .start = adb_usb_start,
+ .stop = usb_stop,
+ .run = usb_run,
+ .read = usb_read,
+ .write = usb_write
+ },
+ {
+ .name = "TCP for adb",
+ .start = adb_tcp_start,
+ .stop = tcp_stop,
+ .run = tcp_run,
+ .read = tcp_read,
+ .write = tcp_write
+ }
+};
+
+EFI_STATUS adb_init()
+{
+ EFI_STATUS ret;
+
+ adb_pkt_in.data = in_buf;
+ exit_bt = UNKNOWN_TARGET;
+
+ ret = transport_register(ADB_TRANSPORT, ARRAY_SIZE(ADB_TRANSPORT));
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"adb failed to register support transport");
+ return ret;
+ }
+
+ return transport_start(adb_read_msg, adb_process_rx, adb_process_tx);
+}
+
+EFI_STATUS adb_run()
+{
+ EFI_STATUS ret;
+
+ ret = transport_run();
+ if (EFI_ERROR(ret) && ret != EFI_TIMEOUT) {
+ efi_perror(ret, L"Error occurred during USB run");
+ return ret;
+ }
+
+ process_msg();
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS adb_exit()
+{
+ asock_close_all();
+ transport_stop();
+ return EFI_SUCCESS;
+}
diff --git a/libadb/adb_socket.c b/libadb/adb_socket.c
new file mode 100644
index 00000000..16a8c39d
--- /dev/null
+++ b/libadb/adb_socket.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+
+#include "adb.h"
+#include "adb_socket.h"
+#include "service.h"
+
+struct asock {
+ UINT32 local;
+ UINT32 remote;
+ adb_pkt_t msg;
+ adb_pkt_t wrt;
+ unsigned char data[ADB_MAX_PAYLOAD];
+ service_t *service;
+ void *context;
+};
+
+static struct asock asocks[MAX_ADB_SOCKET];
+
+/* Host to device */
+EFI_STATUS asock_open(UINT32 remote, service_t *service, char *arg)
+{
+ static adb_pkt_t fail_msg = { .msg.data_length = 0 };
+ EFI_STATUS ret;
+ asock_t s = NULL;
+ UINTN i;
+
+ if (!remote || !service) {
+ error(L"Invalid remote or service");
+ ret = EFI_INVALID_PARAMETER;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(asocks); i++)
+ if (asocks[i].local == 0) {
+ s = &asocks[i];
+ s->local = i + 1;
+ break;
+ }
+
+ if (!s) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ s->remote = remote;
+ s->service = service;
+ s->context = NULL;
+
+ ret = service->open(arg, &s->context);
+ if (EFI_ERROR(ret))
+ goto err;
+
+ debug(L"socket %d/%d created for service %a", s->local, remote, service->name);
+
+ ret = asock_send_okay(s);
+ if (EFI_ERROR(ret)) {
+ service->close(s);
+ efi_perror(ret, L"Failed to send OKAY message");
+ goto err;
+ }
+
+ ret = s->service->ready(s);
+ if (EFI_ERROR(ret)) {
+ service->close(s);
+ goto err;
+ }
+
+ return EFI_SUCCESS;
+
+err:
+ if (s)
+ s->local = 0;
+ efi_perror(ret, L"Failed to open socket for %d remote", remote);
+ return adb_send_pkt(&fail_msg, A_CLSE, 0, remote);
+}
+
+EFI_STATUS asock_close(asock_t s)
+{
+ EFI_STATUS ret;
+
+ if (!s)
+ return EFI_INVALID_PARAMETER;
+
+ ret = s->service->close(s);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to close service on socket %d/%d",
+ s->local, s->remote);
+ return ret;
+ }
+
+ debug(L"socket %d/%d closed", s->local, s->remote);
+ s->local = 0;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS asock_okay(asock_t s)
+{
+ if (!s)
+ return EFI_INVALID_PARAMETER;
+
+ return s->service->okay(s);
+}
+
+EFI_STATUS asock_read(asock_t s, unsigned char *data, UINT32 length)
+{
+ if (!s)
+ return EFI_INVALID_PARAMETER;
+
+ return s->service->read(s, data, length);
+}
+
+/* Device to host */
+EFI_STATUS asock_write(asock_t s, unsigned char *data, UINT32 length)
+{
+ if (!s || length > adb_max_payload)
+ return EFI_INVALID_PARAMETER;
+
+ memcpy(s->data, data, length);
+ s->wrt.data = s->data;
+ s->wrt.msg.data_length = length;
+ return adb_send_pkt(&s->wrt, A_WRTE, s->local, s->remote);
+}
+
+EFI_STATUS asock_send_okay(asock_t s)
+{
+ if (!s)
+ return EFI_INVALID_PARAMETER;
+
+ return adb_send_pkt(&s->msg, A_OKAY, s->local, s->remote);
+}
+
+EFI_STATUS asock_send_close(asock_t s)
+{
+ if (!s)
+ return EFI_INVALID_PARAMETER;
+
+ return adb_send_pkt(&s->msg, A_CLSE, s->local, s->remote);
+}
+
+/* Tools */
+void *asock_context(asock_t s)
+{
+ return s ? s->context : NULL;
+}
+
+asock_t asock_find(UINT32 local, UINT32 remote)
+{
+ asock_t s;
+
+ if (local == 0 || local > ARRAY_SIZE(asocks))
+ return NULL;
+
+ s = &asocks[local - 1];
+ if (s->local == local && s->remote == remote)
+ return s;
+
+ error(L"socket %d/%d not found", local, remote);
+ return NULL;
+}
+
+void asock_close_all()
+{
+ UINTN i;
+
+ for (i = 0; i < ARRAY_SIZE(asocks); i++)
+ if (asocks[i].local)
+ asock_close(&asocks[i]);
+}
diff --git a/libadb/adb_socket.h b/libadb/adb_socket.h
new file mode 100644
index 00000000..6a412bf7
--- /dev/null
+++ b/libadb/adb_socket.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _ADB_SOCKET_H_
+#define _ADB_SOCKET_H_
+
+#include
+#include
+
+#include "adb.h"
+
+typedef struct asock * asock_t;
+
+struct service;
+
+#define MAX_ADB_SOCKET 5
+
+/* Host to device */
+EFI_STATUS asock_open(UINT32 remote, struct service *service, char *arg);
+EFI_STATUS asock_close(asock_t s);
+EFI_STATUS asock_okay(asock_t s);
+EFI_STATUS asock_read(asock_t s, unsigned char *data, UINT32 length);
+
+/* Device to host */
+EFI_STATUS asock_write(asock_t s, unsigned char *data, UINT32 length);
+EFI_STATUS asock_send_okay(asock_t s);
+EFI_STATUS asock_send_close(asock_t s);
+
+/* Tools */
+void *asock_context(asock_t s);
+asock_t asock_find(UINT32 local, UINT32 remote);
+void asock_close_all();
+
+#endif /* _ADB_SOCKET_H_ */
diff --git a/libadb/reader.c b/libadb/reader.c
new file mode 100644
index 00000000..663498c9
--- /dev/null
+++ b/libadb/reader.c
@@ -0,0 +1,1090 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+
+#include "acpi.h"
+#ifndef __LP64__
+#include "pae.h"
+#endif
+#include "reader.h"
+#include "sparse_format.h"
+
+/* Memory dump shared functions. These functions do not make any
+ dynamic memory allocation to avoid RAM corruption during the
+ dump. */
+#define MAX_MEMORY_REGION_NB 256
+
+typedef struct memory_priv {
+ BOOLEAN is_in_used;
+
+ /* Memory map */
+ UINT8 memmap[MAX_MEMORY_REGION_NB * sizeof(EFI_MEMORY_DESCRIPTOR)];
+ UINTN nr_descr;
+ UINTN descr_sz;
+
+ /* Boundaries */
+ EFI_PHYSICAL_ADDRESS start;
+ EFI_PHYSICAL_ADDRESS end;
+
+ /* Current memory region */
+ EFI_PHYSICAL_ADDRESS cur;
+ EFI_PHYSICAL_ADDRESS cur_end;
+} memory_t;
+
+static EFI_STATUS get_sorted_memory_map(memory_t *mem)
+{
+ EFI_STATUS ret;
+ UINT32 descr_ver;
+ UINTN key, memmap_sz;
+
+ memmap_sz = sizeof(mem->memmap);
+ ret = uefi_call_wrapper(BS->GetMemoryMap, 5, &memmap_sz,
+ (EFI_MEMORY_DESCRIPTOR *)mem->memmap,
+ &key, &mem->descr_sz, &descr_ver);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the current memory map");
+ return ret;
+ }
+
+ mem->nr_descr = memmap_sz / mem->descr_sz;
+ sort_memory_map(mem->memmap, mem->nr_descr, mem->descr_sz);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS memory_open(reader_ctx_t *ctx, memory_t *mem,
+ EFI_STATUS (*init)(reader_ctx_t *, void *),
+ UINTN argc, char **argv)
+{
+ EFI_STATUS ret = EFI_SUCCESS;
+ char *endptr;
+ UINT64 length;
+
+ if (argc > 2)
+ return EFI_INVALID_PARAMETER;
+
+ if (mem->is_in_used)
+ return EFI_ALREADY_STARTED;
+
+ mem->is_in_used = TRUE;
+ ctx->private = mem;
+
+ /* Parse argv */
+ if (argc > 0) {
+ mem->start = strtoull(argv[0], &endptr, 16);
+ if (*endptr != '\0')
+ goto err;
+ } else
+ mem->start = 0;
+
+ if (argc == 2) {
+ length = strtoull(argv[1], &endptr, 16);
+ if (*endptr != '\0')
+ goto err;
+ mem->end = mem->start + length;
+ } else
+ mem->end = 0;
+
+ if (mem->start % EFI_PAGE_SIZE || mem->end % EFI_PAGE_SIZE) {
+ error(L"Boundaries must be multiple of %d bytes", EFI_PAGE_SIZE);
+ goto err;
+ }
+
+ ret = get_sorted_memory_map(mem);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ ret = init(ctx, mem);
+ if (EFI_ERROR(ret))
+ goto err;
+
+#ifndef __LP64__
+ ret = pae_init(mem->memmap, mem->nr_descr, mem->descr_sz);
+ if (EFI_ERROR(ret))
+ goto err;
+#endif
+
+ return EFI_SUCCESS;
+
+err:
+ mem->is_in_used = FALSE;
+ return EFI_ERROR(ret) ? ret : EFI_INVALID_PARAMETER;
+}
+
+static EFI_STATUS memory_read_current(memory_t *mem, unsigned char **buf, UINT64 *len)
+{
+#ifndef __LP64__
+ EFI_STATUS ret;
+#endif
+
+ *len = min(*len, mem->cur_end - mem->cur);
+#ifdef __LP64__
+ *buf = (unsigned char *)mem->cur;
+#else
+ ret = pae_map(mem->cur, buf, len);
+ if (EFI_ERROR(ret))
+ return ret;
+#endif
+ mem->cur += *len;
+
+ return EFI_SUCCESS;
+}
+
+static void memory_close(reader_ctx_t *ctx)
+{
+ ((memory_t *)ctx->private)->is_in_used = FALSE;
+#ifndef __LP64__
+ pae_exit();
+#endif
+}
+
+/* RAM reader */
+#define SIZEOF_TOTALSZ sizeof(((chunk_header_t *)0)->total_sz)
+#define MAX_CHUNK_SIZE (((UINT64)1 << (SIZEOF_TOTALSZ * 8)) - EFI_PAGE_SIZE)
+
+static struct ram_priv {
+ memory_t m;
+
+ /* Sparse format */
+ UINTN chunk_nb;
+ UINTN cur_chunk;
+ struct sparse_header sheader;
+ struct chunk_header chunks[MAX_MEMORY_REGION_NB];
+} ram_priv = {
+ .sheader = {
+ .magic = SPARSE_HEADER_MAGIC,
+ .major_version = 0x1,
+ .minor_version = 0,
+ .file_hdr_sz = sizeof(struct sparse_header),
+ .chunk_hdr_sz = sizeof(struct chunk_header),
+ .blk_sz = EFI_PAGE_SIZE
+ }
+};
+
+static EFI_STATUS ram_add_chunk(reader_ctx_t *ctx, struct ram_priv *priv, UINT16 type, UINT64 size)
+{
+ EFI_STATUS ret = EFI_SUCCESS;
+ struct chunk_header *cur = NULL;
+
+ if (size % EFI_PAGE_SIZE) {
+ error(L"chunk size must be multiple of %d bytes", EFI_PAGE_SIZE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (type == CHUNK_TYPE_RAW) {
+ while ((UINT32)(size + sizeof(*cur)) <= size) {
+ /* Overflow detected in UINT32 total_sz field */
+ ret = ram_add_chunk(ctx, priv, type, MAX_CHUNK_SIZE);
+ if (EFI_ERROR(ret))
+ return ret;
+ size -= MAX_CHUNK_SIZE;
+ }
+ }
+
+ if (priv->chunk_nb == MAX_MEMORY_REGION_NB) {
+ error(L"Failed to allocate a new chunk");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ cur = &priv->chunks[priv->chunk_nb++];
+
+ cur->chunk_type = type;
+ cur->chunk_sz = size / EFI_PAGE_SIZE;
+ cur->total_sz = sizeof(*cur);
+ ctx->len += sizeof(*cur);
+ if (type == CHUNK_TYPE_RAW) {
+ cur->total_sz += size;
+ ctx->len += size;
+ }
+
+ priv->sheader.total_chunks++;
+ priv->sheader.total_blks += cur->chunk_sz;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS ram_build_chunks(reader_ctx_t *ctx, void *priv_p)
+{
+ struct ram_priv *priv = priv_p;
+ EFI_STATUS ret = EFI_SUCCESS;
+ UINT16 type;
+ UINTN i;
+ EFI_MEMORY_DESCRIPTOR *entry;
+ UINT64 entry_len, length;
+ EFI_PHYSICAL_ADDRESS entry_end, prev_end;
+ UINT8 *entries = priv->m.memmap;
+
+ priv->sheader.total_chunks = priv->sheader.total_blks = 0;
+ priv->chunk_nb = priv->cur_chunk = 0;
+ prev_end = ctx->cur = ctx->len = 0;
+
+ for (i = 0; i < priv->m.nr_descr; entries += priv->m.descr_sz, i++) {
+ entry = (EFI_MEMORY_DESCRIPTOR *)entries;
+ entry_len = entry->NumberOfPages * EFI_PAGE_SIZE;
+ entry_end = entry->PhysicalStart + entry_len;
+
+ if (priv->m.start >= entry_end)
+ goto next;
+
+ /* Memory hole between two memory regions */
+ if (prev_end != entry->PhysicalStart) {
+ if (prev_end > entry->PhysicalStart) {
+ error(L"overlap detected, aborting");
+ goto err;
+ }
+
+ length = entry->PhysicalStart - prev_end;
+
+ if (priv->m.start > prev_end && priv->m.start < entry->PhysicalStart)
+ length -= priv->m.start - prev_end;
+
+ if (priv->m.end && entry->PhysicalStart > priv->m.end)
+ length -= entry->PhysicalStart - priv->m.end;
+
+ ret = ram_add_chunk(ctx, priv, CHUNK_TYPE_DONT_CARE, length);
+ if (EFI_ERROR(ret))
+ goto err;
+
+ if (priv->m.end && priv->m.end < entry->PhysicalStart)
+ break;
+ }
+
+ length = entry_len;
+ if (priv->m.start > entry->PhysicalStart && priv->m.start < entry_end)
+ length -= priv->m.start - entry->PhysicalStart;
+
+ if (priv->m.end && priv->m.end < entry_end)
+ length -= entry_end - priv->m.end;
+
+ type = entry->Type == EfiConventionalMemory ? CHUNK_TYPE_RAW : CHUNK_TYPE_DONT_CARE;
+ ret = ram_add_chunk(ctx, priv, type, length);
+ if (EFI_ERROR(ret))
+ goto err;
+
+ if (priv->m.end && priv->m.end <= entry_end)
+ break;
+
+next:
+ prev_end = entry_end;
+ }
+
+ if (priv->m.end && i == priv->m.nr_descr) {
+ error(L"End boundary is in unreachable memory region (>= 0x%lx)",
+ prev_end);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!ctx->len) {
+ error(L"Start boundary is in unreachable memory region");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!priv->m.end)
+ priv->m.end = prev_end;
+
+ ctx->len += sizeof(priv->sheader);
+ return EFI_SUCCESS;
+
+err:
+ return EFI_ERROR(ret) ? ret : EFI_INVALID_PARAMETER;
+}
+
+static EFI_STATUS ram_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ return memory_open(ctx, &ram_priv.m, ram_build_chunks, argc, argv);
+}
+
+static EFI_STATUS ram_read(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len)
+{
+ struct ram_priv *priv = ctx->private;
+ struct chunk_header *chunk;
+
+ /* First byte, send the sparse header */
+ if (ctx->cur == 0) {
+ if (*len < sizeof(priv->sheader))
+ return EFI_INVALID_PARAMETER;
+
+ *buf = (unsigned char *)&priv->sheader;
+ *len = sizeof(priv->sheader);
+ priv->m.cur = priv->m.cur_end = priv->m.start;
+ return EFI_SUCCESS;
+ }
+
+ /* Start new chunk */
+ if (priv->m.cur == priv->m.cur_end) {
+ if (priv->cur_chunk == priv->chunk_nb || *len < sizeof(*priv->chunks)) {
+ error(L"Invalid parameter in %a", __func__);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ chunk = &priv->chunks[priv->cur_chunk++];
+ *buf = (unsigned char *)chunk;
+ *len = sizeof(*chunk);
+ priv->m.cur_end = priv->m.cur + chunk->chunk_sz * EFI_PAGE_SIZE;
+ if (chunk->chunk_type != CHUNK_TYPE_RAW)
+ priv->m.cur = priv->m.cur_end;
+ return EFI_SUCCESS;
+ }
+
+ /* Continue to send the current memory region */
+ return memory_read_current(&priv->m, buf, len);
+}
+
+/* VMCore reader */
+#pragma pack(1)
+enum elf_ident {
+ EI_MAG0, /* File identification */
+ EI_MAG1,
+ EI_MAG2,
+ EI_MAG3,
+ EI_CLASS, /* File class */
+ EI_DATA, /* Data encoding */
+ EI_VERSION, /* File version */
+ EI_OSABI, /* OS/ABI identification */
+ EI_ABIVERSION, /* ABI version */
+ EI_PAD, /* Start of padding bytes */
+ EI_NIDENT = 16 /* Size of ident[] */
+};
+
+typedef struct elf64_hdr {
+ unsigned char ident[EI_NIDENT]; /* ELF identification */
+ UINT16 type; /* Object file type */
+ UINT16 machine; /* Machine type */
+ UINT32 version; /* Object file version */
+ EFI_PHYSICAL_ADDRESS entry; /* Entry point address */
+ UINT64 phoff; /* Program header offset */
+ UINT64 shoff; /* Section header offset */
+ UINT32 flags; /* Processor-specific flags */
+ UINT16 ehsize; /* ELF header size */
+ UINT16 phentsize; /* Size of program header entry */
+ UINT16 phnum; /* Number of program header entries */
+ UINT16 shentsize; /* Size of section header entry */
+ UINT16 shnum; /* Number of section header entries */
+ UINT16 shstrndx; /* Section name string table index */
+} elf64_hdr_t;
+
+enum ident_ei_class {
+ ELFCLASS32 = 1, /* 32-bit objects */
+ ELFCLASS64 /* 64-bit objects */
+};
+
+enum ident_ei_data {
+ ELFDATA2LSB = 1, /* Object file data structures are
+ little-endian */
+ ELFDATA2MSB = 2 /* Object-file data structures are
+ big-endian*/
+};
+
+enum elf_type {
+ ET_NONE, /* No file type */
+ ET_REL, /* Relocatable object file */
+ ET_EXEC, /* Executable file */
+ ET_DYN, /* Shared object file */
+ ET_CORE, /* Core file */
+ ET_LOOS = 0xfe00, /* Environment-specific use */
+ ET_HIOS = 0xfeff,
+ ET_LOPROC = 0xff00, /* Processor-specific use */
+ ET_HIPROC = 0xffff
+};
+
+enum elf_machine {
+ EM_NONE, /* No machine */
+ EM_X86_64 = 62 /* AMD x86-64 architecture */
+};
+
+typedef struct elf64_phdr
+{
+ UINT32 type; /* Type of segment */
+ UINT32 flags; /* Segment attributes */
+ UINT64 offset; /* Offset in file */
+ EFI_PHYSICAL_ADDRESS vaddr; /* Virtual address in memory */
+ EFI_PHYSICAL_ADDRESS paddr; /* Reserved */
+ UINT64 filesz; /* Size of segment in file */
+ UINT64 memsz; /* Size of segment in memory */
+ UINT64 align; /* Alignment of segment */
+} elf64_phdr_t;
+
+enum elfp_type {
+ PT_NULL, /* Unused entry */
+ PT_LOAD, /* Loadable segment */
+ PT_DYNAMIC, /* Dynamic linking tables */
+ PT_INTERP, /* Program interpreter path name */
+ PT_NOTE /* Note sections */
+};
+
+#define ELF_VERSION 1
+#define KERNEL_PAGE_FLAGS 7 /* Executable, writable and readable */
+/* The Linux kernel maps all the physical memory from this offset
+ (cf. https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt) */
+#define KERNEL_PAGE_OFFSET 0xffff880000000000
+
+static struct vmcore_priv {
+ memory_t m;
+
+ /* Current program header */
+ INTN cur_phdr;
+
+ /* ELF header and ELF program headers */
+ UINTN hdr_sz;
+ elf64_hdr_t hdr;
+ elf64_phdr_t phdr[MAX_MEMORY_REGION_NB];
+} vmcore_priv = {
+ .hdr = {
+ .ident = {
+ [EI_MAG0] = 0x7f,
+ [EI_MAG1] = 'E',
+ [EI_MAG2] = 'L',
+ [EI_MAG3] = 'F',
+ [EI_CLASS] = ELFCLASS64,
+ [EI_DATA] = ELFDATA2LSB,
+ [EI_VERSION] = ELF_VERSION
+ },
+ .type = ET_CORE,
+ .machine = EM_X86_64,
+ .version = ELF_VERSION,
+ .phoff = sizeof(elf64_hdr_t),
+ .ehsize = sizeof(elf64_hdr_t),
+ .phentsize = sizeof(elf64_phdr_t)
+ },
+ .phdr = {
+ [0] = { .type = PT_NOTE } /* First program header is
+ reserved to notes */
+ }
+};
+#pragma pack()
+
+static EFI_STATUS vmcore_build_header(reader_ctx_t *ctx, void *priv_p)
+
+{
+ struct vmcore_priv *priv = priv_p;
+ UINTN i;
+ EFI_MEMORY_DESCRIPTOR *entry;
+ elf64_phdr_t *phdr;
+ UINT8 *entries = priv->m.memmap;
+ EFI_PHYSICAL_ADDRESS start, end;
+ UINT64 length;
+
+ ctx->cur = 0;
+ priv->hdr_sz = sizeof(priv->hdr) + sizeof(priv->phdr[0]);
+ priv->hdr.phnum = 1;
+
+ for (i = 0; i < priv->m.nr_descr; entries += priv->m.descr_sz, i++) {
+ entry = (EFI_MEMORY_DESCRIPTOR *)entries;
+ if (entry->Type != EfiConventionalMemory)
+ continue;
+
+ start = entry->PhysicalStart;
+ length = entry->NumberOfPages * EFI_PAGE_SIZE;
+ end = start + length;
+
+ if (end <= priv->m.start)
+ continue;
+
+ if (start < priv->m.start) {
+ length -= priv->m.start - start;
+ start = priv->m.start;
+ }
+
+ if (priv->m.end && end > priv->m.end) {
+ length -= end - priv->m.end;
+ end = priv->m.end;
+ }
+
+ priv->hdr.phnum++;
+ if (priv->hdr.phnum == ARRAY_SIZE(priv->phdr)) {
+ error(L"Not enough program headers");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ phdr = &priv->phdr[priv->hdr.phnum - 1];
+ phdr->type = PT_LOAD;
+ phdr->paddr = start;
+ phdr->vaddr = KERNEL_PAGE_OFFSET + start;
+ phdr->filesz = phdr->memsz = length;
+ phdr->flags = KERNEL_PAGE_FLAGS;
+
+ priv->hdr_sz += sizeof(*phdr);
+ }
+
+ if (priv->hdr.phnum == 1) {
+ error(L"No memory region to dump found");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ctx->len = priv->hdr_sz;
+ for (i = 1; i < priv->hdr.phnum; i++) {
+ phdr = &priv->phdr[i];
+ phdr->offset = ctx->len;
+ ctx->len += phdr->memsz;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS vmcore_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ return memory_open(ctx, &vmcore_priv.m, vmcore_build_header, argc, argv);
+}
+
+static EFI_STATUS vmcore_read(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len)
+{
+ struct vmcore_priv *priv = ctx->private;
+
+ /* First byte, send the ELF headers */
+ if (ctx->cur == 0) {
+ if (*len < priv->hdr_sz)
+ return EFI_INVALID_PARAMETER;
+
+ *buf = (unsigned char *)&priv->hdr;
+ *len = priv->hdr_sz;
+
+ priv->m.cur = priv->m.cur_end = 0;
+ priv->cur_phdr = 0;
+ return EFI_SUCCESS;
+ }
+
+ /* Start new memory region */
+ if (priv->m.cur == priv->m.cur_end) {
+ if (priv->cur_phdr == priv->hdr.phnum - 1) {
+ error(L"Invalid parameter in %a", __func__);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ priv->cur_phdr++;
+ priv->m.cur = priv->phdr[priv->cur_phdr].paddr;
+ priv->m.cur_end = priv->m.cur + priv->phdr[priv->cur_phdr].memsz;
+ }
+
+ /* Continue to send the current memory region */
+ return memory_read_current(&priv->m, buf, len);
+}
+
+/* Partition reader */
+#define PART_READER_BUF_SIZE (10 * 1024 * 1024)
+
+struct part_priv {
+ struct gpt_partition_interface gparti;
+ BOOLEAN need_more_data;
+ unsigned char buf[PART_READER_BUF_SIZE];
+ UINTN buf_cur;
+ UINTN buf_len;
+ UINT64 offset;
+};
+
+static EFI_STATUS _part_open(reader_ctx_t *ctx, UINTN argc, char **argv, logical_unit_t log_unit)
+{
+ EFI_STATUS ret = EFI_SUCCESS;
+ struct gpt_partition_interface *gparti;
+ struct part_priv *priv;
+ CHAR16 *partname;
+ UINT64 length;
+
+ if (argc < 1 || argc > 3)
+ return EFI_INVALID_PARAMETER;
+
+ priv = ctx->private = AllocatePool(sizeof(*priv));
+ if (!priv)
+ return EFI_OUT_OF_RESOURCES;
+
+
+ partname = stra_to_str((CHAR8 *)argv[0]);
+ if (!partname) {
+ error(L"Failed to convert partition name to CHAR16");
+ goto err;
+ }
+
+ gparti = &priv->gparti;
+ ret = gpt_get_partition_by_label(slot_label(partname), gparti, log_unit);
+ FreePool(partname);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Cannot access partition '%a'", argv[0]);
+ goto err;
+ }
+
+ priv->offset = gparti->part.starting_lba * gparti->bio->Media->BlockSize;
+ length = (gparti->part.ending_lba + 1 - gparti->part.starting_lba) *
+ gparti->bio->Media->BlockSize;
+
+ ctx->cur = 0;
+ ctx->len = length;
+
+ if (argc > 1) {
+ ctx->cur = strtoull(argv[1], NULL, 16);
+ if (ctx->cur >= length)
+ goto err;
+ }
+
+ if (argc == 3) {
+ ctx->len = strtoull(argv[2], NULL, 16);
+ if (ctx->len == 0 || ctx->len > length || ctx->cur >= length - ctx->len)
+ goto err;
+ }
+
+ priv->buf_cur = 0;
+ priv->buf_len = 0;
+ priv->need_more_data = TRUE;
+
+ return EFI_SUCCESS;
+
+err:
+ FreePool(priv);
+ return EFI_ERROR(ret) ? ret : EFI_INVALID_PARAMETER;
+}
+
+static EFI_STATUS part_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ return _part_open(ctx, argc, argv, LOGICAL_UNIT_USER);
+}
+
+static EFI_STATUS factory_part_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ return _part_open(ctx, argc, argv, LOGICAL_UNIT_FACTORY);
+}
+
+static EFI_STATUS part_read(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len)
+{
+ EFI_STATUS ret;
+ struct part_priv *priv = ctx->private;
+
+ if (priv->need_more_data) {
+ priv->buf_len = min(sizeof(priv->buf), ctx->len - ctx->cur);
+ ret = uefi_call_wrapper(priv->gparti.dio->ReadDisk, 5, priv->gparti.dio,
+ priv->gparti.bio->Media->MediaId,
+ priv->offset + ctx->cur, priv->buf_len, priv->buf);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to read partition");
+ return ret;
+ }
+
+ priv->need_more_data = FALSE;
+ priv->buf_cur = 0;
+ }
+
+ *len = min(*len, priv->buf_len - priv->buf_cur);
+ *buf = priv->buf + priv->buf_cur;
+ priv->buf_cur += *len;
+ if (priv->buf_cur == priv->buf_len)
+ priv->need_more_data = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/* ACPI table reader */
+static EFI_STATUS acpi_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ EFI_STATUS ret;
+ struct ACPI_DESC_HEADER *table;
+
+ if (argc != 1)
+ return EFI_INVALID_PARAMETER;
+
+ ret = get_acpi_table((CHAR8 *)argv[0], (VOID **)&table);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Cannot access ACPI table %a", argv[0]);
+ return ret;
+ }
+
+ ctx->private = table;
+ ctx->cur = 0;
+ ctx->len = table->length;
+
+ return EFI_SUCCESS;
+}
+
+/* EFI variable reader */
+static EFI_STATUS efivar_find(CHAR16 *varname, EFI_GUID *guid_p)
+{
+ EFI_STATUS ret;
+ UINTN bufsize, namesize;
+ CHAR16 *name;
+ EFI_GUID guid;
+ BOOLEAN found = FALSE;
+ EFI_GUID found_guid;
+
+ bufsize = 64; /* Initial size large enough to handle
+ usual variable names length and
+ avoid the ReallocatePool as much as
+ possible. */
+ name = AllocateZeroPool(bufsize);
+ if (!name) {
+ error(L"Failed to re-allocate variable name buffer");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (;;) {
+ namesize = bufsize;
+ ret = uefi_call_wrapper(RT->GetNextVariableName, 3, &namesize,
+ name, &guid);
+ if (ret == EFI_NOT_FOUND) {
+ ret = EFI_SUCCESS;
+ break;
+ }
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ name = ReallocatePool(name, bufsize, namesize);
+ if (!name) {
+ error(L"Failed to re-allocate variable name buffer");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ bufsize = namesize;
+ continue;
+ }
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"GetNextVariableName failed");
+ break;
+ }
+
+ if (!StrCmp(name, varname)) {
+ if (found) {
+ error(L"Found 2 variables named %s", varname);
+ ret = EFI_UNSUPPORTED;
+ break;
+ }
+ found = TRUE;
+ found_guid = guid;
+ }
+ }
+
+ FreePool(name);
+
+ if (EFI_ERROR(ret))
+ return ret;
+
+ if (!found)
+ return EFI_NOT_FOUND;
+
+ *guid_p = found_guid;
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS efivar_open(reader_ctx_t *ctx, UINTN argc, char **argv)
+{
+ EFI_STATUS ret;
+ UINT32 flags;
+ UINTN size;
+ CHAR16 *varname = NULL;
+ EFI_GUID guid;
+
+ if (argc != 1 && argc != 2)
+ return EFI_INVALID_PARAMETER;
+
+ if (argc == 2) {
+ ret = stra_to_guid(argv[1], &guid);
+ if (EFI_ERROR(ret))
+ return ret;
+ }
+
+ varname = stra_to_str((CHAR8 *)argv[0]);
+ if (!varname)
+ return EFI_OUT_OF_RESOURCES;
+
+ if (argc == 1) {
+ ret = efivar_find(varname, &guid);
+ if (EFI_ERROR(ret))
+ goto exit;
+ }
+
+ ret = get_efi_variable(&guid, varname, &size, &ctx->private, &flags);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Cannot access EFI variable %a %g", argv[0], &guid);
+ goto exit;
+ }
+
+ ctx->cur = 0;
+ ctx->len = size;
+
+exit:
+ FreePool(varname);
+ return ret;
+}
+
+/* MBR */
+static EFI_STATUS mbr_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ struct gpt_partition_interface gparti;
+ EFI_STATUS ret;
+
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ ret = gpt_get_root_disk(&gparti, LOGICAL_UNIT_USER);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get disk information");
+ return ret;
+ }
+
+ ctx->private = AllocatePool(MBR_CODE_SIZE);
+ if (!ctx->private) {
+ error(L"Failed to allocate MBR buffer");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ret = uefi_call_wrapper(gparti.dio->ReadDisk, 5, gparti.dio,
+ gparti.bio->Media->MediaId,
+ 0, MBR_CODE_SIZE, ctx->private);
+ if (EFI_ERROR(ret)) {
+ FreePool(ctx->private);
+ efi_perror(ret, L"Failed to read partition");
+ return ret;
+ }
+
+ ctx->len = MBR_CODE_SIZE;
+ ctx->cur = 0;
+
+ return EFI_SUCCESS;
+}
+
+/* GPT-HEADER and GPT-FACTORY-HEADER */
+static EFI_STATUS _gpt_header_open(reader_ctx_t *ctx, logical_unit_t log_unit)
+{
+ UINTN size;
+ EFI_STATUS ret;
+
+ ret = gpt_get_header((struct gpt_header **)&ctx->private, &size, log_unit);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get GPT header");
+ return ret;
+ }
+
+ ctx->len = size;
+ ctx->cur = 0;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS gpt_header_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ return _gpt_header_open(ctx, LOGICAL_UNIT_USER);
+}
+
+static EFI_STATUS gpt_factory_header_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ return _gpt_header_open(ctx, LOGICAL_UNIT_FACTORY);
+}
+
+/* GPT-PARTS and GPT-FACTORY-PARTS */
+static EFI_STATUS _gpt_parts_open(reader_ctx_t *ctx, logical_unit_t log_unit)
+{
+ UINTN size;
+ EFI_STATUS ret;
+
+ ret = gpt_get_partitions((struct gpt_partition **)&ctx->private,
+ &size, log_unit);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get GPT partition table");
+ return ret;
+ }
+
+ ctx->len = size;
+ ctx->cur = 0;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS gpt_parts_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ return _gpt_parts_open(ctx, LOGICAL_UNIT_USER);
+}
+
+static EFI_STATUS gpt_factory_parts_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ return _gpt_parts_open(ctx, LOGICAL_UNIT_FACTORY);
+}
+
+/* BERT Region reader */
+static const char BERR_MAGIC[4] = "BERR"; /* Boot Error Record Region */
+
+static EFI_STATUS bert_region_open(reader_ctx_t *ctx, UINTN argc,
+ __attribute__((__unused__)) char **argv)
+{
+ EFI_STATUS ret;
+ struct BERT_TABLE *bert_table;
+
+ if (argc != 0)
+ return EFI_INVALID_PARAMETER;
+
+ ret = get_acpi_table((CHAR8 *)"BERT", (VOID **)&bert_table);
+ if (ret == EFI_NOT_FOUND) {
+ debug(L"BERT ACPI table not available");
+ return ret;
+ }
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Cannot access ACPI table BERT");
+ return ret;
+ }
+
+ ctx->private = bert_table;
+ ctx->cur = 0;
+ ctx->len = sizeof(BERR_MAGIC) + bert_table->region_length;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS bert_region_read(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len)
+{
+ struct BERT_TABLE *bert_table = ctx->private;
+
+ /* First byte, send the BERR magic */
+ if (ctx->cur == 0) {
+ if (*len < sizeof(BERR_MAGIC))
+ return EFI_INVALID_PARAMETER;
+
+ *buf = (unsigned char *)BERR_MAGIC;
+ *len = sizeof(BERR_MAGIC);
+ return EFI_SUCCESS;
+ }
+
+ *len = min(*len, ctx->len - ctx->cur);
+ *buf = (unsigned char *)(UINTN)bert_table->region + ctx->cur - sizeof(BERR_MAGIC);
+
+ return EFI_SUCCESS;
+}
+
+/* Interface */
+static EFI_STATUS read_from_private(reader_ctx_t *ctx, unsigned char **buf,
+ __attribute__((__unused__)) UINT64 *len)
+{
+ *buf = (unsigned char *)ctx->private + ctx->cur;
+ return EFI_SUCCESS;
+}
+
+static void free_private(reader_ctx_t *ctx)
+{
+ FreePool(ctx->private);
+}
+
+struct reader {
+ const char *name;
+ EFI_STATUS (*open)(reader_ctx_t *ctx, UINTN argc, char **argv);
+ EFI_STATUS (*read)(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len);
+ void (*close)(reader_ctx_t *ctx);
+} READERS[] = {
+ { "ram", ram_open, ram_read, memory_close },
+ { "vmcore", vmcore_open, vmcore_read, memory_close },
+ { "acpi", acpi_open, read_from_private, NULL },
+ { "part", part_open, part_read, free_private },
+ { "factory-part", factory_part_open, part_read, free_private },
+ { "efivar", efivar_open, read_from_private, free_private },
+ { "mbr", mbr_open, read_from_private, free_private },
+ { "gpt-header", gpt_header_open, read_from_private, free_private },
+ { "gpt-parts", gpt_parts_open, read_from_private, free_private },
+ { "gpt-factory-header", gpt_factory_header_open, read_from_private, free_private },
+ { "gpt-factory-parts", gpt_factory_parts_open, read_from_private, free_private },
+ { "bert-region", bert_region_open, bert_region_read, NULL }
+};
+
+#define MAX_ARGS 8
+#define READER_DELIMITER ":"
+
+EFI_STATUS reader_open(reader_ctx_t *ctx, char *args)
+{
+ UINTN argc;
+ UINTN i;
+ char *argv[MAX_ARGS], *token, *saveptr;
+ struct reader *reader = NULL;
+
+ if (!args || !ctx)
+ return EFI_INVALID_PARAMETER;
+
+ argv[0] = strtok_r((char *)args, READER_DELIMITER, &saveptr);
+ if (!argv[0])
+ return EFI_INVALID_PARAMETER;
+
+ for (argc = 1; argc < ARRAY_SIZE(argv); argc++) {
+ token = strtok_r(NULL, READER_DELIMITER, &saveptr);
+ if (!token)
+ break;
+ argv[argc] = token;
+ }
+
+ if (token && strtok_r(NULL, READER_DELIMITER, &saveptr))
+ return EFI_INVALID_PARAMETER;
+
+ for (i = 0; i < ARRAY_SIZE(READERS); i++)
+ if (!strcmp((CHAR8 *)argv[0], (CHAR8 *)READERS[i].name)) {
+ reader = &READERS[i];
+ break;
+ }
+
+ if (!reader)
+ return EFI_UNSUPPORTED;
+
+ ctx->reader = reader;
+ return reader->open(ctx, argc - 1, argv + 1);
+}
+
+EFI_STATUS reader_read(reader_ctx_t *ctx, unsigned char **buf, UINT64 *len)
+{
+ EFI_STATUS ret;
+
+ if (!ctx || !len || !*len || !ctx->reader)
+ return EFI_INVALID_PARAMETER;
+
+ *len = min(*len, ctx->len - ctx->cur);
+ if (*len == 0)
+ return EFI_SUCCESS;
+
+ ret = ctx->reader->read(ctx, buf, len);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ ctx->cur += *len;
+
+ return EFI_SUCCESS;
+}
+
+void reader_close(reader_ctx_t *ctx)
+{
+ if (!ctx || !ctx->reader)
+ return;
+
+ if (ctx->reader->close)
+ ctx->reader->close(ctx);
+}
diff --git a/libadb/reader.h b/libadb/reader.h
new file mode 100644
index 00000000..78f924e4
--- /dev/null
+++ b/libadb/reader.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _READER_H_
+#define _READER_H_
+
+#include
+
+typedef struct reader_context {
+ struct reader *reader;
+ UINT64 cur;
+ UINT64 len;
+ void *private;
+} reader_ctx_t;
+
+EFI_STATUS reader_open(reader_ctx_t *reader, char *args);
+EFI_STATUS reader_read(reader_ctx_t *reader, unsigned char **buf, UINT64 *len);
+void reader_close(reader_ctx_t *reader);
+
+#endif /* _READER_H_ */
diff --git a/libadb/reboot_service.c b/libadb/reboot_service.c
new file mode 100644
index 00000000..9a3c4d63
--- /dev/null
+++ b/libadb/reboot_service.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+
+#include "adb_socket.h"
+#include "service.h"
+
+static EFI_STATUS reboot_service_open(const char *arg, void **context)
+{
+ CHAR16 *target = NULL;
+
+ if (!arg || !context)
+ return EFI_INVALID_PARAMETER;
+
+ target = stra_to_str((CHAR8 *)arg);
+ if (!target) {
+ error(L"Failed to convert reboot target to CHAR16");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Sanity check */
+ if (name_to_boot_target(target) == UNKNOWN_TARGET) {
+ error(L"Unknown boot target %s", target);
+ FreePool(target);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *context = target;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS reboot_service_ready(asock_t s)
+{
+ if (!asock_context(s))
+ return EFI_INVALID_PARAMETER;
+
+ adb_set_boot_target(name_to_boot_target(asock_context(s)));
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS reboot_service_close(asock_t s)
+{
+ if (!asock_context(s))
+ return EFI_INVALID_PARAMETER;
+
+ FreePool(asock_context(s));
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS reboot_service_okay(__attribute__((__unused__)) asock_t s)
+{
+ error(L"reboot_service does not support OKAY message");
+ return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS reboot_service_read(__attribute__((__unused__)) asock_t s,
+ __attribute__((__unused__)) unsigned char *data,
+ __attribute__((__unused__)) UINT32 length)
+{
+ error(L"reboot_service does not support READ message");
+ return EFI_UNSUPPORTED;
+}
+
+service_t reboot_service = {
+ .name = "reboot",
+ .open = reboot_service_open,
+ .ready = reboot_service_ready,
+ .close = reboot_service_close,
+ .okay = reboot_service_okay,
+ .read = reboot_service_read
+};
diff --git a/libadb/service.h b/libadb/service.h
new file mode 100644
index 00000000..1bc3d922
--- /dev/null
+++ b/libadb/service.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SERVICE_H_
+#define _SERVICE_H_
+
+#include
+#include
+
+#include "adb_socket.h"
+
+/* adb service interface */
+typedef struct service {
+ const char *name;
+ EFI_STATUS (*open)(const char *arg, void **context);
+ EFI_STATUS (*ready)(asock_t s);
+ EFI_STATUS (*close)(asock_t s);
+ EFI_STATUS (*okay)(asock_t s);
+ EFI_STATUS (*read)(asock_t s, unsigned char *data, UINT32 length);
+} service_t;
+
+extern service_t sync_service;
+extern service_t reboot_service;
+
+#endif /* _SERVICE_H_ */
diff --git a/libadb/sync_service.c b/libadb/sync_service.c
new file mode 100644
index 00000000..6758cd07
--- /dev/null
+++ b/libadb/sync_service.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Jeremy Compostella
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+
+#include "adb_socket.h"
+#include "service.h"
+#include "reader.h"
+
+#define ID_STAT MKID('S','T','A','T')
+#define ID_RECV MKID('R','E','C','V')
+#define ID_DATA MKID('D','A','T','A')
+#define ID_DONE MKID('D','O','N','E')
+#define ID_QUIT MKID('Q','U','I','T')
+
+typedef enum state {
+ FREE,
+ ESTABLISHED,
+ STAT,
+ RECV,
+ SENDING_DATA,
+ CLOSED
+} state_t;
+
+typedef union {
+ UINT32 id;
+ struct {
+ UINT32 id;
+ UINT32 namelen;
+ } req;
+ struct {
+ UINT32 id;
+ UINT32 mode;
+ UINT32 size;
+ UINT32 time;
+ } stat;
+ struct {
+ UINT32 id;
+ UINT32 size;
+ } data;
+} sync_msg_t;
+
+#define SYNC_DATA_MAX (64 * 1024)
+
+typedef struct {
+ state_t state;
+ reader_ctx_t reader_ctx;
+ BOOLEAN need_more_data;
+ unsigned char *buf;
+ UINT64 buf_cur;
+ UINT64 buf_len;
+ UINT64 sent;
+} sync_ctx_t;
+static sync_ctx_t CONTEXTS[MAX_ADB_SOCKET];
+
+static EFI_STATUS sync_service_open(const char *arg, void **ctx_p)
+{
+ sync_ctx_t *ctx = NULL;
+ UINTN i;
+
+ if (!arg || !ctx_p || strcmp((CHAR8 *)arg, (CHAR8 *)""))
+ return EFI_INVALID_PARAMETER;
+
+ for (i = 0; i < ARRAY_SIZE(CONTEXTS); i++)
+ if (CONTEXTS[i].state == FREE)
+ ctx = &CONTEXTS[i];
+
+ if (!ctx) {
+ error(L"Failed to allocate sync service context structure");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ctx->state = ESTABLISHED;
+
+ *ctx_p = ctx;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS sync_service_ready(__attribute__((__unused__)) asock_t s)
+{
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS sync_service_close(asock_t s)
+{
+ sync_ctx_t *ctx = asock_context(s);
+
+ if (!ctx)
+ return EFI_INVALID_PARAMETER;
+
+ if (ctx->state == SENDING_DATA)
+ reader_close(&ctx->reader_ctx);
+
+ ctx->state = FREE;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS send_done(asock_t s, sync_ctx_t *ctx)
+{
+ sync_msg_t msg;
+
+ reader_close(&ctx->reader_ctx);
+
+ ctx->state = ESTABLISHED;
+
+ msg.req.id = ID_DONE;
+ msg.req.namelen = 0;
+ return asock_write(s, (unsigned char *)&msg, sizeof(msg.req));
+}
+
+#define DATA_PROGRESS_THRESHOLD (5 * 1024 * 1024)
+
+static EFI_STATUS send_more_data(asock_t s, sync_ctx_t *ctx)
+{
+ EFI_STATUS ret;
+ UINT32 sent;
+ sync_msg_t msg;
+
+ /* Need to load more data. */
+ if (ctx->need_more_data) {
+ ctx->buf_len = SYNC_DATA_MAX;
+
+ ret = reader_read(&ctx->reader_ctx, &ctx->buf, &ctx->buf_len);
+ if (EFI_ERROR(ret))
+ return ret;
+ if (ctx->buf_len == 0) /* No more data to send. */
+ return send_done(s, ctx);
+
+ msg.data.id = ID_DATA;
+ msg.data.size = ctx->buf_len;
+ ctx->buf_cur = 0;
+ ctx->need_more_data = FALSE;
+
+ return asock_write(s, (unsigned char *)&msg, sizeof(msg.data));
+ }
+
+ sent = min((UINTN)adb_max_payload, ctx->buf_len - ctx->buf_cur);
+ ret = asock_write(s, ctx->buf + ctx->buf_cur, sent);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ ctx->buf_cur = ctx->buf_cur + sent;
+ if (ctx->buf_cur == ctx->buf_len)
+ ctx->need_more_data = TRUE;
+
+ ctx->sent += sent;
+ if (ctx->sent >= DATA_PROGRESS_THRESHOLD &&
+ ctx->sent % DATA_PROGRESS_THRESHOLD < sent)
+ debug(L"%d MB have been sent", ctx->sent / 1024 / 1024);
+
+ return ret;
+}
+
+static EFI_STATUS sync_service_okay(asock_t s)
+{
+ EFI_STATUS ret = EFI_SUCCESS;
+ sync_ctx_t *ctx = asock_context(s);
+
+ if (!ctx)
+ return EFI_INVALID_PARAMETER;
+
+ if (ctx->state == SENDING_DATA)
+ ret = send_more_data(s, ctx);
+
+ return ret;
+}
+
+static EFI_STATUS sync_service_reader_open(sync_ctx_t *ctx, unsigned char *data, UINT32 length)
+{
+ char path[length + 1];
+
+ memcpy(path, data, length);
+ path[length] = '\0';
+
+ return reader_open(&ctx->reader_ctx, path);
+}
+
+#define REGULAR_FILE_STAT_MODE 0x000081b6
+
+static EFI_STATUS sync_service_stat(asock_t s, sync_ctx_t *ctx, unsigned char *data, UINT32 length)
+{
+ EFI_STATUS ret, write_ret;
+ sync_msg_t msg;
+ EFI_TIME now;
+
+ asock_send_okay(s);
+
+ ctx->state = ESTABLISHED;
+
+ memset(&msg, 0, sizeof(msg.stat));
+ msg.stat.id = ID_STAT;
+
+ ret = sync_service_reader_open(ctx, data, length);
+ if (EFI_ERROR(ret))
+ goto fail;
+
+ reader_close(&ctx->reader_ctx);
+
+ msg.stat.mode = REGULAR_FILE_STAT_MODE;
+
+ ret = uefi_call_wrapper(RT->GetTime, 2, &now, NULL);
+ if (EFI_ERROR(ret)) {
+ efi_perror(ret, L"Failed to get the current time");
+ msg.stat.time = 0;
+ } else
+ msg.stat.time = efi_time_to_ctime(&now);
+
+fail:
+ write_ret = asock_write(s, (unsigned char *)&msg, sizeof(msg.stat));
+ return EFI_ERROR(ret) ? ret : write_ret;
+}
+
+static EFI_STATUS sync_service_recv(asock_t s, sync_ctx_t *ctx, unsigned char *data, UINT32 length)
+{
+ EFI_STATUS ret;
+
+ ret = asock_send_okay(s);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ ret = sync_service_reader_open(ctx, data, length);
+ if (EFI_ERROR(ret))
+ return ret;
+
+ ctx->sent = 0;
+ ctx->state = SENDING_DATA;
+ ctx->need_more_data = TRUE;
+
+ return send_more_data(s, ctx);
+}
+
+static EFI_STATUS sync_service_read(asock_t s, unsigned char *data, UINT32 length)
+{
+ EFI_STATUS ret;
+ sync_msg_t *msg = (sync_msg_t *) data;
+ sync_ctx_t *ctx = asock_context(s);
+
+ if (!ctx) {
+ error(L"sync service: invalid context");
+ goto fail;
+ }
+
+ switch (ctx->state) {
+ case ESTABLISHED:
+ if (length < sizeof(msg->req)) {
+ error(L"sync service: message is too short");
+ goto fail;
+ }
+ if (msg->id == ID_STAT) {
+ ctx->state = STAT;
+ if (length == sizeof(msg->req))
+ return asock_send_okay(s);
+ return sync_service_stat(s, ctx, data + sizeof(msg->req),
+ msg->req.namelen);
+ }
+ if (msg->id == ID_RECV) {
+ ctx->state = RECV;
+ if (length == sizeof(msg->req))
+ return asock_send_okay(s);
+ return sync_service_recv(s, ctx, data + sizeof(msg->req),
+ msg->req.namelen);
+ }
+ if (msg->id == ID_QUIT)
+ return asock_send_close(s);
+ error(L"sync service: unexpected message 0x%08X", msg->id);
+ goto fail;
+
+ case STAT:
+ return sync_service_stat(s, ctx, data, length);
+
+ case RECV:
+ return sync_service_recv(s, ctx, data, length);
+
+ default:
+ error(L"sync service: unexpected state %d", ctx->state);
+ goto fail;
+ }
+
+fail:
+ ret = asock_send_close(s);
+ return ret ? ret : EFI_INVALID_PARAMETER;
+}
+
+service_t sync_service = {
+ .name = "sync",
+ .open = sync_service_open,
+ .ready = sync_service_ready,
+ .close = sync_service_close,
+ .okay = sync_service_okay,
+ .read = sync_service_read
+};
diff --git a/libedk2_tpm/Android.mk b/libedk2_tpm/Android.mk
new file mode 100644
index 00000000..234e8ef6
--- /dev/null
+++ b/libedk2_tpm/Android.mk
@@ -0,0 +1,31 @@
+LIBEDK2_LOCAL_PATH := $(call my-dir)
+include $(call all-subdir-makefiles)
+LOCAL_PATH := $(LIBEDK2_LOCAL_PATH)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libedk2_tpm
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../include/libkernelflinger
+LOCAL_CFLAGS := -Wall -Wextra -Werror -mrdrnd \
+ -DTARGET_BOOTLOADER_BOARD_NAME=\"$(TARGET_BOOTLOADER_BOARD_NAME)\"
+LOCAL_STATIC_LIBRARIES := libgnuefi \
+ libefi
+
+LOCAL_SRC_FILES := \
+ Tpm2NVStorage.c \
+ Tpm2Random.c \
+ Tpm2DeviceLib.c \
+ Tpm2Help.c \
+ Tpm2Context.c \
+ Tpm2EnhancedAuthorization.c \
+ Tpm2Hierarchy.c \
+ Tpm2Integrity.c \
+ Tpm2Sequences.c \
+ Tpm2Session.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../include/libkernelflinger \
+ $(res_intermediates)
+
+include $(BUILD_EFI_STATIC_LIBRARY)
diff --git a/libedk2_tpm/README b/libedk2_tpm/README
new file mode 100644
index 00000000..e7b40b91
--- /dev/null
+++ b/libedk2_tpm/README
@@ -0,0 +1,8 @@
+EDK2 Functionality
+
+We use the edk2 library for creating and managing the TPM
+entities in kernelflinger. The necessary TPM functions are
+ported to kernelflinger/edk2. The Tcg2 protocol headers are
+ported to edk2/include.
+
+Github link : https://github.com/tianocore/edk2
\ No newline at end of file
diff --git a/libedk2_tpm/Tpm2Capability.c b/libedk2_tpm/Tpm2Capability.c
new file mode 100644
index 00000000..d94cf180
--- /dev/null
+++ b/libedk2_tpm/Tpm2Capability.c
@@ -0,0 +1,739 @@
+/** @file
+ Implement TPM2 Capability related command.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPM_CAP Capability;
+ UINT32 Property;
+ UINT32 PropertyCount;
+} TPM2_GET_CAPABILITY_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPMI_YES_NO MoreData;
+ TPMS_CAPABILITY_DATA CapabilityData;
+} TPM2_GET_CAPABILITY_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMT_PUBLIC_PARMS Parameters;
+} TPM2_TEST_PARMS_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_TEST_PARMS_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command returns various information regarding the TPM and its current state.
+
+ The capability parameter determines the category of data returned. The property parameter
+ selects the first value of the selected category to be returned. If there is no property
+ that corresponds to the value of property, the next higher value is returned, if it exists.
+ The moreData parameter will have a value of YES if there are more values of the requested
+ type that were not returned.
+ If no next capability exists, the TPM will return a zero-length list and moreData will have
+ a value of NO.
+
+ NOTE:
+ To simplify this function, leave returned CapabilityData for caller to unpack since there are
+ many capability categories and only few categories will be used in firmware. It means the caller
+ need swap the byte order for the feilds in CapabilityData.
+
+ @param[in] Capability Group selection; determines the format of the response.
+ @param[in] Property Further definition of information.
+ @param[in] PropertyCount Number of properties of the indicated type to return.
+ @param[out] MoreData Flag to indicate if there are more values of this type.
+ @param[out] CapabilityData The capability data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapability (
+ IN TPM_CAP Capability,
+ IN UINT32 Property,
+ IN UINT32 PropertyCount,
+ OUT TPMI_YES_NO *MoreData,
+ OUT TPMS_CAPABILITY_DATA *CapabilityData
+ )
+{
+ EFI_STATUS Status;
+ TPM2_GET_CAPABILITY_COMMAND SendBuffer;
+ TPM2_GET_CAPABILITY_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_GetCapability);
+
+ SendBuffer.Capability = SwapBytes32 (Capability);
+ SendBuffer.Property = SwapBytes32 (Property);
+ SendBuffer.PropertyCount = SwapBytes32 (PropertyCount);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT8)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ *MoreData = RecvBuffer.MoreData;
+ //
+ // Does not unpack all possiable property here, the caller should unpack it and note the byte order.
+ //
+ CopyMem (CapabilityData, &RecvBuffer.CapabilityData, RecvBufferSize - sizeof (TPM2_RESPONSE_HEADER) - sizeof (UINT8));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM Family.
+
+ This function parse the value got from TPM2_GetCapability and return the Family.
+
+ @param[out] Family The Family of TPM. (a 4-octet character string)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFamily (
+ OUT CHAR8 *Family
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FAMILY_INDICATOR,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (Family, &TpmCap.data.tpmProperties.tpmProperty->value, 4);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM manufacture ID.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM manufacture ID.
+
+ @param[out] ManufactureId The manufacture ID of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityManufactureID (
+ OUT UINT32 *ManufactureId
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MANUFACTURER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *ManufactureId = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM FirmwareVersion.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM FirmwareVersion.
+
+ @param[out] FirmwareVersion1 The FirmwareVersion1.
+ @param[out] FirmwareVersion2 The FirmwareVersion2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFirmwareVersion (
+ OUT UINT32 *FirmwareVersion1,
+ OUT UINT32 *FirmwareVersion2
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FIRMWARE_VERSION_1,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *FirmwareVersion1 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FIRMWARE_VERSION_2,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *FirmwareVersion2 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of the maximum value for commandSize and responseSize in a command.
+
+ This function parse the value got from TPM2_GetCapability and return the max command size and response size
+
+ @param[out] MaxCommandSize The maximum value for commandSize in a command.
+ @param[out] MaxResponseSize The maximum value for responseSize in a command.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityMaxCommandResponseSize (
+ OUT UINT32 *MaxCommandSize,
+ OUT UINT32 *MaxResponseSize
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MAX_COMMAND_SIZE,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MaxCommandSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MAX_RESPONSE_SIZE,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MaxResponseSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns Returns a list of TPMS_ALG_PROPERTIES. Each entry is an
+ algorithm ID and a set of properties of the algorithm.
+
+ This function parse the value got from TPM2_GetCapability and return the list.
+
+ @param[out] AlgList List of algorithm.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilitySupportedAlg (
+ OUT TPML_ALG_PROPERTY *AlgList
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_ALGS,
+ 1,
+ MAX_CAP_ALGS,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (AlgList, &TpmCap.data.algorithms, sizeof (TPML_ALG_PROPERTY));
+
+ AlgList->count = SwapBytes32 (AlgList->count);
+ for (Index = 0; Index < AlgList->count; Index++) {
+ AlgList->algProperties[Index].alg = SwapBytes16 (AlgList->algProperties[Index].alg);
+ WriteUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties)));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM LockoutCounter.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutCounter.
+
+ @param[out] LockoutCounter The LockoutCounter of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutCounter (
+ OUT UINT32 *LockoutCounter
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_LOCKOUT_COUNTER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *LockoutCounter = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM LockoutInterval.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutInterval.
+
+ @param[out] LockoutInterval The LockoutInterval of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutInterval (
+ OUT UINT32 *LockoutInterval
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_LOCKOUT_INTERVAL,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *LockoutInterval = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM InputBufferSize.
+
+ This function parse the value got from TPM2_GetCapability and return the InputBufferSize.
+
+ @param[out] InputBufferSize The InputBufferSize of TPM.
+ the maximum size of a parameter (typically, a TPM2B_MAX_BUFFER)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityInputBufferSize (
+ OUT UINT32 *InputBufferSize
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_INPUT_BUFFER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *InputBufferSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM PCRs.
+
+ This function parse the value got from TPM2_GetCapability and return the PcrSelection.
+
+ @param[out] Pcrs The Pcr Selection
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityPcrs (
+ OUT TPML_PCR_SELECTION *Pcrs
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_PCRS,
+ 0,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Pcrs->count = SwapBytes32 (TpmCap.data.assignedPCR.count);
+ for (Index = 0; Index < Pcrs->count; Index++) {
+ Pcrs->pcrSelections[Index].hash = SwapBytes16 (TpmCap.data.assignedPCR.pcrSelections[Index].hash);
+ Pcrs->pcrSelections[Index].sizeofSelect = TpmCap.data.assignedPCR.pcrSelections[Index].sizeofSelect;
+ CopyMem (Pcrs->pcrSelections[Index].pcrSelect, TpmCap.data.assignedPCR.pcrSelections[Index].pcrSelect, Pcrs->pcrSelections[Index].sizeofSelect);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM AlgorithmSet.
+
+ This function parse the value got from TPM2_GetCapability and return the AlgorithmSet.
+
+ @param[out] AlgorithmSet The AlgorithmSet of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityAlgorithmSet (
+ OUT UINT32 *AlgorithmSet
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_ALGORITHM_SET,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *AlgorithmSet = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command is used to check to see if specific combinations of algorithm parameters are supported.
+
+ @param[in] Parameters Algorithm parameters to be validated
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2TestParms (
+ IN TPMT_PUBLIC_PARMS *Parameters
+ )
+{
+ EFI_STATUS Status;
+ TPM2_TEST_PARMS_COMMAND SendBuffer;
+ TPM2_TEST_PARMS_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_TestParms);
+
+ Buffer = (UINT8 *)&SendBuffer.Parameters;
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->type));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->type) {
+ case TPM_ALG_KEYEDHASH:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.keyedHashDetail.scheme.scheme) {
+ case TPM_ALG_HMAC:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.hmac.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.hashAlg));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.kdf));
+ Buffer += sizeof(UINT16);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ case TPM_ALG_SYMCIPHER:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.symDetail.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.xor));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case TPM_ALG_RSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.rsaDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.rsaDetail.scheme.scheme) {
+ case TPM_ALG_RSASSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsassa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAPSS:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsapss.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAES:
+ break;
+ case TPM_ALG_OAEP:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.oaep.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.keyBits));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (Parameters->parameters.rsaDetail.exponent));
+ Buffer += sizeof(UINT32);
+ break;
+ case TPM_ALG_ECC:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.scheme.scheme) {
+ case TPM_ALG_ECDSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdsa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDAA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdaa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECSCHNORR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecSchnorr.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDH:
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.curveID));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.kdf.scheme) {
+ case TPM_ALG_MGF1:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.mgf1.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_108:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_sp800_108.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_56a:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_SP800_56a.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF2:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf2.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2TestParms - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2TestParms - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/libedk2_tpm/Tpm2Context.c b/libedk2_tpm/Tpm2Context.c
new file mode 100644
index 00000000..61babcf8
--- /dev/null
+++ b/libedk2_tpm/Tpm2Context.c
@@ -0,0 +1,84 @@
+/** @file
+ Implement TPM2 Context related command.
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_CONTEXT FlushHandle;
+} TPM2_FLUSH_CONTEXT_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_FLUSH_CONTEXT_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command causes all context associated with a loaded object or session to be removed from TPM memory.
+
+ @param[in] FlushHandle The handle of the item to flush.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2FlushContext (
+ IN TPMI_DH_CONTEXT FlushHandle
+ )
+{
+ EFI_STATUS Status;
+ TPM2_FLUSH_CONTEXT_COMMAND SendBuffer;
+ TPM2_FLUSH_CONTEXT_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_FlushContext);
+
+ SendBuffer.FlushHandle = SwapBytes32 (FlushHandle);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/libedk2_tpm/Tpm2DeviceLib.c b/libedk2_tpm/Tpm2DeviceLib.c
new file mode 100644
index 00000000..5d9d604f
--- /dev/null
+++ b/libedk2_tpm/Tpm2DeviceLib.c
@@ -0,0 +1,62 @@
+/** @file
+ Implement TPM2 SubmitCommand.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include "Tpm2Help.h"
+#include "Tcg2Protocol.h"
+#include "Tpm2DeviceLib.h"
+
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+ TPM2_RESPONSE_HEADER *Header;
+
+ EFI_GUID gEfiTcg2ProtocolGuid = EFI_TCG2_PROTOCOL_GUID;
+ EFI_TCG2_PROTOCOL *mTcg2Protocol;
+
+ Status = LibLocateProtocol (&gEfiTcg2ProtocolGuid, (void **) &mTcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // Tcg2 protocol is not installed. So, TPM2 is not present.
+ //
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Assume when Tcg2 Protocol is ready, RequestUseTpm already done.
+ //
+ Status = mTcg2Protocol->SubmitCommand (
+ mTcg2Protocol,
+ InputParameterBlockSize,
+ InputParameterBlock,
+ *OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Header = (TPM2_RESPONSE_HEADER *)OutputParameterBlock;
+ *OutputParameterBlockSize = SwapBytes32 (Header->paramSize);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/libedk2_tpm/Tpm2EnhancedAuthorization.c b/libedk2_tpm/Tpm2EnhancedAuthorization.c
new file mode 100644
index 00000000..02a7c823
--- /dev/null
+++ b/libedk2_tpm/Tpm2EnhancedAuthorization.c
@@ -0,0 +1,400 @@
+/** @file
+ Implement TPM2 EnhancedAuthorization related command.
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_ENTITY AuthHandle;
+ TPMI_SH_POLICY PolicySession;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_NONCE NonceTPM;
+ TPM2B_DIGEST CpHashA;
+ TPM2B_NONCE PolicyRef;
+ INT32 Expiration;
+} TPM2_POLICY_SECRET_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPM2B_TIMEOUT Timeout;
+ TPMT_TK_AUTH PolicyTicket;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_POLICY_SECRET_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+ TPML_DIGEST HashList;
+} TPM2_POLICY_OR_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_POLICY_OR_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+ TPM_CC Code;
+} TPM2_POLICY_COMMAND_CODE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_POLICY_COMMAND_CODE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+} TPM2_POLICY_GET_DIGEST_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPM2B_DIGEST PolicyHash;
+} TPM2_POLICY_GET_DIGEST_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command includes a secret-based authorization to a policy.
+ The caller proves knowledge of the secret value using an authorization
+ session using the authValue associated with authHandle.
+
+ @param[in] AuthHandle Handle for an entity providing the authorization
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] AuthSession Auth Session context
+ @param[in] NonceTPM The policy nonce for the session.
+ @param[in] CpHashA Digest of the command parameters to which this authorization is limited.
+ @param[in] PolicyRef A reference to a policy relating to the authorization.
+ @param[in] Expiration Time when authorization will expire, measured in seconds from the time that nonceTPM was generated.
+ @param[out] Timeout Time value used to indicate to the TPM when the ticket expires.
+ @param[out] PolicyTicket A ticket that includes a value indicating when the authorization expires.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicySecret (
+ IN TPMI_DH_ENTITY AuthHandle,
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_NONCE *NonceTPM,
+ IN TPM2B_DIGEST *CpHashA,
+ IN TPM2B_NONCE *PolicyRef,
+ IN INT32 Expiration,
+ OUT TPM2B_TIMEOUT *Timeout,
+ OUT TPMT_TK_AUTH *PolicyTicket
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_SECRET_COMMAND SendBuffer;
+ TPM2_POLICY_SECRET_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicySecret);
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // Real data
+ //
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NonceTPM->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, NonceTPM->buffer, NonceTPM->size);
+ Buffer += NonceTPM->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(CpHashA->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, CpHashA->buffer, CpHashA->size);
+ Buffer += CpHashA->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PolicyRef->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, PolicyRef->buffer, PolicyRef->size);
+ Buffer += PolicyRef->size;
+
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32((UINT32)Expiration));
+ Buffer += sizeof(UINT32);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Return the response
+ //
+ Buffer = (UINT8 *)&RecvBuffer.Timeout;
+ Timeout->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ if (Timeout->size > sizeof(UINT64)) {
+ DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - Timeout->size error %x\n", Timeout->size));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Buffer += sizeof(UINT16);
+ CopyMem (Timeout->buffer, Buffer, Timeout->size);
+
+ PolicyTicket->tag = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ PolicyTicket->hierarchy = SwapBytes32(ReadUnaligned32 ((UINT32 *)Buffer));
+ Buffer += sizeof(UINT32);
+ PolicyTicket->digest.size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ if (PolicyTicket->digest.size > sizeof(TPMU_HA)) {
+ DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - digest.size error %x\n", PolicyTicket->digest.size));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ CopyMem (PolicyTicket->digest.buffer, Buffer, PolicyTicket->digest.size);
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command allows options in authorizations without requiring that the TPM evaluate all of the options.
+ If a policy may be satisfied by different sets of conditions, the TPM need only evaluate one set that
+ satisfies the policy. This command will indicate that one of the required sets of conditions has been
+ satisfied.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] HashList the list of hashes to check for a match.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyOR (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPML_DIGEST *HashList
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_OR_COMMAND SendBuffer;
+ TPM2_POLICY_OR_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINTN Index;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyOR);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+ Buffer = (UINT8 *)&SendBuffer.HashList;
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (HashList->count));
+ Buffer += sizeof(UINT32);
+ for (Index = 0; Index < HashList->count; Index++) {
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (HashList->digests[Index].size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, HashList->digests[Index].buffer, HashList->digests[Index].size);
+ Buffer += HashList->digests[Index].size;
+ }
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command indicates that the authorization will be limited to a specific command code.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] Code The allowed commandCode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyCommandCode (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPM_CC Code
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_COMMAND_CODE_COMMAND SendBuffer;
+ TPM2_POLICY_COMMAND_CODE_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyCommandCode);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+ SendBuffer.Code = SwapBytes32 (Code);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the current policyDigest of the session. This command allows the TPM
+ to be used to perform the actions required to precompute the authPolicy for an object.
+
+ @param[in] PolicySession Handle for the policy session.
+ @param[out] PolicyHash the current value of the policyHash of policySession.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyGetDigest (
+ IN TPMI_SH_POLICY PolicySession,
+ OUT TPM2B_DIGEST *PolicyHash
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_GET_DIGEST_COMMAND SendBuffer;
+ TPM2_POLICY_GET_DIGEST_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyGetDigest);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ PolicyHash->size = SwapBytes16 (RecvBuffer.PolicyHash.size);
+ if (PolicyHash->size > sizeof(TPMU_HA)) {
+ DEBUG ((DEBUG_ERROR, "Tpm2PolicyGetDigest - PolicyHash->size error %x\n", PolicyHash->size));
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (PolicyHash->buffer, &RecvBuffer.PolicyHash.buffer, PolicyHash->size);
+
+ return EFI_SUCCESS;
+}
diff --git a/libedk2_tpm/Tpm2Help.c b/libedk2_tpm/Tpm2Help.c
new file mode 100644
index 00000000..39b0f136
--- /dev/null
+++ b/libedk2_tpm/Tpm2Help.c
@@ -0,0 +1,334 @@
+/** @file
+ Implement TPM2 helper functions.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include "Tpm2Help.h"
+#include "Tcg2Protocol.h"
+
+typedef struct {
+ TPMI_ALG_HASH HashAlgo;
+ UINT16 HashSize;
+ UINT32 HashMask;
+} INTERNAL_HASH_INFO;
+
+STATIC INTERNAL_HASH_INFO mHashInfo[] = {
+ {TPM_ALG_SHA1, SHA1_DIGEST_SIZE, HASH_ALG_SHA1},
+ {TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256},
+ {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, HASH_ALG_SM3_256},
+ {TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384},
+ {TPM_ALG_SHA512, SHA512_DIGEST_SIZE, HASH_ALG_SHA512},
+};
+
+/**
+ Return size of digest.
+
+ @param[in] HashAlgo Hash algorithm
+
+ @return size of digest
+**/
+UINT16
+EFIAPI
+GetHashSizeFromAlgo (
+ IN TPMI_ALG_HASH HashAlgo
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
+ if (mHashInfo[Index].HashAlgo == HashAlgo) {
+ return mHashInfo[Index].HashSize;
+ }
+ }
+ return 0;
+}
+
+/**
+ Switches the endianness of a 16-bit integer.
+
+ This function swaps the bytes in a 16-bit unsigned value to switch the value
+ from little endian to big endian or vice versa. The byte swapped value is
+ returned.
+
+ @param Value A 16-bit unsigned value.
+
+ @return The byte swapped Value.
+
+**/
+
+UINT16
+EFIAPI
+SwapBytes16 (
+ IN UINT16 Operand
+ )
+{
+ return (UINT16) ((Operand << 8) | (Operand >> 8));
+}
+
+/**
+ Switches the endianness of a 32-bit integer.
+
+ This function swaps the bytes in a 32-bit unsigned value to switch the value
+ from little endian to big endian or vice versa. The byte swapped value is
+ returned.
+
+ @param Value A 32-bit unsigned value.
+
+ @return The byte swapped Value.
+
+**/
+
+UINT32
+EFIAPI
+SwapBytes32 (
+ IN UINT32 Operand
+ )
+{
+ UINT32 LowerBytes;
+ UINT32 HigherBytes;
+
+ LowerBytes = (UINT32) SwapBytes16 ((UINT16) Operand);
+ HigherBytes = (UINT32) SwapBytes16 ((UINT16) (Operand >> 16));
+
+ return (LowerBytes << 16 | HigherBytes);
+}
+
+/**
+ Switches the endianness of a 64-bit integer.
+
+ This function swaps the bytes in a 64-bit unsigned value to switch the value
+ from little endian to big endian or vice versa. The byte swapped value is
+ returned.
+
+ @param Value A 64-bit unsigned value.
+
+ @return The byte swapped Value.
+
+**/
+
+UINT64
+EFIAPI
+SwapBytes64 (
+ IN UINT64 Operand
+ )
+{
+ UINT64 LowerBytes;
+ UINT64 HigherBytes;
+
+ LowerBytes = (UINT64) SwapBytes32 ((UINT32) Operand);
+ HigherBytes = (UINT64) SwapBytes32 ((UINT32) (Operand >> 32));
+
+ return (LowerBytes << 32 | HigherBytes);
+}
+
+/**
+ Writes a 32-bit value to memory that may be unaligned.
+
+ This function writes the 32-bit value specified by Value to Buffer. Value is
+ returned. The function guarantees that the write operation does not produce
+ an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 32-bit value that may be unaligned.
+ @param Value The 32-bit value to write to Buffer.
+
+ @return The 32-bit value to write to Buffer.
+
+**/
+
+UINT32
+EFIAPI
+WriteUnaligned32 (
+ OUT UINT32 *Buffer,
+ IN UINT32 Value
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer = Value;
+}
+
+/**
+ Writes a 16-bit value to memory that may be unaligned.
+
+ This function writes the 16-bit value specified by Value to Buffer. Value is
+ returned. The function guarantees that the write operation does not produce
+ an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 16-bit value that may be unaligned.
+ @param Value 16-bit value to write to Buffer.
+
+ @return The 16-bit value to write to Buffer.
+
+**/
+
+UINT16
+EFIAPI
+WriteUnaligned16 (
+ OUT UINT16 *Buffer,
+ IN UINT16 Value
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer = Value;
+}
+
+/**
+ Reads a 16-bit value from memory that may be unaligned.
+
+ This function returns the 16-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 16-bit value that may be unaligned.
+
+ @return The 16-bit value read from Buffer.
+
+**/
+
+UINT16
+EFIAPI
+ReadUnaligned16 (
+ IN CONST UINT16 *Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Reads a 32-bit value from memory that may be unaligned.
+
+ This function returns the 32-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 32-bit value that may be unaligned.
+
+ @return The 32-bit value read from Buffer.
+
+**/
+
+UINT32
+EFIAPI
+ReadUnaligned32 (
+ IN CONST UINT32 *Buffer
+ )
+
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Writes a 64-bit value to memory that may be unaligned.
+
+ This function writes the 64-bit value specified by Value to Buffer. Value is
+ returned. The function guarantees that the write operation does not produce
+ an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 64-bit value that may be unaligned.
+ @param Value The 64-bit value to write to Buffer.
+
+ @return The 64-bit value to write to Buffer.
+
+**/
+
+UINT64
+EFIAPI
+WriteUnaligned64 (
+ OUT UINT64 *Buffer,
+ IN UINT64 Value
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer = Value;
+}
+
+/**
+ Copy AuthSessionIn to TPM2 command buffer.
+
+ @param [in] AuthSessionIn Input AuthSession data
+ @param [out] AuthSessionOut Output AuthSession data in TPM2 command buffer
+
+ @return AuthSession size
+**/
+
+UINT32
+EFIAPI
+CopyAuthSessionCommand (
+ IN TPMS_AUTH_COMMAND *AuthSessionIn, OPTIONAL
+ OUT UINT8 *AuthSessionOut
+ )
+{
+ UINT8 *Buffer;
+
+ Buffer = (UINT8 *)AuthSessionOut;
+
+ //
+ // Add in Auth session
+ //
+ if (AuthSessionIn != NULL) {
+ // sessionHandle
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AuthSessionIn->sessionHandle));
+ Buffer += sizeof(UINT32);
+
+ // nonce
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->nonce.size));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (Buffer, AuthSessionIn->nonce.buffer, AuthSessionIn->nonce.size);
+ Buffer += AuthSessionIn->nonce.size;
+
+ // sessionAttributes
+ *(UINT8 *)Buffer = *(UINT8 *)&AuthSessionIn->sessionAttributes;
+ Buffer++;
+
+ // hmac
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->hmac.size));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (Buffer, AuthSessionIn->hmac.buffer, AuthSessionIn->hmac.size);
+ Buffer += AuthSessionIn->hmac.size;
+ } else {
+ // sessionHandle
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(TPM_RS_PW));
+ Buffer += sizeof(UINT32);
+
+ // nonce = nullNonce
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
+ Buffer += sizeof(UINT16);
+
+ // sessionAttributes = 0
+ *(UINT8 *)Buffer = 0x00;
+ Buffer++;
+
+ // hmac = nullAuth
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
+ Buffer += sizeof(UINT16);
+ }
+
+ return (UINT32)(UINTN)(Buffer - (UINT8 *)AuthSessionOut);
+}
diff --git a/libedk2_tpm/Tpm2Hierarchy.c b/libedk2_tpm/Tpm2Hierarchy.c
new file mode 100644
index 00000000..99bb9d8f
--- /dev/null
+++ b/libedk2_tpm/Tpm2Hierarchy.c
@@ -0,0 +1,801 @@
+/** @file
+ Implement TPM2 Hierarchy related command.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include