|
43 | 43 | #include "bootutil/enc_key.h"
|
44 | 44 | #endif
|
45 | 45 |
|
| 46 | +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_SWAP_USING_SCRATCH) |
| 47 | +#include "swap_priv.h" |
| 48 | +#endif |
| 49 | + |
46 | 50 | BOOT_LOG_MODULE_DECLARE(mcuboot);
|
47 | 51 |
|
48 | 52 | /* Currently only used by imgmgr */
|
49 | 53 | int boot_current_slot;
|
50 | 54 |
|
| 55 | +#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ |
| 56 | +defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) |
| 57 | +/* Used for holding static buffers in multiple functions to work around issues |
| 58 | + * in older versions of gcc (e.g. 4.8.4) |
| 59 | + */ |
| 60 | +static struct boot_sector_buffer sector_buffers; |
| 61 | +#endif |
| 62 | + |
51 | 63 | /**
|
52 | 64 | * @brief Determine if the data at two memory addresses is equal
|
53 | 65 | *
|
@@ -696,3 +708,206 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool
|
696 | 708 | end:
|
697 | 709 | return rc;
|
698 | 710 | }
|
| 711 | + |
| 712 | +#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ |
| 713 | +defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) |
| 714 | +int |
| 715 | +boot_initialize_area(struct boot_loader_state *state, int flash_area) |
| 716 | +{ |
| 717 | + uint32_t num_sectors = BOOT_MAX_IMG_SECTORS; |
| 718 | + boot_sector_t *out_sectors; |
| 719 | + uint32_t *out_num_sectors; |
| 720 | + int rc; |
| 721 | + |
| 722 | + num_sectors = BOOT_MAX_IMG_SECTORS; |
| 723 | + |
| 724 | + if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) { |
| 725 | + out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors; |
| 726 | + out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors; |
| 727 | +#if BOOT_NUM_SLOTS > 1 |
| 728 | + } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) { |
| 729 | + out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors; |
| 730 | + out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors; |
| 731 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 732 | + } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) { |
| 733 | + out_sectors = state->scratch.sectors; |
| 734 | + out_num_sectors = &state->scratch.num_sectors; |
| 735 | +#endif |
| 736 | +#endif |
| 737 | + } else { |
| 738 | + return BOOT_EFLASH; |
| 739 | + } |
| 740 | + |
| 741 | +#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS |
| 742 | + rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors); |
| 743 | +#else |
| 744 | + _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed"); |
| 745 | + rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors); |
| 746 | +#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */ |
| 747 | + if (rc != 0) { |
| 748 | + return rc; |
| 749 | + } |
| 750 | + *out_num_sectors = num_sectors; |
| 751 | + return 0; |
| 752 | +} |
| 753 | + |
| 754 | +static uint32_t |
| 755 | +boot_write_sz(struct boot_loader_state *state) |
| 756 | +{ |
| 757 | + uint32_t elem_sz; |
| 758 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 759 | + uint32_t align; |
| 760 | +#endif |
| 761 | + |
| 762 | + /* Figure out what size to write update status update as. The size depends |
| 763 | + * on what the minimum write size is for scratch area, active image slot. |
| 764 | + * We need to use the bigger of those 2 values. |
| 765 | + */ |
| 766 | + elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); |
| 767 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 768 | + align = flash_area_align(BOOT_SCRATCH_AREA(state)); |
| 769 | + if (align > elem_sz) { |
| 770 | + elem_sz = align; |
| 771 | + } |
| 772 | +#endif |
| 773 | + |
| 774 | + return elem_sz; |
| 775 | +} |
| 776 | + |
| 777 | +int |
| 778 | +boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *sectors) |
| 779 | +{ |
| 780 | + uint8_t image_index; |
| 781 | + int rc; |
| 782 | + |
| 783 | + if (sectors == NULL) { |
| 784 | + sectors = §or_buffers; |
| 785 | + } |
| 786 | + |
| 787 | + image_index = BOOT_CURR_IMG(state); |
| 788 | + |
| 789 | + BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors = |
| 790 | + sectors->primary[image_index]; |
| 791 | +#if BOOT_NUM_SLOTS > 1 |
| 792 | + BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors = |
| 793 | + sectors->secondary[image_index]; |
| 794 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 795 | + state->scratch.sectors = sectors->scratch; |
| 796 | +#endif |
| 797 | +#endif |
| 798 | + |
| 799 | + rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index)); |
| 800 | + if (rc != 0) { |
| 801 | + return BOOT_EFLASH; |
| 802 | + } |
| 803 | + |
| 804 | +#if BOOT_NUM_SLOTS > 1 |
| 805 | + rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index)); |
| 806 | + if (rc != 0) { |
| 807 | + /* We need to differentiate from the primary image issue */ |
| 808 | + return BOOT_EFLASH_SEC; |
| 809 | + } |
| 810 | + |
| 811 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 812 | + rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH); |
| 813 | + if (rc != 0) { |
| 814 | + return BOOT_EFLASH; |
| 815 | + } |
| 816 | +#endif |
| 817 | +#endif |
| 818 | + |
| 819 | + BOOT_WRITE_SZ(state) = boot_write_sz(state); |
| 820 | + |
| 821 | + return 0; |
| 822 | +} |
| 823 | +#endif |
| 824 | + |
| 825 | +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) |
| 826 | +static int |
| 827 | +boot_read_sectors_recovery(struct boot_loader_state *state) |
| 828 | +{ |
| 829 | + uint8_t image_index; |
| 830 | + int rc; |
| 831 | + |
| 832 | + image_index = BOOT_CURR_IMG(state); |
| 833 | + |
| 834 | + rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index)); |
| 835 | + if (rc != 0) { |
| 836 | + return BOOT_EFLASH; |
| 837 | + } |
| 838 | + |
| 839 | + rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index)); |
| 840 | + if (rc != 0) { |
| 841 | + /* We need to differentiate from the primary image issue */ |
| 842 | + return BOOT_EFLASH_SEC; |
| 843 | + } |
| 844 | + |
| 845 | + return 0; |
| 846 | +} |
| 847 | + |
| 848 | +/** |
| 849 | + * Reads image data to find out the maximum application sizes. Only needs to |
| 850 | + * be called in serial recovery mode, as the state information is unpopulated |
| 851 | + * at that time |
| 852 | + */ |
| 853 | +void boot_fetch_slot_state_sizes(void) |
| 854 | +{ |
| 855 | + int rc = -1; |
| 856 | + int image_index; |
| 857 | + |
| 858 | + rc = boot_open_all_flash_areas(boot_get_loader_state()); |
| 859 | + if (rc != 0) { |
| 860 | + BOOT_LOG_DBG("boot_fetch_slot_state_sizes: error %d while opening flash areas", rc); |
| 861 | + goto finish; |
| 862 | + } |
| 863 | + |
| 864 | + IMAGES_ITER(BOOT_CURR_IMG(boot_get_loader_state())) { |
| 865 | + int max_size = 0; |
| 866 | + |
| 867 | + image_index = BOOT_CURR_IMG(boot_get_loader_state()); |
| 868 | + |
| 869 | + BOOT_IMG(boot_get_loader_state(), BOOT_PRIMARY_SLOT).sectors = |
| 870 | + sector_buffers.primary[image_index]; |
| 871 | +#if BOOT_NUM_SLOTS > 1 |
| 872 | + BOOT_IMG(boot_get_loader_state(), BOOT_SECONDARY_SLOT).sectors = |
| 873 | + sector_buffers.secondary[image_index]; |
| 874 | +#if MCUBOOT_SWAP_USING_SCRATCH |
| 875 | + boot_get_loader_state()->scratch.sectors = sector_buffers.scratch; |
| 876 | +#endif |
| 877 | +#endif |
| 878 | + |
| 879 | + /* Determine the sector layout of the image slots and scratch area. */ |
| 880 | + rc = boot_read_sectors_recovery(boot_get_loader_state()); |
| 881 | + |
| 882 | + if (rc == 0) { |
| 883 | + max_size = app_max_size(boot_get_loader_state()); |
| 884 | + |
| 885 | + if (max_size > 0) { |
| 886 | + boot_get_image_max_sizes()[image_index].calculated = true; |
| 887 | + boot_get_image_max_sizes()[image_index].max_size = max_size; |
| 888 | + } |
| 889 | + } |
| 890 | + } |
| 891 | + |
| 892 | +finish: |
| 893 | + boot_close_all_flash_areas(boot_get_loader_state()); |
| 894 | + memset(boot_get_loader_state(), 0, sizeof(struct boot_loader_state)); |
| 895 | +} |
| 896 | +#endif |
| 897 | + |
| 898 | +/** |
| 899 | + * Clears the boot state, so that previous operations have no effect on new |
| 900 | + * ones. |
| 901 | + * |
| 902 | + * @param state The state that should be cleared. If the value |
| 903 | + * is NULL, the default bootloader state will be |
| 904 | + * cleared. |
| 905 | + */ |
| 906 | +void boot_state_clear(struct boot_loader_state *state) |
| 907 | +{ |
| 908 | + if (state != NULL) { |
| 909 | + memset(state, 0, sizeof(struct boot_loader_state)); |
| 910 | + } else { |
| 911 | + memset(boot_get_loader_state(), 0, sizeof(struct boot_loader_state)); |
| 912 | + } |
| 913 | +} |
0 commit comments