summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChe-Liang Chiou <clchiou@chromium.org>2011-02-17 17:56:16 +0800
committerChe-Liang Chiou <clchiou@chromium.org>2011-02-17 17:56:16 +0800
commit305e9e5e85592652eb362050679a3b0d8fada3be (patch)
tree67a8cad69fd725d5fb7053f8a354a5b4e206bcc5
parentee2bc91d4393796721dc8a48d3510e3352f2b893 (diff)
downloadvboot-305e9e5e85592652eb362050679a3b0d8fada3be.tar.gz
Add load_firmware_test utility program
BUG=chromium-os:1302 TEST=emerge vboot_reference && (load_firmware_test firmware_image.bin | grep LOAD_FIRMWARE_SUCCESS) Review URL: http://codereview.chromium.org/6465018 Change-Id: I85fce39aaf4abb50bd70d126ac8c7cb892a7857b
-rw-r--r--host/Makefile3
-rw-r--r--host/include/fmap.h47
-rw-r--r--host/lib/fmap.c30
-rw-r--r--utility/Makefile10
-rw-r--r--utility/dump_fmap.c64
-rw-r--r--utility/load_firmware_test.c265
6 files changed, 371 insertions, 48 deletions
diff --git a/host/Makefile b/host/Makefile
index 450f15ae..3226ac38 100644
--- a/host/Makefile
+++ b/host/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# 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.
@@ -16,6 +16,7 @@ INCLUDES += \
LIB_SRCS = \
./lib/crossystem.c \
./lib/file_keys.c \
+ ./lib/fmap.c \
./lib/host_common.c \
./lib/host_key.c \
./lib/host_keyblock.c \
diff --git a/host/include/fmap.h b/host/include/fmap.h
new file mode 100644
index 00000000..7da2dd90
--- /dev/null
+++ b/host/include/fmap.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __FMAP_H__
+#define __FMAP_H__
+
+#include <inttypes.h>
+#include <stddef.h>
+
+/* FMAP structs. See http://code.google.com/p/flashmap/wiki/FmapSpec */
+#define FMAP_NAMELEN 32
+#define FMAP_SIGNATURE "__FMAP__"
+#define FMAP_SIGNATURE_SIZE 8
+#define FMAP_SEARCH_STRIDE 4
+typedef struct _FmapHeader {
+ char fmap_signature[FMAP_SIGNATURE_SIZE]; /* avoiding endian issues */
+ uint8_t fmap_ver_major;
+ uint8_t fmap_ver_minor;
+ uint64_t fmap_base;
+ uint32_t fmap_size;
+ char fmap_name[FMAP_NAMELEN];
+ uint16_t fmap_nareas;
+} __attribute__((packed)) FmapHeader;
+
+typedef struct _FmapAreaHeader {
+ uint32_t area_offset;
+ uint32_t area_size;
+ char area_name[FMAP_NAMELEN];
+ uint16_t area_flags;
+} __attribute__((packed)) FmapAreaHeader;
+
+
+/* Scan firmware image, pointed by [ptr] with length [size], for fmap header.
+ * Return pointer to fmap header, or NULL if not found.
+ */
+const char* FmapFind(const char *ptr, size_t size);
+
+/* Look up fmap area by name, that is, strcmp(fh->fmap_name, name) == 0.
+ * Return index of fmap area, that is, ah[returned_index],
+ * or -1 if not found. */
+int FmapAreaIndex(const FmapHeader* fh, const FmapAreaHeader* ah,
+ const char* name);
+
+#endif /* __FMAP_H__ */
diff --git a/host/lib/fmap.c b/host/lib/fmap.c
new file mode 100644
index 00000000..3c3f340b
--- /dev/null
+++ b/host/lib/fmap.c
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "fmap.h"
+
+const char* FmapFind(const char* ptr, size_t size)
+{
+ size_t i;
+ for (i=0; i<size; i += FMAP_SEARCH_STRIDE) {
+ if (0 == strncmp(ptr, FMAP_SIGNATURE, FMAP_SIGNATURE_SIZE))
+ return ptr;
+ ptr += FMAP_SEARCH_STRIDE;
+ }
+ return NULL;
+}
+
+int FmapAreaIndex(const FmapHeader* fh, const FmapAreaHeader* ah,
+ const char* name) {
+ int i;
+ for (i = 0; i < fh->fmap_nareas; i++)
+ if (!strcmp((const char*) ah[i].area_name, name))
+ return i;
+ return -1;
+}
diff --git a/utility/Makefile b/utility/Makefile
index 8ea53a62..6cf19c0a 100644
--- a/utility/Makefile
+++ b/utility/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# 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.
@@ -21,6 +21,7 @@ TARGET_NAMES = crossystem \
dumpRSAPublicKey \
dump_kernel_config \
gbb_utility \
+ load_firmware_test \
load_kernel_test \
pad_digest_utility \
signature_digest_utility \
@@ -77,6 +78,9 @@ ${BUILD_ROOT}/bmpblk_utility: ${BUILD_ROOT}/bmpblk_utility.o \
${BUILD_ROOT}/efidecompress.o
$(CXX) -llzma -lyaml $(CFLAGS) $^ -o $@
+${BUILD_ROOT}/load_firmware_test: load_firmware_test.c $(LIBS)
+ $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
+
${BUILD_ROOT}/load_kernel_test: load_kernel_test.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
@@ -127,8 +131,8 @@ ${BUILD_ROOT}/tpmc: tpmc.c $(LIBS)
${BUILD_ROOT}/dev_sign_file: dev_sign_file.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
-${BUILD_ROOT}/dump_fmap: dump_fmap.c
- $(CC) $(CFLAGS) $< -o $@
+${BUILD_ROOT}/dump_fmap: dump_fmap.c $(LIBS)
+ $(CC) $(CFLAGS) $< -o $@ $(LIBS)
${BUILD_ROOT}/pack_firmware_image: pack_firmware_image
cp -f $< $@
diff --git a/utility/dump_fmap.c b/utility/dump_fmap.c
index ab92b82a..bd7abac9 100644
--- a/utility/dump_fmap.c
+++ b/utility/dump_fmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * 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.
*/
@@ -15,41 +15,22 @@
#include <sys/types.h>
#include <unistd.h>
+#include "fmap.h"
+
/* global variables */
static int opt_extract = 0;
-static char *progname;
-static void *base_of_rom;
-
-/* FMAP structs. See http://code.google.com/p/flashmap/wiki/FmapSpec */
-#define FMAP_SIGLEN 8
-#define FMAP_NAMELEN 32
-#define FMAP_SEARCH_STRIDE 4
-typedef struct _FmapHeader {
- char fmap_signature[FMAP_SIGLEN]; /* avoiding endian issues */
- uint8_t fmap_ver_major;
- uint8_t fmap_ver_minor;
- uint64_t fmap_base;
- uint32_t fmap_size;
- char fmap_name[FMAP_NAMELEN];
- uint16_t fmap_nareas;
-} __attribute__((packed)) FmapHeader;
-
-typedef struct _AreaHeader {
- uint32_t area_offset;
- uint32_t area_size;
- char area_name[FMAP_NAMELEN];
- uint16_t area_flags;
-} __attribute__((packed)) AreaHeader;
+static char* progname;
+static void* base_of_rom;
/* Return 0 if successful */
-static int dump_fmap(void *ptr) {
+static int dump_fmap(const void* ptr) {
int i,retval = 0;
char buf[80]; // DWR: magic number
- FmapHeader *fmh = (FmapHeader *)ptr;
- AreaHeader *ah = (AreaHeader *)(ptr + sizeof(FmapHeader));
+ const FmapHeader* fmh = (const FmapHeader*) ptr;
+ const FmapAreaHeader* ah = (const FmapAreaHeader*) (ptr + sizeof(FmapHeader));
- snprintf(buf, FMAP_SIGLEN+1, "%s", fmh->fmap_signature);
+ snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature);
printf("fmap_signature %s\n", buf);
printf("fmap_version: %d.%d\n", fmh->fmap_ver_major, fmh->fmap_ver_minor);
printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
@@ -66,11 +47,11 @@ static int dump_fmap(void *ptr) {
printf("area_name: %s\n", buf);
if (opt_extract) {
- char *s;
- for (s=buf; *s; s++)
+ char* s;
+ for (s=buf;* s; s++)
if (*s == ' ')
- *s = '_';
- FILE *fp = fopen(buf,"wb");
+ *s = '_';
+ FILE* fp = fopen(buf,"wb");
if (!fp) {
fprintf(stderr, "%s: can't open %s: %s\n",
progname, buf, strerror(errno));
@@ -94,13 +75,12 @@ static int dump_fmap(void *ptr) {
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
int c;
int errorcnt = 0;
struct stat sb;
int fd;
- char *s;
- size_t i;
+ const char* fmap;
int retval = 1;
progname = strrchr(argv[0], '/');
@@ -160,7 +140,7 @@ int main(int argc, char *argv[]) {
printf("opened %s\n", argv[optind]);
base_of_rom = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (base_of_rom == (char *)-1) {
+ if (base_of_rom == (char*)-1) {
fprintf(stderr, "%s: can't mmap %s: %s\n",
progname,
argv[optind],
@@ -170,14 +150,10 @@ int main(int argc, char *argv[]) {
}
close(fd); /* done with this now */
- s = (char *)base_of_rom;
- for (i=0; i<sb.st_size; i += FMAP_SEARCH_STRIDE) {
- if (0 == strncmp(s, "__FMAP__", 8)) {
- printf("hit at 0x%08x\n", (uint32_t)i);
- retval = dump_fmap(s);
- break;
- }
- s += FMAP_SEARCH_STRIDE;
+ fmap = FmapFind((char*) base_of_rom, sb.st_size);
+ if (fmap) {
+ printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom));
+ retval = dump_fmap(fmap);
}
if (0 != munmap(base_of_rom, sb.st_size)) {
diff --git a/utility/load_firmware_test.c b/utility/load_firmware_test.c
new file mode 100644
index 00000000..c5f3cd59
--- /dev/null
+++ b/utility/load_firmware_test.c
@@ -0,0 +1,265 @@
+/* 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.
+ *
+ * Routines for verifying a firmware image's signature.
+ */
+
+#include <stdio.h>
+
+#include "fmap.h"
+#include "gbb_header.h"
+#include "host_misc.h"
+#include "load_firmware_fw.h"
+#include "vboot_struct.h"
+
+
+typedef struct _CallerInternal {
+ struct {
+ uint8_t* fw;
+ uint64_t size;
+ } firmware[2];
+} CallerInternal;
+
+static char* progname = NULL;
+static char* image_path = NULL;
+
+
+/* wrapper of FmapAreaIndex; print error when not found */
+int FmapAreaIndexOrError(const FmapHeader* fh, const FmapAreaHeader* ah,
+ const char* name);
+/* return NULL on error */
+const char* status_string(int status);
+
+int GetFirmwareBody(LoadFirmwareParams* params, uint64_t firmware_index) {
+ CallerInternal* ci = (CallerInternal*) params->caller_internal;
+
+ if (firmware_index != 0 && firmware_index != 1)
+ return 1;
+
+ UpdateFirmwareBodyHash(params,
+ ci->firmware[firmware_index].fw,
+ ci->firmware[firmware_index].size);
+
+ return 0;
+}
+
+/* Get firmware root key
+ *
+ * Return pointer to firmware root key of firmware image, or NULL if not found
+ *
+ * [base_of_rom] pointer to firmware image
+ * [fmap] pointer to Flash Map of firmware image
+ */
+void* GetFirmwareRootKey(const void* base_of_rom, const void* fmap) {
+ const FmapHeader* fh = (const FmapHeader*) fmap;
+ const FmapAreaHeader* ah = (const FmapAreaHeader*)
+ (fmap + sizeof(FmapHeader));
+ int i = FmapAreaIndexOrError(fh, ah, "GBB Area");
+ const void* gbb;
+ const GoogleBinaryBlockHeader* gbbh;
+
+ if (i < 0)
+ return NULL;
+
+ gbb = base_of_rom + ah[i].area_offset;
+ gbbh = (const GoogleBinaryBlockHeader*) gbb;
+ return (void*) gbb + gbbh->rootkey_offset;
+}
+
+/* Get verification block
+ *
+ * Return zero if succeed, or non-zero if failed
+ *
+ * [base_of_rom] pointer to firmware image
+ * [fmap] pointer to Flash Map of firmware image
+ * [index] index of verification block
+ * [verification_block_ptr] pointer to storing the found verification block
+ * [verification_size_ptr] pointer to store the found verification block size
+ */
+int GetVerificationBlock(const void* base_of_rom, const void* fmap, int index,
+ void** verification_block_ptr, uint64_t* verification_size_ptr) {
+ const char* key_area_name[2] = {
+ "Firmware A Key",
+ "Firmware B Key"
+ };
+ const FmapHeader* fh = (const FmapHeader*) fmap;
+ const FmapAreaHeader* ah = (const FmapAreaHeader*)
+ (fmap + sizeof(FmapHeader));
+ int i = FmapAreaIndexOrError(fh, ah, key_area_name[index]);
+ const void* kb;
+ const VbKeyBlockHeader* kbh;
+ const VbFirmwarePreambleHeader* fph;
+
+ if (i < 0)
+ return 1;
+
+ kb = base_of_rom + ah[i].area_offset;
+ *verification_block_ptr = (void*) kb;
+
+ kbh = (const VbKeyBlockHeader*) kb;
+ fph = (const VbFirmwarePreambleHeader*) (kb + kbh->key_block_size);
+
+ *verification_size_ptr = kbh->key_block_size + fph->preamble_size;
+
+ return 0;
+}
+
+/* Return non-zero if not found */
+int GetFirmwareData(const void* base_of_rom, const void* fmap, int index,
+ void *verification_block, uint8_t** body_ptr, uint64_t *size_ptr) {
+ const char* data_area_name[2] = {
+ "Firmware A Data",
+ "Firmware B Data"
+ };
+ const FmapHeader* fh = (const FmapHeader*) fmap;
+ const FmapAreaHeader* ah = (const FmapAreaHeader*)
+ (fmap + sizeof(FmapHeader));
+ const VbKeyBlockHeader* kbh = (const VbKeyBlockHeader*) verification_block;
+ const VbFirmwarePreambleHeader* fph = (const VbFirmwarePreambleHeader*)
+ (verification_block + kbh->key_block_size);
+ int i = FmapAreaIndexOrError(fh, ah, data_area_name[index]);
+
+ if (i < 0)
+ return 1;
+
+ *body_ptr = (uint8_t*) (base_of_rom + ah[i].area_offset);
+ *size_ptr = (uint64_t) fph->body_signature.data_size;
+ return 0;
+}
+
+/* Verify firmware image [base_of_rom] using [fmap] for looking up areas.
+ * Return zero on success, non-zero on error
+ *
+ * [base_of_rom] pointer to start of firmware image
+ * [fmap] pointer to start of Flash Map of firmware image
+ */
+int DriveLoadFirmware(const void* base_of_rom, const void* fmap) {
+ LoadFirmwareParams lfp;
+ CallerInternal ci;
+
+ const char* status_str;
+ int index, status;
+
+ void** vblock_ptr[2] = {
+ &lfp.verification_block_0, &lfp.verification_block_1
+ };
+ uint64_t* vsize_ptr[2] = {
+ &lfp.verification_size_0, &lfp.verification_size_1
+ };
+
+ /* Initialize LoadFirmwareParams lfp */
+
+ lfp.caller_internal = &ci;
+
+ lfp.firmware_root_key_blob = GetFirmwareRootKey(base_of_rom, fmap);
+ if (!lfp.firmware_root_key_blob) {
+ printf("ERROR: cannot get firmware root key blob\n");
+ return 1;
+ }
+
+ printf("firmware root key blob at 0x%08" PRIx64 "\n",
+ lfp.firmware_root_key_blob - base_of_rom);
+
+ /* Loop to initialize firmware key and data A / B */
+ for (index = 0; index < 2; ++index) {
+ if (GetVerificationBlock(base_of_rom, fmap, index,
+ vblock_ptr[index], vsize_ptr[index])) {
+ printf("ERROR: cannot get key block %d\n", index);
+ return 1;
+ }
+
+ printf("verification block %d at 0x%08" PRIx64 "\n", index,
+ *vblock_ptr[index] - base_of_rom);
+ printf("verification block %d size is 0x%08" PRIx64 "\n", index,
+ *vsize_ptr[index]);
+
+ if (GetFirmwareData(base_of_rom, fmap, index, *vblock_ptr[index],
+ &(ci.firmware[index].fw), &(ci.firmware[index].size))) {
+ printf("ERROR: cannot get firmware body %d\n", index);
+ return 1;
+ }
+
+ printf("firmware %c at 0x%08" PRIx64 "\n", "AB"[index],
+ (void*) ci.firmware[index].fw - base_of_rom);
+ printf("firmware %c size is 0x%08" PRIx64 "\n", "AB"[index],
+ ci.firmware[index].size);
+ }
+
+ lfp.kernel_sign_key_blob = Malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE);
+ lfp.kernel_sign_key_size = LOAD_FIRMWARE_KEY_BLOB_REC_SIZE;
+ printf("kernel sign key size is 0x%08" PRIx64 "\n", lfp.kernel_sign_key_size);
+
+ lfp.boot_flags = 0;
+ printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags);
+
+ status = LoadFirmware(&lfp);
+ status_str = status_string(status);
+ if (status_str)
+ printf("LoadFirmware returns %s\n", status_str);
+ else
+ printf("LoadFirmware returns unknown status code: %d\n", status);
+ if (status == LOAD_FIRMWARE_SUCCESS)
+ printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index);
+
+ Free(lfp.kernel_sign_key_blob);
+
+ return 0;
+}
+
+/* wrap FmapAreaIndex; print error when not found */
+int FmapAreaIndexOrError(const FmapHeader* fh, const FmapAreaHeader* ah,
+ const char* name) {
+ int i = FmapAreaIndex(fh, ah, name);
+ if (i < 0)
+ fprintf(stderr, "%s: can't find %s in firmware image\n", progname, name);
+ return i;
+}
+
+/* Convert status returned by LoadFirmware to string. Return NULL on error. */
+const char* status_string(int status) {
+ switch (status) {
+ case LOAD_FIRMWARE_SUCCESS:
+ return "LOAD_FIRMWARE_SUCCESS";
+ case LOAD_FIRMWARE_RECOVERY:
+ return "LOAD_FIRMWARE_RECOVERY";
+ case LOAD_FIRMWARE_REBOOT:
+ return "LOAD_FIRMWARE_REBOOT";
+ case LOAD_FIRMWARE_RECOVERY_TPM:
+ return "LOAD_FIRMWARE_RECOVERY_TPM";
+ default:
+ return NULL;
+ }
+}
+
+int main(int argc, char* argv[]) {
+ int retval = 0;
+ const void* base_of_rom;
+ const void* fmap;
+ uint64_t rom_size;
+
+ progname = argv[0];
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <firmware_image>\n", progname);
+ exit(1);
+ }
+
+ image_path = argv[1];
+
+ base_of_rom = ReadFile(image_path, &rom_size);
+ if (base_of_rom == NULL) {
+ fprintf(stderr, "%s: can not open %s\n", progname, image_path);
+ exit(1);
+ }
+
+ printf("opened %s\n", image_path);
+
+ fmap = FmapFind((char*) base_of_rom, rom_size);
+
+ retval = DriveLoadFirmware(base_of_rom, fmap);
+
+ Free((void*) base_of_rom);
+
+ return retval;
+}