summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Reizner <zachr@chromium.org>2015-02-20 14:55:02 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-02-23 18:41:01 +0000
commit317bb498a697ae49f070e3ca46100b879f25aa1b (patch)
treeaa3a68bc9e3f06d58ca311c996a53520a323dcd0
parentf44ebbe36b2c1603437edc57b534244e89bfcd9c (diff)
downloadvboot-317bb498a697ae49f070e3ca46100b879f25aa1b.tar.gz
vboot2: add library function for extracting vmlinuz from kernel part
postinst needs access to a kernel that is bootable from legacy BIOS. futility provides extraction of a bootable vmlinuz from the kernel partition via the command line. This patch provides a function which does the same thing and is suitable for static linking into postinst with minimal additonal code linked in. This way we can avoid issues with running dynamic executables during postinst. BRANCH=none TEST=None BUG=chromium:455343 Change-Id: Iaec2f48e4d8f78a4bbfcc1636b6ce478e95e9a8e Reviewed-on: https://chromium-review.googlesource.com/251760 Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Queue: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org>
-rw-r--r--Makefile4
-rw-r--r--host/include/vboot_host.h9
-rw-r--r--host/lib/extract_vmlinuz.c74
3 files changed, 86 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 08049720..dfa971cf 100644
--- a/Makefile
+++ b/Makefile
@@ -454,6 +454,7 @@ HOSTLIB_SRCS = \
futility/dump_kernel_config_lib.c \
host/arch/${ARCH}/lib/crossystem_arch.c \
host/lib/crossystem.c \
+ host/lib/extract_vmlinuz.c \
host/lib/fmap.c \
host/lib/host_misc.c
@@ -478,7 +479,8 @@ TINYHOSTLIB_SRCS = \
firmware/stub/vboot_api_stub_disk.c \
firmware/stub/vboot_api_stub_sf.c \
firmware/stub/utility_stub.c \
- futility/dump_kernel_config_lib.c
+ futility/dump_kernel_config_lib.c \
+ host/lib/extract_vmlinuz.c
TINYHOSTLIB_OBJS = ${TINYHOSTLIB_SRCS:%.c=${BUILD}/%.o}
diff --git a/host/include/vboot_host.h b/host/include/vboot_host.h
index b22eea2d..4b5db67e 100644
--- a/host/include/vboot_host.h
+++ b/host/include/vboot_host.h
@@ -58,5 +58,14 @@ char *FindKernelConfig(const char *filename,
uint64_t kernel_body_load_address);
/****************************************************************************/
+/* Kernel partition */
+
+/* Used to get a bootable vmlinuz from the kernel partition. vmlinuz_out must
+ * be free'd after this function returns success. Success is indicated by a
+ * zero return value.
+ */
+int ExtractVmlinuz(void *kpart_data, size_t kpart_size,
+ void **vmlinuz_out, size_t *vmlinuz_size);
+
#endif /* VBOOT_HOST_H_ */
diff --git a/host/lib/extract_vmlinuz.c b/host/lib/extract_vmlinuz.c
new file mode 100644
index 00000000..81d3918e
--- /dev/null
+++ b/host/lib/extract_vmlinuz.c
@@ -0,0 +1,74 @@
+/* Copyright 2015 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.
+ *
+ * Exports a vmlinuz from a kernel partition in memory.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vboot_struct.h"
+
+
+int ExtractVmlinuz(void *kpart_data, size_t kpart_size,
+ void **vmlinuz_out, size_t *vmlinuz_size) {
+ uint64_t now = 0;
+ VbKeyBlockHeader *keyblock = NULL;
+ VbKernelPreambleHeader *preamble = NULL;
+ uint8_t *kblob_data = NULL;
+ uint64_t kblob_size = 0;
+ uint64_t vmlinuz_header_size = 0;
+ uint64_t vmlinuz_header_address = 0;
+ uint64_t vmlinuz_header_offset = 0;
+ void *vmlinuz = NULL;
+
+ keyblock = (VbKeyBlockHeader *)kpart_data;
+ now += keyblock->key_block_size;
+ if (now > kpart_size)
+ return 1;
+
+ preamble = (VbKernelPreambleHeader *)(kpart_data + now);
+ now += preamble->preamble_size;
+ if (now > kpart_size)
+ return 1;
+
+ kblob_data = kpart_data + now;
+ kblob_size = preamble->body_signature.data_size;
+
+ if (!kblob_data || (now + kblob_size) > kpart_size)
+ return 1;
+
+ if (preamble->header_version_minor > 0) {
+ vmlinuz_header_address = preamble->vmlinuz_header_address;
+ vmlinuz_header_size = preamble->vmlinuz_header_size;
+ }
+
+ if (!vmlinuz_header_size ||
+ kpart_data + vmlinuz_header_offset + vmlinuz_header_size > kpart_data) {
+ return 1;
+ }
+
+ // calculate the vmlinuz_header offset from
+ // the beginning of the kpart_data. The kblob doesn't
+ // include the body_load_offset, but does include
+ // the keyblock and preamble sections.
+ vmlinuz_header_offset = vmlinuz_header_address -
+ preamble->body_load_address +
+ keyblock->key_block_size +
+ preamble->preamble_size;
+
+ vmlinuz = malloc(vmlinuz_header_size + kblob_size);
+ if (vmlinuz == NULL)
+ return 1;
+
+ memcpy(vmlinuz, kpart_data + vmlinuz_header_offset,
+ vmlinuz_header_size);
+
+ memcpy(vmlinuz + vmlinuz_header_size, kblob_data, kblob_size);
+
+ *vmlinuz_out = vmlinuz;
+ *vmlinuz_size = vmlinuz_header_size + kblob_size;
+
+ return 0;
+}