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 | 5 |
6 #include "cgpt.h" | 6 #include "cgpt.h" |
7 #include <string.h> | 7 #include <string.h> |
8 #include "cgpt_internal.h" | 8 #include "cgpt_internal.h" |
9 #include "crc32.h" | 9 #include "crc32.h" |
10 #include "gpt.h" | 10 #include "gpt.h" |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 return 0; | 458 return 0; |
459 } | 459 } |
460 | 460 |
461 /* Update CRC value if necessary. */ | 461 /* Update CRC value if necessary. */ |
462 void UpdateCrc(GptData *gpt) { | 462 void UpdateCrc(GptData *gpt) { |
463 GptHeader *primary_header, *secondary_header; | 463 GptHeader *primary_header, *secondary_header; |
464 | 464 |
465 primary_header = (GptHeader*)gpt->primary_header; | 465 primary_header = (GptHeader*)gpt->primary_header; |
466 secondary_header = (GptHeader*)gpt->secondary_header; | 466 secondary_header = (GptHeader*)gpt->secondary_header; |
467 | 467 |
| 468 if (gpt->modified & GPT_MODIFIED_ENTRIES1) { |
| 469 primary_header->entries_crc32 = |
| 470 Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
| 471 } |
| 472 if (gpt->modified & GPT_MODIFIED_ENTRIES2) { |
| 473 secondary_header->entries_crc32 = |
| 474 Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE); |
| 475 } |
468 if (gpt->modified & GPT_MODIFIED_HEADER1) { | 476 if (gpt->modified & GPT_MODIFIED_HEADER1) { |
469 primary_header->header_crc32 = 0; | 477 primary_header->header_crc32 = 0; |
470 primary_header->header_crc32 = Crc32( | 478 primary_header->header_crc32 = Crc32( |
471 (const uint8_t *)primary_header, primary_header->size); | 479 (const uint8_t *)primary_header, primary_header->size); |
472 } | 480 } |
473 if (gpt->modified & GPT_MODIFIED_HEADER2) { | 481 if (gpt->modified & GPT_MODIFIED_HEADER2) { |
474 secondary_header->header_crc32 = 0; | 482 secondary_header->header_crc32 = 0; |
475 secondary_header->header_crc32 = Crc32( | 483 secondary_header->header_crc32 = Crc32( |
476 (const uint8_t *)secondary_header, secondary_header->size); | 484 (const uint8_t *)secondary_header, secondary_header->size); |
477 } | 485 } |
478 if (gpt->modified & GPT_MODIFIED_ENTRIES1) { | |
479 primary_header->entries_crc32 = | |
480 Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); | |
481 } | |
482 if (gpt->modified & GPT_MODIFIED_ENTRIES2) { | |
483 secondary_header->entries_crc32 = | |
484 Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE); | |
485 } | |
486 } | 486 } |
487 | 487 |
488 /* Does every sanity check, and returns if any header/entries needs to be | 488 /* Does every sanity check, and returns if any header/entries needs to be |
489 * written back. */ | 489 * written back. */ |
490 int GptInit(GptData *gpt) { | 490 int GptInit(GptData *gpt) { |
491 uint32_t valid_headers = MASK_BOTH; | 491 uint32_t valid_headers = MASK_BOTH; |
492 uint32_t valid_entries = MASK_BOTH; | 492 uint32_t valid_entries = MASK_BOTH; |
493 int retval; | 493 int retval; |
494 | 494 |
495 retval = CheckParameters(gpt); | 495 retval = CheckParameters(gpt); |
(...skipping 25 matching lines...) Expand all Loading... |
521 gpt->modified |= RepairEntries(gpt, valid_entries); | 521 gpt->modified |= RepairEntries(gpt, valid_entries); |
522 | 522 |
523 /* Returns error if we don't have any valid header/entries to use. */ | 523 /* Returns error if we don't have any valid header/entries to use. */ |
524 if (!valid_headers) | 524 if (!valid_headers) |
525 return GPT_ERROR_INVALID_HEADERS; | 525 return GPT_ERROR_INVALID_HEADERS; |
526 if (!valid_entries) | 526 if (!valid_entries) |
527 return GPT_ERROR_INVALID_ENTRIES; | 527 return GPT_ERROR_INVALID_ENTRIES; |
528 | 528 |
529 UpdateCrc(gpt); | 529 UpdateCrc(gpt); |
530 | 530 |
531 /* FIXME: will remove the next line soon. */ | 531 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND; |
532 gpt->current_kernel = 1; | 532 |
533 return GPT_SUCCESS; | 533 return GPT_SUCCESS; |
534 } | 534 } |
535 | 535 |
536 /* stub code */ | 536 /* Helper function to get a pointer to the partition entry. |
537 static int start[] = { 34, 10034 }; | 537 * 'secondary' is either PRIMARY or SECONDARY. |
538 | 538 * 'entry_index' is the partition index: [0, number_of_entries). |
| 539 */ |
| 540 GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) { |
| 541 GptHeader *header; |
| 542 uint8_t *entries; |
| 543 |
| 544 if (secondary == PRIMARY) { |
| 545 header = (GptHeader*)gpt->primary_header; |
| 546 entries = gpt->primary_entries; |
| 547 } else { |
| 548 header = (GptHeader*)gpt->secondary_header; |
| 549 entries = gpt->secondary_entries; |
| 550 } |
| 551 |
| 552 return (GptEntry*)(&entries[header->size_of_entry * entry_index]); |
| 553 } |
| 554 |
| 555 /* The following functions are helpers to access attributes bit more easily. |
| 556 * 'secondary' is either PRIMARY or SECONDARY. |
| 557 * 'entry_index' is the partition index: [0, number_of_entries). |
| 558 * |
| 559 * Get*() return the exact value (shifted and masked). |
| 560 */ |
| 561 void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) { |
| 562 GptEntry *entry; |
| 563 entry = GetEntry(gpt, secondary, entry_index); |
| 564 |
| 565 assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); |
| 566 entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; |
| 567 entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
| 568 } |
| 569 |
| 570 int GetPriority(GptData *gpt, int secondary, int entry_index) { |
| 571 GptEntry *entry; |
| 572 entry = GetEntry(gpt, secondary, entry_index); |
| 573 return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >> |
| 574 CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
| 575 } |
| 576 |
| 577 void SetBad(GptData *gpt, int secondary, int entry_index, int bad) { |
| 578 GptEntry *entry; |
| 579 entry = GetEntry(gpt, secondary, entry_index); |
| 580 |
| 581 assert(bad >= 0 && bad <= CGPT_ATTRIBUTE_MAX_BAD); |
| 582 entry->attributes &= ~CGPT_ATTRIBUTE_BAD_MASK; |
| 583 entry->attributes |= (uint64_t)bad << CGPT_ATTRIBUTE_BAD_OFFSET; |
| 584 } |
| 585 |
| 586 int GetBad(GptData *gpt, int secondary, int entry_index) { |
| 587 GptEntry *entry; |
| 588 entry = GetEntry(gpt, secondary, entry_index); |
| 589 return (entry->attributes & CGPT_ATTRIBUTE_BAD_MASK) >> |
| 590 CGPT_ATTRIBUTE_BAD_OFFSET; |
| 591 } |
| 592 |
| 593 void SetTries(GptData *gpt, int secondary, int entry_index, int tries) { |
| 594 GptEntry *entry; |
| 595 entry = GetEntry(gpt, secondary, entry_index); |
| 596 |
| 597 assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); |
| 598 entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK; |
| 599 entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET; |
| 600 } |
| 601 |
| 602 int GetTries(GptData *gpt, int secondary, int entry_index) { |
| 603 GptEntry *entry; |
| 604 entry = GetEntry(gpt, secondary, entry_index); |
| 605 return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> |
| 606 CGPT_ATTRIBUTE_TRIES_OFFSET; |
| 607 } |
| 608 |
| 609 void SetSuccess(GptData *gpt, int secondary, int entry_index, int success) { |
| 610 GptEntry *entry; |
| 611 entry = GetEntry(gpt, secondary, entry_index); |
| 612 |
| 613 assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESS); |
| 614 entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESS_MASK; |
| 615 entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESS_OFFSET; |
| 616 } |
| 617 |
| 618 int GetSuccess(GptData *gpt, int secondary, int entry_index) { |
| 619 GptEntry *entry; |
| 620 entry = GetEntry(gpt, secondary, entry_index); |
| 621 return (entry->attributes & CGPT_ATTRIBUTE_SUCCESS_MASK) >> |
| 622 CGPT_ATTRIBUTE_SUCCESS_OFFSET; |
| 623 } |
| 624 |
| 625 /* Compare two priority values. Actually it is a circular priority, which is: |
| 626 * 3 > 2 > 1 > 0, but 0 > 3. (-1 means very low, and anyone is higher than -1) |
| 627 * |
| 628 * Return 1 if 'a' has higher priority than 'b'. |
| 629 */ |
| 630 int IsHigherPriority(int a, int b) { |
| 631 if ((a == 0) && (b == CGPT_ATTRIBUTE_MAX_PRIORITY)) |
| 632 return 1; |
| 633 else if ((a == CGPT_ATTRIBUTE_MAX_PRIORITY) && (b == 0)) |
| 634 return 0; |
| 635 else |
| 636 return (a > b) ? 1 : 0; |
| 637 } |
| 638 |
| 639 /* This function walks through the whole partition table (see note below), |
| 640 * and pick up the active and valid (not marked as bad) kernel entry with |
| 641 * *highest* priority (except gpt->current_kernel itself). |
| 642 * |
| 643 * Returns start_sector and its size if a candidate kernel is found. |
| 644 * |
| 645 * Note: in the first walk (gpt->current_kernel==CGPT_KERNEL_ENTRY_NOT_FOUND), |
| 646 * the scan range is whole table. But in later scans, we only scan |
| 647 * (header->number_of_entries - 1) entries because we are looking for |
| 648 * next kernel with lower priority (consider the case that highest |
| 649 * priority kernel is still active and valid). |
| 650 */ |
539 int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) { | 651 int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) { |
540 /* FIXME: the following code is not really code, just returns anything */ | 652 GptHeader *header; |
541 gpt->current_kernel ^= 1; | 653 GptEntry *entry; |
542 if (start_sector) *start_sector = start[gpt->current_kernel]; | 654 int scan, current_priority; |
543 if (size) *size = 10000; | 655 int begin, end; /* [begin, end], which end is included. */ |
| 656 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; |
| 657 |
| 658 header = (GptHeader*)gpt->primary_header; |
| 659 current_priority = -1; /* pretty low priority */ |
| 660 if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND) { |
| 661 begin = 0; |
| 662 end = header->number_of_entries - 1; |
| 663 } else { |
| 664 begin = (gpt->current_kernel + 1) % header->number_of_entries; |
| 665 end = (gpt->current_kernel - 1 + header->number_of_entries) % |
| 666 header->number_of_entries; |
| 667 } |
| 668 |
| 669 scan = begin; |
| 670 do { |
| 671 entry = GetEntry(gpt, PRIMARY, scan); |
| 672 if (!Memcmp(&entry->type, &chromeos_kernel, sizeof(Guid)) && |
| 673 !GetBad(gpt, PRIMARY, scan) && |
| 674 ((gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND) || |
| 675 (IsHigherPriority(GetPriority(gpt, PRIMARY, scan), |
| 676 current_priority)))) { |
| 677 gpt->current_kernel = scan; |
| 678 current_priority = GetPriority(gpt, PRIMARY, gpt->current_kernel); |
| 679 } |
| 680 |
| 681 if (scan == end) break; |
| 682 scan = (scan + 1) % header->number_of_entries; |
| 683 } while (1); |
| 684 |
| 685 if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND) |
| 686 return GPT_ERROR_NO_VALID_KERNEL; |
| 687 |
| 688 entry = GetEntry(gpt, PRIMARY, gpt->current_kernel); |
| 689 assert(entry->starting_lba <= entry->ending_lba); |
| 690 |
| 691 if (start_sector) *start_sector = entry->starting_lba; |
| 692 if (size) *size = entry->ending_lba - entry->starting_lba + 1; |
| 693 |
544 return GPT_SUCCESS; | 694 return GPT_SUCCESS; |
545 } | 695 } |
546 | 696 |
| 697 /* Given a update_type, this function updates the corresponding bits in GptData. |
| 698 * |
| 699 * Returns GPT_SUCCESS if no error. gpt->modified is set if any header and |
| 700 * entries needs to be updated to hard drive. |
| 701 * GPT_ERROR_INVALID_UPDATE_TYPE if given an invalid update_type. |
| 702 */ |
547 int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type) { | 703 int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type) { |
548 /* FIXME: the following code is not really code, just return anything */ | 704 Guid chromeos_type = GPT_ENT_TYPE_CHROMEOS_KERNEL; |
549 gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) << | 705 int primary_is_modified = 0; |
550 gpt->current_kernel; | 706 |
| 707 assert(gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND); |
| 708 assert(!Memcmp(&(GetEntry(gpt, PRIMARY, gpt->current_kernel)->type), |
| 709 &chromeos_type, sizeof(Guid))); |
| 710 |
| 711 /* Modify primary entries first, then copy to secondary later. */ |
| 712 switch (update_type) { |
| 713 case GPT_UPDATE_ENTRY_TRY: { |
| 714 /* Increase tries value until CGPT_ATTRIBUTE_MAX_TRIES. */ |
| 715 int tries; |
| 716 tries = GetTries(gpt, PRIMARY, gpt->current_kernel); |
| 717 if (tries < CGPT_ATTRIBUTE_MAX_TRIES) { |
| 718 ++tries; |
| 719 SetTries(gpt, PRIMARY, gpt->current_kernel, tries); |
| 720 primary_is_modified = 1; |
| 721 } |
| 722 break; |
| 723 } |
| 724 case GPT_UPDATE_ENTRY_BAD: { |
| 725 GetEntry(gpt, PRIMARY, gpt->current_kernel)->attributes |= |
| 726 CGPT_ATTRIBUTE_BAD_MASK; |
| 727 primary_is_modified = 1; |
| 728 break; |
| 729 } |
| 730 default: { |
| 731 return GPT_ERROR_INVALID_UPDATE_TYPE; |
| 732 } |
| 733 } |
| 734 |
| 735 if (primary_is_modified) { |
| 736 /* Claim only primary is valid so that secondary is overwritten. */ |
| 737 RepairEntries(gpt, MASK_PRIMARY); |
| 738 /* Actually two entries are dirty now. |
| 739 * Also two headers are dirty because entries_crc32 has been updated. */ |
| 740 gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | |
| 741 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); |
| 742 UpdateCrc(gpt); |
| 743 } |
| 744 |
551 return GPT_SUCCESS; | 745 return GPT_SUCCESS; |
552 } | 746 } |
OLD | NEW |