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..b6cf98b6cba28c78e3bf4a62a991624fada2b461 |
| --- /dev/null |
| +++ b/utility/load_firmware_test.c |
| @@ -0,0 +1,240 @@ |
| +/* 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 <errno.h> |
| +#include <fcntl.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| +#include <sys/mman.h> |
| +#include <sys/stat.h> |
| +#include <sys/types.h> |
| +#include <unistd.h> |
| + |
| +#include "fmap.h" |
| +#include "gbb_header.h" |
| +#include "load_firmware_fw.h" |
| +#include "vboot_struct.h" |
| + |
| + |
| +typedef struct _CallerInternal { |
| + struct { |
| + uint8_t *fw; |
|
Randall Spangler
2011/02/09 19:42:14
Google style nit: * is next to the type, not the v
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + uint64_t size; |
| + } firmware[2]; |
| +} CallerInternal; |
| + |
| +static char *progname = NULL; |
| +static char *image_path = NULL; |
| + |
| + |
| +/* return -1 on error */ |
| +int area_index(FmapHeader *fh, AreaHeader *ah, const char name[]); |
|
Randall Spangler
2011/02/09 19:42:14
move to fmap.h; add more description
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| +/* wrapper of area_index; print error when not found */ |
| +int area_index_or_error(FmapHeader *fh, AreaHeader *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 zero on success, non-zero on error */ |
| +int drive_load_firmware(void *base_of_rom, void *fmap) { |
|
gauravsh
2011/02/09 19:58:22
comment on arguments and what the function does?
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + LoadFirmwareParams lfp; |
| + CallerInternal ci; |
| + |
| + FmapHeader *fh = (FmapHeader *) fmap; |
| + AreaHeader *ah = (AreaHeader *) (fmap + sizeof(FmapHeader)); |
| + int retval = 1; |
| + int i, j, k, status; |
| + void *gbb, *kb; |
| + GoogleBinaryBlockHeader *gbbh; |
| + VbKeyBlockHeader *kbh; |
| + VbFirmwarePreambleHeader *fph; |
| + const char *status_str; |
| + |
| + const char *key_area_name[2] = { |
| + "Firmware A Key", |
| + "Firmware B Key" |
| + }; |
| + 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 |
| + }; |
| + |
| + const char *data_area_name[2] = { |
| + "Firmware A Data", |
| + "Firmware B Data" |
| + }; |
| + |
| + i = area_index_or_error(fh, ah, "GBB Area"); |
| + if (i < 0) |
| + goto EXIT; |
| + |
| + gbb = base_of_rom + ah[i].area_offset; |
|
gauravsh
2011/02/09 19:58:22
2 comments -
1) this method is pretty big. conside
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + gbbh = (GoogleBinaryBlockHeader *) gbb; |
| + lfp.firmware_root_key_blob = gbb + gbbh->rootkey_offset; |
| + printf("firmware root key blob at 0x%08" PRIx64 "\n", |
| + lfp.firmware_root_key_blob - base_of_rom); |
| + |
| + for (k = 0; k < 2; k ++) { |
| + i = area_index_or_error(fh, ah, key_area_name[k]); |
| + if (i < 0) |
| + goto EXIT; |
| + |
| + j = area_index_or_error(fh, ah, data_area_name[k]); |
| + if (j < 0) |
| + goto EXIT; |
| + |
| + kb = base_of_rom + ah[i].area_offset; |
| + |
| + *vblock_ptr[k] = kb; |
| + printf("verification block %d at 0x%08" PRIx64 "\n", k, |
| + *vblock_ptr[k] - base_of_rom); |
| + |
| + kbh = (VbKeyBlockHeader *) kb; |
| + fph = (VbFirmwarePreambleHeader *) (kb + kbh->key_block_size); |
| + |
| + *vsize_ptr[k] = kbh->key_block_size + fph->preamble_size; |
| + printf("verification block %d size is 0x%08" PRIx64 "\n", k, *vsize_ptr[k]); |
| + |
| + ci.firmware[k].fw = (uint8_t *) (base_of_rom + ah[j].area_offset); |
| + printf("firmware %c at 0x%08" PRIx64 "\n", "AB"[k], |
| + (void *) ci.firmware[k].fw - base_of_rom); |
| + |
| + ci.firmware[k].size = (uint64_t) fph->body_signature.data_size; |
| + printf("firmware %c size is 0x%08" PRIx64 "\n", "AB"[k], |
| + ci.firmware[k].size); |
| + } |
| + lfp.caller_internal = &ci; |
| + |
| + /* remember to free kernel_sign_key_blob before exit */ |
| + 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); |
| + retval = 0; |
| + |
| +EXIT: |
|
gauravsh
2011/02/09 19:58:22
in general, we try to avoid goto. refactor to not
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + return retval; |
| +} |
| + |
| +/* return -1 on error */ |
| +int area_index(FmapHeader *fh, AreaHeader *ah, const char name[]) { |
|
Randall Spangler
2011/02/09 19:42:14
Move these to fmap.c
Use Fmap prefix on all funct
Randall Spangler
2011/02/09 19:42:14
const char* name
Che-Liang Chiou
2011/02/10 09:11:03
Done.
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + size_t len = strlen(name); |
|
Randall Spangler
2011/02/09 19:42:14
Is this just an optimization to save doing the imp
Che-Liang Chiou
2011/02/10 09:11:03
I guess not.
|
| + int i; |
| + for (i = 0; i < fh->fmap_nareas; i++) |
| + if (!strncmp((const char *) ah[i].area_name, name, len)) |
| + return i; |
| + return -1; |
| +} |
| + |
| +/* wrap area_index; print error when not found */ |
| +int area_index_or_error(FmapHeader *fh, AreaHeader *ah, const char name[]) { |
|
gauravsh
2011/02/09 19:58:22
this looks like it could be moved to fmap.c
Che-Liang Chiou
2011/02/10 09:11:03
progname is a static global variable of load_firmw
|
| + int i = area_index(fh, ah, name); |
| + if (i < 0) |
| + fprintf(stderr, "%s: can't find %s in firmware image\n", progname, name); |
| + return i; |
| +} |
| + |
| +/* return NULL on error */ |
| +const char *status_string(int status) { |
|
gauravsh
2011/02/09 19:58:22
comment?
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + 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; |
| + } |
| +} |
| + |
| +/* main function and its subroutines */ |
| + |
| +void error_and_exit(char *action_name) { |
| + fprintf(stderr, "%s: can't %s %s: %s\n", |
| + progname, |
| + action_name, |
| + image_path, |
| + strerror(errno)); |
| + exit(1); |
| +} |
| + |
| +int main(int argc, char *argv[]) { |
| + int fd, retval = 0; |
| + struct stat sb; |
| + void *base_of_rom, *fmap; |
| + |
| + progname = argv[0]; |
| + |
| + if (argc < 2) { |
| + fprintf(stderr, "usage: %s <firmware_image>\n", progname); |
| + exit(1); |
| + } |
| + |
| + image_path = argv[1]; |
| + |
| + if (0 != stat(image_path, &sb)) |
| + error_and_exit("stat"); |
| + |
| + fd = open(image_path, O_RDONLY); |
|
Randall Spangler
2011/02/09 19:42:14
Why not just use ReadFile() from host lib? Code w
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + if (fd < 0) |
| + error_and_exit("open"); |
| + |
| + printf("opened %s\n", image_path); |
| + |
| + base_of_rom = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
|
gauravsh
2011/02/09 19:58:22
i don't think it is really any better to use mmap(
Che-Liang Chiou
2011/02/10 09:11:03
Done.
|
| + if (base_of_rom == (void *) -1) { |
| + close(fd); |
| + error_and_exit("mmap"); |
| + } |
| + |
| + fmap = find_fmap((char *) base_of_rom, sb.st_size); |
| + |
| + retval = drive_load_firmware(base_of_rom, fmap); |
| + |
| + if (0 != munmap(base_of_rom, sb.st_size)) { |
| + close(fd); |
| + error_and_exit("munmap"); |
| + } |
| + |
| + if (0 != close(fd)) |
| + error_and_exit("close"); |
| + |
| + return retval; |
| +} |