blob: 91a0ae8c43f31414112badb533af5bf94cf96d3d [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handleyeb839ce2015-03-23 18:13:33 +00002 * Copyright (c) 2013-2015, 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>
Achin Gupta4f6ad662013-10-25 09:08:21 +010041
Achin Gupta4f6ad662013-10-25 09:08:21 +010042unsigned 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
56static 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
Sandrine Bailleux467d0572014-06-24 14:02:34 +010062/******************************************************************************
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 *****************************************************************************/
67static 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}
Achin Gupta4f6ad662013-10-25 09:08:21 +010072
Sandrine Bailleux467d0572014-06-24 14:02:34 +010073/******************************************************************************
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 *****************************************************************************/
79static 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)
Achin Gupta4f6ad662013-10-25 09:08:21 +010082{
Sandrine Bailleux467d0572014-06-24 14:02:34 +010083 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);
Achin Gupta4f6ad662013-10-25 09:08:21 +010089
Sandrine Bailleux467d0572014-06-24 14:02:34 +010090 top_chunk_size = mem_end - submem_end;
91 bottom_chunk_size = submem_start - mem_start;
Achin Gupta4f6ad662013-10-25 09:08:21 +010092
Sandrine Bailleux467d0572014-06-24 14:02:34 +010093 if (top_chunk_size < bottom_chunk_size) {
94 *small_chunk_size = top_chunk_size;
95 return TOP;
Achin Gupta4f6ad662013-10-25 09:08:21 +010096 } else {
Sandrine Bailleux467d0572014-06-24 14:02:34 +010097 *small_chunk_size = bottom_chunk_size;
98 return BOTTOM;
Achin Gupta4f6ad662013-10-25 09:08:21 +010099 }
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100100}
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 *****************************************************************************/
108void 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;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100114
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100115 assert(free_base != NULL);
116 assert(free_size != NULL);
117 assert(is_mem_free(*free_base, *free_size, addr, size));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100118
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100119 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
Dan Handleyeb839ce2015-03-23 18:13:33 +0000129 VERBOSE("Reserved 0x%lx bytes (discarded 0x%lx bytes %s)\n",
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100130 reserved_size, discard_size,
131 pos == TOP ? "above" : "below");
Achin Gupta4f6ad662013-10-25 09:08:21 +0100132}
133
134static void dump_load_info(unsigned long image_load_addr,
135 unsigned long image_size,
Dan Handleye2712bc2014-04-10 15:37:22 +0100136 const meminfo_t *mem_layout)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100137{
Dan Handley91b624e2014-07-29 17:14:00 +0100138 INFO("Trying to load image at address 0x%lx, size = 0x%lx\n",
Achin Gupta4f6ad662013-10-25 09:08:21 +0100139 image_load_addr, image_size);
Dan Handley91b624e2014-07-29 17:14:00 +0100140 INFO("Current memory layout:\n");
141 INFO(" total region = [0x%lx, 0x%lx]\n", mem_layout->total_base,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100142 mem_layout->total_base + mem_layout->total_size);
Dan Handley91b624e2014-07-29 17:14:00 +0100143 INFO(" free region = [0x%lx, 0x%lx]\n", mem_layout->free_base,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100144 mem_layout->free_base + mem_layout->free_size);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100145}
146
Ryan Harkin87274c42014-02-04 11:43:57 +0000147/* Generic function to return the size of an image */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100148unsigned long image_size(unsigned int image_id)
Ryan Harkin87274c42014-02-04 11:43:57 +0000149{
Dan Handleya4cb68e2014-04-23 13:47:06 +0100150 uintptr_t dev_handle;
151 uintptr_t image_handle;
152 uintptr_t image_spec;
Ryan Harkin87274c42014-02-04 11:43:57 +0000153 size_t image_size = 0;
154 int io_result = IO_FAIL;
155
Ryan Harkin87274c42014-02-04 11:43:57 +0000156 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100157 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
Ryan Harkin87274c42014-02-04 11:43:57 +0000158 if (io_result != IO_SUCCESS) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100159 WARN("Failed to obtain reference to image id=%u (%i)\n",
160 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000161 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 != IO_SUCCESS) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100167 WARN("Failed to access image id=%u (%i)\n",
168 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000169 return 0;
170 }
171
172 /* Find the size of the image */
173 io_result = io_size(image_handle, &image_size);
174 if ((io_result != IO_SUCCESS) || (image_size == 0)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100175 WARN("Failed to determine the size of the image id=%u (%i)\n",
176 image_id, io_result);
Ryan Harkin87274c42014-02-04 11:43:57 +0000177 }
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}
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100189
Achin Gupta4f6ad662013-10-25 09:08:21 +0100190/*******************************************************************************
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100191 * 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.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100198 ******************************************************************************/
Vikram Kanigirida567432014-04-15 18:08:08 +0100199int load_image(meminfo_t *mem_layout,
Juan Castillo3a66aca2015-04-13 17:36:19 +0100200 unsigned int image_id,
Juan Castilloa08a5e72015-05-19 11:54:12 +0100201 uintptr_t image_base,
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100202 image_info_t *image_data,
203 entry_point_info_t *entry_point_info)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100204{
Dan Handleya4cb68e2014-04-23 13:47:06 +0100205 uintptr_t dev_handle;
206 uintptr_t image_handle;
207 uintptr_t image_spec;
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100208 size_t image_size;
209 size_t bytes_read;
Juan Castilloec813f52015-10-01 18:37:40 +0100210 int io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100211
James Morrissey9d72b4e2014-02-10 17:04:32 +0000212 assert(mem_layout != NULL);
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100213 assert(image_data != NULL);
Vikram Kanigirida567432014-04-15 18:08:08 +0100214 assert(image_data->h.version >= VERSION_1);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000215
216 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100217 io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
Juan Castilloec813f52015-10-01 18:37:40 +0100218 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100219 WARN("Failed to obtain reference to image id=%u (%i)\n",
220 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100221 return io_result;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000222 }
223
224 /* Attempt to access the image */
225 io_result = io_open(dev_handle, image_spec, &image_handle);
Juan Castilloec813f52015-10-01 18:37:40 +0100226 if (io_result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100227 WARN("Failed to access image id=%u (%i)\n",
228 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100229 return io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100230 }
231
Juan Castillo3a66aca2015-04-13 17:36:19 +0100232 INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base);
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100233
James Morrissey9d72b4e2014-02-10 17:04:32 +0000234 /* Find the size of the image */
235 io_result = io_size(image_handle, &image_size);
Juan Castilloec813f52015-10-01 18:37:40 +0100236 if ((io_result != 0) || (image_size == 0)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100237 WARN("Failed to determine the size of the image id=%u (%i)\n",
238 image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100239 goto exit;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000240 }
241
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100242 /* 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);
Vikram Kanigirida567432014-04-15 18:08:08 +0100247 dump_load_info(image_base, image_size, mem_layout);
248 io_result = -ENOMEM;
249 goto exit;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100250 }
251
252 /* We have enough space so load the image now */
James Morrissey9d72b4e2014-02-10 17:04:32 +0000253 /* TODO: Consider whether to try to recover/retry a partially successful read */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100254 io_result = io_read(image_handle, image_base, image_size, &bytes_read);
Juan Castilloec813f52015-10-01 18:37:40 +0100255 if ((io_result != 0) || (bytes_read < image_size)) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100256 WARN("Failed to load image id=%u (%i)\n", image_id, io_result);
Vikram Kanigirida567432014-04-15 18:08:08 +0100257 goto exit;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100258 }
259
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100260 /*
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.
Juan Castillo09a55a82015-01-19 16:51:21 +0000264 * If the caller does not provide an entry point, bypass the memory
265 * reservation.
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100266 */
Juan Castillo09a55a82015-01-19 16:51:21 +0000267 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 }
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100274
Vikram Kanigirida567432014-04-15 18:08:08 +0100275 image_data->image_base = image_base;
276 image_data->image_size = image_size;
277
Sandrine Bailleux3ab33f32014-05-28 11:31:18 +0100278 if (entry_point_info != NULL)
279 entry_point_info->pc = image_base;
Vikram Kanigirida567432014-04-15 18:08:08 +0100280
Achin Gupta4f6ad662013-10-25 09:08:21 +0100281 /*
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100282 * File has been successfully loaded.
283 * Flush the image in TZRAM so that the next EL can see it.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100284 */
James Morrissey9d72b4e2014-02-10 17:04:32 +0000285 flush_dcache_range(image_base, image_size);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100286
Juan Castillo3a66aca2015-04-13 17:36:19 +0100287 INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base,
Sandrine Bailleux467d0572014-06-24 14:02:34 +0100288 image_base + image_size);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000289
290exit:
Vikram Kanigirida567432014-04-15 18:08:08 +0100291 io_close(image_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000292 /* Ignore improbable/unrecoverable error in 'close' */
293
294 /* TODO: Consider maintaining open device connection from this bootloader stage */
Vikram Kanigirida567432014-04-15 18:08:08 +0100295 io_dev_close(dev_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000296 /* Ignore improbable/unrecoverable error in 'dev_close' */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100297
Vikram Kanigirida567432014-04-15 18:08:08 +0100298 return io_result;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100299}
Juan Castilloa08a5e72015-05-19 11:54:12 +0100300
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 ******************************************************************************/
306int 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);
Juan Castilloec813f52015-10-01 18:37:40 +0100322 if (rc != 0) {
Juan Castilloa08a5e72015-05-19 11:54:12 +0100323 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);
Juan Castilloec813f52015-10-01 18:37:40 +0100331 if (rc != 0) {
332 return rc;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100333 }
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) {
Juan Castillo97dbcf12015-08-17 10:43:27 +0100341 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);
Juan Castilloec813f52015-10-01 18:37:40 +0100345 return -EAUTH;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100346 }
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
Juan Castilloec813f52015-10-01 18:37:40 +0100353 return 0;
Juan Castilloa08a5e72015-05-19 11:54:12 +0100354}