1 /* 2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch.h> 32 #include <arch_helpers.h> 33 #include <assert.h> 34 #include <auth_mod.h> 35 #include <bl_common.h> 36 #include <debug.h> 37 #include <errno.h> 38 #include <io_storage.h> 39 #include <platform.h> 40 #include <string.h> 41 42 unsigned long page_align(unsigned long value, unsigned dir) 43 { 44 unsigned long page_size = 1 << FOUR_KB_SHIFT; 45 46 /* Round up the limit to the next page boundary */ 47 if (value & (page_size - 1)) { 48 value &= ~(page_size - 1); 49 if (dir == UP) 50 value += page_size; 51 } 52 53 return value; 54 } 55 56 static inline unsigned int is_page_aligned (unsigned long addr) { 57 const unsigned long page_size = 1 << FOUR_KB_SHIFT; 58 59 return (addr & (page_size - 1)) == 0; 60 } 61 62 /****************************************************************************** 63 * Determine whether the memory region delimited by 'addr' and 'size' is free, 64 * given the extents of free memory. 65 * Return 1 if it is free, 0 otherwise. 66 *****************************************************************************/ 67 static int is_mem_free(uint64_t free_base, size_t free_size, 68 uint64_t addr, size_t size) 69 { 70 return (addr >= free_base) && (addr + size <= free_base + free_size); 71 } 72 73 /****************************************************************************** 74 * Inside a given memory region, determine whether a sub-region of memory is 75 * closer from the top or the bottom of the encompassing region. Return the 76 * size of the smallest chunk of free memory surrounding the sub-region in 77 * 'small_chunk_size'. 78 *****************************************************************************/ 79 static unsigned int choose_mem_pos(uint64_t mem_start, uint64_t mem_end, 80 uint64_t submem_start, uint64_t submem_end, 81 size_t *small_chunk_size) 82 { 83 size_t top_chunk_size, bottom_chunk_size; 84 85 assert(mem_start <= submem_start); 86 assert(submem_start <= submem_end); 87 assert(submem_end <= mem_end); 88 assert(small_chunk_size != NULL); 89 90 top_chunk_size = mem_end - submem_end; 91 bottom_chunk_size = submem_start - mem_start; 92 93 if (top_chunk_size < bottom_chunk_size) { 94 *small_chunk_size = top_chunk_size; 95 return TOP; 96 } else { 97 *small_chunk_size = bottom_chunk_size; 98 return BOTTOM; 99 } 100 } 101 102 /****************************************************************************** 103 * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 104 * memory are passed in 'free_base' and 'free_size' and they will be updated to 105 * reflect the memory usage. 106 * The caller must ensure the memory to reserve is free. 107 *****************************************************************************/ 108 void reserve_mem(uint64_t *free_base, size_t *free_size, 109 uint64_t addr, size_t size) 110 { 111 size_t discard_size; 112 size_t reserved_size; 113 unsigned int pos; 114 115 assert(free_base != NULL); 116 assert(free_size != NULL); 117 assert(is_mem_free(*free_base, *free_size, addr, size)); 118 119 pos = choose_mem_pos(*free_base, *free_base + *free_size, 120 addr, addr + size, 121 &discard_size); 122 123 reserved_size = size + discard_size; 124 *free_size -= reserved_size; 125 126 if (pos == BOTTOM) 127 *free_base = addr + size; 128 129 VERBOSE("Reserved 0x%lx bytes (discarded 0x%lx bytes %s)\n", 130 reserved_size, discard_size, 131 pos == TOP ? "above" : "below"); 132 } 133 134 static void dump_load_info(unsigned long image_load_addr, 135 unsigned long image_size, 136 const meminfo_t *mem_layout) 137 { 138 INFO("Trying to load image at address 0x%lx, size = 0x%lx\n", 139 image_load_addr, image_size); 140 INFO("Current memory layout:\n"); 141 INFO(" total region = [0x%lx, 0x%lx]\n", mem_layout->total_base, 142 mem_layout->total_base + mem_layout->total_size); 143 INFO(" free region = [0x%lx, 0x%lx]\n", mem_layout->free_base, 144 mem_layout->free_base + mem_layout->free_size); 145 } 146 147 /* Generic function to return the size of an image */ 148 unsigned long image_size(unsigned int image_id) 149 { 150 uintptr_t dev_handle; 151 uintptr_t image_handle; 152 uintptr_t image_spec; 153 size_t image_size = 0; 154 int io_result; 155 156 /* Obtain a reference to the image by querying the platform layer */ 157 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 158 if (io_result != 0) { 159 WARN("Failed to obtain reference to image id=%u (%i)\n", 160 image_id, io_result); 161 return 0; 162 } 163 164 /* Attempt to access the image */ 165 io_result = io_open(dev_handle, image_spec, &image_handle); 166 if (io_result != 0) { 167 WARN("Failed to access image id=%u (%i)\n", 168 image_id, io_result); 169 return 0; 170 } 171 172 /* Find the size of the image */ 173 io_result = io_size(image_handle, &image_size); 174 if ((io_result != 0) || (image_size == 0)) { 175 WARN("Failed to determine the size of the image id=%u (%i)\n", 176 image_id, io_result); 177 } 178 io_result = io_close(image_handle); 179 /* Ignore improbable/unrecoverable error in 'close' */ 180 181 /* TODO: Consider maintaining open device connection from this 182 * bootloader stage 183 */ 184 io_result = io_dev_close(dev_handle); 185 /* Ignore improbable/unrecoverable error in 'dev_close' */ 186 187 return image_size; 188 } 189 190 /******************************************************************************* 191 * Generic function to load an image at a specific address given a name and 192 * extents of free memory. It updates the memory layout if the load is 193 * successful, as well as the image information and the entry point information. 194 * The caller might pass a NULL pointer for the entry point if it is not 195 * interested in this information, e.g. because the image just needs to be 196 * loaded in memory but won't ever be executed. 197 * Returns 0 on success, a negative error code otherwise. 198 ******************************************************************************/ 199 int load_image(meminfo_t *mem_layout, 200 unsigned int image_id, 201 uintptr_t image_base, 202 image_info_t *image_data, 203 entry_point_info_t *entry_point_info) 204 { 205 uintptr_t dev_handle; 206 uintptr_t image_handle; 207 uintptr_t image_spec; 208 size_t image_size; 209 size_t bytes_read; 210 int io_result; 211 212 assert(mem_layout != NULL); 213 assert(image_data != NULL); 214 assert(image_data->h.version >= VERSION_1); 215 216 /* Obtain a reference to the image by querying the platform layer */ 217 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 218 if (io_result != 0) { 219 WARN("Failed to obtain reference to image id=%u (%i)\n", 220 image_id, io_result); 221 return io_result; 222 } 223 224 /* Attempt to access the image */ 225 io_result = io_open(dev_handle, image_spec, &image_handle); 226 if (io_result != 0) { 227 WARN("Failed to access image id=%u (%i)\n", 228 image_id, io_result); 229 return io_result; 230 } 231 232 INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); 233 234 /* Find the size of the image */ 235 io_result = io_size(image_handle, &image_size); 236 if ((io_result != 0) || (image_size == 0)) { 237 WARN("Failed to determine the size of the image id=%u (%i)\n", 238 image_id, io_result); 239 goto exit; 240 } 241 242 /* Check that the memory where the image will be loaded is free */ 243 if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 244 image_base, image_size)) { 245 WARN("Failed to reserve memory: 0x%lx - 0x%lx\n", 246 image_base, image_base + image_size); 247 dump_load_info(image_base, image_size, mem_layout); 248 io_result = -ENOMEM; 249 goto exit; 250 } 251 252 /* We have enough space so load the image now */ 253 /* TODO: Consider whether to try to recover/retry a partially successful read */ 254 io_result = io_read(image_handle, image_base, image_size, &bytes_read); 255 if ((io_result != 0) || (bytes_read < image_size)) { 256 WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 257 goto exit; 258 } 259 260 /* 261 * Update the memory usage info. 262 * This is done after the actual loading so that it is not updated when 263 * the load is unsuccessful. 264 * If the caller does not provide an entry point, bypass the memory 265 * reservation. 266 */ 267 if (entry_point_info != NULL) { 268 reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 269 image_base, image_size); 270 } else { 271 INFO("Skip reserving memory: 0x%lx - 0x%lx\n", 272 image_base, image_base + image_size); 273 } 274 275 image_data->image_base = image_base; 276 image_data->image_size = image_size; 277 278 if (entry_point_info != NULL) 279 entry_point_info->pc = image_base; 280 281 /* 282 * File has been successfully loaded. 283 * Flush the image in TZRAM so that the next EL can see it. 284 */ 285 flush_dcache_range(image_base, image_size); 286 287 INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, 288 image_base + image_size); 289 290 exit: 291 io_close(image_handle); 292 /* Ignore improbable/unrecoverable error in 'close' */ 293 294 /* TODO: Consider maintaining open device connection from this bootloader stage */ 295 io_dev_close(dev_handle); 296 /* Ignore improbable/unrecoverable error in 'dev_close' */ 297 298 return io_result; 299 } 300 301 /******************************************************************************* 302 * Generic function to load and authenticate an image. The image is actually 303 * loaded by calling the 'load_image()' function. In addition, this function 304 * uses recursion to authenticate the parent images up to the root of trust. 305 ******************************************************************************/ 306 int load_auth_image(meminfo_t *mem_layout, 307 unsigned int image_id, 308 uintptr_t image_base, 309 image_info_t *image_data, 310 entry_point_info_t *entry_point_info) 311 { 312 int rc; 313 314 #if TRUSTED_BOARD_BOOT 315 unsigned int parent_id; 316 317 /* Use recursion to authenticate parent images */ 318 rc = auth_mod_get_parent_id(image_id, &parent_id); 319 if (rc == 0) { 320 rc = load_auth_image(mem_layout, parent_id, image_base, 321 image_data, NULL); 322 if (rc != 0) { 323 return rc; 324 } 325 } 326 #endif /* TRUSTED_BOARD_BOOT */ 327 328 /* Load the image */ 329 rc = load_image(mem_layout, image_id, image_base, image_data, 330 entry_point_info); 331 if (rc != 0) { 332 return rc; 333 } 334 335 #if TRUSTED_BOARD_BOOT 336 /* Authenticate it */ 337 rc = auth_mod_verify_img(image_id, 338 (void *)image_data->image_base, 339 image_data->image_size); 340 if (rc != 0) { 341 memset((void *)image_data->image_base, 0x00, 342 image_data->image_size); 343 flush_dcache_range(image_data->image_base, 344 image_data->image_size); 345 return -EAUTH; 346 } 347 348 /* After working with data, invalidate the data cache */ 349 inv_dcache_range(image_data->image_base, 350 (size_t)image_data->image_size); 351 #endif /* TRUSTED_BOARD_BOOT */ 352 353 return 0; 354 } 355