Chromium Code Reviews| Index: utility/load_firmware_test.c |
| diff --git a/utility/load_firmware_test.c b/utility/load_firmware_test.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c8759152022fb6fc71a2e69cbb26aa0cc9b231ba |
| --- /dev/null |
| +++ b/utility/load_firmware_test.c |
| @@ -0,0 +1,249 @@ |
| +/* 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; |
| +} |
| + |
| +/* Return NULL if cannot get firmware root key */ |
|
gauravsh
2011/02/10 20:02:05
i still don't see any comments for the arguments o
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| +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; |
| +} |
| + |
| +/* Return non-zero if cannot get verification block */ |
|
gauravsh
2011/02/10 20:02:05
comment about the arguments and what this function
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| +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 */ |
|
gauravsh
2011/02/10 20:02:05
ok, I see you added the comment here - but still t
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| +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 == NULL) { |
|
gauravsh
2011/02/10 20:02:05
!lfp.firmware_root_key_blob is the usual way than
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| + 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 for initialize firmware key and data A / B */ |
|
gauravsh
2011/02/10 20:02:05
s/for/to/
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| + 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); |
| + } |
| + |
| + /* remember to free kernel_sign_key_blob before exit */ |
|
gauravsh
2011/02/10 20:02:05
i would get rid of the comment. it is not clear wh
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| + 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); |
| + |
| + /* Call to LoadFirmware */ |
|
gauravsh
2011/02/10 20:02:05
this is not a useful comment. please remove.
Che-Liang Chiou
2011/02/14 02:27:53
Done.
|
| + |
| + 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 = FindFmap((char*) base_of_rom, rom_size); |
| + |
| + retval = DriveLoadFirmware(base_of_rom, fmap); |
| + |
| + Free((void*) base_of_rom); |
| + |
| + return retval; |
| +} |