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/load_firmware_test.c | |
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/load_firmware_test.c')
-rw-r--r-- | utility/load_firmware_test.c | 265 |
1 files changed, 265 insertions, 0 deletions
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; +} |