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 * Functions for generating and manipulating a verified boot kernel image. | 5 * Functions for generating and manipulating a verified boot kernel image. |
6 * (Userland portion) | 6 * (Userland portion) |
7 */ | 7 */ |
8 #include "kernel_image.h" | 8 #include "kernel_image.h" |
9 | 9 |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 image->preamble_signature = (uint8_t*) Malloc(signature_len); | 592 image->preamble_signature = (uint8_t*) Malloc(signature_len); |
593 Memcpy(image->preamble_signature, preamble_signature, signature_len); | 593 Memcpy(image->preamble_signature, preamble_signature, signature_len); |
594 | 594 |
595 Free(preamble_signature); | 595 Free(preamble_signature); |
596 Free(preamble_blob); | 596 Free(preamble_blob); |
597 Free(kernel_signature); | 597 Free(kernel_signature); |
598 Free(kernel_buf); | 598 Free(kernel_buf); |
599 return 1; | 599 return 1; |
600 } | 600 } |
601 | 601 |
602 void PrintKernelEntry(kernel_entry* entry) { | 602 /* Return the smallest integral multiple of [alignment] that is equal to or |
603 debug("Boot Priority = %d\n", entry->boot_priority); | 603 * greater than [val]. Used to determine the number of |
604 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining); | 604 * pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc. */ |
605 debug("Boot Success Flag = %d\n", entry->boot_success_flag); | |
606 } | |
607 | |
608 // Return the smallest integral multiple of [alignment] that is equal to or | |
609 // greater than [val]. Used to determine the number of | |
610 // pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc. | |
611 static uint64_t roundup(uint64_t val, uint64_t alignment) { | 605 static uint64_t roundup(uint64_t val, uint64_t alignment) { |
612 uint64_t rem = val % alignment; | 606 uint64_t rem = val % alignment; |
613 if ( rem ) | 607 if ( rem ) |
614 return val + (alignment - rem); | 608 return val + (alignment - rem); |
615 return val; | 609 return val; |
616 } | 610 } |
617 | 611 |
618 // Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we | 612 /* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we |
619 // don't find one, we'll use the whole thing. | 613 * don't find one, we'll use the whole thing. */ |
620 static unsigned int find_cmdline_start(char *input, unsigned int max_len) { | 614 static unsigned int find_cmdline_start(char *input, unsigned int max_len) { |
621 int start = 0; | 615 int start = 0; |
622 int i; | 616 int i; |
623 for(i = 0; i < max_len-1 && input[i]; i++) { | 617 for(i = 0; i < max_len-1 && input[i]; i++) { |
624 if (input[i] == '-' && input[i+1] == '-') { // found a "--" | 618 if (input[i] == '-' && input[i+1] == '-') { /* found a "--" */ |
625 if ((i == 0 || input[i-1] == ' ') && // nothing before it | 619 if ((i == 0 || input[i-1] == ' ') && /* nothing before it */ |
626 (i+2 >= max_len || input[i+2] == ' ')) { // nothing after it | 620 (i+2 >= max_len || input[i+2] == ' ')) { /* nothing after it */ |
627 start = i+2; // note: hope there's a trailing '\0' | 621 start = i+2; /* note: hope there's a trailing '\0' */ |
628 break; | 622 break; |
629 } | 623 } |
630 } | 624 } |
631 } | 625 } |
632 while(input[start] == ' ') // skip leading spaces | 626 while(input[start] == ' ') /* skip leading spaces */ |
633 start++; | 627 start++; |
634 | 628 |
635 return start; | 629 return start; |
636 } | 630 } |
637 | 631 |
638 uint8_t* GenerateKernelBlob(const char* kernel_file, | 632 uint8_t* GenerateKernelBlob(const char* kernel_file, |
639 const char* config_file, | 633 const char* config_file, |
640 const char* bootloader_file, | 634 const char* bootloader_file, |
641 uint64_t* ret_blob_len, | 635 uint64_t* ret_blob_len, |
642 uint64_t* ret_bootloader_offset, | 636 uint64_t* ret_bootloader_offset, |
643 uint64_t* ret_bootloader_size) { | 637 uint64_t* ret_bootloader_size) { |
644 uint8_t* kernel_buf; | 638 uint8_t* kernel_buf; |
645 uint8_t* config_buf; | 639 uint8_t* config_buf; |
646 uint8_t* bootloader_buf; | 640 uint8_t* bootloader_buf; |
647 uint8_t* blob = 0; | 641 uint8_t* blob = 0; |
648 uint64_t kernel_size; | 642 uint64_t kernel_size; |
649 uint64_t config_size; | 643 uint64_t config_size; |
650 uint64_t bootloader_size; | 644 uint64_t bootloader_size; |
651 uint64_t blob_size; | 645 uint64_t blob_size; |
652 uint64_t kernel32_start = 0; | 646 uint64_t kernel32_start = 0; |
653 uint64_t kernel32_size = 0; | 647 uint64_t kernel32_size = 0; |
654 uint64_t bootloader_mem_start; | 648 uint64_t bootloader_mem_start; |
655 uint64_t bootloader_mem_size; | 649 uint64_t bootloader_mem_size; |
656 uint64_t now; | 650 uint64_t now; |
657 struct linux_kernel_header *lh = 0; | 651 struct linux_kernel_header *lh = 0; |
658 struct linux_kernel_params *params = 0; | 652 struct linux_kernel_params *params = 0; |
659 uint32_t cmdline_addr; | 653 uint32_t cmdline_addr; |
660 uint64_t i; | 654 uint64_t i; |
661 | 655 |
662 // Read the input files. | 656 /* Read the input files. */ |
663 kernel_buf = BufferFromFile(kernel_file, &kernel_size); | 657 kernel_buf = BufferFromFile(kernel_file, &kernel_size); |
664 if (!kernel_buf) | 658 if (!kernel_buf) |
665 goto done0; | 659 goto done0; |
666 | 660 |
667 config_buf = BufferFromFile(config_file, &config_size); | 661 config_buf = BufferFromFile(config_file, &config_size); |
668 if (!config_buf) | 662 if (!config_buf) |
669 goto done1; | 663 goto done1; |
670 if (config_size >= CROS_CONFIG_SIZE) { // need room for trailing '\0' | 664 if (config_size >= CROS_CONFIG_SIZE) { /* need room for trailing '\0' */ |
671 error("config file %s is too large (>= %d bytes)\n", | 665 error("config file %s is too large (>= %d bytes)\n", |
672 config_file, CROS_CONFIG_SIZE); | 666 config_file, CROS_CONFIG_SIZE); |
673 goto done1; | 667 goto done1; |
674 } | 668 } |
675 | 669 |
676 // Replace any newlines with spaces in the config file. | 670 /* Replace any newlines with spaces in the config file. */ |
677 for (i=0; i < config_size; i++) | 671 for (i=0; i < config_size; i++) |
678 if (config_buf[i] == '\n') | 672 if (config_buf[i] == '\n') |
679 config_buf[i] = ' '; | 673 config_buf[i] = ' '; |
680 | 674 |
681 bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size); | 675 bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size); |
682 if (!bootloader_buf) | 676 if (!bootloader_buf) |
683 goto done2; | 677 goto done2; |
684 | 678 |
685 // The first part of vmlinuz is a header, followed by a real-mode boot stub. | 679 /* The first part of vmlinuz is a header, followed by a real-mode boot stub. |
686 // We only want the 32-bit part. | 680 * We only want the 32-bit part. */ |
687 if (kernel_size) { | 681 if (kernel_size) { |
688 lh = (struct linux_kernel_header *)kernel_buf; | 682 lh = (struct linux_kernel_header *)kernel_buf; |
689 kernel32_start = (lh->setup_sects+1) << 9; | 683 kernel32_start = (lh->setup_sects+1) << 9; |
690 kernel32_size = kernel_size - kernel32_start; | 684 kernel32_size = kernel_size - kernel32_start; |
691 } | 685 } |
692 | 686 |
693 // Allocate and zero the blob we need. | 687 /* Allocate and zero the blob we need. */ |
694 blob_size = roundup(kernel32_size, CROS_ALIGN) + | 688 blob_size = roundup(kernel32_size, CROS_ALIGN) + |
695 CROS_CONFIG_SIZE + | 689 CROS_CONFIG_SIZE + |
696 CROS_PARAMS_SIZE + | 690 CROS_PARAMS_SIZE + |
697 roundup(bootloader_size, CROS_ALIGN); | 691 roundup(bootloader_size, CROS_ALIGN); |
698 blob = (uint8_t *)Malloc(blob_size); | 692 blob = (uint8_t *)Malloc(blob_size); |
699 if (!blob) { | 693 if (!blob) { |
700 error("Couldn't allocate %ld bytes.\n", blob_size); | 694 error("Couldn't allocate %ld bytes.\n", blob_size); |
701 goto done3; | 695 goto done3; |
702 } | 696 } |
703 Memset(blob, 0, blob_size); | 697 Memset(blob, 0, blob_size); |
704 now = 0; | 698 now = 0; |
705 | 699 |
706 // Copy the 32-bit kernel. | 700 /* Copy the 32-bit kernel. */ |
707 if (kernel32_size) | 701 if (kernel32_size) |
708 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); | 702 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); |
709 now += roundup(now + kernel32_size, CROS_ALIGN); | 703 now += roundup(now + kernel32_size, CROS_ALIGN); |
710 | 704 |
711 // Find the load address of the commandline. We'll need it later. | 705 /* Find the load address of the commandline. We'll need it later. */ |
712 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now | 706 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now |
713 + find_cmdline_start((char *)config_buf, config_size); | 707 + find_cmdline_start((char *)config_buf, config_size); |
714 | 708 |
715 // Copy the config. | 709 /* Copy the config. */ |
716 if (config_size) | 710 if (config_size) |
717 Memcpy(blob + now, config_buf, config_size); | 711 Memcpy(blob + now, config_buf, config_size); |
718 now += CROS_CONFIG_SIZE; | 712 now += CROS_CONFIG_SIZE; |
719 | 713 |
720 // The zeropage data is next. Overlay the linux_kernel_header onto it, and | 714 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and |
721 // tweak a few fields. | 715 * tweak a few fields. */ |
722 params = (struct linux_kernel_params *)(blob + now); | 716 params = (struct linux_kernel_params *)(blob + now); |
723 | 717 |
724 if (kernel_size) | 718 if (kernel_size) |
725 Memcpy(&(params->setup_sects), &(lh->setup_sects), | 719 Memcpy(&(params->setup_sects), &(lh->setup_sects), |
726 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); | 720 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); |
727 params->boot_flag = 0; | 721 params->boot_flag = 0; |
728 params->ramdisk_image = 0; // we don't support initrd | 722 params->ramdisk_image = 0; /* we don't support initrd */ |
729 params->ramdisk_size = 0; | 723 params->ramdisk_size = 0; |
730 params->type_of_loader = 0xff; | 724 params->type_of_loader = 0xff; |
731 params->cmd_line_ptr = cmdline_addr; | 725 params->cmd_line_ptr = cmdline_addr; |
732 now += CROS_PARAMS_SIZE; | 726 now += CROS_PARAMS_SIZE; |
733 | 727 |
734 // Finally, append the bootloader. Remember where it will load in memory, too. | 728 /* Finally, append the bootloader. Remember where it will load in memory, too. |
| 729 */ |
735 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; | 730 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; |
736 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); | 731 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); |
737 if (bootloader_size) | 732 if (bootloader_size) |
738 Memcpy(blob + now, bootloader_buf, bootloader_size); | 733 Memcpy(blob + now, bootloader_buf, bootloader_size); |
739 now += bootloader_mem_size; | 734 now += bootloader_mem_size; |
740 | 735 |
741 // Pass back some info. | 736 /* Pass back some info. */ |
742 if (ret_blob_len) | 737 if (ret_blob_len) |
743 *ret_blob_len = blob_size; | 738 *ret_blob_len = blob_size; |
744 if (ret_bootloader_offset) | 739 if (ret_bootloader_offset) |
745 *ret_bootloader_offset = bootloader_mem_start; | 740 *ret_bootloader_offset = bootloader_mem_start; |
746 if (ret_bootloader_size) | 741 if (ret_bootloader_size) |
747 *ret_bootloader_size = bootloader_mem_size; | 742 *ret_bootloader_size = bootloader_mem_size; |
748 | 743 |
749 // Clean up and return the blob. | 744 /* Clean up and return the blob. */ |
750 done3: | 745 done3: |
751 Free(bootloader_buf); | 746 Free(bootloader_buf); |
752 done2: | 747 done2: |
753 Free(config_buf); | 748 Free(config_buf); |
754 done1: | 749 done1: |
755 Free(kernel_buf); | 750 Free(kernel_buf); |
756 done0: | 751 done0: |
757 return blob; | 752 return blob; |
758 } | 753 } |
OLD | NEW |