blob: acb2ec627400819a3f965e1e523c46b3a4964035 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Soby Mathewa0fedc42016-06-16 14:52:04 +01002 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
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
Dan Handley2bd4ef22014-04-09 13:14:54 +010031#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <arch_helpers.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010033#include <assert.h>
Juan Castilloa08a5e72015-05-19 11:54:12 +010034#include <auth_mod.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010035#include <bl_common.h>
Dan Handley714a0d22014-04-09 13:13:04 +010036#include <debug.h>
Sandrine Bailleux467d0572014-06-24 14:02:34 +010037#include <errno.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010038#include <io_storage.h>
39#include <platform.h>
Juan Castillo97dbcf12015-08-17 10:43:27 +010040#include <string.h>
Soby Mathew44170c42016-03-22 15:51:08 +000041#include <xlat_tables.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010042
Soby Mathewa0fedc42016-06-16 14:52:04 +010043uintptr_t page_align(uintptr_t value, unsigned dir)
Achin Gupta4f6ad662013-10-25 09:08:21 +010044{
Achin Gupta4f6ad662013-10-25 09:08:21 +010045 /* Round up the limit to the next page boundary */
Soby Mathewa0fedc42016-06-16 14:52:04 +010046 if (value & (PAGE_SIZE - 1)) {
47 value &= ~(PAGE_SIZE - 1);
Achin Gupta4f6ad662013-10-25 09:08:21 +010048 if (dir == UP)
Soby Mathewa0fedc42016-06-16 14:52:04 +010049 value += PAGE_SIZE;
Achin Gupta4f6ad662013-10-25 09:08:21 +010050 }
51
52 return value;
53}
54
Soby Mathewa0fedc42016-06-16 14:52:04 +010055static inline unsigned int is_page_aligned (uintptr_t addr) {
56 return (addr & (PAGE_SIZE - 1)) == 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +010057}
58
Sandrine Bailleux467d0572014-06-24 14:02:34 +010059/******************************************************************************
60 * Determine whether the memory region delimited by 'addr' and 'size' is free,
61 * given the extents of free memory.
62 * Return 1 if it is free, 0 otherwise.
63 *****************************************************************************/
Soby Mathewa0fedc42016-06-16 14:52:04 +010064static int is_mem_free(uintptr_t free_base, size_t free_size,
65 uintptr_t addr, size_t size)
Sandrine Bailleux467d0572014-06-24 14:02:34 +010066{
67 return (addr >= free_base) && (addr + size <= free_base + free_size);
68}
Achin Gupta4f6ad662013-10-25 09:08:21 +010069
Sandrine Bailleux467d0572014-06-24 14:02:34 +010070/******************************************************************************
71 * Inside a given memory region, determine whether a sub-region of memory is
72 * closer from the top or the bottom of the encompassing region. Return the
73 * size of the smallest chunk of free memory surrounding the sub-region in
74 * 'small_chunk_size'.
75 *****************************************************************************/
Soby Mathewa0fedc42016-06-16 14:52:04 +010076static unsigned int choose_mem_pos(uintptr_t mem_start, uintptr_t mem_end,
77 uintptr_t submem_start, uintptr_t submem_end,
78 size_t *small_chunk_size)
Achin Gupta4f6ad662013-10-25 09:08:21 +010079{
Sandrine Bailleux467d0572014-06-24 14:02:34 +010080 size_t top_chunk_size, bottom_chunk_size;
81
82 assert(mem_start <= submem_start);
83 assert(submem_start <= submem_end);
84 assert(submem_end <= mem_end);
85 assert(small_chunk_size != NULL);
Achin Gupta4f6ad662013-10-25 09:08:21 +010086
Sandrine Bailleux467d0572014-06-24 14:02:34 +010087 top_chunk_size = mem_end - submem_end;
88 bottom_chunk_size = submem_start - mem_start;
Achin Gupta4f6ad662013-10-25 09:08:21 +010089
Sandrine Bailleux467d0572014-06-24 14:02:34 +010090 if (top_chunk_size < bottom_chunk_size) {
91 *small_chunk_size = top_chunk_size;
92 return TOP;
Achin Gupta4f6ad662013-10-25 09:08:21 +010093 } else {
Sandrine Bailleux467d0572014-06-24 14:02:34 +010094 *small_chunk_size = bottom_chunk_size;
95 return BOTTOM;
Achin Gupta4f6ad662013-10-25 09:08:21 +010096 }
Sandrine Bailleux467d0572014-06-24 14:02:34 +010097}
98
99/******************************************************************************
100 * Reserve the memory region delimited by 'addr' and 'size'. The extents of free
101 * memory are passed in 'free_base' and 'free_size' and they will be updated to
102 * reflect the memory usage.
103 * The caller must ensure the memory to reserve is free.
104 *****************************************************************************/
Soby Mathewa0fedc42016-06-16 14:52:04 +0100105void reserve_mem(uintptr_t *free_base, size_t *free_size,
106 uintptr_t addr, size_t size)
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100107{
108 size_t discard_size;
109 size_t reserved_size;
110 unsigned int pos;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100111
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100112 assert(free_base != NULL);
113 assert(free_size != NULL);
114 assert(is_mem_free(*free_base, *free_size, addr, size));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100115
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100116 pos = choose_mem_pos(*free_base, *free_base + *free_size,
117 addr, addr + size,
118 &discard_size);
119
120 reserved_size = size + discard_size;
121 *free_size -= reserved_size;
122
123 if (pos == BOTTOM)
124 *free_base = addr + size;
125
Soby Mathewa0fedc42016-06-16 14:52:04 +0100126 VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n",
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100127 reserved_size, discard_size,
128 pos == TOP ? "above" : "below");
Achin Gupta4f6ad662013-10-25 09:08:21 +0100129}
130
Soby Mathewa0fedc42016-06-16 14:52:04 +0100131static void dump_load_info(uintptr_t image_load_addr,
132 size_t image_size,
Dan Handleye2712bc2014-04-10 15:37:22 +0100133 const meminfo_t *mem_layout)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100134{
Soby Mathewa0fedc42016-06-16 14:52:04 +0100135 INFO("Trying to load image at address %p, size = 0x%zx\n",
136 (void *)image_load_addr, image_size);
Dan Handley91b624e2014-07-29 17:14:00 +0100137 INFO("Current memory layout:\n");
Soby Mathewa0fedc42016-06-16 14:52:04 +0100138 INFO(" total region = [%p, %p]\n", (void *)mem_layout->total_base,
139 (void *)(mem_layout->total_base + mem_layout->total_size));
140 INFO(" free region = [%p, %p]\n", (void *)mem_layout->free_base,
141 (void *)(mem_layout->free_base + mem_layout->free_size));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100142}
143
Ryan Harkin87274c42014-02-04 11:43:57 +0000144/* Generic function to return the size of an image */
Soby Mathewa0fedc42016-06-16 14:52:04 +0100145size_t image_size(unsigned int image_id)
Ryan Harkin87274c42014-02-04 11:43:57 +0000146{
Dan Handleya4cb68e2014-04-23 13:47:06 +0100147 uintptr_t dev_handle;
148 uintptr_t image_handle;
149 uintptr_t image_spec;
Ryan Harkin87274c42014-02-04 11:43:57 +0000150 size_t image_size = 0;
Juan Castillo6e762062015-11-02 10:47:01 +0000151 int io_result;
Ryan Harkin87274c42014-02-04 11:43:57 +0000152
Ryan Harkin87274c42014-02-04 11:43:57 +0000153 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100154 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
Juan Castillo6e762062015-11-02 10:47:01 +0000155 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100156 WARN("Failed to obtain reference to image id=%u (%i)\n",
157 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000158 return 0;
159 }
160
161 /* Attempt to access the image */
162 io_result = io_open(dev_handle, image_spec, &image_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000163 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100164 WARN("Failed to access image id=%u (%i)\n",
165 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000166 return 0;
167 }
168
169 /* Find the size of the image */
170 io_result = io_size(image_handle, &image_size);
Juan Castillo6e762062015-11-02 10:47:01 +0000171 if ((io_result != 0) || (image_size == 0)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100172 WARN("Failed to determine the size of the image id=%u (%i)\n",
173 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000174 }
175 io_result = io_close(image_handle);
176 /* Ignore improbable/unrecoverable error in 'close' */
177
178 /* TODO: Consider maintaining open device connection from this
179 * bootloader stage
180 */
181 io_result = io_dev_close(dev_handle);
182 /* Ignore improbable/unrecoverable error in 'dev_close' */
183
184 return image_size;
185}
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100186
Achin Gupta4f6ad662013-10-25 09:08:21 +0100187/*******************************************************************************
Sandrine Bailleux8eaf46e2016-05-27 14:08:10 +0100188 * Generic function to load an image at a specific address given an image ID and
189 * extents of free memory.
190 *
191 * If the load is successful then the image information is updated.
192 *
193 * If the entry_point_info argument is not NULL then this function also updates:
194 * - the memory layout to mark the memory as reserved;
195 * - the entry point information.
196 *
197 * The caller might pass a NULL pointer for the entry point if they are not
198 * interested in this information. This is typically the case for non-executable
199 * images (e.g. certificates) and executable images that won't ever be executed
200 * on the application processor (e.g. additional microcontroller firmware).
201 *
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100202 * Returns 0 on success, a negative error code otherwise.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100203 ******************************************************************************/
Vikram Kanigirida567432014-04-15 18:08:08 +0100204int load_image(meminfo_t *mem_layout,
Juan Castillo3a66aca2015-04-13 17:36:19 +0100205 unsigned int image_id,
Juan Castilloa08a5e72015-05-19 11:54:12 +0100206 uintptr_t image_base,
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100207 image_info_t *image_data,
208 entry_point_info_t *entry_point_info)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100209{
Dan Handleya4cb68e2014-04-23 13:47:06 +0100210 uintptr_t dev_handle;
211 uintptr_t image_handle;
212 uintptr_t image_spec;
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100213 size_t image_size;
214 size_t bytes_read;
Juan Castilloec813f52015-10-01 18:37:40 +0100215 int io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100216
James Morrissey9d72b4e2014-02-10 17:04:32 +0000217 assert(mem_layout != NULL);
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100218 assert(image_data != NULL);
Vikram Kanigirida567432014-04-15 18:08:08 +0100219 assert(image_data->h.version >= VERSION_1);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000220
221 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100222 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
Juan Castilloec813f52015-10-01 18:37:40 +0100223 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100224 WARN("Failed to obtain reference to image id=%u (%i)\n",
225 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100226 return io_result;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000227 }
228
229 /* Attempt to access the image */
230 io_result = io_open(dev_handle, image_spec, &image_handle);
Juan Castilloec813f52015-10-01 18:37:40 +0100231 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100232 WARN("Failed to access image id=%u (%i)\n",
233 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100234 return io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100235 }
236
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000237 INFO("Loading image id=%u at address %p\n", image_id,
238 (void *) image_base);
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100239
James Morrissey9d72b4e2014-02-10 17:04:32 +0000240 /* Find the size of the image */
241 io_result = io_size(image_handle, &image_size);
Juan Castilloec813f52015-10-01 18:37:40 +0100242 if ((io_result != 0) || (image_size == 0)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100243 WARN("Failed to determine the size of the image id=%u (%i)\n",
244 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100245 goto exit;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000246 }
247
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100248 /* Check that the memory where the image will be loaded is free */
249 if (!is_mem_free(mem_layout->free_base, mem_layout->free_size,
250 image_base, image_size)) {
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000251 WARN("Failed to reserve memory: %p - %p\n", (void *) image_base,
252 (void *) (image_base + image_size));
Vikram Kanigirida567432014-04-15 18:08:08 +0100253 dump_load_info(image_base, image_size, mem_layout);
254 io_result = -ENOMEM;
255 goto exit;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100256 }
257
258 /* We have enough space so load the image now */
James Morrissey9d72b4e2014-02-10 17:04:32 +0000259 /* TODO: Consider whether to try to recover/retry a partially successful read */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100260 io_result = io_read(image_handle, image_base, image_size, &bytes_read);
Juan Castilloec813f52015-10-01 18:37:40 +0100261 if ((io_result != 0) || (bytes_read < image_size)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100262 WARN("Failed to load image id=%u (%i)\n", image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100263 goto exit;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100264 }
265
Sandrine Bailleux8eaf46e2016-05-27 14:08:10 +0100266 image_data->image_base = image_base;
267 image_data->image_size = image_size;
268
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100269 /*
270 * Update the memory usage info.
271 * This is done after the actual loading so that it is not updated when
272 * the load is unsuccessful.
Juan Castillo09a55a82015-01-19 16:51:21 +0000273 * If the caller does not provide an entry point, bypass the memory
274 * reservation.
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100275 */
Juan Castillo09a55a82015-01-19 16:51:21 +0000276 if (entry_point_info != NULL) {
277 reserve_mem(&mem_layout->free_base, &mem_layout->free_size,
278 image_base, image_size);
Sandrine Bailleux8eaf46e2016-05-27 14:08:10 +0100279 entry_point_info->pc = image_base;
Juan Castillo09a55a82015-01-19 16:51:21 +0000280 } else {
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000281 INFO("Skip reserving memory: %p - %p\n", (void *) image_base,
282 (void *) (image_base + image_size));
Juan Castillo09a55a82015-01-19 16:51:21 +0000283 }
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100284
Achin Gupta4f6ad662013-10-25 09:08:21 +0100285 /*
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100286 * File has been successfully loaded.
Sandrine Bailleux8eaf46e2016-05-27 14:08:10 +0100287 * Flush the image in Trusted SRAM so that the next exception level can
288 * see it.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100289 */
James Morrissey9d72b4e2014-02-10 17:04:32 +0000290 flush_dcache_range(image_base, image_size);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100291
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000292 INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base,
293 (void *) (image_base + image_size));
James Morrissey9d72b4e2014-02-10 17:04:32 +0000294
295exit:
Vikram Kanigirida567432014-04-15 18:08:08 +0100296 io_close(image_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000297 /* Ignore improbable/unrecoverable error in 'close' */
298
299 /* TODO: Consider maintaining open device connection from this bootloader stage */
Vikram Kanigirida567432014-04-15 18:08:08 +0100300 io_dev_close(dev_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000301 /* Ignore improbable/unrecoverable error in 'dev_close' */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100302
Vikram Kanigirida567432014-04-15 18:08:08 +0100303 return io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100304}
Juan Castilloa08a5e72015-05-19 11:54:12 +0100305
306/*******************************************************************************
307 * Generic function to load and authenticate an image. The image is actually
308 * loaded by calling the 'load_image()' function. In addition, this function
309 * uses recursion to authenticate the parent images up to the root of trust.
310 ******************************************************************************/
311int load_auth_image(meminfo_t *mem_layout,
312 unsigned int image_id,
313 uintptr_t image_base,
314 image_info_t *image_data,
315 entry_point_info_t *entry_point_info)
316{
317 int rc;
318
319#if TRUSTED_BOARD_BOOT
320 unsigned int parent_id;
321
322 /* Use recursion to authenticate parent images */
323 rc = auth_mod_get_parent_id(image_id, &parent_id);
324 if (rc == 0) {
325 rc = load_auth_image(mem_layout, parent_id, image_base,
326 image_data, NULL);
Juan Castilloec813f52015-10-01 18:37:40 +0100327 if (rc != 0) {
Juan Castilloa08a5e72015-05-19 11:54:12 +0100328 return rc;
329 }
330 }
331#endif /* TRUSTED_BOARD_BOOT */
332
333 /* Load the image */
334 rc = load_image(mem_layout, image_id, image_base, image_data,
335 entry_point_info);
Juan Castilloec813f52015-10-01 18:37:40 +0100336 if (rc != 0) {
337 return rc;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100338 }
339
340#if TRUSTED_BOARD_BOOT
341 /* Authenticate it */
342 rc = auth_mod_verify_img(image_id,
343 (void *)image_data->image_base,
344 image_data->image_size);
345 if (rc != 0) {
Juan Castillo97dbcf12015-08-17 10:43:27 +0100346 memset((void *)image_data->image_base, 0x00,
347 image_data->image_size);
348 flush_dcache_range(image_data->image_base,
349 image_data->image_size);
Juan Castilloec813f52015-10-01 18:37:40 +0100350 return -EAUTH;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100351 }
352
353 /* After working with data, invalidate the data cache */
354 inv_dcache_range(image_data->image_base,
355 (size_t)image_data->image_size);
356#endif /* TRUSTED_BOARD_BOOT */
357
Juan Castilloec813f52015-10-01 18:37:40 +0100358 return 0;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100359}
Sandrine Bailleuxb2e224c2015-09-28 17:03:06 +0100360
361/*******************************************************************************
362 * Print the content of an entry_point_info_t structure.
363 ******************************************************************************/
364void print_entry_point_info(const entry_point_info_t *ep_info)
365{
Soby Mathewa0fedc42016-06-16 14:52:04 +0100366 INFO("Entry point address = %p\n", (void *)ep_info->pc);
367 INFO("SPSR = 0x%x\n", ep_info->spsr);
Sandrine Bailleuxb2e224c2015-09-28 17:03:06 +0100368
369#define PRINT_IMAGE_ARG(n) \
370 VERBOSE("Argument #" #n " = 0x%llx\n", \
371 (unsigned long long) ep_info->args.arg##n)
372
373 PRINT_IMAGE_ARG(0);
374 PRINT_IMAGE_ARG(1);
375 PRINT_IMAGE_ARG(2);
376 PRINT_IMAGE_ARG(3);
377 PRINT_IMAGE_ARG(4);
378 PRINT_IMAGE_ARG(5);
379 PRINT_IMAGE_ARG(6);
380 PRINT_IMAGE_ARG(7);
381#undef PRINT_IMAGE_ARG
382}