Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. | 2 * Copyright (C) 2010 Google Inc. |
| 3 * | 3 * |
| 4 * This program is free software; you can redistribute it and/or | 4 * This program is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU General Public License | 5 * modify it under the terms of the GNU General Public License |
| 6 * as published by the Free Software Foundation; either version 2 | 6 * as published by the Free Software Foundation; either version 2 |
| 7 * of the License, or (at your option) any later version. | 7 * of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 #include "lib/flashrom.h" | 27 #include "lib/flashrom.h" |
| 28 #include "lib/fmap.h" | 28 #include "lib/fmap.h" |
| 29 #include "lib/lib_vpd.h" | 29 #include "lib/lib_vpd.h" |
| 30 #include "lib/lib_smbios.h" | 30 #include "lib/lib_smbios.h" |
| 31 #include "lib/vpd.h" | 31 #include "lib/vpd.h" |
| 32 #include "lib/vpd_tables.h" | 32 #include "lib/vpd_tables.h" |
| 33 | 33 |
| 34 /* The buffer length. Right now the VPD partition size on flash is 128KB. */ | 34 /* The buffer length. Right now the VPD partition size on flash is 128KB. */ |
| 35 #define BUF_LEN (128 * 1024) | 35 #define BUF_LEN (128 * 1024) |
| 36 | 36 |
| 37 static uint8_t flashrom_tmp_file[] = "/tmp/vpd.flashrom.XXXXXX"; | 37 /* temp filename for partial read area. */ |
| 38 static uint8_t tmp_part_file[] = "/tmp/vpd.flashrom.XXXXXX"; | |
| 39 /* temp filename for the full flash content (actually only partial content | |
| 40 * is available). But for flashrom -w to match flash size, we need to keep this | |
| 41 * file from flashromRead() to writeFlashrom(). */ | |
| 42 static uint8_t tmp_full_file[] = "/tmp/vpd.flashrom.XXXXXX"; | |
|
dhendrix
2011/03/10 01:33:51
Just a thought (not worth the effort for this CL):
Louis
2011/03/10 08:22:51
mkstemp() is a good idea. I will modify that next
| |
| 38 | 43 |
| 39 /* 2 containers: | 44 /* 2 containers: |
| 40 * file: stores decoded pairs from file. | 45 * file: stores decoded pairs from file. |
| 41 * argument: stores parsed pairs from command arguments. | 46 * argument: stores parsed pairs from command arguments. |
| 42 */ | 47 */ |
| 43 struct PairContainer file; | 48 struct PairContainer file; |
| 44 struct PairContainer argument; | 49 struct PairContainer argument; |
| 45 | 50 |
| 46 /* The current padding length value. | 51 /* The current padding length value. |
| 47 * Default: VPD_AS_LONG_AS | 52 * Default: VPD_AS_LONG_AS |
| 48 */ | 53 */ |
| 49 int pad_value_len = VPD_AS_LONG_AS; | 54 int pad_value_len = VPD_AS_LONG_AS; |
| 50 | 55 |
| 51 /* The output buffer */ | 56 /* The output buffer */ |
| 52 unsigned char buf[BUF_LEN]; | 57 unsigned char buf[BUF_LEN]; |
| 53 int buf_len = 0; | 58 int buf_len = 0; |
| 54 int max_buf_len = sizeof(buf); | 59 int max_buf_len = sizeof(buf); |
| 55 | 60 |
| 56 /* The EPS base address used to fill the EPS table entry. | 61 /* The EPS base address used to fill the EPS table entry. |
| 57 * If the VPD partition can be found in fmap, this points to the starting | 62 * If the VPD partition can be found in fmap, this points to the starting |
| 58 * offset of VPD partition. If not found, this is used to be the base address | 63 * offset of VPD partition. If not found, this is used to be the base address |
| 59 * to increase SPD and VPD 2.0 offset fields. | 64 * to increase SPD and VPD 2.0 offset fields. |
| 60 * | 65 * |
| 61 * User can overwrite this by -E argument. | 66 * User can overwrite this by -E argument. |
| 62 */ | 67 */ |
| 63 uint32_t eps_base = GOOGLE_EPS_BASE; | 68 uint32_t eps_base = GOOGLE_EPS_BASE; |
| 69 int eps_base_force_specified = 0; /* a bool value to indicate if -E argument | |
| 70 * is given. */ | |
| 64 | 71 |
| 65 /* the fmap name of VPD. */ | 72 /* the fmap name of VPD. */ |
| 66 uint8_t fmap_vpd_area_name[FMAP_STRLEN] = "RO VPD"; | 73 uint8_t fmap_vpd_area_name[FMAP_STRLEN] = "RO_VPD"; |
| 67 | 74 |
| 68 /* If found_vpd, replace the VPD partition when saveFile(). | 75 /* If found_vpd, replace the VPD partition when saveFile(). |
| 69 * If not found, always create new file when saveFlie(). */ | 76 * If not found, always create new file when saveFlie(). */ |
| 70 int found_vpd = 0; | 77 int found_vpd = 0; |
| 71 | 78 |
| 72 /* The VPD partition offset and size in buf[]. The whole partition includes: | 79 /* The VPD partition offset and size in buf[]. The whole partition includes: |
| 73 * | 80 * |
| 74 * SMBIOS EPS | 81 * SMBIOS EPS |
| 75 * SMBIOS tables[] | 82 * SMBIOS tables[] |
| 76 * SPD | 83 * SPD |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 if (-1 == sig_offset) { | 257 if (-1 == sig_offset) { |
| 251 /* FMAP signature is not found, assume it is pure VPD partition. */ | 258 /* FMAP signature is not found, assume it is pure VPD partition. */ |
| 252 vpd_buf = read_buf; | 259 vpd_buf = read_buf; |
| 253 eps = (struct vpd_entry *)vpd_buf; | 260 eps = (struct vpd_entry *)vpd_buf; |
| 254 | 261 |
| 255 /* In overwrite mode, ignore all existing data. */ | 262 /* In overwrite mode, ignore all existing data. */ |
| 256 if (overwrite_it) { | 263 if (overwrite_it) { |
| 257 retval = 0; | 264 retval = 0; |
| 258 goto teardown; | 265 goto teardown; |
| 259 } | 266 } |
| 267 | |
| 268 if (!eps_base_force_specified) { | |
| 269 /* Since we lost the fmap info in this mode, we try to guess the | |
| 270 * eps_base from EPS field. */ | |
| 271 if (eps->table_address > file_size) { | |
| 272 eps_base = eps->table_address - sizeof(*eps); | |
| 273 fprintf(stderr, "[INFO] we guess eps_base is 0x%x.\n", eps_base); | |
| 274 } | |
| 275 } | |
| 260 } else { | 276 } else { |
| 277 /* FMAP signature is found, try to search the partition name in table. */ | |
| 261 int i; | 278 int i; |
| 262 | 279 |
| 263 fmap = (struct fmap *)&read_buf[sig_offset]; | 280 fmap = (struct fmap *)&read_buf[sig_offset]; |
| 264 for(i = 0; i < fmap->nareas; i++) { | 281 for(i = 0; i < fmap->nareas; i++) { |
| 265 fmapNormalizeAreaName(fmap->areas[i].name); | 282 fmapNormalizeAreaName(fmap->areas[i].name); |
| 266 } | 283 } |
| 267 | 284 |
| 268 if (FMAP_OK == fmapGetArea(fmap_vpd_area_name, fmap, | 285 if (FMAP_OK == fmapGetArea(fmap_vpd_area_name, fmap, |
| 269 &vpd_offset, &vpd_size)) { | 286 &vpd_offset, &vpd_size)) { |
| 270 found_vpd = 1; /* Mark found here then saveFile() knows where to | 287 found_vpd = 1; /* Mark found here then saveFile() knows where to |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 285 goto teardown; | 302 goto teardown; |
| 286 } | 303 } |
| 287 } | 304 } |
| 288 /* Now, vpd_buf points to the VPD partition in buffer. | 305 /* Now, vpd_buf points to the VPD partition in buffer. |
| 289 * eps points to the EPS structure, which is usually equal to vpd_buf. */ | 306 * eps points to the EPS structure, which is usually equal to vpd_buf. */ |
| 290 eps_offset = (uint8_t*)eps - vpd_buf; | 307 eps_offset = (uint8_t*)eps - vpd_buf; |
| 291 | 308 |
| 292 /* jump if the VPD partition is not recognized. */ | 309 /* jump if the VPD partition is not recognized. */ |
| 293 if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { | 310 if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { |
| 294 /* But OKAY if the VPD partition is all-FF, which is un-used. */ | 311 /* But OKAY if the VPD partition is all-FF, which is un-used. */ |
| 295 if (memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { | 312 if (!memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { |
| 313 fprintf(stderr, "[WARN] VPD partition not formatted. Ignored.\n"); | |
| 314 retval = 0; | |
| 315 goto teardown; | |
| 316 } else { | |
|
dhendrix
2011/03/10 01:33:51
nice!
Louis
2011/03/10 08:22:51
Done.
| |
| 296 fprintf(stderr, "SMBIOS signature is not matched.\n"); | 317 fprintf(stderr, "SMBIOS signature is not matched.\n"); |
| 297 fprintf(stderr, "You may use -O to overwrite the data.\n"); | 318 fprintf(stderr, "You may use -O to overwrite the data.\n"); |
| 298 retval = 1; | 319 retval = 1; |
| 299 goto teardown; | 320 goto teardown; |
| 300 } | 321 } |
| 301 /* TODO(yjlou): need more EPS sanity checks here. */ | 322 /* TODO(yjlou): need more EPS sanity checks here. */ |
| 302 } | 323 } |
| 303 /* EPS is done above. Parse structure tables below. */ | 324 /* EPS is done above. Parse structure tables below. */ |
| 304 /* Get the first type 241 blob, at the tail of EPS. */ | 325 /* Get the first type 241 blob, at the tail of EPS. */ |
| 305 header = (struct vpd_header*)(((uint8_t*)eps) + eps->entry_length); | 326 header = (struct vpd_header*)(((uint8_t*)eps) + eps->entry_length); |
| 306 data = (struct vpd_table_binary_blob_pointer *) | 327 data = (struct vpd_table_binary_blob_pointer *) |
| 307 ((uint8_t *)header + sizeof(*header)); | 328 ((uint8_t *)header + sizeof(*header)); |
| 308 | 329 |
| 309 /* TODO(yjlou): Re-factor the parsing code to support more SMBIOS entries. | 330 /* TODO(yjlou): Re-factor the parsing code to support more SMBIOS entries. |
| 310 * The current code only supports 2 combinations: | 331 * The current code only supports 2 combinations: |
| 311 * 1. Type 241 (SPD) + Type 241 (VPD 2.0) + Type 127 | 332 * 1. Type 241 (SPD) + Type 241 (VPD 2.0) + Type 127 |
| 312 * 2. Type 241 (VPD 2.0) + Type 127 | 333 * 2. Type 241 (VPD 2.0) + Type 127 |
| 313 */ | 334 */ |
| 314 | 335 |
| 315 /* Now header points to the first SMBIOS entry, and data points to the | 336 /* Now header points to the first SMBIOS entry, and data points to the |
| 316 * first BBP entry. The first entry could be SPD data. We don't care. */ | 337 * first BBP entry. The first entry could be SPD data. We don't care. */ |
| 317 if (header->handle != expected_handle) { | 338 if (header->handle != expected_handle) { |
| 318 fprintf(stderr, "The first handle value must be 0, but is %d.\n", | 339 fprintf(stderr, "[ERROR] The first handle value must be 0, but is %d.\n" |
| 340 " Use -O option to re-format.\n", | |
| 319 header->handle); | 341 header->handle); |
| 320 retval = 1; | 342 retval = 1; |
| 321 goto teardown; | 343 goto teardown; |
| 322 } | 344 } |
| 323 if (header->type != VPD_TYPE_BINARY_BLOB_POINTER) { | 345 if (header->type != VPD_TYPE_BINARY_BLOB_POINTER) { |
| 324 fprintf(stderr, "Expect first entry is type Binary Blob Pointer (241)," | 346 fprintf(stderr, "Expect first entry is type Binary Blob Pointer (241)," |
| 325 " but actually is %d\n", header->type); | 347 " but actually is %d\n", header->type); |
| 326 fprintf(stderr, "You may use -O to overwrite the data.\n"); | 348 fprintf(stderr, "You may use -O to overwrite the data.\n"); |
| 327 retval = 1; | 349 retval = 1; |
| 328 goto teardown; | 350 goto teardown; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 355 retval = 1; | 377 retval = 1; |
| 356 goto teardown; | 378 goto teardown; |
| 357 } | 379 } |
| 358 header = (struct vpd_header*)((uint8_t*)header + table_len); | 380 header = (struct vpd_header*)((uint8_t*)header + table_len); |
| 359 data = (struct vpd_table_binary_blob_pointer *) | 381 data = (struct vpd_table_binary_blob_pointer *) |
| 360 ((uint8_t *)header + sizeof(*header)); | 382 ((uint8_t *)header + sizeof(*header)); |
| 361 } | 383 } |
| 362 | 384 |
| 363 /* The 2nd could be VPD 2.0 data or End Of Table. */ | 385 /* The 2nd could be VPD 2.0 data or End Of Table. */ |
| 364 if (header->handle != expected_handle) { | 386 if (header->handle != expected_handle) { |
| 365 fprintf(stderr, "The second handle value must be 1, but is %d.\n", | 387 fprintf(stderr, "[ERROR] The second handle value must be 1, but is %d.\n" |
| 388 " Use -O option to re-format.\n", | |
| 366 header->handle); | 389 header->handle); |
| 367 retval = 1; | 390 retval = 1; |
| 368 goto teardown; | 391 goto teardown; |
| 369 } | 392 } |
| 370 uuid_parse(GOOGLE_VPD_2_0_UUID, vpd_2_0_uuid); | 393 uuid_parse(GOOGLE_VPD_2_0_UUID, vpd_2_0_uuid); |
| 371 if (header->type == VPD_TYPE_BINARY_BLOB_POINTER && | 394 if (header->type == VPD_TYPE_BINARY_BLOB_POINTER && |
| 372 !memcmp(data->uuid, vpd_2_0_uuid, sizeof(data->uuid))) { | 395 !memcmp(data->uuid, vpd_2_0_uuid, sizeof(data->uuid))) { |
| 373 ++expected_handle; | 396 ++expected_handle; |
| 374 | 397 |
| 375 /* iterate all pairs */ | 398 /* iterate all pairs */ |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 fprintf(stderr, "fwrite(VPD 2.0) error (%s)\n", strerror(errno)); | 506 fprintf(stderr, "fwrite(VPD 2.0) error (%s)\n", strerror(errno)); |
| 484 retval = 1; | 507 retval = 1; |
| 485 goto teardown; | 508 goto teardown; |
| 486 } | 509 } |
| 487 fclose(fp); | 510 fclose(fp); |
| 488 | 511 |
| 489 teardown: | 512 teardown: |
| 490 return retval; | 513 return retval; |
| 491 } | 514 } |
| 492 | 515 |
| 516 int myMkTemp(uint8_t *tmp_file) { | |
| 517 int fd; | |
| 518 fd = mkstemp(tmp_file); | |
| 519 if (fd < 0) { | |
| 520 fprintf(stderr, "mkstemp(%s) failed\n", tmp_file); | |
| 521 } | |
| 522 return fd; | |
| 523 } | |
| 524 | |
| 525 int generateTempFilenames(void) { | |
| 526 if (myMkTemp(tmp_part_file) < 0) return -1; | |
| 527 if (myMkTemp(tmp_full_file) < 0) return -1; | |
| 528 return 0; | |
| 529 } | |
| 493 | 530 |
| 494 static void usage(const char *progname) { | 531 static void usage(const char *progname) { |
| 495 printf("Chrome OS VPD 2.0 utility --\n"); | 532 printf("Chrome OS VPD 2.0 utility --\n"); |
| 496 #ifdef VPD_VERSION | 533 #ifdef VPD_VERSION |
| 497 printf("%s\n", VPD_VERSION); | 534 printf("%s\n", VPD_VERSION); |
| 498 #endif | 535 #endif |
| 499 printf("\n"); | 536 printf("\n"); |
| 500 printf("Usage: %s [OPTION] ...\n", progname); | 537 printf("Usage: %s [OPTION] ...\n", progname); |
| 501 printf(" OPTIONs include:\n"); | 538 printf(" OPTIONs include:\n"); |
| 502 printf(" -h This help page and version.\n"); | 539 printf(" -h This help page and version.\n"); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 goto teardown; | 581 goto teardown; |
| 545 break; | 582 break; |
| 546 | 583 |
| 547 case 'f': | 584 case 'f': |
| 548 filename = strdup(optarg); | 585 filename = strdup(optarg); |
| 549 break; | 586 break; |
| 550 | 587 |
| 551 case 'E': | 588 case 'E': |
| 552 errno = 0; | 589 errno = 0; |
| 553 eps_base = strtoul(optarg, (char **) NULL, 0); | 590 eps_base = strtoul(optarg, (char **) NULL, 0); |
| 591 eps_base_force_specified = 1; | |
| 554 | 592 |
| 555 /* FIXME: this is not a stable way to detect error because | 593 /* FIXME: this is not a stable way to detect error because |
| 556 * implementation may (or may not) assign errno. */ | 594 * implementation may (or may not) assign errno. */ |
| 557 if (!eps_base && errno == EINVAL) { | 595 if (!eps_base && errno == EINVAL) { |
| 558 fprintf(stderr, "Not a number for EPS base address: %s\n", optarg); | 596 fprintf(stderr, "Not a number for EPS base address: %s\n", optarg); |
| 559 retval = 1; | 597 retval = 1; |
| 560 goto teardown; | 598 goto teardown; |
| 561 } | 599 } |
| 562 break; | 600 break; |
| 563 | 601 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 break; | 636 break; |
| 599 | 637 |
| 600 default: | 638 default: |
| 601 fprintf(stderr, "Invalid option, use --help for usage.\n"); | 639 fprintf(stderr, "Invalid option, use --help for usage.\n"); |
| 602 retval = 1; | 640 retval = 1; |
| 603 goto teardown; | 641 goto teardown; |
| 604 break; | 642 break; |
| 605 } | 643 } |
| 606 } | 644 } |
| 607 | 645 |
| 608 fd = mkstemp(flashrom_tmp_file); | 646 if (optind < argc) { |
| 609 if (fd < 0) { | 647 fprintf(stderr, "[ERROR] unexpected argument: %s\n\n", argv[optind]); |
| 610 fprintf(stderr, "mkstemp(%s) failed\n", flashrom_tmp_file); | 648 usage(argv[0]); |
| 611 retval = 1; | 649 retval = 1; |
| 612 goto teardown; | 650 goto teardown; |
| 613 } | 651 } |
| 652 | |
| 653 if (generateTempFilenames() < 0) { | |
| 654 retval = 1; | |
| 655 goto teardown; | |
| 656 } | |
| 614 | 657 |
| 615 /* to avoid malicious attack, we replace suspicious chars. */ | 658 /* to avoid malicious attack, we replace suspicious chars. */ |
| 616 fmapNormalizeAreaName(fmap_vpd_area_name); | 659 fmapNormalizeAreaName(fmap_vpd_area_name); |
| 617 | 660 |
| 618 /* if no filename is specified, call flashrom to read from flash. */ | 661 /* if no filename is specified, call flashrom to read from flash. */ |
| 619 if (!filename) { | 662 if (!filename) { |
| 620 if (FLASHROM_OK != flashromRead(flashrom_tmp_file)) { | 663 if (FLASHROM_OK != flashromRead(tmp_part_file, tmp_full_file, |
| 664 fmap_vpd_area_name)) { | |
| 621 fprintf(stderr, "flashromRead() error!\n"); | 665 fprintf(stderr, "flashromRead() error!\n"); |
| 622 retval = 1; | 666 retval = 1; |
| 623 goto teardown; | 667 goto teardown; |
| 624 } | 668 } |
| 625 write_back_to_flash = 1; | 669 write_back_to_flash = 1; |
| 626 filename = strdup(flashrom_tmp_file); | 670 filename = strdup(tmp_part_file); |
| 627 } | 671 } |
| 628 | 672 |
| 629 if (retval = loadFile(filename, &file, overwrite_it)) { | 673 if (retval = loadFile(filename, &file, overwrite_it)) { |
| 630 fprintf(stderr, "loadFile('%s') error.\n", filename); | 674 fprintf(stderr, "loadFile('%s') error.\n", filename); |
| 631 goto teardown; | 675 goto teardown; |
| 632 } | 676 } |
| 633 | 677 |
| 634 mergeContainer(&file, &argument); | 678 mergeContainer(&file, &argument); |
| 635 | 679 |
| 636 if (list_it) { | 680 if (list_it) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 648 printf("%s", list_buf); | 692 printf("%s", list_buf); |
| 649 } | 693 } |
| 650 | 694 |
| 651 if (modified) { | 695 if (modified) { |
| 652 if (retval = saveFile(&file, filename)) { | 696 if (retval = saveFile(&file, filename)) { |
| 653 fprintf(stderr, "saveFile('%s') error.\n", filename); | 697 fprintf(stderr, "saveFile('%s') error.\n", filename); |
| 654 goto teardown; | 698 goto teardown; |
| 655 } | 699 } |
| 656 | 700 |
| 657 if (write_back_to_flash) { | 701 if (write_back_to_flash) { |
| 658 if (FLASHROM_OK != flashromPartialWrite(filename, vpd_offset, vpd_size)) { | 702 if (FLASHROM_OK != flashromPartialWrite(filename, tmp_full_file, |
| 703 fmap_vpd_area_name)) { | |
| 659 fprintf(stderr, "flashromPartialWrite() error.\n"); | 704 fprintf(stderr, "flashromPartialWrite() error.\n"); |
| 660 retval = 1; | 705 retval = 1; |
| 661 goto teardown; | 706 goto teardown; |
| 662 } | 707 } |
| 663 } | 708 } |
| 664 } | 709 } |
| 665 | 710 |
| 666 teardown: | 711 teardown: |
| 667 if (spd_data) free(spd_data); | 712 if (spd_data) free(spd_data); |
| 668 if (filename) free(filename); | 713 if (filename) free(filename); |
| 669 destroyContainer(&file); | 714 destroyContainer(&file); |
| 670 destroyContainer(&argument); | 715 destroyContainer(&argument); |
| 671 | 716 |
| 672 return retval; | 717 return retval; |
| 673 } | 718 } |
| OLD | NEW |