Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Utility for manipulating Google Binary Block (GBB) | 5 // Utility for manipulating Google Binary Block (GBB) |
| 6 // | 6 // |
| 7 | 7 |
| 8 #include "gbb_utility.h" | 8 #include "gbb_utility.h" |
| 9 | 9 |
| 10 #include <assert.h> | 10 #include <assert.h> |
| 11 #include <getopt.h> | 11 #include <getopt.h> |
| 12 #include <stdio.h> | 12 #include <stdio.h> |
| 13 #include <stdlib.h> | |
| 13 #include <string.h> | 14 #include <string.h> |
| 14 | 15 |
| 15 #include <string> | 16 #include <string> |
| 16 #include <vector> | 17 #include <vector> |
| 17 #include <algorithm> | 18 #include <algorithm> |
| 18 | 19 |
| 19 using std::string; | 20 using std::string; |
| 20 | 21 |
| 21 /////////////////////////////////////////////////////////////////////// | 22 /////////////////////////////////////////////////////////////////////// |
| 22 // Simple File Utilities | 23 // Simple File Utilities |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 367 // command line utilities | 368 // command line utilities |
| 368 | 369 |
| 369 #include <map> | 370 #include <map> |
| 370 | 371 |
| 371 using vboot_reference::GoogleBinaryBlockUtil; | 372 using vboot_reference::GoogleBinaryBlockUtil; |
| 372 | 373 |
| 373 // utility function: provide usage of this utility and exit. | 374 // utility function: provide usage of this utility and exit. |
| 374 static void usagehelp_exit(const char *prog_name) { | 375 static void usagehelp_exit(const char *prog_name) { |
| 375 printf( | 376 printf( |
| 376 "Utility to manage Google Binary Block (GBB)\n" | 377 "Utility to manage Google Binary Block (GBB)\n" |
| 377 "Usage: %s [-g|-s] [OPTIONS] bios_file [output_file]\n" | 378 "Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n" |
| 378 "\n" | 379 "\n" |
| 379 "GET MODE:\n" | 380 "GET MODE:\n" |
| 380 "-g, --get (default)\tGet (read) from bios_file, " | 381 "-g, --get (default)\tGet (read) from bios_file, " |
| 381 "with following options:\n" | 382 "with following options:\n" |
| 382 " --hwid \tReport hardware id (default).\n" | 383 " --hwid \tReport hardware id (default).\n" |
| 383 " -k, --rootkey=FILE \tFile name to export Root Key.\n" | 384 " -k, --rootkey=FILE \tFile name to export Root Key.\n" |
| 384 " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" | 385 " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" |
| 385 " --recoverykey=FILE\tFile name to export Recovery Key.\n" | 386 " --recoverykey=FILE\tFile name to export Recovery Key.\n" |
| 386 "\n" | 387 "\n" |
| 387 "SET MODE:\n" | 388 "SET MODE:\n" |
| 388 "-s, --set \tSet (write) to bios_file, " | 389 "-s, --set \tSet (write) to bios_file, " |
| 389 "with following options:\n" | 390 "with following options:\n" |
| 390 " -o, --output=FILE \tNew file name for ouptput.\n" | 391 " -o, --output=FILE \tNew file name for ouptput.\n" |
| 391 " -i, --hwid=HWID \tThe new hardware id to be changed.\n" | 392 " -i, --hwid=HWID \tThe new hardware id to be changed.\n" |
| 392 " -k, --rootkey=FILE \tFile name of new Root Key.\n" | 393 " -k, --rootkey=FILE \tFile name of new Root Key.\n" |
| 393 " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" | 394 " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" |
| 394 " --recoverykey=FILE\tFile name of new Recovery Key.\n" | 395 " --recoverykey=FILE\tFile name of new Recovery Key.\n" |
| 395 "\n" | 396 "\n" |
| 397 "CREATE MODE:\n" | |
| 398 "-c, --create=prop1_size,prop2_size...\n" | |
| 399 " \tCreate a GBB blob by given size list.\n" | |
| 396 "SAMPLE:\n" | 400 "SAMPLE:\n" |
| 397 " %s -g bios.bin\n" | 401 " %s -g bios.bin\n" |
| 398 " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" | 402 " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" |
| 399 , prog_name, prog_name, prog_name); | 403 " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n" |
| 404 , prog_name, prog_name, prog_name, prog_name); | |
| 400 exit(1); | 405 exit(1); |
| 401 } | 406 } |
| 402 | 407 |
| 403 // utility function: export a property from GBB to given file. | 408 // utility function: export a property from GBB to given file. |
| 404 // if filename was empty, export to console (screen). | 409 // if filename was empty, export to console (screen). |
| 405 // return true on success, otherwise false. | 410 // return true on success, otherwise false. |
| 406 static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, | 411 static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, |
| 407 const string &filename, | 412 const string &filename, |
| 408 const GoogleBinaryBlockUtil &util) { | 413 const GoogleBinaryBlockUtil &util) { |
| 409 string prop_name = util.get_property_name(idx), | 414 string prop_name = util.get_property_name(idx), |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 454 printf(" - %s changed from '%s' to '%s': %s\n", | 459 printf(" - %s changed from '%s' to '%s': %s\n", |
| 455 prop_name.c_str(), old_value.c_str(), source.c_str(), | 460 prop_name.c_str(), old_value.c_str(), source.c_str(), |
| 456 result ? "success" : "failed"); | 461 result ? "success" : "failed"); |
| 457 if (!result) | 462 if (!result) |
| 458 return false; | 463 return false; |
| 459 } | 464 } |
| 460 | 465 |
| 461 return true; | 466 return true; |
| 462 } | 467 } |
| 463 | 468 |
| 469 static bool parse_creation_param(const string &input_string, | |
| 470 std::vector<uint32_t> &output_vector) { | |
| 471 const char *input = input_string.c_str(); | |
| 472 char *parsed = NULL; | |
| 473 uint32_t param; | |
| 474 | |
| 475 do { | |
| 476 param = (uint32_t)strtol(input, &parsed, 0); | |
| 477 if (*parsed && *parsed != ',') | |
| 478 return false; | |
| 479 output_vector.push_back(param); | |
| 480 input = parsed + 1; | |
| 481 // printf("(debug) param: %zd\n", param); | |
| 482 } while(*input); | |
| 483 | |
| 484 return true; | |
| 485 } | |
| 486 | |
| 487 static string create_new_gbb(const std::vector<uint32_t> &create_param) { | |
|
Randall Spangler
2011/01/07 21:47:34
The current implementation of the GBB is done via
Hung-Te
2011/01/10 03:40:58
Done.
| |
| 488 GoogleBinaryBlockHeader header = {0}; | |
| 489 uint32_t *prop = &header.hwid_offset; // must be first entry. | |
| 490 uint32_t allocated_size = sizeof(header); | |
| 491 std::vector<uint32_t>::const_iterator i = create_param.begin(); | |
| 492 string blob; | |
| 493 | |
| 494 // max properties = available space in header / size of record (offset+size) | |
| 495 size_t max_properties = | |
| 496 (sizeof(header) - ((uint8_t*)prop - (uint8_t*)&header)) / | |
| 497 (sizeof(uint32_t) * 2); | |
| 498 | |
| 499 if (create_param.size() >= max_properties) { | |
| 500 printf("error: creation parameters cannot exceed %zu entries.\n", | |
| 501 max_properties); | |
| 502 return blob; | |
| 503 } | |
| 504 | |
| 505 memcpy(header.signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE); | |
| 506 header.major_version = GBB_MAJOR_VER; | |
| 507 header.minor_version = GBB_MINOR_VER; | |
| 508 header.header_size = GBB_HEADER_SIZE; | |
| 509 | |
| 510 while (i != create_param.end()) { | |
| 511 *prop++ = allocated_size; // property offset | |
| 512 *prop++ = *i; // property size | |
| 513 allocated_size += *i; | |
| 514 i++; | |
| 515 } | |
| 516 | |
| 517 blob.resize(allocated_size); | |
| 518 std::copy((char*)&header, (char*)(&header + 1), blob.begin()); | |
| 519 return blob; | |
| 520 } | |
| 521 | |
| 464 /////////////////////////////////////////////////////////////////////// | 522 /////////////////////////////////////////////////////////////////////// |
| 465 // main | 523 // main |
| 466 | 524 |
| 467 int main(int argc, char *argv[]) { | 525 int main(int argc, char *argv[]) { |
| 468 const char *myname = argv[0]; | 526 const char *myname = argv[0]; |
| 469 int err_stage = 0; // an indicator for error exits | 527 int err_stage = 0; // an indicator for error exits |
| 470 | 528 |
| 471 // small parameter helper class | 529 // small parameter helper class |
| 472 class OptPropertyMap: public | 530 class OptPropertyMap: public |
| 473 std::map<GoogleBinaryBlockUtil::PROPINDEX, string> { | 531 std::map<GoogleBinaryBlockUtil::PROPINDEX, string> { |
| 474 public: | 532 public: |
| 475 bool set_new_value(GoogleBinaryBlockUtil::PROPINDEX id, const string &v) { | 533 bool set_new_value(GoogleBinaryBlockUtil::PROPINDEX id, const string &v) { |
| 476 if (find(id) != end()) | 534 if (find(id) != end()) |
| 477 return false; | 535 return false; |
| 478 | 536 |
| 479 (*this)[id] = v; | 537 (*this)[id] = v; |
| 480 return true; | 538 return true; |
| 481 } | 539 } |
| 482 }; | 540 }; |
| 483 OptPropertyMap opt_props; | 541 OptPropertyMap opt_props; |
| 484 | 542 |
| 485 struct GBBUtilOptions { | 543 struct GBBUtilOptions { |
| 486 bool get_mode, set_mode; | 544 bool get_mode, set_mode, create_mode; |
| 487 string input_fn, output_fn; | 545 string input_fn, output_fn; |
| 546 std::vector<uint32_t> create_param; | |
| 488 } myopts; | 547 } myopts; |
| 489 myopts.get_mode = myopts.set_mode = false; | 548 myopts.get_mode = myopts.set_mode = false; |
|
Che-Liang Chiou
2011/01/10 02:55:20
I'm not sure, but doesn't myopts.create_mode have
Hung-Te
2011/01/10 03:40:58
My bad. fixed.
| |
| 490 | 549 |
| 491 // snippets for getopt_long | 550 // snippets for getopt_long |
| 492 int option_index, opt; | 551 int option_index, opt; |
| 493 static struct option long_options[] = { | 552 static struct option long_options[] = { |
| 494 {"get", 0, NULL, 'g' }, | 553 {"get", 0, NULL, 'g' }, |
| 495 {"set", 0, NULL, 's' }, | 554 {"set", 0, NULL, 's' }, |
| 555 {"create", 0, NULL, 'c' }, | |
| 496 {"output", 1, NULL, 'o' }, | 556 {"output", 1, NULL, 'o' }, |
| 497 {"hwid", 2, NULL, 'i' }, | 557 {"hwid", 2, NULL, 'i' }, |
| 498 {"rootkey", 1, NULL, 'k' }, | 558 {"rootkey", 1, NULL, 'k' }, |
| 499 {"bmpfv", 1, NULL, 'b' }, | 559 {"bmpfv", 1, NULL, 'b' }, |
| 500 {"recoverykey", 1, NULL, 'R' }, | 560 {"recoverykey", 1, NULL, 'R' }, |
| 501 { NULL, 0, NULL, 0 }, | 561 { NULL, 0, NULL, 0 }, |
| 502 }; | 562 }; |
| 503 | 563 |
| 504 // parse command line options | 564 // parse command line options |
| 505 while ((opt = getopt_long(argc, argv, "gso:i:k:b:", | 565 while ((opt = getopt_long(argc, argv, "gsc:o:i:k:b:", |
| 506 long_options, &option_index)) >= 0) { | 566 long_options, &option_index)) >= 0) { |
| 507 switch (opt) { | 567 switch (opt) { |
| 508 case 'g': | 568 case 'g': |
| 509 myopts.get_mode = true; | 569 myopts.get_mode = true; |
| 510 break; | 570 break; |
| 511 | 571 |
| 512 case 's': | 572 case 's': |
| 513 myopts.set_mode = true; | 573 myopts.set_mode = true; |
| 514 break; | 574 break; |
| 515 | 575 |
| 576 case 'c': | |
| 577 myopts.create_mode = true; | |
| 578 { | |
| 579 const char *param = optarg ? optarg : "(empty)"; | |
| 580 if (!parse_creation_param(param, myopts.create_param)) { | |
|
Che-Liang Chiou
2011/01/10 02:55:20
Isn't this equivalent to "if (!optarg || !parse_cr
Hung-Te
2011/01/10 03:40:58
Because in that case I need to put something in er
| |
| 581 printf("error: invalid creation parameter: %s\n", param); | |
| 582 usagehelp_exit(myname); | |
| 583 } | |
| 584 } | |
| 585 break; | |
| 586 | |
| 516 case 'o': | 587 case 'o': |
| 517 myopts.output_fn = optarg; | 588 myopts.output_fn = optarg; |
| 518 break; | 589 break; |
| 519 | 590 |
| 520 case 'i': | 591 case 'i': |
| 521 if (!opt_props.set_new_value( | 592 if (!opt_props.set_new_value( |
| 522 GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) | 593 GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) |
| 523 usagehelp_exit(myname); | 594 usagehelp_exit(myname); |
| 524 break; | 595 break; |
| 525 | 596 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 558 | 629 |
| 559 // currently, the only parameter is 'input file'. | 630 // currently, the only parameter is 'input file'. |
| 560 if (argc == 1) { | 631 if (argc == 1) { |
| 561 myopts.input_fn = argv[0]; | 632 myopts.input_fn = argv[0]; |
| 562 } else { | 633 } else { |
| 563 usagehelp_exit(myname); | 634 usagehelp_exit(myname); |
| 564 } | 635 } |
| 565 | 636 |
| 566 // stage: complete parameter parsing and checking | 637 // stage: complete parameter parsing and checking |
| 567 err_stage++; | 638 err_stage++; |
| 568 if (myopts.get_mode == myopts.set_mode) { | 639 if (myopts.create_mode) { |
| 640 if (myopts.get_mode || myopts.set_mode) { | |
| 641 printf("error: please assign only one mode from get/set/create.\n"); | |
| 642 return err_stage; | |
| 643 } | |
| 644 if (!opt_props.empty() || myopts.create_param.empty()) { | |
| 645 printf("error: creation parameter syntax error.\n"); | |
| 646 return err_stage; | |
| 647 } | |
| 648 if (myopts.output_fn.empty()) { | |
| 649 myopts.output_fn = myopts.input_fn; | |
| 650 } | |
| 651 } else if (myopts.get_mode == myopts.set_mode) { | |
| 569 if (myopts.get_mode) { | 652 if (myopts.get_mode) { |
| 570 printf("error: please assign either get or set mode.\n"); | 653 printf("error: please assign either get or set mode.\n"); |
| 571 return err_stage; | 654 return err_stage; |
| 572 } else { | 655 } else { |
| 573 // enter 'get' mode by default, if not assigned. | 656 // enter 'get' mode by default, if not assigned. |
| 574 myopts.get_mode = true; | 657 myopts.get_mode = true; |
| 575 } | 658 } |
| 576 } | 659 } |
| 577 if (myopts.get_mode && !myopts.output_fn.empty()) { | 660 if (myopts.get_mode && !myopts.output_fn.empty()) { |
| 578 printf("error: get-mode does not create output files.\n"); | 661 printf("error: get-mode does not create output files.\n"); |
| 579 return err_stage; | 662 return err_stage; |
| 580 } | 663 } |
| 581 | 664 |
| 665 if (myopts.create_mode) { | |
| 666 // creation is not handled by GoogleBinaryBlockUtil. | |
| 667 string blob = create_new_gbb(myopts.create_param); | |
| 668 | |
| 669 if (blob.empty()) | |
| 670 return err_stage; | |
| 671 | |
| 672 if (!write_nonempty_file(myopts.output_fn.c_str(), blob)) { | |
| 673 printf("error: cannot create to file: %s\n", myopts.output_fn.c_str()); | |
| 674 return err_stage; | |
| 675 } else { | |
| 676 printf("successfully created new GBB to: %s\n", myopts.output_fn.c_str()); | |
| 677 } | |
| 678 return 0; | |
| 679 } | |
| 680 | |
| 582 // stage: load image files | 681 // stage: load image files |
| 583 err_stage++; | 682 err_stage++; |
| 584 GoogleBinaryBlockUtil util; | 683 GoogleBinaryBlockUtil util; |
| 585 | 684 |
| 586 assert(!myopts.input_fn.empty()); | 685 assert(!myopts.input_fn.empty()); |
| 587 if (!util.load_from_file(myopts.input_fn.c_str())) { | 686 if (!util.load_from_file(myopts.input_fn.c_str())) { |
| 588 printf("error: cannot load valid BIOS file: %s\n", myopts.input_fn.c_str()); | 687 printf("error: cannot load valid BIOS file: %s\n", myopts.input_fn.c_str()); |
| 589 return err_stage; | 688 return err_stage; |
| 590 } | 689 } |
| 591 | 690 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 return err_stage; | 738 return err_stage; |
| 640 } else { | 739 } else { |
| 641 printf("successfully saved new image to: %s\n", myopts.output_fn.c_str()); | 740 printf("successfully saved new image to: %s\n", myopts.output_fn.c_str()); |
| 642 } | 741 } |
| 643 } | 742 } |
| 644 | 743 |
| 645 return 0; | 744 return 0; |
| 646 } | 745 } |
| 647 | 746 |
| 648 #endif // WITH_UTIL_MAIN | 747 #endif // WITH_UTIL_MAIN |
| OLD | NEW |