1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park
9*54fd6939SJiyong Park #include <common/debug.h>
10*54fd6939SJiyong Park #include <lib/optee_utils.h>
11*54fd6939SJiyong Park
12*54fd6939SJiyong Park /*
13*54fd6939SJiyong Park * load_addr_hi and load_addr_lo: image load address.
14*54fd6939SJiyong Park * image_id: 0 - pager, 1 - paged
15*54fd6939SJiyong Park * size: image size in bytes.
16*54fd6939SJiyong Park */
17*54fd6939SJiyong Park typedef struct optee_image {
18*54fd6939SJiyong Park uint32_t load_addr_hi;
19*54fd6939SJiyong Park uint32_t load_addr_lo;
20*54fd6939SJiyong Park uint32_t image_id;
21*54fd6939SJiyong Park uint32_t size;
22*54fd6939SJiyong Park } optee_image_t;
23*54fd6939SJiyong Park
24*54fd6939SJiyong Park #define OPTEE_PAGER_IMAGE_ID 0
25*54fd6939SJiyong Park #define OPTEE_PAGED_IMAGE_ID 1
26*54fd6939SJiyong Park
27*54fd6939SJiyong Park #define OPTEE_MAX_NUM_IMAGES 2u
28*54fd6939SJiyong Park
29*54fd6939SJiyong Park #define TEE_MAGIC_NUM_OPTEE 0x4554504f
30*54fd6939SJiyong Park /*
31*54fd6939SJiyong Park * magic: header magic number.
32*54fd6939SJiyong Park * version: OPTEE header version:
33*54fd6939SJiyong Park * 1 - not supported
34*54fd6939SJiyong Park * 2 - supported
35*54fd6939SJiyong Park * arch: OPTEE os architecture type: 0 - AARCH32, 1 - AARCH64.
36*54fd6939SJiyong Park * flags: unused currently.
37*54fd6939SJiyong Park * nb_images: number of images.
38*54fd6939SJiyong Park */
39*54fd6939SJiyong Park typedef struct optee_header {
40*54fd6939SJiyong Park uint32_t magic;
41*54fd6939SJiyong Park uint8_t version;
42*54fd6939SJiyong Park uint8_t arch;
43*54fd6939SJiyong Park uint16_t flags;
44*54fd6939SJiyong Park uint32_t nb_images;
45*54fd6939SJiyong Park optee_image_t optee_image_list[];
46*54fd6939SJiyong Park } optee_header_t;
47*54fd6939SJiyong Park
48*54fd6939SJiyong Park /*******************************************************************************
49*54fd6939SJiyong Park * Check if it is a valid tee header
50*54fd6939SJiyong Park * Return true if valid
51*54fd6939SJiyong Park * Return false if invalid
52*54fd6939SJiyong Park ******************************************************************************/
tee_validate_header(optee_header_t * header)53*54fd6939SJiyong Park static bool tee_validate_header(optee_header_t *header)
54*54fd6939SJiyong Park {
55*54fd6939SJiyong Park if ((header->magic == TEE_MAGIC_NUM_OPTEE) &&
56*54fd6939SJiyong Park (header->version == 2u) &&
57*54fd6939SJiyong Park (header->nb_images > 0u) &&
58*54fd6939SJiyong Park (header->nb_images <= OPTEE_MAX_NUM_IMAGES)) {
59*54fd6939SJiyong Park return true;
60*54fd6939SJiyong Park }
61*54fd6939SJiyong Park
62*54fd6939SJiyong Park return false;
63*54fd6939SJiyong Park }
64*54fd6939SJiyong Park
optee_header_is_valid(uintptr_t header_base)65*54fd6939SJiyong Park bool optee_header_is_valid(uintptr_t header_base)
66*54fd6939SJiyong Park {
67*54fd6939SJiyong Park return tee_validate_header((optee_header_t *)header_base);
68*54fd6939SJiyong Park }
69*54fd6939SJiyong Park
70*54fd6939SJiyong Park /*******************************************************************************
71*54fd6939SJiyong Park * Parse the OPTEE image
72*54fd6939SJiyong Park * Return 0 on success or a negative error code otherwise.
73*54fd6939SJiyong Park ******************************************************************************/
parse_optee_image(image_info_t * image_info,optee_image_t * image)74*54fd6939SJiyong Park static int parse_optee_image(image_info_t *image_info,
75*54fd6939SJiyong Park optee_image_t *image)
76*54fd6939SJiyong Park {
77*54fd6939SJiyong Park uintptr_t init_load_addr, free_end, requested_end;
78*54fd6939SJiyong Park size_t init_size;
79*54fd6939SJiyong Park
80*54fd6939SJiyong Park init_load_addr = ((uint64_t)image->load_addr_hi << 32) |
81*54fd6939SJiyong Park image->load_addr_lo;
82*54fd6939SJiyong Park init_size = image->size;
83*54fd6939SJiyong Park
84*54fd6939SJiyong Park /*
85*54fd6939SJiyong Park * image->load_addr_hi & image->load_addr_lo set to UINT32_MAX indicate
86*54fd6939SJiyong Park * loader decided address; take our pre-mapped area for current image
87*54fd6939SJiyong Park * since arm-tf could not allocate memory dynamically
88*54fd6939SJiyong Park */
89*54fd6939SJiyong Park if ((image->load_addr_hi == UINT32_MAX) &&
90*54fd6939SJiyong Park (image->load_addr_lo == UINT32_MAX)) {
91*54fd6939SJiyong Park init_load_addr = image_info->image_base;
92*54fd6939SJiyong Park }
93*54fd6939SJiyong Park
94*54fd6939SJiyong Park /* Check that the default end address doesn't overflow */
95*54fd6939SJiyong Park if (check_uptr_overflow(image_info->image_base,
96*54fd6939SJiyong Park image_info->image_max_size - 1))
97*54fd6939SJiyong Park return -1;
98*54fd6939SJiyong Park free_end = image_info->image_base + (image_info->image_max_size - 1);
99*54fd6939SJiyong Park
100*54fd6939SJiyong Park /* Check that the image end address doesn't overflow */
101*54fd6939SJiyong Park if (check_uptr_overflow(init_load_addr, init_size - 1))
102*54fd6939SJiyong Park return -1;
103*54fd6939SJiyong Park requested_end = init_load_addr + (init_size - 1);
104*54fd6939SJiyong Park /*
105*54fd6939SJiyong Park * Check that the requested RAM location is within reserved
106*54fd6939SJiyong Park * space for OPTEE.
107*54fd6939SJiyong Park */
108*54fd6939SJiyong Park if (!((init_load_addr >= image_info->image_base) &&
109*54fd6939SJiyong Park (requested_end <= free_end))) {
110*54fd6939SJiyong Park WARN("The load address in optee header %p - %p is not in reserved area: %p - %p.\n",
111*54fd6939SJiyong Park (void *)init_load_addr,
112*54fd6939SJiyong Park (void *)(init_load_addr + init_size),
113*54fd6939SJiyong Park (void *)image_info->image_base,
114*54fd6939SJiyong Park (void *)(image_info->image_base +
115*54fd6939SJiyong Park image_info->image_max_size));
116*54fd6939SJiyong Park return -1;
117*54fd6939SJiyong Park }
118*54fd6939SJiyong Park
119*54fd6939SJiyong Park /*
120*54fd6939SJiyong Park * Remove the skip attr from image_info, the image will be loaded.
121*54fd6939SJiyong Park * The default attr in image_info is "IMAGE_ATTRIB_SKIP_LOADING", which
122*54fd6939SJiyong Park * mean the image will not be loaded. Here, we parse the header image to
123*54fd6939SJiyong Park * know that the extra image need to be loaded, so remove the skip attr.
124*54fd6939SJiyong Park */
125*54fd6939SJiyong Park image_info->h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
126*54fd6939SJiyong Park
127*54fd6939SJiyong Park /* Update image base and size of image_info */
128*54fd6939SJiyong Park image_info->image_base = init_load_addr;
129*54fd6939SJiyong Park image_info->image_size = init_size;
130*54fd6939SJiyong Park
131*54fd6939SJiyong Park return 0;
132*54fd6939SJiyong Park }
133*54fd6939SJiyong Park
134*54fd6939SJiyong Park /*******************************************************************************
135*54fd6939SJiyong Park * Parse the OPTEE header
136*54fd6939SJiyong Park * Return 0 on success or a negative error code otherwise.
137*54fd6939SJiyong Park ******************************************************************************/
parse_optee_header(entry_point_info_t * header_ep,image_info_t * pager_image_info,image_info_t * paged_image_info)138*54fd6939SJiyong Park int parse_optee_header(entry_point_info_t *header_ep,
139*54fd6939SJiyong Park image_info_t *pager_image_info,
140*54fd6939SJiyong Park image_info_t *paged_image_info)
141*54fd6939SJiyong Park
142*54fd6939SJiyong Park {
143*54fd6939SJiyong Park optee_header_t *header;
144*54fd6939SJiyong Park uint32_t num;
145*54fd6939SJiyong Park int ret;
146*54fd6939SJiyong Park
147*54fd6939SJiyong Park assert(header_ep);
148*54fd6939SJiyong Park header = (optee_header_t *)header_ep->pc;
149*54fd6939SJiyong Park assert(header);
150*54fd6939SJiyong Park
151*54fd6939SJiyong Park /* Print the OPTEE header information */
152*54fd6939SJiyong Park INFO("OPTEE ep=0x%x\n", (unsigned int)header_ep->pc);
153*54fd6939SJiyong Park INFO("OPTEE header info:\n");
154*54fd6939SJiyong Park INFO(" magic=0x%x\n", header->magic);
155*54fd6939SJiyong Park INFO(" version=0x%x\n", header->version);
156*54fd6939SJiyong Park INFO(" arch=0x%x\n", header->arch);
157*54fd6939SJiyong Park INFO(" flags=0x%x\n", header->flags);
158*54fd6939SJiyong Park INFO(" nb_images=0x%x\n", header->nb_images);
159*54fd6939SJiyong Park
160*54fd6939SJiyong Park /*
161*54fd6939SJiyong Park * OPTEE image has 3 types:
162*54fd6939SJiyong Park *
163*54fd6939SJiyong Park * 1. Plain OPTEE bin without header.
164*54fd6939SJiyong Park * Original bin without header, return directly,
165*54fd6939SJiyong Park * BL32_EXTRA1_IMAGE_ID and BL32_EXTRA2_IMAGE_ID will be skipped.
166*54fd6939SJiyong Park *
167*54fd6939SJiyong Park * 2. OPTEE bin with header bin, but no paging.
168*54fd6939SJiyong Park * Header available and nb_images = 1, remove skip attr for
169*54fd6939SJiyong Park * BL32_EXTRA1_IMAGE_ID. BL32_EXTRA1_IMAGE_ID will be loaded,
170*54fd6939SJiyong Park * and BL32_EXTRA2_IMAGE_ID be skipped.
171*54fd6939SJiyong Park *
172*54fd6939SJiyong Park * 3. OPTEE image with paging support.
173*54fd6939SJiyong Park * Header available and nb_images = 2, there are 3 bins: header,
174*54fd6939SJiyong Park * pager and pageable. Remove skip attr for BL32_EXTRA1_IMAGE_ID
175*54fd6939SJiyong Park * and BL32_EXTRA2_IMAGE_ID to load pager and paged bin.
176*54fd6939SJiyong Park */
177*54fd6939SJiyong Park if (!tee_validate_header(header)) {
178*54fd6939SJiyong Park INFO("Invalid OPTEE header, set legacy mode.\n");
179*54fd6939SJiyong Park #ifdef __aarch64__
180*54fd6939SJiyong Park header_ep->args.arg0 = MODE_RW_64;
181*54fd6939SJiyong Park #else
182*54fd6939SJiyong Park header_ep->args.arg0 = MODE_RW_32;
183*54fd6939SJiyong Park #endif
184*54fd6939SJiyong Park return 0;
185*54fd6939SJiyong Park }
186*54fd6939SJiyong Park
187*54fd6939SJiyong Park /* Parse OPTEE image */
188*54fd6939SJiyong Park for (num = 0U; num < header->nb_images; num++) {
189*54fd6939SJiyong Park if (header->optee_image_list[num].image_id ==
190*54fd6939SJiyong Park OPTEE_PAGER_IMAGE_ID) {
191*54fd6939SJiyong Park ret = parse_optee_image(pager_image_info,
192*54fd6939SJiyong Park &header->optee_image_list[num]);
193*54fd6939SJiyong Park } else if (header->optee_image_list[num].image_id ==
194*54fd6939SJiyong Park OPTEE_PAGED_IMAGE_ID) {
195*54fd6939SJiyong Park ret = parse_optee_image(paged_image_info,
196*54fd6939SJiyong Park &header->optee_image_list[num]);
197*54fd6939SJiyong Park } else {
198*54fd6939SJiyong Park ERROR("Parse optee image failed.\n");
199*54fd6939SJiyong Park return -1;
200*54fd6939SJiyong Park }
201*54fd6939SJiyong Park
202*54fd6939SJiyong Park if (ret != 0)
203*54fd6939SJiyong Park return -1;
204*54fd6939SJiyong Park }
205*54fd6939SJiyong Park
206*54fd6939SJiyong Park /*
207*54fd6939SJiyong Park * Update "pc" value which should comes from pager image. After the
208*54fd6939SJiyong Park * header image is parsed, it will be unuseful, and the actual
209*54fd6939SJiyong Park * execution image after BL31 is pager image.
210*54fd6939SJiyong Park */
211*54fd6939SJiyong Park header_ep->pc = pager_image_info->image_base;
212*54fd6939SJiyong Park
213*54fd6939SJiyong Park /*
214*54fd6939SJiyong Park * The paged load address and size are populated in
215*54fd6939SJiyong Park * header image arguments so that can be read by the
216*54fd6939SJiyong Park * BL32 SPD.
217*54fd6939SJiyong Park */
218*54fd6939SJiyong Park header_ep->args.arg1 = paged_image_info->image_base;
219*54fd6939SJiyong Park header_ep->args.arg2 = paged_image_info->image_size;
220*54fd6939SJiyong Park
221*54fd6939SJiyong Park /* Set OPTEE runtime arch - aarch32/aarch64 */
222*54fd6939SJiyong Park if (header->arch == 0) {
223*54fd6939SJiyong Park header_ep->args.arg0 = MODE_RW_32;
224*54fd6939SJiyong Park } else {
225*54fd6939SJiyong Park #ifdef __aarch64__
226*54fd6939SJiyong Park header_ep->args.arg0 = MODE_RW_64;
227*54fd6939SJiyong Park #else
228*54fd6939SJiyong Park ERROR("Cannot boot an AArch64 OP-TEE\n");
229*54fd6939SJiyong Park return -1;
230*54fd6939SJiyong Park #endif
231*54fd6939SJiyong Park }
232*54fd6939SJiyong Park
233*54fd6939SJiyong Park return 0;
234*54fd6939SJiyong Park }
235