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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 } | 87 } |
87 | 88 |
88 void GoogleBinaryBlockUtil::initialize() { | 89 void GoogleBinaryBlockUtil::initialize() { |
89 verbose = true; | 90 verbose = true; |
90 is_valid_gbb = false; | 91 is_valid_gbb = false; |
91 header_offset_ = 0; | 92 header_offset_ = 0; |
92 memset(&header_, 0, sizeof(header_)); | 93 memset(&header_, 0, sizeof(header_)); |
93 file_content_.clear(); | 94 file_content_.clear(); |
94 } | 95 } |
95 | 96 |
| 97 bool GoogleBinaryBlockUtil::create_new( |
| 98 const std::vector<uint32_t> &create_param) { |
| 99 uint32_t *prop = &header_.hwid_offset; // must be first entry. |
| 100 uint32_t allocated_size = sizeof(header_); |
| 101 std::vector<uint32_t>::const_iterator i = create_param.begin(); |
| 102 |
| 103 // max properties = available space in header / size of record (offset+size) |
| 104 size_t max_properties = |
| 105 (sizeof(header_) - (reinterpret_cast<uint8_t*>(prop) - |
| 106 reinterpret_cast<uint8_t*>(&header_))) / |
| 107 (sizeof(uint32_t) * 2); |
| 108 |
| 109 if (create_param.size() >= max_properties) { |
| 110 if (verbose) |
| 111 fprintf(stderr, "error: creation parameters cannot exceed %zu entries.\n", |
| 112 max_properties); |
| 113 return false; |
| 114 } |
| 115 |
| 116 initialize(); |
| 117 memcpy(header_.signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE); |
| 118 header_.major_version = GBB_MAJOR_VER; |
| 119 header_.minor_version = GBB_MINOR_VER; |
| 120 header_.header_size = GBB_HEADER_SIZE; |
| 121 |
| 122 while (i != create_param.end()) { |
| 123 *prop++ = allocated_size; // property offset |
| 124 *prop++ = *i; // property size |
| 125 allocated_size += *i; |
| 126 i++; |
| 127 } |
| 128 |
| 129 file_content_.resize(allocated_size); |
| 130 std::copy(reinterpret_cast<char*>(&header_), |
| 131 reinterpret_cast<char*>(&header_ + 1), |
| 132 file_content_.begin()); |
| 133 is_valid_gbb = true; |
| 134 return true; |
| 135 } |
| 136 |
| 137 |
96 bool GoogleBinaryBlockUtil::load_from_file(const char *filename) { | 138 bool GoogleBinaryBlockUtil::load_from_file(const char *filename) { |
97 is_valid_gbb = false; | 139 is_valid_gbb = false; |
98 | 140 |
99 file_content_ = read_nonempty_file(filename); | 141 file_content_ = read_nonempty_file(filename); |
100 if (file_content_.empty()) | 142 if (file_content_.empty()) |
101 return false; | 143 return false; |
102 | 144 |
103 switch (search_header_signatures(file_content_, &header_offset_)) { | 145 switch (search_header_signatures(file_content_, &header_offset_)) { |
104 case 0: | 146 case 0: |
105 if (verbose) | 147 if (verbose) |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 // command line utilities | 409 // command line utilities |
368 | 410 |
369 #include <map> | 411 #include <map> |
370 | 412 |
371 using vboot_reference::GoogleBinaryBlockUtil; | 413 using vboot_reference::GoogleBinaryBlockUtil; |
372 | 414 |
373 // utility function: provide usage of this utility and exit. | 415 // utility function: provide usage of this utility and exit. |
374 static void usagehelp_exit(const char *prog_name) { | 416 static void usagehelp_exit(const char *prog_name) { |
375 printf( | 417 printf( |
376 "Utility to manage Google Binary Block (GBB)\n" | 418 "Utility to manage Google Binary Block (GBB)\n" |
377 "Usage: %s [-g|-s] [OPTIONS] bios_file [output_file]\n" | 419 "Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n" |
378 "\n" | 420 "\n" |
379 "GET MODE:\n" | 421 "GET MODE:\n" |
380 "-g, --get (default)\tGet (read) from bios_file, " | 422 "-g, --get (default)\tGet (read) from bios_file, " |
381 "with following options:\n" | 423 "with following options:\n" |
382 " --hwid \tReport hardware id (default).\n" | 424 " --hwid \tReport hardware id (default).\n" |
383 " -k, --rootkey=FILE \tFile name to export Root Key.\n" | 425 " -k, --rootkey=FILE \tFile name to export Root Key.\n" |
384 " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" | 426 " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" |
385 " --recoverykey=FILE\tFile name to export Recovery Key.\n" | 427 " --recoverykey=FILE\tFile name to export Recovery Key.\n" |
386 "\n" | 428 "\n" |
387 "SET MODE:\n" | 429 "SET MODE:\n" |
388 "-s, --set \tSet (write) to bios_file, " | 430 "-s, --set \tSet (write) to bios_file, " |
389 "with following options:\n" | 431 "with following options:\n" |
390 " -o, --output=FILE \tNew file name for ouptput.\n" | 432 " -o, --output=FILE \tNew file name for ouptput.\n" |
391 " -i, --hwid=HWID \tThe new hardware id to be changed.\n" | 433 " -i, --hwid=HWID \tThe new hardware id to be changed.\n" |
392 " -k, --rootkey=FILE \tFile name of new Root Key.\n" | 434 " -k, --rootkey=FILE \tFile name of new Root Key.\n" |
393 " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" | 435 " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" |
394 " --recoverykey=FILE\tFile name of new Recovery Key.\n" | 436 " --recoverykey=FILE\tFile name of new Recovery Key.\n" |
395 "\n" | 437 "\n" |
| 438 "CREATE MODE:\n" |
| 439 "-c, --create=prop1_size,prop2_size...\n" |
| 440 " \tCreate a GBB blob by given size list.\n" |
396 "SAMPLE:\n" | 441 "SAMPLE:\n" |
397 " %s -g bios.bin\n" | 442 " %s -g bios.bin\n" |
398 " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" | 443 " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" |
399 , prog_name, prog_name, prog_name); | 444 " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n" |
| 445 , prog_name, prog_name, prog_name, prog_name); |
400 exit(1); | 446 exit(1); |
401 } | 447 } |
402 | 448 |
403 // utility function: export a property from GBB to given file. | 449 // utility function: export a property from GBB to given file. |
404 // if filename was empty, export to console (screen). | 450 // if filename was empty, export to console (screen). |
405 // return true on success, otherwise false. | 451 // return true on success, otherwise false. |
406 static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, | 452 static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, |
407 const string &filename, | 453 const string &filename, |
408 const GoogleBinaryBlockUtil &util) { | 454 const GoogleBinaryBlockUtil &util) { |
409 string prop_name = util.get_property_name(idx), | 455 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", | 500 printf(" - %s changed from '%s' to '%s': %s\n", |
455 prop_name.c_str(), old_value.c_str(), source.c_str(), | 501 prop_name.c_str(), old_value.c_str(), source.c_str(), |
456 result ? "success" : "failed"); | 502 result ? "success" : "failed"); |
457 if (!result) | 503 if (!result) |
458 return false; | 504 return false; |
459 } | 505 } |
460 | 506 |
461 return true; | 507 return true; |
462 } | 508 } |
463 | 509 |
| 510 static bool parse_creation_param(const string &input_string, |
| 511 std::vector<uint32_t> *output_vector) { |
| 512 const char *input = input_string.c_str(); |
| 513 char *parsed = NULL; |
| 514 uint32_t param; |
| 515 |
| 516 if (input_string.empty()) |
| 517 return false; |
| 518 |
| 519 do { |
| 520 param = (uint32_t)strtol(input, &parsed, 0); |
| 521 if (*parsed && *parsed != ',') |
| 522 return false; |
| 523 output_vector->push_back(param); |
| 524 input = parsed + 1; |
| 525 // printf("(debug) param: %zd\n", param); |
| 526 } while (*input); |
| 527 |
| 528 return true; |
| 529 } |
| 530 |
464 /////////////////////////////////////////////////////////////////////// | 531 /////////////////////////////////////////////////////////////////////// |
465 // main | 532 // main |
466 | 533 |
467 int main(int argc, char *argv[]) { | 534 int main(int argc, char *argv[]) { |
468 const char *myname = argv[0]; | 535 const char *myname = argv[0]; |
469 int err_stage = 0; // an indicator for error exits | 536 int err_stage = 0; // an indicator for error exits |
| 537 GoogleBinaryBlockUtil util; |
470 | 538 |
471 // small parameter helper class | 539 // small parameter helper class |
472 class OptPropertyMap: public | 540 class OptPropertyMap: public |
473 std::map<GoogleBinaryBlockUtil::PROPINDEX, string> { | 541 std::map<GoogleBinaryBlockUtil::PROPINDEX, string> { |
474 public: | 542 public: |
475 bool set_new_value(GoogleBinaryBlockUtil::PROPINDEX id, const string &v) { | 543 bool set_new_value(GoogleBinaryBlockUtil::PROPINDEX id, const string &v) { |
476 if (find(id) != end()) | 544 if (find(id) != end()) |
477 return false; | 545 return false; |
478 | 546 |
479 (*this)[id] = v; | 547 (*this)[id] = v; |
480 return true; | 548 return true; |
481 } | 549 } |
482 }; | 550 }; |
483 OptPropertyMap opt_props; | 551 OptPropertyMap opt_props; |
484 | 552 |
485 struct GBBUtilOptions { | 553 struct GBBUtilOptions { |
486 bool get_mode, set_mode; | 554 bool get_mode, set_mode, create_mode; |
487 string input_fn, output_fn; | 555 string input_fn, output_fn; |
| 556 std::vector<uint32_t> create_param; |
488 } myopts; | 557 } myopts; |
489 myopts.get_mode = myopts.set_mode = false; | 558 myopts.get_mode = myopts.set_mode = myopts.create_mode = false; |
490 | 559 |
491 // snippets for getopt_long | 560 // snippets for getopt_long |
492 int option_index, opt; | 561 int option_index, opt; |
493 static struct option long_options[] = { | 562 static struct option long_options[] = { |
494 {"get", 0, NULL, 'g' }, | 563 {"get", 0, NULL, 'g' }, |
495 {"set", 0, NULL, 's' }, | 564 {"set", 0, NULL, 's' }, |
| 565 {"create", 1, NULL, 'c' }, |
496 {"output", 1, NULL, 'o' }, | 566 {"output", 1, NULL, 'o' }, |
497 {"hwid", 2, NULL, 'i' }, | 567 {"hwid", 2, NULL, 'i' }, |
498 {"rootkey", 1, NULL, 'k' }, | 568 {"rootkey", 1, NULL, 'k' }, |
499 {"bmpfv", 1, NULL, 'b' }, | 569 {"bmpfv", 1, NULL, 'b' }, |
500 {"recoverykey", 1, NULL, 'R' }, | 570 {"recoverykey", 1, NULL, 'R' }, |
501 { NULL, 0, NULL, 0 }, | 571 { NULL, 0, NULL, 0 }, |
502 }; | 572 }; |
503 | 573 |
504 // parse command line options | 574 // parse command line options |
505 while ((opt = getopt_long(argc, argv, "gso:i:k:b:", | 575 while ((opt = getopt_long(argc, argv, "gsc:o:i:k:b:", |
506 long_options, &option_index)) >= 0) { | 576 long_options, &option_index)) >= 0) { |
507 switch (opt) { | 577 switch (opt) { |
508 case 'g': | 578 case 'g': |
509 myopts.get_mode = true; | 579 myopts.get_mode = true; |
510 break; | 580 break; |
511 | 581 |
512 case 's': | 582 case 's': |
513 myopts.set_mode = true; | 583 myopts.set_mode = true; |
514 break; | 584 break; |
515 | 585 |
| 586 case 'c': |
| 587 myopts.create_mode = true; |
| 588 assert(optarg); |
| 589 if (!*optarg || !parse_creation_param(optarg, &myopts.create_param)) { |
| 590 printf("error: invalid creation parameter: %s\n", optarg); |
| 591 usagehelp_exit(myname); |
| 592 } |
| 593 break; |
| 594 |
516 case 'o': | 595 case 'o': |
517 myopts.output_fn = optarg; | 596 myopts.output_fn = optarg; |
518 break; | 597 break; |
519 | 598 |
520 case 'i': | 599 case 'i': |
521 if (!opt_props.set_new_value( | 600 if (!opt_props.set_new_value( |
522 GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) | 601 GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) |
523 usagehelp_exit(myname); | 602 usagehelp_exit(myname); |
524 break; | 603 break; |
525 | 604 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 | 637 |
559 // currently, the only parameter is 'input file'. | 638 // currently, the only parameter is 'input file'. |
560 if (argc == 1) { | 639 if (argc == 1) { |
561 myopts.input_fn = argv[0]; | 640 myopts.input_fn = argv[0]; |
562 } else { | 641 } else { |
563 usagehelp_exit(myname); | 642 usagehelp_exit(myname); |
564 } | 643 } |
565 | 644 |
566 // stage: complete parameter parsing and checking | 645 // stage: complete parameter parsing and checking |
567 err_stage++; | 646 err_stage++; |
568 if (myopts.get_mode == myopts.set_mode) { | 647 if (myopts.create_mode) { |
| 648 if (myopts.get_mode || myopts.set_mode) { |
| 649 printf("error: please assign only one mode from get/set/create.\n"); |
| 650 return err_stage; |
| 651 } |
| 652 if (!opt_props.empty() || myopts.create_param.empty()) { |
| 653 printf("error: creation parameter syntax error.\n"); |
| 654 return err_stage; |
| 655 } |
| 656 if (myopts.output_fn.empty()) { |
| 657 myopts.output_fn = myopts.input_fn; |
| 658 } |
| 659 } else if (myopts.get_mode == myopts.set_mode) { |
569 if (myopts.get_mode) { | 660 if (myopts.get_mode) { |
570 printf("error: please assign either get or set mode.\n"); | 661 printf("error: please assign either get or set mode.\n"); |
571 return err_stage; | 662 return err_stage; |
572 } else { | 663 } else { |
573 // enter 'get' mode by default, if not assigned. | 664 // enter 'get' mode by default, if not assigned. |
574 myopts.get_mode = true; | 665 myopts.get_mode = true; |
575 } | 666 } |
576 } | 667 } |
577 if (myopts.get_mode && !myopts.output_fn.empty()) { | 668 if (myopts.get_mode && !myopts.output_fn.empty()) { |
578 printf("error: get-mode does not create output files.\n"); | 669 printf("error: get-mode does not create output files.\n"); |
579 return err_stage; | 670 return err_stage; |
580 } | 671 } |
581 | 672 |
| 673 if (myopts.create_mode) { |
| 674 if (!util.create_new(myopts.create_param)) |
| 675 return err_stage; |
| 676 |
| 677 assert(!myopts.output_fn.empty()); |
| 678 if (!util.save_to_file(myopts.output_fn.c_str())) { |
| 679 printf("error: cannot create to file: %s\n", myopts.output_fn.c_str()); |
| 680 return err_stage; |
| 681 } else { |
| 682 printf("successfully created new GBB to: %s\n", myopts.output_fn.c_str()); |
| 683 } |
| 684 return 0; |
| 685 } |
| 686 |
582 // stage: load image files | 687 // stage: load image files |
583 err_stage++; | 688 err_stage++; |
584 GoogleBinaryBlockUtil util; | |
585 | |
586 assert(!myopts.input_fn.empty()); | 689 assert(!myopts.input_fn.empty()); |
587 if (!util.load_from_file(myopts.input_fn.c_str())) { | 690 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()); | 691 printf("error: cannot load valid BIOS file: %s\n", myopts.input_fn.c_str()); |
589 return err_stage; | 692 return err_stage; |
590 } | 693 } |
591 | 694 |
592 // stage: processing by mode | 695 // stage: processing by mode |
593 err_stage++; | 696 err_stage++; |
594 if (myopts.get_mode) { | 697 if (myopts.get_mode) { |
595 // get mode | 698 // get mode |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 return err_stage; | 742 return err_stage; |
640 } else { | 743 } else { |
641 printf("successfully saved new image to: %s\n", myopts.output_fn.c_str()); | 744 printf("successfully saved new image to: %s\n", myopts.output_fn.c_str()); |
642 } | 745 } |
643 } | 746 } |
644 | 747 |
645 return 0; | 748 return 0; |
646 } | 749 } |
647 | 750 |
648 #endif // WITH_UTIL_MAIN | 751 #endif // WITH_UTIL_MAIN |
OLD | NEW |