summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-05-22 13:27:07 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-06-03 23:24:15 +0000
commit786acdabcc15f023330d7c628aca9679e757a238 (patch)
tree6bbc0da5d5a65c65ce1f2cdd5a928ff08a286f2a
parent4c3b4ea3d810a2ed907078a6b9a379442aaf6def (diff)
downloadvboot-786acdabcc15f023330d7c628aca9679e757a238.tar.gz
vboot2: Add workbuf functions
We'll try breaking this up into smaller pieces. This one's pretty small - just the work buffer utility functions. BUG=chromium:370082 BRANCH=none TEST=make clean && VBOOT2=1 COV=1 make Change-Id: I4c417438053c155d6f7f9725552066e9b059951c Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/201141
-rw-r--r--Makefile44
-rw-r--r--firmware/2lib/2common.c95
-rw-r--r--firmware/2lib/include/2common.h120
-rw-r--r--firmware/2lib/include/2return_codes.h62
-rw-r--r--firmware/2lib/include/2sysincludes.h27
-rw-r--r--tests/vb2_common_tests.c102
6 files changed, 445 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index ffe3946d..c9bcec32 100644
--- a/Makefile
+++ b/Makefile
@@ -221,7 +221,8 @@ INCLUDES += \
-Ifirmware/lib/include \
-Ifirmware/lib/cgptlib/include \
-Ifirmware/lib/cryptolib/include \
- -Ifirmware/lib/tpm_lite/include
+ -Ifirmware/lib/tpm_lite/include \
+ -Ifirmware/2lib/include
# If we're not building for a specific target, just stub out things like the
# TPM commands and various external functions that are provided by the BIOS.
@@ -234,6 +235,11 @@ endif
# Firmware library. TODO: Do we still need to export this?
FWLIB = ${BUILD}/vboot_fw.a
+# Smaller firmware library. TODO: Do we still need to export this?
+ifneq (${VBOOT2},)
+FWLIB2 = ${BUILD}/vboot_fw2.a
+endif
+
# Firmware library sources needed by VbInit() call
VBINIT_SRCS = \
firmware/lib/crc8.c \
@@ -271,6 +277,10 @@ VBSLK_SRCS = \
firmware/lib/vboot_kernel.c \
firmware/lib/region-kernel.c \
+# Firmware library source needed for smaller library 2
+FWLIB2_SRCS = \
+ firmware/2lib/2common.c \
+
# Support real TPM unless BIOS sets MOCK_TPM
ifeq (${MOCK_TPM},)
VBINIT_SRCS += \
@@ -313,8 +323,11 @@ VBSF_OBJS = ${VBSF_SRCS:%.c=${BUILD}/%.o}
FWLIB_OBJS = ${FWLIB_SRCS:%.c=${BUILD}/%.o}
-ALL_OBJS += ${FWLIB_OBJS} ${VBINIT_OBJS} ${VBSF_OBJS}
+ifneq (${VBOOT2},)
+FWLIB2_OBJS = ${FWLIB2_SRCS:%.c=${BUILD}/%.o}
+endif
+ALL_OBJS += ${FWLIB_OBJS} ${FWLIB2_OBJS} ${VBINIT_OBJS} ${VBSF_OBJS}
# Library to build the utilities. "HOST" mostly means "userspace".
HOSTLIB = ${BUILD}/libvboot_host.a
@@ -543,6 +556,12 @@ ifdef REGION_READ
TEST_NAMES += tests/vboot_region_tests
endif
+ifneq (${VBOOT2},)
+TEST_NAMES += \
+ tests/vb2_common_tests \
+
+endif
+
# TODO: port these tests to new API, if not already eqivalent
# functionality in other tests. These don't even compile at present.
#
@@ -598,7 +617,8 @@ _dir_create := $(foreach d, \
# Default target.
.PHONY: all
-all: fwlib $(if ${FIRMWARE_ARCH},,host_stuff) $(if ${COV},coverage)
+all: fwlib $(if ${VBOOT2},fwlib2) $(if ${FIRMWARE_ARCH},,host_stuff) \
+ $(if ${COV},coverage)
# Host targets
.PHONY: host_stuff
@@ -639,6 +659,7 @@ ${FWLIB_OBJS}: CFLAGS += -DTPM_BLOCKING_CONTINUESELFTEST
ifeq (${FIRMWARE_ARCH},i386)
# Unrolling loops in cryptolib makes it faster
${FWLIB_OBJS}: CFLAGS += -DUNROLL_LOOPS
+${FWLIB2_OBJS}: CFLAGS += -DUNROLL_LOOPS
# Workaround for coreboot on x86, which will power off asynchronously
# without giving us a chance to react. This is not an example of the Right
@@ -682,12 +703,21 @@ fwlinktest: ${FWLIB} \
.PHONY: fwlib
fwlib: $(if ${FIRMWARE_ARCH},${FWLIB},fwlinktest)
+.PHONY: fwlib2
+fwlib2: ${FWLIB2}
+
${FWLIB}: ${FWLIB_OBJS}
@$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
+${FWLIB2}: ${FWLIB2_OBJS}
+ @$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
+ ${Q}rm -f $@
+ @$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
+ ${Q}ar qc $@ $^
+
# ----------------------------------------------------------------------------
# Host library
@@ -706,7 +736,7 @@ ${BUILD}/host/% ${HOSTLIB}: INCLUDES += \
-Ihost/lib/include
# TODO: better way to make .a than duplicating this recipe each time?
-${HOSTLIB}: ${HOSTLIB_OBJS} ${FWLIB_OBJS}
+${HOSTLIB}: ${HOSTLIB_OBJS} ${FWLIB_OBJS} $(if ${VBOOT2},${FWLIB2_OBJS})
@$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
@@ -957,7 +987,7 @@ ALL_OBJS += ${BUILD}/tests/tpm_lite/tlcl_tests.o
# Frequently-run tests
.PHONY: test_targets
-test_targets:: runcgpttests runmisctests
+test_targets:: runcgpttests runmisctests $(if ${VBOOT2},run2tests)
ifeq (${MINIMAL},)
# Bitmap utility isn't compiled for minimal variant
@@ -1044,6 +1074,10 @@ runmisctests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_nvstorage_test
+.PHONY: run2tests
+run2tests: test_setup
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests
+
.PHONY: runfutiltests
runfutiltests: override DESTDIR = ${TEST_INSTALL_DIR}
runfutiltests: test_setup install
diff --git a/firmware/2lib/2common.c b/firmware/2lib/2common.c
new file mode 100644
index 00000000..9849b22b
--- /dev/null
+++ b/firmware/2lib/2common.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2014 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.
+ *
+ * Common functions between firmware and kernel verified boot.
+ * (Firmware portion)
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+
+int vb2_align(uint8_t **ptr, uint32_t *size, uint32_t align, uint32_t want_size)
+{
+ uintptr_t p = (uintptr_t)*ptr;
+ uintptr_t offs = p & (align - 1);
+
+ if (offs) {
+ offs = align - offs;
+
+ if (*size < offs)
+ return VB2_ERROR_BUFFER_TOO_SMALL;
+
+ *ptr += offs;
+ *size -= offs;
+ }
+
+ if (*size < want_size)
+ return VB2_ERROR_BUFFER_TOO_SMALL;
+
+ return VB2_SUCCESS;
+}
+
+void vb2_workbuf_init(struct vb2_workbuf *wb, uint8_t *buf, uint32_t size)
+{
+ wb->buf = buf;
+ wb->size = size;
+
+ /* Align the buffer so allocations will be aligned */
+ if (vb2_align(&wb->buf, &wb->size, VB2_WORKBUF_ALIGN, 0))
+ wb->size = 0;
+}
+
+/**
+ * Round up a number to a multiple of VB2_WORKBUF_ALIGN
+ *
+ * @param v Number to round up
+ * @return The number, rounded up.
+ */
+static __inline uint32_t wb_round_up(uint32_t v)
+{
+ return (v + VB2_WORKBUF_ALIGN - 1) & ~(VB2_WORKBUF_ALIGN - 1);
+}
+
+void *vb2_workbuf_alloc(struct vb2_workbuf *wb, uint32_t size)
+{
+ uint8_t *ptr = wb->buf;
+
+ /* Round up size to work buffer alignment */
+ size = wb_round_up(size);
+
+ if (size > wb->size)
+ return NULL;
+
+ wb->buf += size;
+ wb->size -= size;
+
+ return ptr;
+}
+
+void *vb2_workbuf_realloc(struct vb2_workbuf *wb,
+ uint32_t oldsize,
+ uint32_t newsize)
+{
+ /*
+ * Just free and allocate to update the size. No need to move/copy
+ * memory, since the new pointer is guaranteed to be the same as the
+ * old one. The new allocation can fail, if the new size is too big.
+ */
+ vb2_workbuf_free(wb, oldsize);
+ return vb2_workbuf_alloc(wb, newsize);
+}
+
+void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size)
+{
+ /* Round up size to work buffer alignment */
+ size = wb_round_up(size);
+
+ wb->buf -= size;
+ wb->size += size;
+}
+
+ptrdiff_t vb2_offset_of(const void *base, const void *ptr)
+{
+ return (uintptr_t)ptr - (uintptr_t)base;
+}
diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h
new file mode 100644
index 00000000..3724354b
--- /dev/null
+++ b/firmware/2lib/include/2common.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2014 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.
+ *
+ * Common functions between firmware and kernel verified boot.
+ */
+
+#ifndef VBOOT_REFERENCE_VBOOT_2COMMON_H_
+#define VBOOT_REFERENCE_VBOOT_2COMMON_H_
+
+#include "2return_codes.h"
+
+struct vb2_public_key;
+
+/*
+ * Return the greater of A and B. This is used in macros which calculate the
+ * required buffer size, so can't be turned into a static inline function.
+ */
+#ifndef VB2_MAX
+#define VB2_MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+/*
+ * Debug output. Defaults to printf(), but can be overridden on a per-platform
+ * basis.
+ */
+#if defined(VBOOT_DEBUG) && !defined(VB2_DEBUG)
+#define VB2_DEBUG(format, args...) printf(format, ## args)
+#else
+#define VB2_DEBUG(format, args...)
+#endif
+
+/* Alignment for work buffer pointers/allocations */
+#define VB2_WORKBUF_ALIGN 8
+
+/* Work buffer */
+struct vb2_workbuf {
+ uint8_t *buf;
+ uint32_t size;
+};
+
+/**
+ * Initialize a work buffer.
+ *
+ * @param wb Work buffer to init
+ * @param buf Pointer to work buffer data
+ * @param size Size of work buffer data in bytes
+ */
+void vb2_workbuf_init(struct vb2_workbuf *wb, uint8_t *buf, uint32_t size);
+
+/**
+ * Allocate space in a work buffer.
+ *
+ * Note that the returned buffer will always be aligned to VB2_WORKBUF_ALIGN.
+ *
+ * The work buffer acts like a stack, and detailed tracking of allocs and frees
+ * is not done. The caller must track the size of each allocation and free via
+ * vb2_workbuf_free() in the reverse order they were allocated.
+ *
+ * @param wb Work buffer
+ * @param size Requested size in bytes
+ * @return A pointer to the allocated space, or NULL if error.
+ */
+void *vb2_workbuf_alloc(struct vb2_workbuf *wb, uint32_t size);
+
+/**
+ * Reallocate space in a work buffer.
+ *
+ * Note that the returned buffer will always be aligned to VB2_WORKBUF_ALIGN.
+ * The work buffer acts like a stack, so this must only be done to the most
+ * recently allocated buffer.
+ *
+ * @param wb Work buffer
+ * @param oldsize Old allocation size in bytes
+ * @param newsize Requested size in bytes
+ * @return A pointer to the allocated space, or NULL if error.
+ */
+void *vb2_workbuf_realloc(struct vb2_workbuf *wb,
+ uint32_t oldsize,
+ uint32_t newsize);
+
+/**
+ * Free the preceding allocation.
+ *
+ * Note that the work buffer acts like a stack, and detailed tracking of
+ * allocs and frees is not done. The caller must track the size of each
+ * allocation and free them in reverse order.
+ *
+ * @param wb Work buffer
+ * @param size Size of data to free
+ */
+void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size);
+
+/* Check if a pointer is aligned on an align-byte boundary */
+#define vb_aligned(ptr, align) (!(((size_t)(ptr)) & ((align) - 1)))
+
+/**
+ * Align a buffer and check its size.
+ *
+ * @param **ptr Pointer to pointer to align
+ * @param *size Points to size of buffer pointed to by *ptr
+ * @param align Required alignment (must be power of 2)
+ * @param want_size Required size
+ * @return VB2_SUCCESS, or non-zero if error.
+ */
+int vb2_align(uint8_t **ptr,
+ uint32_t *size,
+ uint32_t align,
+ uint32_t want_size);
+
+/**
+ * Return offset of ptr from base.
+ *
+ * @param base Base pointer
+ * @param ptr Pointer at some offset from base
+ * @return The offset of ptr from base.
+ */
+ptrdiff_t vb2_offset_of(const void *base, const void *ptr);
+
+#endif /* VBOOT_REFERENCE_VBOOT_2COMMON_H_ */
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
new file mode 100644
index 00000000..73a37b5e
--- /dev/null
+++ b/firmware/2lib/include/2return_codes.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2014 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.
+ */
+
+#ifndef VBOOT_2_RETURN_CODES_H_
+#define VBOOT_2_RETURN_CODES_H_
+
+/*
+ * Return codes from verified boot functions.
+ *
+ * TODO: Go through code and replace VB2_ERROR_UNKNOWN with more specific
+ * error codes, and make the existing codes more consistent and useful.
+ */
+enum vb2_return_code {
+ /* Success - no error */
+ VB2_SUCCESS = 0,
+
+ /* Unknown / unspecified error */
+ VB2_ERROR_UNKNOWN = 0x10000,
+
+ /* Work buffer too small */
+ VB2_ERROR_WORKBUF_TOO_SMALL,
+
+ /* Buffer too small (other than the work buffer) */
+ VB2_ERROR_BUFFER_TOO_SMALL,
+
+ /* Buffer unaligned */
+ VB2_ERROR_BUFFER_UNALIGNED,
+
+ /* Bad GBB header */
+ VB2_ERROR_BAD_GBB_HEADER,
+
+ /* Bad algorithm - unknown, or unsupported */
+ VB2_ERROR_BAD_ALGORITHM,
+
+ /* Signature check failed */
+ VB2_ERROR_BAD_SIGNATURE,
+
+ /* Bad secure data */
+ VB2_ERROR_BAD_SECDATA,
+
+ /* Bad key */
+ VB2_ERROR_BAD_KEY,
+
+ /* Bad keyblock */
+ VB2_ERROR_BAD_KEYBLOCK,
+
+ /* Bad preamble */
+ VB2_ERROR_BAD_PREAMBLE,
+
+ /* Bad firmware keyblock version (out of range, or rollback) */
+ VB2_ERROR_FW_KEYBLOCK_VERSION,
+
+ /* Bad firmware version (out of range, or rollback) */
+ VB2_ERROR_FW_VERSION,
+
+ /* Bad hash tag */
+ VB2_ERROR_BAD_TAG,
+};
+
+#endif /* VBOOT_2_RETURN_CODES_H_ */
diff --git a/firmware/2lib/include/2sysincludes.h b/firmware/2lib/include/2sysincludes.h
new file mode 100644
index 00000000..4c9e66c6
--- /dev/null
+++ b/firmware/2lib/include/2sysincludes.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2014 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.
+ */
+
+/*
+ * System includes for vboot reference library. With few exceptions, this is
+ * the ONLY place in firmware/ where system headers may be included via
+ * #include <...>, so that there's only one place that needs to be fixed up for
+ * platforms which don't have all the system includes.
+ */
+
+#ifndef VBOOT_REFERENCE_2_SYSINCLUDES_H_
+#define VBOOT_REFERENCE_2_SYSINCLUDES_H_
+
+#include <inttypes.h> /* For PRIu64 */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+#include <byteswap.h>
+#include <memory.h>
+#endif
+
+#endif /* VBOOT_REFERENCE_2_SYSINCLUDES_H_ */
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
new file mode 100644
index 00000000..123de811
--- /dev/null
+++ b/tests/vb2_common_tests.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2014 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.
+ *
+ * Tests for firmware 2common.c
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+
+#include "test_common.h"
+
+/**
+ * Test alignment functions
+ */
+static void test_align(void)
+{
+ uint64_t buf[4];
+ uint8_t *p0, *ptr;
+ uint32_t size;
+
+ /* Already aligned */
+ p0 = (uint8_t *)buf;
+ ptr = p0;
+ size = 16;
+ TEST_EQ(vb2_align(&ptr, &size, 4, 16), 0, "vb2_align() aligned");
+ TEST_EQ(vb2_offset_of(p0, ptr), 0, "ptr");
+ TEST_EQ(size, 16, " size");
+ TEST_NEQ(vb2_align(&ptr, &size, 4, 17), 0, "vb2_align() small");
+
+ /* Offset */
+ ptr = p0 + 1;
+ size = 15;
+ TEST_EQ(vb2_align(&ptr, &size, 4, 12), 0, "vb2_align() offset");
+ TEST_EQ(vb2_offset_of(p0, ptr), 4, "ptr");
+ TEST_EQ(size, 12, " size");
+
+ /* Offset, now too small */
+ ptr = p0 + 1;
+ size = 15;
+ TEST_NEQ(vb2_align(&ptr, &size, 4, 15), 0, "vb2_align() offset small");
+
+ /* Offset, too small even to align */
+ ptr = p0 + 1;
+ size = 1;
+ TEST_NEQ(vb2_align(&ptr, &size, 4, 1), 0, "vb2_align() offset tiny");
+}
+
+/**
+ * Test work buffer functions
+ */
+static void test_workbuf(void)
+{
+ uint64_t buf[8];
+ uint8_t *p0 = (uint8_t *)buf, *ptr;
+ struct vb2_workbuf wb;
+
+ /* Init */
+ vb2_workbuf_init(&wb, p0, 32);
+ TEST_EQ(vb2_offset_of(p0, wb.buf), 0, "Workbuf init aligned");
+ TEST_EQ(wb.size, 32, " size");
+
+ vb2_workbuf_init(&wb, p0 + 4, 32);
+ TEST_EQ(vb2_offset_of(p0, wb.buf), 8, "Workbuf init unaligned");
+ TEST_EQ(wb.size, 28, " size");
+
+ vb2_workbuf_init(&wb, p0 + 2, 5);
+ TEST_EQ(wb.size, 0, "Workbuf init tiny unaligned size");
+
+ /* Alloc rounds up */
+ vb2_workbuf_init(&wb, p0, 32);
+ ptr = vb2_workbuf_alloc(&wb, 22);
+ TEST_EQ(vb2_offset_of(p0, ptr), 0, "Workbuf alloc");
+ TEST_EQ(vb2_offset_of(p0, wb.buf), 24, " buf");
+ TEST_EQ(wb.size, 8, " size");
+
+ vb2_workbuf_init(&wb, p0, 32);
+ TEST_PTR_EQ(vb2_workbuf_alloc(&wb, 33), NULL, "Workbuf alloc too big");
+
+ /* Free reverses alloc */
+ vb2_workbuf_init(&wb, p0, 32);
+ vb2_workbuf_alloc(&wb, 22);
+ vb2_workbuf_free(&wb, 22);
+ TEST_EQ(vb2_offset_of(p0, wb.buf), 0, "Workbuf free buf");
+ TEST_EQ(wb.size, 32, " size");
+
+ /* Realloc keeps same pointer as alloc */
+ vb2_workbuf_init(&wb, p0, 32);
+ vb2_workbuf_alloc(&wb, 6);
+ ptr = vb2_workbuf_realloc(&wb, 6, 21);
+ TEST_EQ(vb2_offset_of(p0, ptr), 0, "Workbuf realloc");
+ TEST_EQ(vb2_offset_of(p0, wb.buf), 24, " buf");
+ TEST_EQ(wb.size, 8, " size");
+}
+
+int main(int argc, char* argv[])
+{
+ test_align();
+ test_workbuf();
+
+ return gTestSuccess ? 0 : 255;
+}