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 |