diff options
author | Che-Liang Chiou <clchiou@chromium.org> | 2011-02-17 17:56:16 +0800 |
---|---|---|
committer | Che-Liang Chiou <clchiou@chromium.org> | 2011-02-17 17:56:16 +0800 |
commit | 305e9e5e85592652eb362050679a3b0d8fada3be (patch) | |
tree | 67a8cad69fd725d5fb7053f8a354a5b4e206bcc5 /utility | |
parent | ee2bc91d4393796721dc8a48d3510e3352f2b893 (diff) | |
download | vboot-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
Diffstat (limited to 'utility')
-rw-r--r-- | utility/Makefile | 10 | ||||
-rw-r--r-- | utility/dump_fmap.c | 64 | ||||
-rw-r--r-- | utility/load_firmware_test.c | 265 |
3 files changed, 292 insertions, 47 deletions
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; +} |