Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2020 Stefan Roese <sr@denx.de> */ #include <common.h> #include <image.h> #include <log.h> #include <malloc.h> #include <mapmem.h> #include <asm/sections.h> #include <spl.h> #include <lzma/LzmaTypes.h> #include <lzma/LzmaDec.h> #include <lzma/LzmaTools.h> #define LZMA_LEN (1 << 20) static void spl_parse_legacy_validate(uintptr_t start, uintptr_t size) { uintptr_t spl_start = (uintptr_t)_start; uintptr_t spl_end = (uintptr_t)&_image_binary_end; uintptr_t end = start + size; if ((start >= spl_start && start < spl_end) || (end > spl_start && end <= spl_end) || (start < spl_start && end >= spl_end) || (start > end && end > spl_start)) panic("SPL: Image overlaps SPL\n"); if (size > CONFIG_SYS_BOOTM_LEN) panic("SPL: Image too large\n"); } int spl_parse_legacy_header(struct spl_image_info *spl_image, const struct legacy_img_hdr *header) { u32 header_size = sizeof(struct legacy_img_hdr); /* check uImage header CRC */ if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK) && !image_check_hcrc(header)) { puts("SPL: Image header CRC check failed!\n"); return -EINVAL; } if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY) { /* * On some system (e.g. powerpc), the load-address and * entry-point is located at address 0. We can't load * to 0-0x40. So skip header in this case. */ spl_image->load_addr = image_get_load(header); spl_image->entry_point = image_get_ep(header); spl_image->size = image_get_data_size(header); } else { spl_image->entry_point = image_get_ep(header); /* Load including the header */ spl_image->load_addr = image_get_load(header) - header_size; spl_image->size = image_get_data_size(header) + header_size; } #ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK /* store uImage data length and CRC to check later */ spl_image->dcrc_data = image_get_load(header); spl_image->dcrc_length = image_get_data_size(header); spl_image->dcrc = image_get_dcrc(header); #endif spl_image->os = image_get_os(header); spl_image->name = image_get_name(header); debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n", spl_image->name, spl_image->load_addr, spl_image->size); spl_parse_legacy_validate(spl_image->load_addr, spl_image->size); spl_parse_legacy_validate(spl_image->entry_point, 0); return 0; } /* * This function is added explicitly to avoid code size increase, when * no compression method is enabled. The compiler will optimize the * following switch/case statement in spl_load_legacy_img() away due to * Dead Code Elimination. */ static inline int spl_image_get_comp(const struct legacy_img_hdr *hdr) { if (IS_ENABLED(CONFIG_SPL_LZMA)) return image_get_comp(hdr); return IH_COMP_NONE; } int spl_load_legacy_img(struct spl_image_info *spl_image, struct spl_boot_device *bootdev, struct spl_load_info *load, ulong offset, struct legacy_img_hdr *hdr) { __maybe_unused SizeT lzma_len; __maybe_unused void *src; ulong dataptr; int ret; /* * If the payload is compressed, the decompressed data should be * directly write to its load address. */ if (spl_image_get_comp(hdr) != IH_COMP_NONE) spl_image->flags |= SPL_COPY_PAYLOAD_ONLY; ret = spl_parse_image_header(spl_image, bootdev, hdr); if (ret) return ret; /* Read image */ switch (spl_image_get_comp(hdr)) { case IH_COMP_NONE: dataptr = offset; /* * Image header will be skipped only if SPL_COPY_PAYLOAD_ONLY * is set */ if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY) dataptr += sizeof(*hdr); load->read(load, dataptr, spl_image->size, map_sysmem(spl_image->load_addr, spl_image->size)); break; case IH_COMP_LZMA: lzma_len = LZMA_LEN; /* dataptr points to compressed payload */ dataptr = offset + sizeof(*hdr); debug("LZMA: Decompressing %08lx to %08lx\n", dataptr, spl_image->load_addr); src = malloc(spl_image->size); if (!src) { printf("Unable to allocate %d bytes for LZMA\n", spl_image->size); return -ENOMEM; } load->read(load, dataptr, spl_image->size, src); ret = lzmaBuffToBuffDecompress(map_sysmem(spl_image->load_addr, spl_image->size), &lzma_len, src, spl_image->size); if (ret) { printf("LZMA decompression error: %d\n", ret); return ret; } spl_image->size = lzma_len; break; default: debug("Compression method %s is not supported\n", genimg_get_comp_short_name(image_get_comp(hdr))); return -EINVAL; } return 0; } |