From fec47595ce655c580749f9a3f47e1fd6bd4d8ee3 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Fri, 26 Aug 2011 15:13:45 +0800 Subject: gbb_utility: add --flags parameter. The --flags is added to get/set the "flags" field. BUG=chrome-os-partner:2317 TEST=gbb_utiltiy --get --flags bios.bin # see flags as 0 gbb_utility --set --flags=0x3052 bios.bin # for version error message for GBB1.0 files, # and see flag value changed for GBB1.1+ files gbb_utility --get --flags bios.bin # flag as 0 for GBB1.0, 0x3052 for GBB1.1+ Change-Id: I7aab62c8fc32ea08b4822e496f543511ff5e5ebc Reviewed-on: http://gerrit.chromium.org/gerrit/6721 Reviewed-by: Bill Richardson Reviewed-by: Randall Spangler Tested-by: Hung-Te Lin --- firmware/include/gbb_header.h | 8 +- utility/gbb_utility.cc | 167 ++++++++++++++++++++++++++++++++++++------ utility/include/gbb_utility.h | 9 +++ 3 files changed, 156 insertions(+), 28 deletions(-) diff --git a/firmware/include/gbb_header.h b/firmware/include/gbb_header.h index b9ac3e82..c9d2909c 100644 --- a/firmware/include/gbb_header.h +++ b/firmware/include/gbb_header.h @@ -46,7 +46,7 @@ typedef struct GoogleBinaryBlockHeader { uint16_t major_version; /* See GBB_MAJOR_VER */ uint16_t minor_version; /* See GBB_MINOR_VER */ uint32_t header_size; /* size of GBB header in bytes */ - uint32_t reserved; + uint32_t flags; /* Flags (see GBB_FLAG_*), should be 0 for 1.0. */ uint32_t hwid_offset; /* HWID offset from start of header */ uint32_t hwid_size; /* HWID size in bytes */ @@ -57,11 +57,7 @@ typedef struct GoogleBinaryBlockHeader { uint32_t recovery_key_offset; /* Recovery Key offset from start of header */ uint32_t recovery_key_size; /* Recovery Key size in bytes */ - /* Fields added in version 1.1 */ - uint32_t flags; /* Flags (see GBB_FLAG_*). Readers should return - * flags=0 for v1.0 structs. */ - - uint8_t pad[76]; /* To match GBB_HEADER_SIZE. Initialize to 0. */ + uint8_t pad[80]; /* To match GBB_HEADER_SIZE. Initialize to 0. */ } __attribute__((packed)) GoogleBinaryBlockHeader; #ifdef __cplusplus diff --git a/utility/gbb_utility.cc b/utility/gbb_utility.cc index a051589c..544e1848 100644 --- a/utility/gbb_utility.cc +++ b/utility/gbb_utility.cc @@ -73,6 +73,29 @@ static bool write_nonempty_file(const char *filename, const string &content) { return r == 1; } +// utility function: convert integer to little-endian encoded bytes +// return the byte array in string type +static string int2bytes(const uint32_t value) { + const char *pvalue = reinterpret_cast(&value); + return string(pvalue, sizeof(value)); +} + +// utility function: convert little-endian encoded bytes to integer +// return value in uint32_t type +static uint32_t bytes2int(const string &bytes) { + assert(bytes.size() == sizeof(uint32_t)); + return *reinterpret_cast(bytes.c_str()); +} + +// utility function: compare a GBB header with given version numbers. +// return 1 for "larger", 0 for "equal" and -1 for "smaller". +static int version_compare(const GoogleBinaryBlockHeader& header, + int major, int minor) { + if (header.major_version != major) + return header.major_version - major; + return header.minor_version - minor; +} + /////////////////////////////////////////////////////////////////////// // GBB Utility implementation @@ -277,6 +300,13 @@ bool GoogleBinaryBlockUtil::find_property(PROPINDEX i, uint32_t *psize, const char** pname) const { switch (i) { + case PROP_FLAGS: + *poffset = (uint8_t*)&header_.flags - (uint8_t*)&header_; + *psize = sizeof(header_.flags); + if (pname) + *pname = "flags"; + break; + case PROP_HWID: *poffset = header_.hwid_offset; *psize = header_.hwid_size; @@ -327,19 +357,48 @@ bool GoogleBinaryBlockUtil::set_property(PROPINDEX i, const string &value) { if (!find_property(i, &prop_offset, &prop_size, &prop_name)) return false; + // special processing by version + if (version_compare(header_, 1, 1) < 0) { + if (i == PROP_FLAGS) { + assert(value.size() == prop.size()); + if (int2bytes(0) != value) { + if (verbose) + fprintf(stderr, + "error: property %s is not supported on GBB version %d.%d\n", + prop_name, header_.major_version, header_.minor_version); + return false; + } + } + } + + + if (prop_size < value.size()) { if (verbose) - fprintf(stderr, " error: value size (%zu) exceed property capacity " + fprintf(stderr, "error: value size (%zu) exceed property capacity " "(%u): %s\n", value.size(), prop_size, prop_name); return false; } - if (i == PROP_HWID && prop_size == value.size()) { - // special case: this is NUL-terminated so it's better to keep one more \0 - if (verbose) - fprintf(stderr, "error: NUL-terminated string exceed capacity (%d): %s\n", - prop_size, prop_name); - return false; + // special properties + switch (i) { + case PROP_HWID: + if (value.size() == prop_size) { + if (verbose) + fprintf(stderr, + "error: NUL-terminated string exceed capacity (%d): %s\n", + prop_size, prop_name); + return false; + } + break; + + case PROP_FLAGS: + assert(value.size() == prop_size); + header_.flags = bytes2int(value); + break; + + default: + break; } string::iterator dest = file_content_.begin() + header_offset_ + prop_offset; @@ -367,6 +426,12 @@ string GoogleBinaryBlockUtil::get_property(PROPINDEX i) const { return ""; } + // special processing by version + if (version_compare(header_, 1, 1) < 0) { + if (i == PROP_FLAGS) + return int2bytes(0); + } + string::const_iterator dest = file_content_.begin() + header_offset_ + prop_offset; return string(dest, dest + prop_size); @@ -384,6 +449,14 @@ string GoogleBinaryBlockUtil::get_property_name(PROPINDEX i) const { return prop_name; } +uint32_t GoogleBinaryBlockUtil::get_flags() const { + return bytes2int(get_property(PROP_FLAGS)); +} + +bool GoogleBinaryBlockUtil::set_flags(const uint32_t flags) { + return set_property(PROP_FLAGS, int2bytes(flags)); +} + bool GoogleBinaryBlockUtil::set_hwid(const char *hwid) { return set_property(PROP_HWID, hwid); } @@ -413,7 +486,7 @@ using vboot_reference::GoogleBinaryBlockUtil; // utility function: provide usage of this utility and exit. static void usagehelp_exit(const char *prog_name) { - printf( + fprintf(stderr, "Utility to manage Google Binary Block (GBB)\n" "Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n" "\n" @@ -421,6 +494,7 @@ static void usagehelp_exit(const char *prog_name) { "-g, --get (default)\tGet (read) from bios_file, " "with following options:\n" " --hwid \tReport hardware id (default).\n" + " --flags \tReport header flags.\n" " -k, --rootkey=FILE \tFile name to export Root Key.\n" " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" " --recoverykey=FILE\tFile name to export Recovery Key.\n" @@ -430,6 +504,7 @@ static void usagehelp_exit(const char *prog_name) { "with following options:\n" " -o, --output=FILE \tNew file name for ouptput.\n" " -i, --hwid=HWID \tThe new hardware id to be changed.\n" + " --flags=FLAGS \tThe new (numeric) flags value.\n" " -k, --rootkey=FILE \tFile name of new Root Key.\n" " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" " --recoverykey=FILE\tFile name of new Recovery Key.\n" @@ -440,8 +515,8 @@ static void usagehelp_exit(const char *prog_name) { "SAMPLE:\n" " %s -g bios.bin\n" " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" - " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n" - , prog_name, prog_name, prog_name, prog_name); + " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n", + prog_name, prog_name, prog_name, prog_name); exit(1); } @@ -457,7 +532,10 @@ static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, if (filename.empty()) { // write to console - printf("%s: %s\n", name, value.c_str()); + if (idx == GoogleBinaryBlockUtil::PROP_FLAGS) + printf("%s: 0x%08x\n", name, bytes2int(value)); + else + printf("%s: %s\n", name, value.c_str()); } else { const char *fn = filename.c_str(); @@ -496,9 +574,14 @@ static bool import_property( // source as string string old_value = putil->get_property(idx); bool result = putil->set_property(idx, source); - printf(" - %s changed from '%s' to '%s': %s\n", - prop_name.c_str(), old_value.c_str(), source.c_str(), - result ? "success" : "failed"); + if (idx == GoogleBinaryBlockUtil::PROP_FLAGS) + printf(" - %s changed from 0x%08x to 0x%08x: %s\n", + prop_name.c_str(), bytes2int(old_value), bytes2int(source), + result ? "success" : "failed"); + else + printf(" - %s changed from '%s' to '%s': %s\n", + prop_name.c_str(), old_value.c_str(), source.c_str(), + result ? "success" : "failed"); if (!result) return false; } @@ -521,7 +604,6 @@ static bool parse_creation_param(const string &input_string, return false; output_vector->push_back(param); input = parsed + 1; - // printf("(debug) param: %zd\n", param); } while (*input); return true; @@ -567,6 +649,7 @@ int main(int argc, char *argv[]) { {"rootkey", 1, NULL, 'k' }, {"bmpfv", 1, NULL, 'b' }, {"recoverykey", 1, NULL, 'R' }, + {"flags", 2, NULL, 'L' }, { NULL, 0, NULL, 0 }, }; @@ -586,7 +669,7 @@ int main(int argc, char *argv[]) { myopts.create_mode = true; assert(optarg); if (!*optarg || !parse_creation_param(optarg, &myopts.create_param)) { - printf("error: invalid creation parameter: %s\n", optarg); + fprintf(stderr, "error: invalid creation parameter: %s\n", optarg); usagehelp_exit(myname); } break; @@ -597,30 +680,61 @@ int main(int argc, char *argv[]) { case 'i': if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) + GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) { + fprintf(stderr, "error: cannot assign multiple HWID parameters\n"); usagehelp_exit(myname); + } break; case 'k': if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_ROOTKEY, optarg)) + GoogleBinaryBlockUtil::PROP_ROOTKEY, optarg)) { + fprintf(stderr, "error: cannot assign multiple rootkey parameters\n"); usagehelp_exit(myname); + } break; case 'b': if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_BMPFV, optarg)) + GoogleBinaryBlockUtil::PROP_BMPFV, optarg)) { + fprintf(stderr, "error: cannot assign multiple bmpfv parameters\n"); usagehelp_exit(myname); + } break; case 'R': if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_RCVKEY, optarg)) + GoogleBinaryBlockUtil::PROP_RCVKEY, optarg)) { + fprintf(stderr, + "error: cannot assign multiple recovery_key parameters\n"); usagehelp_exit(myname); + } + break; + + case 'L': + { + uint32_t flags = 0; + char *endptr = optarg; + + if (optarg) { + flags = strtoul(optarg, &endptr, 0); + if (endptr == optarg) { + fprintf(stderr, "error: invalid --flags value\n"); + usagehelp_exit(myname); + } + } + + if (!opt_props.set_new_value(GoogleBinaryBlockUtil::PROP_FLAGS, + optarg ? int2bytes(flags) : "")) { + fprintf(stderr, "error: cannot assign multiple flags parameters\n"); + usagehelp_exit(myname); + } + } break; default: case '?': + fprintf(stderr, "error: unknown param: %c\n", opt); usagehelp_exit(myname); break; } @@ -638,6 +752,7 @@ int main(int argc, char *argv[]) { if (argc == 1) { myopts.input_fn = argv[0]; } else { + fprintf(stderr, "error: unexpected parameters (%d)\n", argc); usagehelp_exit(myname); } @@ -701,6 +816,13 @@ int main(int argc, char *argv[]) { for (OptPropertyMap::const_iterator i = opt_props.begin(); i != opt_props.end(); i++) { + if (i->first == GoogleBinaryBlockUtil::PROP_HWID || + i->first == GoogleBinaryBlockUtil::PROP_FLAGS) { + if (!i->second.empty()) { + printf("error: cannot assign value for --hwid/flags in --get.\n"); + usagehelp_exit(myname); + } + } export_property(i->first, i->second, util); } @@ -718,8 +840,9 @@ int main(int argc, char *argv[]) { i++) { bool source_as_file = true; - // the hwid command line parameter was a simple string. - if (i->first == GoogleBinaryBlockUtil::PROP_HWID) + // the hwid/flags are assigned in command line parameters + if (i->first == GoogleBinaryBlockUtil::PROP_HWID || + i->first == GoogleBinaryBlockUtil::PROP_FLAGS) source_as_file = false; if (!import_property(i->first, i->second, source_as_file, &util)) { diff --git a/utility/include/gbb_utility.h b/utility/include/gbb_utility.h index 55d4a390..49d6d43a 100644 --- a/utility/include/gbb_utility.h +++ b/utility/include/gbb_utility.h @@ -16,6 +16,7 @@ class GoogleBinaryBlockUtil { public: // enumerate of available data fields enum PROPINDEX { + PROP_FLAGS = -1,// flags (virtual property) PROP_HWID, // hardware id PROP_ROOTKEY, // root key PROP_BMPFV, // bitmap FV @@ -39,6 +40,14 @@ class GoogleBinaryBlockUtil { // return true on success. bool create_new(const std::vector &create_param); + // retrieve the value of GBB header flags. + // return the flags value. + uint32_t get_flags() const; + + // overwrite GBB header flags. + // return true on success. + bool set_flags(const uint32_t flags); + // retrieve the value of a property from GBB data. // return the property value. std::string get_property(PROPINDEX i) const; -- cgit v1.2.1