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 |