| # Copyright 2013 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # This Makefile normally builds in a 'build' subdir, but use | |
| # | |
| # make BUILD=<dir> | |
| # | |
| # to put the output somewhere else. | |
| ############################################################################## | |
| # Configuration variables come first. | |
| # We should only run pwd once, not every time we refer to ${BUILD}. | |
| SRCDIR := $(shell pwd) | |
| BUILD = ${SRCDIR}/build | |
| export BUILD | |
| LIBAVB_SRCDIR ?= ../../aosp/external/avb/ | |
| # Stuff for 'make install' | |
| INSTALL = install | |
| DESTDIR = / | |
| LIBDIR ?= lib | |
| # Where exactly do the pieces go? | |
| UB_DIR=${DESTDIR}/usr/bin | |
| UL_DIR=${DESTDIR}/usr/${LIBDIR} | |
| ULP_DIR=${UL_DIR}/pkgconfig | |
| UI_DIR=${DESTDIR}/usr/include/vboot | |
| US_DIR=${DESTDIR}/usr/share/vboot | |
| DF_DIR=${DESTDIR}/etc/default | |
| VB_DIR=${US_DIR}/bin | |
| DUT_TEST_DIR=${US_DIR}/tests | |
| # Where to install the (exportable) executables for testing? | |
| TEST_INSTALL_DIR = ${BUILD}/install_for_test | |
| # Set when installing into the SDK instead of building for a board sysroot. | |
| SDK_BUILD ?= | |
| # Verbose? Use V=1 | |
| ifeq ($(filter-out 0,${V}),) | |
| Q := @ | |
| endif | |
| # Quiet? Use QUIET=1 | |
| ifeq ($(filter-out 0,${QUIET}),) | |
| PRINTF := printf | |
| else | |
| PRINTF := : | |
| endif | |
| # ARCH and/or FIRMWARE_ARCH are defined by the ChromiumOS ebuild. | |
| ifeq (${ARCH},) | |
| ARCH := $(shell uname -m) | |
| endif | |
| ifeq (${ARCH},armv7l) | |
| override ARCH := arm | |
| else ifeq (${ARCH},aarch64) | |
| override ARCH := arm64 | |
| else ifeq (${ARCH},i386) | |
| override ARCH := x86 | |
| else ifeq (${ARCH},i686) | |
| override ARCH := x86 | |
| else ifeq (${ARCH},amd64) | |
| override ARCH := x86_64 | |
| endif | |
| ifneq (,$(filter arm arm64,${ARCH})) | |
| ARCH_DIR := arm | |
| else ifneq (,$(filter x86 x86_64,${ARCH})) | |
| ARCH_DIR := x86 | |
| else | |
| ARCH_DIR := stub | |
| endif | |
| # Compiler flags | |
| DEBUG_FLAGS := $(if $(filter-out 0,${DEBUG}),-g -Og,-Os) | |
| WERROR := -Werror | |
| FIRMWARE_FLAGS := -nostdinc -ffreestanding -fno-builtin -fno-stack-protector | |
| COMMON_FLAGS := -pipe ${WERROR} -Wall -Wstrict-prototypes -Wtype-limits \ | |
| -Wundef -Wmissing-prototypes -Wno-trigraphs -Wredundant-decls -Wshadow \ | |
| -Wwrite-strings -Wstrict-aliasing -Wdate-time \ | |
| -Wint-conversion -ffunction-sections -fdata-sections \ | |
| -Wformat -Wno-format-security -std=gnu11 ${DEBUG_FLAGS} ${CPPFLAGS} | |
| # test_ccflag | |
| # $(1): compiler flags to test | |
| # $(2): code to insert into test snippet | |
| # returns: $(1) if compiler was successful, empty string otherwise | |
| test_ccflag = $(shell \ | |
| printf "$(2)\nvoid _start(void) {}\n" | \ | |
| $(CC) -nostdlib -Werror $(1) -xc -c - -o /dev/null \ | |
| >/dev/null 2>&1 && echo "$(1)") | |
| COMMON_FLAGS += $(call test_ccflag,-Wimplicit-fallthrough) | |
| COMMON_FLAGS += $(call test_ccflag,-Wno-address-of-packed-member) | |
| COMMON_FLAGS += $(call test_ccflag,-Wno-unknown-warning) | |
| COMMON_FLAGS += $(call test_ccflag,-Wincompatible-function-pointer-types) | |
| TEST_FLAGS := $(call test_ccflag,-Wno-address-of-packed-member) | |
| # FIRMWARE_ARCH is only defined by the ChromiumOS ebuild if compiling | |
| # for a firmware target (coreboot or depthcharge). It must map to the same | |
| # consistent set of architectures as the host. | |
| ifeq (${FIRMWARE_ARCH},i386) | |
| override FIRMWARE_ARCH := x86 | |
| else ifeq (${FIRMWARE_ARCH},amd64) | |
| override FIRMWARE_ARCH := x86_64 | |
| else ifneq ($(filter arm64 armv7 armv8 armv8_64,${FIRMWARE_ARCH}),) | |
| override FIRMWARE_ARCH := arm | |
| endif | |
| ifeq (${FIRMWARE_ARCH},arm) | |
| CC ?= armv7a-cros-linux-gnueabihf-gcc | |
| CFLAGS ?= -march=armv5 -fno-common -ffixed-r8 -mfloat-abi=hard -marm \ | |
| -mabi=aapcs-linux -mno-thumb-interwork ${FIRMWARE_FLAGS} ${COMMON_FLAGS} | |
| else ifeq (${FIRMWARE_ARCH},x86) | |
| CC ?= i686-pc-linux-gnu-gcc | |
| CFLAGS ?= -fvisibility=hidden -fomit-frame-pointer \ | |
| -fno-toplevel-reorder -fno-dwarf2-cfi-asm -mpreferred-stack-boundary=2 \ | |
| ${FIRMWARE_FLAGS} ${COMMON_FLAGS} | |
| else ifeq (${FIRMWARE_ARCH},x86_64) | |
| CFLAGS ?= ${FIRMWARE_FLAGS} ${COMMON_FLAGS} -fvisibility=hidden \ | |
| -fomit-frame-pointer | |
| else ifeq (${FIRMWARE_ARCH},riscv) | |
| CC ?= riscv64-linux-gnu-gcc | |
| else ifeq (${FIRMWARE_ARCH},mock) | |
| FIRMWARE_STUB := 1 | |
| CFLAGS += ${TEST_FLAGS} | |
| else ifneq (${FIRMWARE_ARCH},) | |
| $(error Unexpected FIRMWARE_ARCH ${FIRMWARE_ARCH}) | |
| else | |
| # FIRMWARE_ARCH not defined; assuming local compile. | |
| FIRMWARE_STUB := 1 | |
| CC ?= gcc | |
| CFLAGS += -DCHROMEOS_ENVIRONMENT ${COMMON_FLAGS} | |
| endif | |
| LDFLAGS += -Wl,--gc-sections | |
| LDLIBS += -ldl | |
| ifneq ($(filter-out 0,${DEBUG})$(filter-out 0,${TEST_PRINT}),) | |
| CFLAGS += -DVBOOT_DEBUG | |
| endif | |
| ifneq ($(filter-out 0,${NDEBUG}),) | |
| CFLAGS += -DNDEBUG | |
| endif | |
| ifneq ($(filter-out 0,${TPM2_MODE}),) | |
| CFLAGS += -DTPM2_MODE | |
| endif | |
| # Enable EC early firmware selection. | |
| ifneq ($(filter-out 0,${EC_EFS}),) | |
| CFLAGS += -DEC_EFS=1 | |
| else | |
| CFLAGS += -DEC_EFS=0 | |
| endif | |
| # Some tests need to be disabled when using mocked_secdata_tpm. | |
| ifneq ($(filter-out 0,${MOCK_TPM}),) | |
| CFLAGS += -DMOCK_TPM | |
| endif | |
| # EXTERNAL_TPM_CLEAR_REQUEST indicates whether we want to use the external | |
| # tpm_clear_request tool or not. | |
| ifneq ($(filter-out 0,${EXTERNAL_TPM_CLEAR_REQUEST}),) | |
| CFLAGS += -DEXTERNAL_TPM_CLEAR_REQUEST=1 | |
| else | |
| CFLAGS += -DEXTERNAL_TPM_CLEAR_REQUEST=0 | |
| endif | |
| # Configurable temporary directory for host tools | |
| VBOOT_TMP_DIR := /tmp | |
| CFLAGS += -DVBOOT_TMP_DIR=\"${VBOOT_TMP_DIR}\" | |
| # Directory used by crossystem to create a lock file | |
| CROSSYSTEM_LOCK_DIR := /run/lock | |
| CFLAGS += -DCROSSYSTEM_LOCK_DIR=\"${CROSSYSTEM_LOCK_DIR}\" | |
| PC_IN_FILES = vboot_host.pc.in | |
| # Create / use dependency files | |
| CFLAGS += -MMD -MF $@.d | |
| ifeq (${FIRMWARE_ARCH},) | |
| CFLAGS += -fPIC | |
| endif | |
| CFLAGS += -D_GNU_SOURCE | |
| # This is required to access large disks and files on 32-bit systems, | |
| # but if the environment doesn't support it, at least compile support | |
| # for what is possible. | |
| # Pass through cflags_use_64bits to evaluate it only once, here. | |
| HASH_CONST := \# | |
| cflags_use_64bits := $(call test_ccflag,$\ | |
| -D_FILE_OFFSET_BITS=64,$\ | |
| ${HASH_CONST}include <fts.h>) | |
| CFLAGS += $(cflags_use_64bits) | |
| # Code coverage | |
| ifneq ($(filter-out 0,${COV}),) | |
| COV_FLAGS = -Og --coverage -DCOVERAGE | |
| CFLAGS += ${COV_FLAGS} | |
| LDFLAGS += ${COV_FLAGS} | |
| COV_INFO = ${BUILD}/coverage.info | |
| endif | |
| ifdef HAVE_MACOS | |
| CFLAGS += -DHAVE_MACOS -Wno-deprecated-declarations | |
| endif | |
| # Musl doesn't have execinfo.h. | |
| ifndef HAVE_MUSL | |
| CFLAGS += -DHAVE_EXECINFO_H | |
| endif | |
| LD = ${CC} | |
| CXX ?= g++ | |
| PKG_CONFIG ?= pkg-config | |
| ifneq ($(filter-out 0,${STATIC}),) | |
| LDFLAGS += -static | |
| PKG_CONFIG += --static | |
| endif | |
| ifneq (${FUZZ_FLAGS},) | |
| CFLAGS += ${FUZZ_FLAGS} | |
| endif | |
| # Optional Libraries | |
| LIBZIP_VERSION := $(shell ${PKG_CONFIG} --modversion libzip 2>/dev/null) | |
| HAVE_LIBZIP := $(if ${LIBZIP_VERSION},1) | |
| ifneq ($(filter-out 0,${HAVE_LIBZIP}),) | |
| CFLAGS += -DHAVE_LIBZIP $(shell ${PKG_CONFIG} --cflags libzip) | |
| LIBZIP_LIBS := $(shell ${PKG_CONFIG} --libs libzip) | |
| endif | |
| LIBARCHIVE_VERSION := $(shell ${PKG_CONFIG} --modversion libarchive 2>/dev/null) | |
| HAVE_LIBARCHIVE := $(if ${LIBARCHIVE_VERSION},1) | |
| ifneq ($(filter-out 0,${HAVE_LIBARCHIVE}),) | |
| CFLAGS += -DHAVE_LIBARCHIVE $(shell ${PKG_CONFIG} --cflags libarchive) | |
| LIBARCHIVE_LIBS := $(shell ${PKG_CONFIG} --libs libarchive) | |
| endif | |
| HAVE_CROSID := $(shell ${PKG_CONFIG} --exists crosid && echo 1) | |
| ifeq ($(HAVE_CROSID),1) | |
| CFLAGS += -DHAVE_CROSID $(shell ${PKG_CONFIG} --cflags crosid) | |
| CROSID_LIBS := $(shell ${PKG_CONFIG} --libs crosid) | |
| endif | |
| HAVE_NSS := $(shell ${PKG_CONFIG} --exists nss && echo 1) | |
| ifeq ($(HAVE_NSS),1) | |
| CFLAGS += -DHAVE_NSS $(shell ${PKG_CONFIG} --cflags nss) | |
| else | |
| $(warning Missing NSS. PKCS11 signing not supported. Install libnss3 to enable this feature.) | |
| endif | |
| # Get major version of openssl (e.g. version 3.0.5 -> "3") | |
| OPENSSL_VERSION := $(shell ${PKG_CONFIG} --modversion openssl | cut -d. -f1) | |
| # A test wrapper can be specified. Tests are run inside the wrapper eg: | |
| # make RUNTEST=env runtests | |
| RUNTEST = | |
| # The Path to the $BUILD inside the runtest wrapper, used by the test scripts. | |
| # The top of the chroot for RUNTEST must be passed in via the SYSROOT | |
| # environment variable. In the ChromiumOS chroot, this is done automatically by | |
| # the ebuild. | |
| export BUILD_RUN = $(subst ${SYSROOT},,${BUILD}) | |
| # Path to the $SRCDIR inside the wrapper, the test scripts rederive this. | |
| SRC_RUN = $(subst ${SYSROOT},,${SRCDIR}) | |
| INCLUDES += \ | |
| -Ifirmware/include \ | |
| -Ifirmware/lib/include \ | |
| -Ifirmware/lib/cgptlib/include \ | |
| -Ifirmware/lib/tpm_lite/include \ | |
| -Ifirmware/2lib/include | |
| ifneq (${FIRMWARE_STUB},) | |
| INCLUDES += -Ihost/include -Ihost/lib/include -Ihost/lib21/include | |
| ifeq ($(shell uname -s), OpenBSD) | |
| INCLUDES += -I/usr/local/include | |
| endif | |
| endif | |
| CRYPTO_LIBS := $(shell ${PKG_CONFIG} --libs libcrypto) | |
| ifeq ($(shell uname -s), FreeBSD) | |
| CRYPTO_LIBS += -lcrypto | |
| endif | |
| ifeq ($(shell uname -s), OpenBSD) | |
| LDFLAGS += -Wl,-z,notext | |
| endif | |
| ############################################################################## | |
| # Subdirectory inclusion | |
| SUBMODULES = firmware host cgpt utility futility tests scripts | |
| # Initial empty definitions for common accumulation variables | |
| ALL_OBJS = | |
| ALL_DEPS = | |
| TEST_OBJS = | |
| TEST_DEPS = | |
| FWLIB_OBJS = | |
| TLCL_OBJS = | |
| UTILLIB_OBJS = | |
| HOSTLIB_OBJS = | |
| CGPT_OBJS = | |
| FUTIL_OBJS = | |
| LIBS = | |
| OBJS = | |
| COMMONLIB_SRCS = | |
| FWLIB_ASMS = | |
| FWLIB_SRCS = | |
| TLCL_SRCS = | |
| TESTLIB_SRCS = | |
| # Include sub-makefiles only if they exist (for external projects like libpayload) | |
| include $(foreach m,${SUBMODULES},$(wildcard $(m)/Makefile.inc)) | |
| ############################################################################## | |
| # High-level targets | |
| .PHONY: all | |
| all: fwlib futil utillib hostlib cgpt tlcl util_files \ | |
| $(if $(filter x86_64,${ARCH}),$(if $(filter clang,${CC}),fuzzers)) \ | |
| $(if $(filter-out 0,${COV}),coverage) | |
| .PHONY: clean | |
| clean: | |
| ${Q}/bin/rm -rf "${BUILD}" | |
| .PHONY: install | |
| install: cgpt_install signing_install futil_install pc_files_install \ | |
| lib_install $(if ${SDK_BUILD},,util_install_defaults) \ | |
| $(foreach f,$(if ${SDK_BUILD},${UTIL_FILES_SDK},${UTIL_FILES_BOARD}), \ | |
| util_install-$(patsubst ${BUILD}/%,%,${f})) | |
| .PHONY: install_dev | |
| install_dev: devkeys_install headers_install | |
| .PHONY: install_for_test | |
| install_for_test: override DESTDIR = ${TEST_INSTALL_DIR} | |
| install_for_test: test_setup install \ | |
| $(foreach f,${UTIL_FILES_SDK} ${UTIL_FILES_BOARD}, \ | |
| util_install-$(patsubst ${BUILD}/%,%,${f})) | |
| .PHONY: util_files | |
| util_files: $(if ${SDK_BUILD},${UTIL_FILES_SDK},${UTIL_FILES_BOARD}) | |
| .PHONY: fwlib | |
| fwlib: $(if ${FIRMWARE_ARCH},${FWLIB},) | |
| .PHONY: futil | |
| futil: ${FUTIL_BIN} | |
| .PHONY: test_setup | |
| test_setup:: cgpt ${UTIL_FILES_SDK} ${UTIL_FILES_BOARD} futil tests | |
| # Generate test keys | |
| .PHONY: genkeys | |
| genkeys: install_for_test | |
| ${RUNTEST} ${SRC_RUN}/tests/gen_test_keys.sh | |
| # Generate test cases | |
| .PHONY: gentestcases | |
| gentestcases: install_for_test | |
| ${RUNTEST} ${SRC_RUN}/tests/gen_test_cases.sh | |
| # Generate test cases for fuzzing | |
| .PHONY: genfuzztestcases | |
| genfuzztestcases: install_for_test | |
| ${RUNTEST} ${SRC_RUN}/tests/gen_fuzz_test_cases.sh | |
| .SECONDARY: | |
| # ---------------------------------------------------------------------------- | |
| # Firmware library | |
| # TPM-specific flags. These depend on the particular TPM we're targeting for. | |
| # They are needed here only for compiling parts of the firmware code into | |
| # user-level tests. | |
| # TPM_BLOCKING_CONTINUESELFTEST is defined if TPM_ContinueSelfTest blocks until | |
| # the self test has completed. | |
| ${TLCL_OBJS}: CFLAGS += -DTPM_BLOCKING_CONTINUESELFTEST | |
| # TPM_MANUAL_SELFTEST is defined if the self test must be started manually | |
| # (with a call to TPM_ContinueSelfTest) instead of starting automatically at | |
| # power on. | |
| # | |
| # We sincerely hope that TPM_BLOCKING_CONTINUESELFTEST and TPM_MANUAL_SELFTEST | |
| # are not both defined at the same time. (See comment in code.) | |
| # CFLAGS += -DTPM_MANUAL_SELFTEST | |
| # NOTE: UNROLL_LOOPS *only* affects SHA256, *not* SHA512. This seems to have | |
| # been a conscious decision at some point (see b/35501356) but whether it still | |
| # holds up in all situations on all architectures today might need to be | |
| # reevaluated. For now, since we currently always use SHA256 for (non-recovery) | |
| # kernel bodies and don't unroll loops for firmware verification, it's not very | |
| # relevant in practice. To unroll SHA512, UNROLL_LOOPS_SHA512 would need to be | |
| # defined. | |
| ifneq ($(filter-out 0,$(UNROLL_LOOPS)),) | |
| # Disable unrolling loops in the software SHA256 implementation when | |
| # ARMV8_CRYPTO_EXT is enabled to save space (b/511201478). | |
| ifeq ($(filter-out 0,$(ARMV8_CRYPTO_EXT)),) | |
| $(info vboot SHA256 built with unrolled loops (faster, larger code size)) | |
| CFLAGS += -DUNROLL_LOOPS | |
| else | |
| $(info vboot SHA256 built with hardware acceleration (ARMV8_CRYPTO_EXT enabled)) | |
| endif | |
| else | |
| $(info vboot SHA256 built with tight loops (slower, smaller code size)) | |
| endif | |
| ############################################################################## | |
| # Generic build rules | |
| ${BUILD}/%: ${BUILD}/%.o ${OBJS} ${LIBS} | |
| @${PRINTF} " LD $(subst ${BUILD}/,,$@)\n" | |
| ${Q}${LD} -o $@ ${LDFLAGS} $< ${OBJS} ${LIBS} ${LDLIBS} | |
| ${BUILD}/%.o: %.c | |
| @${PRINTF} " CC $(subst ${BUILD}/,,$@)\n" | |
| ${Q}mkdir -p $(dir $@) | |
| ${Q}${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< | |
| ${BUILD}/%.o: ${BUILD}/%.c | |
| @${PRINTF} " CC $(subst ${BUILD}/,,$@)\n" | |
| ${Q}mkdir -p $(dir $@) | |
| ${Q}${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< | |
| ${BUILD}/%.o: %.S | |
| @${PRINTF} " CC $(subst ${BUILD}/,,$@)\n" | |
| ${Q}mkdir -p $(dir $@) | |
| ${Q}${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< | |
| ############################################################################## | |
| # Other targets | |
| .PHONY: devkeys_install | |
| devkeys_install: | |
| @${PRINTF} " INSTALL DEVKEYS\n" | |
| ${Q}mkdir -p ${US_DIR}/devkeys | |
| ${Q}${INSTALL} -t ${US_DIR}/devkeys -m 644 \ | |
| `find tests/devkeys -type f -maxdepth 1` | |
| # Code coverage | |
| .PHONY: coverage | |
| ifeq ($(filter-out 0,${COV}),) | |
| coverage: | |
| $(error Build coverage like this: make clean && COV=1 make coverage) | |
| else | |
| .PHONY: coverage_init | |
| coverage_init: install_for_test | |
| rm -f ${COV_INFO}* | |
| lcov -c -i -d . -b . -o ${COV_INFO}.initial | |
| .PHONY: coverage_html | |
| coverage_html: coverage_init runtests | |
| lcov -c -d . -b . -o ${COV_INFO}.tests | |
| lcov -a ${COV_INFO}.initial -a ${COV_INFO}.tests -o ${COV_INFO}.total | |
| lcov -r ${COV_INFO}.total '/usr/*' -o ${COV_INFO}.local | |
| genhtml ${COV_INFO}.local -o ${BUILD}/coverage | |
| lcov -r ${COV_INFO}.local '*/stub/*' -o ${COV_INFO}.nostub | |
| lcov -e ${COV_INFO}.nostub '${SRCDIR}/firmware/*' -o ${COV_INFO}.firmware | |
| coverage: coverage_init runtests coverage_html | |
| endif | |
| # Dependencies | |
| ALL_DEPS += ${ALL_OBJS:%.o=%.o.d} | |
| TEST_DEPS += ${TEST_OBJS:%.o=%.o.d} | |
| -include ${ALL_DEPS} | |
| -include ${TEST_DEPS} | |
| # Tags and symbols | |
| SRCDIRPAT=$(subst /,\/,${SRCDIR}/) | |
| ${BUILD}/cscope.files: all install_for_test | |
| ${Q}rm -f $@ | |
| ${Q}cat ${ALL_DEPS} | tr -d ':\\' | tr ' ' '\012' | \ | |
| sed -e "s/${SRCDIRPAT}//" | \ | |
| egrep '\.[chS]$$' | sort | uniq > $@ | |
| cmd_etags = etags -o ${BUILD}/TAGS $(shell cat ${BUILD}/cscope.files) | |
| cmd_ctags = ctags -o ${BUILD}/tags $(shell cat ${BUILD}/cscope.files) | |
| run_if_prog = $(if $(shell which $(1) 2>/dev/null),$(2),) | |
| .PHONY: tags TAGS xrefs | |
| tags TAGS xrefs: ${BUILD}/cscope.files | |
| ${Q}\rm -f ${BUILD}/tags ${BUILD}/TAGS | |
| ${Q}$(call run_if_prog,etags,${cmd_etags}) | |
| ${Q}$(call run_if_prog,ctags,${cmd_ctags}) | |
| PC_FILES = ${PC_IN_FILES:%.pc.in=${BUILD}/%.pc} | |
| ${PC_FILES}: ${PC_IN_FILES} | |
| ${Q}sed \ | |
| -e 's:@LDLIBS@:${LDLIBS}:' \ | |
| -e 's:@LIBDIR@:${LIBDIR}:' \ | |
| $< > $@ | |
| .PHONY: pc_files_install | |
| pc_files_install: ${PC_FILES} | |
| ${Q}mkdir -p ${ULP_DIR} | |
| ${Q}${INSTALL} -D -m 0644 $< ${ULP_DIR}/$(notdir $<) |