xref: /optee_os/ta/remoteproc/src/remoteproc_core.c (revision 14a1a72ba445a12c4680c14379d1602c1acbc954)
1fcf382e2SArnaud Pouliquen // SPDX-License-Identifier: BSD-2-Clause
2fcf382e2SArnaud Pouliquen /*
3fcf382e2SArnaud Pouliquen  * Copyright (C) 2023, STMicroelectronics
4fcf382e2SArnaud Pouliquen  */
5fcf382e2SArnaud Pouliquen 
61a442a9fSArnaud Pouliquen #include <assert.h>
7fcf382e2SArnaud Pouliquen #include <elf_parser.h>
8fcf382e2SArnaud Pouliquen #include <remoteproc_pta.h>
9fcf382e2SArnaud Pouliquen #include <string.h>
10fcf382e2SArnaud Pouliquen #include <sys/queue.h>
11fcf382e2SArnaud Pouliquen #include <ta_remoteproc.h>
12fcf382e2SArnaud Pouliquen #include <tee_internal_api.h>
13fcf382e2SArnaud Pouliquen #include <tee_internal_api_extensions.h>
14fcf382e2SArnaud Pouliquen #include <types_ext.h>
15fcf382e2SArnaud Pouliquen #include <utee_defines.h>
16fcf382e2SArnaud Pouliquen 
17fcf382e2SArnaud Pouliquen /*
18fcf382e2SArnaud Pouliquen  * The remoteproc Trusted Application is in charge of authenticating and loading
19fcf382e2SArnaud Pouliquen  * images signed by the scripts/sign_rproc_fw.py. The TA is also in charge of
20fcf382e2SArnaud Pouliquen  * starting and stopping the remote processor.
21fcf382e2SArnaud Pouliquen  * The structure of the signed image is:
22fcf382e2SArnaud Pouliquen  *
23fcf382e2SArnaud Pouliquen  *                   -----+-------------+
24fcf382e2SArnaud Pouliquen  *                  /     |    Magic    |  32-bit word, magic value equal to
25fcf382e2SArnaud Pouliquen  *                 /      +-------------+  0x3543A468
26fcf382e2SArnaud Pouliquen  *                /       +-------------+
27fcf382e2SArnaud Pouliquen  *               /        |   version   |  32-bit word, version of the format
28fcf382e2SArnaud Pouliquen  *              /         +-------------+
29fcf382e2SArnaud Pouliquen  * +-----------+          +-------------+
30fcf382e2SArnaud Pouliquen  * |   Header  |          |  TLV size   |  32-bit word, size of the TLV
31fcf382e2SArnaud Pouliquen  * +-----------+          +-------------+  (aligned on 64-bit), in bytes.
32fcf382e2SArnaud Pouliquen  *              \         +-------------+
33fcf382e2SArnaud Pouliquen  *               \        |  sign size  |  32-bit word, size of the signature
34fcf382e2SArnaud Pouliquen  *                \       +-------------+  (aligned on 64-bit), in bytes.
35fcf382e2SArnaud Pouliquen  *                 \      +-------------+
36fcf382e2SArnaud Pouliquen  *                  \     | images size |  32-bit word, size of the images to
37fcf382e2SArnaud Pouliquen  *                   -----+-------------+  load (aligned on 64-bit), in bytes.
38fcf382e2SArnaud Pouliquen  *
39fcf382e2SArnaud Pouliquen  *                        +-------------+  Information used to authenticate the
40fcf382e2SArnaud Pouliquen  *                        |     TLV     |  images and boot the remote processor,
41fcf382e2SArnaud Pouliquen  *                        |             |  stored in Type-Length-Value format.
42fcf382e2SArnaud Pouliquen  *                        +-------------+  'Type' and 'Length' are 32-bit words.
43fcf382e2SArnaud Pouliquen  *
44fcf382e2SArnaud Pouliquen  *                        +-------------+
45fcf382e2SArnaud Pouliquen  *                        | Signature   |   Signature of the header and the TLV.
46fcf382e2SArnaud Pouliquen  *                        +-------------+
47fcf382e2SArnaud Pouliquen  *
48fcf382e2SArnaud Pouliquen  *                        +-------------+
49fcf382e2SArnaud Pouliquen  *                        |   Firmware  |
50fcf382e2SArnaud Pouliquen  *                        |    image 1  |
51fcf382e2SArnaud Pouliquen  *                        +-------------+
52fcf382e2SArnaud Pouliquen  *                               ...
53fcf382e2SArnaud Pouliquen  *                        +-------------+
54fcf382e2SArnaud Pouliquen  *                        |   Firmware  |
55fcf382e2SArnaud Pouliquen  *                        |    image n  |
56fcf382e2SArnaud Pouliquen  *                        +-------------+
57fcf382e2SArnaud Pouliquen  */
58fcf382e2SArnaud Pouliquen 
59fcf382e2SArnaud Pouliquen /* Firmware state */
60fcf382e2SArnaud Pouliquen enum remoteproc_state {
61fcf382e2SArnaud Pouliquen 	REMOTEPROC_OFF = 0,
62fcf382e2SArnaud Pouliquen 	REMOTEPROC_LOADED,
63fcf382e2SArnaud Pouliquen 	REMOTEPROC_STARTED,
64fcf382e2SArnaud Pouliquen };
65fcf382e2SArnaud Pouliquen 
66fcf382e2SArnaud Pouliquen #define RPROC_HDR_MAGIC		0x3543A468
67fcf382e2SArnaud Pouliquen #define HEADER_VERSION		1
68fcf382e2SArnaud Pouliquen 
69fcf382e2SArnaud Pouliquen /* Supported signature algorithm */
70fcf382e2SArnaud Pouliquen enum remoteproc_sign_type {
71fcf382e2SArnaud Pouliquen 	RPROC_RSASSA_PKCS1_v1_5_SHA256 = 1,
72fcf382e2SArnaud Pouliquen 	RPROC_ECDSA_SHA256 = 2,
73fcf382e2SArnaud Pouliquen };
74fcf382e2SArnaud Pouliquen 
75fcf382e2SArnaud Pouliquen enum remoteproc_img_type {
76fcf382e2SArnaud Pouliquen 	REMOTEPROC_ELF_TYPE = 1,
77fcf382e2SArnaud Pouliquen 	REMOTEPROC_INVALID_TYPE = 0xFF
78fcf382e2SArnaud Pouliquen };
79fcf382e2SArnaud Pouliquen 
80fcf382e2SArnaud Pouliquen /* remoteproc_tlv structure offsets */
81fcf382e2SArnaud Pouliquen #define RPROC_TLV_LENGTH_OF	U(0x04)
82fcf382e2SArnaud Pouliquen #define RPROC_TLV_VALUE_OF	U(0x08)
83fcf382e2SArnaud Pouliquen 
84fcf382e2SArnaud Pouliquen /* TLV types */
85fcf382e2SArnaud Pouliquen #define RPROC_TLV_SIGNTYPE	U(0x00000001)
86fcf382e2SArnaud Pouliquen #define RPROC_TLV_HASHTYPE	U(0x00000002)
87fcf382e2SArnaud Pouliquen #define RPROC_TLV_NUM_IMG	U(0x00000003)
88fcf382e2SArnaud Pouliquen #define RPROC_TLV_IMGTYPE	U(0x00000004)
89fcf382e2SArnaud Pouliquen #define RPROC_TLV_IMGSIZE	U(0x00000005)
90fcf382e2SArnaud Pouliquen #define RPROC_TLV_HASHTABLE	U(0x00000010)
91fcf382e2SArnaud Pouliquen #define RPROC_TLV_PKEYINFO	U(0x00000011)
92fcf382e2SArnaud Pouliquen 
93fcf382e2SArnaud Pouliquen #define RPROC_PLAT_TLV_TYPE_MIN	U(0x00010000)
94fcf382e2SArnaud Pouliquen #define RPROC_PLAT_TLV_TYPE_MAX	U(0x00020000)
95fcf382e2SArnaud Pouliquen 
96fcf382e2SArnaud Pouliquen #define RPROC_TLV_SIGNTYPE_LGTH U(1)
97fcf382e2SArnaud Pouliquen 
98fcf382e2SArnaud Pouliquen #define ROUNDUP_64(x) ROUNDUP((x), sizeof(uint64_t))
99fcf382e2SArnaud Pouliquen 
100fcf382e2SArnaud Pouliquen /*
101fcf382e2SArnaud Pouliquen  * struct remoteproc_tlv - Type-Length-Value structure
102fcf382e2SArnaud Pouliquen  * @type: type of data
103fcf382e2SArnaud Pouliquen  * @length: size of the data.
104fcf382e2SArnaud Pouliquen  * @value: pointer to the data.
105fcf382e2SArnaud Pouliquen  */
106fcf382e2SArnaud Pouliquen struct remoteproc_tlv {
107fcf382e2SArnaud Pouliquen 	uint32_t type;
108fcf382e2SArnaud Pouliquen 	uint32_t length;
109fcf382e2SArnaud Pouliquen 	uint8_t value[];
110fcf382e2SArnaud Pouliquen };
111fcf382e2SArnaud Pouliquen 
112fcf382e2SArnaud Pouliquen /*
113fcf382e2SArnaud Pouliquen  * struct remoteproc_segment - program header with hash structure
114fcf382e2SArnaud Pouliquen  * @phdr: program header
115fcf382e2SArnaud Pouliquen  * @hash: hash associated to the program segment.
116fcf382e2SArnaud Pouliquen  */
117fcf382e2SArnaud Pouliquen struct remoteproc_segment {
118fcf382e2SArnaud Pouliquen 	Elf32_Phdr phdr;
119fcf382e2SArnaud Pouliquen 	uint8_t hash[TEE_SHA256_HASH_SIZE];
120fcf382e2SArnaud Pouliquen };
121fcf382e2SArnaud Pouliquen 
122fcf382e2SArnaud Pouliquen /*
123fcf382e2SArnaud Pouliquen  * struct remoteproc_fw_hdr - firmware header
124fcf382e2SArnaud Pouliquen  * @magic:        Magic number, must be equal to RPROC_HDR_MAGIC
125fcf382e2SArnaud Pouliquen  * @version:      Version of the header (must be 1)
126fcf382e2SArnaud Pouliquen  * @tlv_len:      Generic meta data chunk (TLV format)
127fcf382e2SArnaud Pouliquen  * @sign_len:     Signature chunk byte length
128fcf382e2SArnaud Pouliquen  * @img_len:      Firmware image chunk byte length
129fcf382e2SArnaud Pouliquen  */
130fcf382e2SArnaud Pouliquen struct remoteproc_fw_hdr {
131fcf382e2SArnaud Pouliquen 	uint32_t magic;
132fcf382e2SArnaud Pouliquen 	uint32_t version;
133fcf382e2SArnaud Pouliquen 	uint32_t tlv_len;
134fcf382e2SArnaud Pouliquen 	uint32_t sign_len;
135fcf382e2SArnaud Pouliquen 	uint32_t img_len;
136fcf382e2SArnaud Pouliquen };
137fcf382e2SArnaud Pouliquen 
138fcf382e2SArnaud Pouliquen #define FW_TLV_PTR(img, hdr)  ((img) + sizeof(*(hdr)))
139fcf382e2SArnaud Pouliquen #define FW_SIGN_PTR(img, hdr) ({					\
140fcf382e2SArnaud Pouliquen 		struct remoteproc_fw_hdr *__hdr = (hdr);		\
141fcf382e2SArnaud Pouliquen 									\
142fcf382e2SArnaud Pouliquen 		FW_TLV_PTR((img), __hdr) + ROUNDUP_64(__hdr->tlv_len);	\
143fcf382e2SArnaud Pouliquen 	})
144fcf382e2SArnaud Pouliquen #define FW_IMG_PTR(img, hdr) ({						   \
145fcf382e2SArnaud Pouliquen 		struct remoteproc_fw_hdr *___hdr = (hdr);		   \
146fcf382e2SArnaud Pouliquen 									   \
147fcf382e2SArnaud Pouliquen 		FW_SIGN_PTR((img), ___hdr) + ROUNDUP_64(___hdr->sign_len); \
148fcf382e2SArnaud Pouliquen 	})
149fcf382e2SArnaud Pouliquen 
150fcf382e2SArnaud Pouliquen /*
151fcf382e2SArnaud Pouliquen  * struct remoteproc_sig_algo - signature algorithm information
152fcf382e2SArnaud Pouliquen  * @sign_type: Header signature type
153fcf382e2SArnaud Pouliquen  * @id:        Signature algorithm identifier TEE_ALG_*
154fcf382e2SArnaud Pouliquen  * @hash_len:  Signature hash length
155fcf382e2SArnaud Pouliquen  */
156fcf382e2SArnaud Pouliquen struct remoteproc_sig_algo {
157fcf382e2SArnaud Pouliquen 	enum remoteproc_sign_type sign_type;
158fcf382e2SArnaud Pouliquen 	uint32_t id;
159fcf382e2SArnaud Pouliquen 	size_t hash_len;
160fcf382e2SArnaud Pouliquen };
161fcf382e2SArnaud Pouliquen 
162fcf382e2SArnaud Pouliquen /*
163fcf382e2SArnaud Pouliquen  * struct remoteproc_context - firmware context
164fcf382e2SArnaud Pouliquen  * @rproc_id:    Unique Id of the processor
165fcf382e2SArnaud Pouliquen  * @sec_cpy:     Location of a secure copy of the header, TLVs and signature
166fcf382e2SArnaud Pouliquen  * @tlvs:        Location of a secure copy of the firmware TLVs
167fcf382e2SArnaud Pouliquen  * @tlvs_sz:     Byte size of the firmware TLVs blob.
168fcf382e2SArnaud Pouliquen  * @fw_img:      Firmware image
169fcf382e2SArnaud Pouliquen  * @fw_img_sz:   Byte size of the firmware image
170fcf382e2SArnaud Pouliquen  * @hash_table:  Location of a copy of the segment's hash table
171fcf382e2SArnaud Pouliquen  * @nb_segment:  number of segment to load
1721a442a9fSArnaud Pouliquen  * @rsc_pa:      Physical address of the firmware resource table
1731a442a9fSArnaud Pouliquen  * @rsc_size:    Byte size of the firmware resource table
174fcf382e2SArnaud Pouliquen  * @state:       Remote-processor state
175fcf382e2SArnaud Pouliquen  * @hw_fmt:      Image format capabilities of the remoteproc PTA
176fcf382e2SArnaud Pouliquen  * @hw_img_prot: Image protection capabilities of the remoteproc PTA
177fcf382e2SArnaud Pouliquen  * @link:        Linked list element
178fcf382e2SArnaud Pouliquen  */
179fcf382e2SArnaud Pouliquen struct remoteproc_context {
180fcf382e2SArnaud Pouliquen 	uint32_t rproc_id;
181fcf382e2SArnaud Pouliquen 	uint8_t *sec_cpy;
182fcf382e2SArnaud Pouliquen 	uint8_t *tlvs;
183fcf382e2SArnaud Pouliquen 	size_t tlvs_sz;
184fcf382e2SArnaud Pouliquen 	uint8_t *fw_img;
185fcf382e2SArnaud Pouliquen 	size_t fw_img_sz;
186fcf382e2SArnaud Pouliquen 	struct remoteproc_segment *hash_table;
187fcf382e2SArnaud Pouliquen 	uint32_t nb_segment;
1881a442a9fSArnaud Pouliquen 	paddr_t rsc_pa;
1891a442a9fSArnaud Pouliquen 	size_t rsc_size;
190fcf382e2SArnaud Pouliquen 	enum remoteproc_state state;
191fcf382e2SArnaud Pouliquen 	uint32_t hw_fmt;
192fcf382e2SArnaud Pouliquen 	uint32_t hw_img_prot;
193fcf382e2SArnaud Pouliquen 	TAILQ_ENTRY(remoteproc_context) link;
194fcf382e2SArnaud Pouliquen };
195fcf382e2SArnaud Pouliquen 
196fcf382e2SArnaud Pouliquen TAILQ_HEAD(remoteproc_firmware_head, remoteproc_context);
197fcf382e2SArnaud Pouliquen 
198fcf382e2SArnaud Pouliquen static struct remoteproc_firmware_head firmware_head =
199fcf382e2SArnaud Pouliquen 	TAILQ_HEAD_INITIALIZER(firmware_head);
200fcf382e2SArnaud Pouliquen 
201fcf382e2SArnaud Pouliquen static const struct remoteproc_sig_algo rproc_ta_sign_algo[] = {
202fcf382e2SArnaud Pouliquen 	{
203fcf382e2SArnaud Pouliquen 		.sign_type = RPROC_RSASSA_PKCS1_v1_5_SHA256,
204fcf382e2SArnaud Pouliquen 		.id = TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
205fcf382e2SArnaud Pouliquen 		.hash_len = TEE_SHA256_HASH_SIZE,
206fcf382e2SArnaud Pouliquen 	},
207fcf382e2SArnaud Pouliquen 	{
208fcf382e2SArnaud Pouliquen 		.sign_type = RPROC_ECDSA_SHA256,
209fcf382e2SArnaud Pouliquen 		.id = TEE_ALG_ECDSA_P256,
210fcf382e2SArnaud Pouliquen 		.hash_len = TEE_SHA256_HASH_SIZE,
211fcf382e2SArnaud Pouliquen 	},
212fcf382e2SArnaud Pouliquen };
213fcf382e2SArnaud Pouliquen 
214fcf382e2SArnaud Pouliquen static size_t session_refcount;
215fcf382e2SArnaud Pouliquen static TEE_TASessionHandle pta_session;
216fcf382e2SArnaud Pouliquen 
remoteproc_header_dump(struct remoteproc_fw_hdr __maybe_unused * hdr)217fcf382e2SArnaud Pouliquen static void remoteproc_header_dump(struct remoteproc_fw_hdr __maybe_unused *hdr)
218fcf382e2SArnaud Pouliquen {
219fcf382e2SArnaud Pouliquen 	DMSG("magic :\t%#"PRIx32, hdr->magic);
220fcf382e2SArnaud Pouliquen 	DMSG("version :\t%#"PRIx32, hdr->version);
221fcf382e2SArnaud Pouliquen 	DMSG("tlv_len :\t%#"PRIx32, hdr->tlv_len);
222fcf382e2SArnaud Pouliquen 	DMSG("sign_len :\t%#"PRIx32, hdr->sign_len);
223fcf382e2SArnaud Pouliquen 	DMSG("img_len :\t%#"PRIx32, hdr->img_len);
224fcf382e2SArnaud Pouliquen }
225fcf382e2SArnaud Pouliquen 
226*14a1a72bSEtienne Carriere /*
227*14a1a72bSEtienne Carriere  * This function loads output data in @value and @length in 2 cases.
228*14a1a72bSEtienne Carriere  * Upon TEE_SUCCESS, output arguments provide the requested TLV information.
229*14a1a72bSEtienne Carriere  * Upon TEE_ERROR_NO_DATA, @value is set to NULL and @length to 0.
230*14a1a72bSEtienne Carriere  */
remoteproc_get_tlv(void * tlv_chunk,size_t tlv_size,uint16_t type,uint8_t ** value,size_t * length)231fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_get_tlv(void *tlv_chunk, size_t tlv_size,
232fcf382e2SArnaud Pouliquen 				     uint16_t type, uint8_t **value,
233fcf382e2SArnaud Pouliquen 				     size_t *length)
234fcf382e2SArnaud Pouliquen {
235fcf382e2SArnaud Pouliquen 	uint8_t *p_tlv = (uint8_t *)tlv_chunk;
236fcf382e2SArnaud Pouliquen 	uint8_t *p_end_tlv = p_tlv + tlv_size;
237fcf382e2SArnaud Pouliquen 	uint32_t tlv_type = 0;
238fcf382e2SArnaud Pouliquen 	uint32_t tlv_length = 0;
239fcf382e2SArnaud Pouliquen 	uint32_t tlv_v = 0;
24007917406SAlexandre Gonzalo 	uintptr_t tmp_p_tlv = 0;
241fcf382e2SArnaud Pouliquen 
242fcf382e2SArnaud Pouliquen 	*value = NULL;
243fcf382e2SArnaud Pouliquen 	*length = 0;
244fcf382e2SArnaud Pouliquen 
245fcf382e2SArnaud Pouliquen 	/* Parse the TLV area */
24668dc1d62SEtienne Carriere 	while (p_tlv + RPROC_TLV_VALUE_OF <= p_end_tlv) {
247fcf382e2SArnaud Pouliquen 		memcpy(&tlv_v, p_tlv, sizeof(tlv_v));
248fcf382e2SArnaud Pouliquen 		tlv_type = TEE_U32_FROM_LITTLE_ENDIAN(tlv_v);
249fcf382e2SArnaud Pouliquen 		memcpy(&tlv_v, p_tlv + RPROC_TLV_LENGTH_OF, sizeof(tlv_v));
25007917406SAlexandre Gonzalo 		p_tlv += RPROC_TLV_VALUE_OF;
251fcf382e2SArnaud Pouliquen 		tlv_length = TEE_U32_FROM_LITTLE_ENDIAN(tlv_v);
25207917406SAlexandre Gonzalo 		if (ADD_OVERFLOW((uintptr_t)p_tlv, tlv_length, &tmp_p_tlv))
25307917406SAlexandre Gonzalo 			break;
25407917406SAlexandre Gonzalo 		if (tmp_p_tlv <= (uintptr_t)p_end_tlv && tlv_type == type) {
255fcf382e2SArnaud Pouliquen 			/* The specified TLV has been found */
256fcf382e2SArnaud Pouliquen 			DMSG("TLV type %#"PRIx32" found, size %#"PRIx32,
257fcf382e2SArnaud Pouliquen 			     type, tlv_length);
25807917406SAlexandre Gonzalo 			*value = p_tlv;
259fcf382e2SArnaud Pouliquen 			*length = tlv_length;
260fcf382e2SArnaud Pouliquen 			if (tlv_length)
261fcf382e2SArnaud Pouliquen 				return TEE_SUCCESS;
262fcf382e2SArnaud Pouliquen 			else
263fcf382e2SArnaud Pouliquen 				return TEE_ERROR_NO_DATA;
264fcf382e2SArnaud Pouliquen 		}
26507917406SAlexandre Gonzalo 		p_tlv += ROUNDUP_64(tlv_length);
266fcf382e2SArnaud Pouliquen 	}
267fcf382e2SArnaud Pouliquen 
268fcf382e2SArnaud Pouliquen 	return TEE_ERROR_NO_DATA;
269fcf382e2SArnaud Pouliquen }
270fcf382e2SArnaud Pouliquen 
remoteproc_find_firmware(uint32_t rproc_id)271fcf382e2SArnaud Pouliquen static struct remoteproc_context *remoteproc_find_firmware(uint32_t rproc_id)
272fcf382e2SArnaud Pouliquen {
273fcf382e2SArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
274fcf382e2SArnaud Pouliquen 
275fcf382e2SArnaud Pouliquen 	TAILQ_FOREACH(ctx, &firmware_head, link)
276fcf382e2SArnaud Pouliquen 		if (ctx->rproc_id == rproc_id)
277fcf382e2SArnaud Pouliquen 			return ctx;
278fcf382e2SArnaud Pouliquen 
279fcf382e2SArnaud Pouliquen 	return NULL;
280fcf382e2SArnaud Pouliquen }
281fcf382e2SArnaud Pouliquen 
remoteproc_add_firmware(uint32_t rproc_id)282fcf382e2SArnaud Pouliquen static struct remoteproc_context *remoteproc_add_firmware(uint32_t rproc_id)
283fcf382e2SArnaud Pouliquen {
284fcf382e2SArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
285fcf382e2SArnaud Pouliquen 
286fcf382e2SArnaud Pouliquen 	ctx = TEE_Malloc(sizeof(*ctx), TEE_MALLOC_FILL_ZERO);
287fcf382e2SArnaud Pouliquen 	if (!ctx)
288fcf382e2SArnaud Pouliquen 		return NULL;
289fcf382e2SArnaud Pouliquen 
290fcf382e2SArnaud Pouliquen 	ctx->rproc_id = rproc_id;
291fcf382e2SArnaud Pouliquen 
292fcf382e2SArnaud Pouliquen 	TAILQ_INSERT_TAIL(&firmware_head, ctx, link);
293fcf382e2SArnaud Pouliquen 
294fcf382e2SArnaud Pouliquen 	return ctx;
295fcf382e2SArnaud Pouliquen }
296fcf382e2SArnaud Pouliquen 
remoteproc_get_algo(uint32_t sign_type)297fcf382e2SArnaud Pouliquen static const struct remoteproc_sig_algo *remoteproc_get_algo(uint32_t sign_type)
298fcf382e2SArnaud Pouliquen {
299fcf382e2SArnaud Pouliquen 	unsigned int i = 0;
300fcf382e2SArnaud Pouliquen 
301fcf382e2SArnaud Pouliquen 	for (i = 0; i < ARRAY_SIZE(rproc_ta_sign_algo); i++)
302fcf382e2SArnaud Pouliquen 		if (sign_type == rproc_ta_sign_algo[i].sign_type)
303fcf382e2SArnaud Pouliquen 			return &rproc_ta_sign_algo[i];
304fcf382e2SArnaud Pouliquen 
305fcf382e2SArnaud Pouliquen 	return NULL;
306fcf382e2SArnaud Pouliquen }
307fcf382e2SArnaud Pouliquen 
remoteproc_pta_verify(struct remoteproc_context * ctx,const struct remoteproc_sig_algo * algo,uint8_t * hash,uint32_t hash_len)308fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_pta_verify(struct remoteproc_context *ctx,
309fcf382e2SArnaud Pouliquen 					const struct remoteproc_sig_algo *algo,
310fcf382e2SArnaud Pouliquen 					uint8_t *hash, uint32_t hash_len)
311fcf382e2SArnaud Pouliquen {
312fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
313fcf382e2SArnaud Pouliquen 	struct remoteproc_fw_hdr *hdr = (void *)ctx->sec_cpy;
314fcf382e2SArnaud Pouliquen 	struct rproc_pta_key_info *keyinfo = NULL;
315fcf382e2SArnaud Pouliquen 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
316fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_MEMREF_INPUT,
317fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_MEMREF_INPUT,
318fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_MEMREF_INPUT);
319fcf382e2SArnaud Pouliquen 	TEE_Param params[TEE_NUM_PARAMS] = { };
320fcf382e2SArnaud Pouliquen 	size_t length = 0;
321fcf382e2SArnaud Pouliquen 	uint8_t *tlv_keyinfo = NULL;
322fcf382e2SArnaud Pouliquen 	uint8_t *sign = NULL;
323fcf382e2SArnaud Pouliquen 
324fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, hdr->tlv_len,
325fcf382e2SArnaud Pouliquen 				 RPROC_TLV_PKEYINFO, &tlv_keyinfo,
326fcf382e2SArnaud Pouliquen 				 &length);
327fcf382e2SArnaud Pouliquen 	if (res != TEE_SUCCESS && res != TEE_ERROR_NO_DATA)
328fcf382e2SArnaud Pouliquen 		return res;
329fcf382e2SArnaud Pouliquen 
330fcf382e2SArnaud Pouliquen 	keyinfo = TEE_Malloc(sizeof(*keyinfo) + length, TEE_MALLOC_FILL_ZERO);
331fcf382e2SArnaud Pouliquen 	if (!keyinfo)
332fcf382e2SArnaud Pouliquen 		return TEE_ERROR_OUT_OF_MEMORY;
333fcf382e2SArnaud Pouliquen 
334fcf382e2SArnaud Pouliquen 	keyinfo->algo = algo->id;
335fcf382e2SArnaud Pouliquen 	keyinfo->info_size = length;
336fcf382e2SArnaud Pouliquen 	memcpy(keyinfo->info, tlv_keyinfo, length);
337fcf382e2SArnaud Pouliquen 
338fcf382e2SArnaud Pouliquen 	sign = FW_SIGN_PTR(ctx->sec_cpy, hdr);
339fcf382e2SArnaud Pouliquen 
340fcf382e2SArnaud Pouliquen 	params[0].value.a = ctx->rproc_id;
341fcf382e2SArnaud Pouliquen 	params[1].memref.buffer = keyinfo;
342fcf382e2SArnaud Pouliquen 	params[1].memref.size = rproc_pta_keyinfo_size(keyinfo);
343fcf382e2SArnaud Pouliquen 	params[2].memref.buffer = hash;
344fcf382e2SArnaud Pouliquen 	params[2].memref.size = hash_len;
345fcf382e2SArnaud Pouliquen 	params[3].memref.buffer = sign;
346fcf382e2SArnaud Pouliquen 	params[3].memref.size = hdr->sign_len;
347fcf382e2SArnaud Pouliquen 
348fcf382e2SArnaud Pouliquen 	res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
349fcf382e2SArnaud Pouliquen 				  PTA_RPROC_VERIFY_DIGEST,
350fcf382e2SArnaud Pouliquen 				  param_types, params, NULL);
351fcf382e2SArnaud Pouliquen 	if (res != TEE_SUCCESS)
352fcf382e2SArnaud Pouliquen 		EMSG("Failed to verify signature, res = %#"PRIx32, res);
353fcf382e2SArnaud Pouliquen 
354fcf382e2SArnaud Pouliquen 	TEE_Free(keyinfo);
355fcf382e2SArnaud Pouliquen 
356fcf382e2SArnaud Pouliquen 	return res;
357fcf382e2SArnaud Pouliquen }
358fcf382e2SArnaud Pouliquen 
359fcf382e2SArnaud Pouliquen static TEE_Result
remoteproc_save_fw_header_and_tlvs(struct remoteproc_context * ctx,void * fw_orig,uint32_t fw_orig_size)360fcf382e2SArnaud Pouliquen remoteproc_save_fw_header_and_tlvs(struct remoteproc_context *ctx,
361fcf382e2SArnaud Pouliquen 				   void *fw_orig, uint32_t fw_orig_size)
362fcf382e2SArnaud Pouliquen {
363fcf382e2SArnaud Pouliquen 	struct remoteproc_fw_hdr *hdr = fw_orig;
364fcf382e2SArnaud Pouliquen 	uint32_t length = 0;
365fcf382e2SArnaud Pouliquen 
366fcf382e2SArnaud Pouliquen 	if (!IS_ALIGNED_WITH_TYPE(fw_orig, struct remoteproc_fw_hdr))
367fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
368fcf382e2SArnaud Pouliquen 
369fcf382e2SArnaud Pouliquen 	if (ADD_OVERFLOW(sizeof(*hdr), ROUNDUP_64(hdr->tlv_len), &length) ||
370fcf382e2SArnaud Pouliquen 	    ADD_OVERFLOW(length, ROUNDUP_64(hdr->sign_len), &length))
371fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
372fcf382e2SArnaud Pouliquen 
373fcf382e2SArnaud Pouliquen 	if (fw_orig_size <= length || !hdr->sign_len || !hdr->tlv_len)
374fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
375fcf382e2SArnaud Pouliquen 
376fcf382e2SArnaud Pouliquen 	remoteproc_header_dump(hdr);
377fcf382e2SArnaud Pouliquen 
378fcf382e2SArnaud Pouliquen 	/* Copy the header, the TLVs and the signature in secure memory */
379fcf382e2SArnaud Pouliquen 	ctx->sec_cpy = TEE_Malloc(length, TEE_MALLOC_FILL_ZERO);
380fcf382e2SArnaud Pouliquen 	if (!ctx->sec_cpy)
381fcf382e2SArnaud Pouliquen 		return TEE_ERROR_OUT_OF_MEMORY;
382fcf382e2SArnaud Pouliquen 
383fcf382e2SArnaud Pouliquen 	memcpy(ctx->sec_cpy, fw_orig, length);
384fcf382e2SArnaud Pouliquen 
385fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
386fcf382e2SArnaud Pouliquen }
387fcf382e2SArnaud Pouliquen 
remoteproc_verify_signature(struct remoteproc_context * ctx)388fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_verify_signature(struct remoteproc_context *ctx)
389fcf382e2SArnaud Pouliquen {
390fcf382e2SArnaud Pouliquen 	TEE_OperationHandle op = TEE_HANDLE_NULL;
391fcf382e2SArnaud Pouliquen 	struct remoteproc_fw_hdr *hdr = (void *)ctx->sec_cpy;
392fcf382e2SArnaud Pouliquen 	const struct remoteproc_sig_algo *algo = NULL;
393fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
394fcf382e2SArnaud Pouliquen 	uint8_t *tlv_sign_algo = NULL;
395fcf382e2SArnaud Pouliquen 	size_t length = 0;
396fcf382e2SArnaud Pouliquen 	uint8_t *hash = NULL;
397fcf382e2SArnaud Pouliquen 	size_t hash_len = 0;
398fcf382e2SArnaud Pouliquen 
399fcf382e2SArnaud Pouliquen 	/* Get the algo type from TLV data */
400fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, hdr->tlv_len, RPROC_TLV_SIGNTYPE,
401fcf382e2SArnaud Pouliquen 				 &tlv_sign_algo, &length);
402fcf382e2SArnaud Pouliquen 
403fcf382e2SArnaud Pouliquen 	if (res != TEE_SUCCESS || length != RPROC_TLV_SIGNTYPE_LGTH)
404fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
405fcf382e2SArnaud Pouliquen 
406fcf382e2SArnaud Pouliquen 	algo = remoteproc_get_algo(*tlv_sign_algo);
407fcf382e2SArnaud Pouliquen 	if (!algo) {
408fcf382e2SArnaud Pouliquen 		EMSG("Unsupported signature type %"PRId8, *tlv_sign_algo);
409fcf382e2SArnaud Pouliquen 		return TEE_ERROR_NOT_SUPPORTED;
410fcf382e2SArnaud Pouliquen 	}
411fcf382e2SArnaud Pouliquen 
412fcf382e2SArnaud Pouliquen 	/* Compute the header and TLVs hashes */
413fcf382e2SArnaud Pouliquen 	hash_len = algo->hash_len;
414fcf382e2SArnaud Pouliquen 	hash = TEE_Malloc(hash_len, TEE_MALLOC_FILL_ZERO);
415fcf382e2SArnaud Pouliquen 	if (!hash)
416fcf382e2SArnaud Pouliquen 		return TEE_ERROR_OUT_OF_MEMORY;
417fcf382e2SArnaud Pouliquen 
418fcf382e2SArnaud Pouliquen 	res = TEE_AllocateOperation(&op, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0);
419fcf382e2SArnaud Pouliquen 	if (res != TEE_SUCCESS)
420fcf382e2SArnaud Pouliquen 		goto free_hash;
421fcf382e2SArnaud Pouliquen 
422fcf382e2SArnaud Pouliquen 	TEE_DigestUpdate(op, hdr, sizeof(*hdr));
423fcf382e2SArnaud Pouliquen 	res = TEE_DigestDoFinal(op, ctx->tlvs, ROUNDUP_64(hdr->tlv_len),
424fcf382e2SArnaud Pouliquen 				hash, &hash_len);
425fcf382e2SArnaud Pouliquen 
426fcf382e2SArnaud Pouliquen 	if (res != TEE_SUCCESS)
427fcf382e2SArnaud Pouliquen 		goto out;
428fcf382e2SArnaud Pouliquen 
429fcf382e2SArnaud Pouliquen 	/*
430fcf382e2SArnaud Pouliquen 	 * This implementation could be enhanced by providing alternative to
431fcf382e2SArnaud Pouliquen 	 * verify the signature in the TA. This could be done for instance by
432fcf382e2SArnaud Pouliquen 	 * getting the key object from secure storage.
433fcf382e2SArnaud Pouliquen 	 */
434fcf382e2SArnaud Pouliquen 
435fcf382e2SArnaud Pouliquen 	/* By default ask the remoteproc PTA to verify the signature. */
436fcf382e2SArnaud Pouliquen 	res = remoteproc_pta_verify(ctx, algo, hash, hash_len);
437fcf382e2SArnaud Pouliquen 
438fcf382e2SArnaud Pouliquen out:
439fcf382e2SArnaud Pouliquen 	TEE_FreeOperation(op);
440fcf382e2SArnaud Pouliquen free_hash:
441fcf382e2SArnaud Pouliquen 	TEE_Free(hash);
442fcf382e2SArnaud Pouliquen 
443fcf382e2SArnaud Pouliquen 	return res;
444fcf382e2SArnaud Pouliquen }
445fcf382e2SArnaud Pouliquen 
remoteproc_verify_header(struct remoteproc_context * ctx,uint32_t fw_orig_size)446fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_verify_header(struct remoteproc_context *ctx,
447fcf382e2SArnaud Pouliquen 					   uint32_t fw_orig_size)
448fcf382e2SArnaud Pouliquen {
449fcf382e2SArnaud Pouliquen 	struct remoteproc_fw_hdr *hdr = (void *)ctx->sec_cpy;
450fcf382e2SArnaud Pouliquen 	uint32_t size = 0;
451fcf382e2SArnaud Pouliquen 
452fcf382e2SArnaud Pouliquen 	if (hdr->magic != RPROC_HDR_MAGIC)
453fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
454fcf382e2SArnaud Pouliquen 
455fcf382e2SArnaud Pouliquen 	if (hdr->version != HEADER_VERSION)
456fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
457fcf382e2SArnaud Pouliquen 
458fcf382e2SArnaud Pouliquen 	/*
459fcf382e2SArnaud Pouliquen 	 * The offsets are aligned to 64 bits format. While the length of each
460fcf382e2SArnaud Pouliquen 	 * chunks are the effective length, excluding the alignment padding
461fcf382e2SArnaud Pouliquen 	 * bytes.
462fcf382e2SArnaud Pouliquen 	 */
463fcf382e2SArnaud Pouliquen 	if (ADD_OVERFLOW(sizeof(*hdr), ROUNDUP_64(hdr->sign_len), &size) ||
464fcf382e2SArnaud Pouliquen 	    ADD_OVERFLOW(size, ROUNDUP_64(hdr->img_len), &size) ||
465fcf382e2SArnaud Pouliquen 	    ADD_OVERFLOW(size, ROUNDUP_64(hdr->tlv_len), &size) ||
466fcf382e2SArnaud Pouliquen 	    fw_orig_size != size)
467fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
468fcf382e2SArnaud Pouliquen 
469fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
470fcf382e2SArnaud Pouliquen }
471fcf382e2SArnaud Pouliquen 
get_rproc_pta_capabilities(struct remoteproc_context * ctx)472fcf382e2SArnaud Pouliquen static TEE_Result get_rproc_pta_capabilities(struct remoteproc_context *ctx)
473fcf382e2SArnaud Pouliquen {
474fcf382e2SArnaud Pouliquen 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
475fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_OUTPUT,
476fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_OUTPUT,
477fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_NONE);
478fcf382e2SArnaud Pouliquen 	TEE_Param params[TEE_NUM_PARAMS] = { };
479fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
480fcf382e2SArnaud Pouliquen 
481fcf382e2SArnaud Pouliquen 	params[0].value.a = ctx->rproc_id;
482fcf382e2SArnaud Pouliquen 
483fcf382e2SArnaud Pouliquen 	res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
484fcf382e2SArnaud Pouliquen 				  PTA_RPROC_HW_CAPABILITIES,
485fcf382e2SArnaud Pouliquen 				  param_types, params, NULL);
486fcf382e2SArnaud Pouliquen 	if (res)
487fcf382e2SArnaud Pouliquen 		return res;
488fcf382e2SArnaud Pouliquen 
489fcf382e2SArnaud Pouliquen 	ctx->hw_fmt = params[1].value.a;
490fcf382e2SArnaud Pouliquen 	ctx->hw_img_prot = params[2].value.a;
491fcf382e2SArnaud Pouliquen 
492fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
493fcf382e2SArnaud Pouliquen }
494fcf382e2SArnaud Pouliquen 
remoteproc_verify_firmware(struct remoteproc_context * ctx,uint8_t * fw_orig,uint32_t fw_orig_size)495fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_verify_firmware(struct remoteproc_context *ctx,
496fcf382e2SArnaud Pouliquen 					     uint8_t *fw_orig,
497fcf382e2SArnaud Pouliquen 					     uint32_t fw_orig_size)
498fcf382e2SArnaud Pouliquen {
499fcf382e2SArnaud Pouliquen 	struct remoteproc_fw_hdr *hdr = NULL;
500fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
501fcf382e2SArnaud Pouliquen 
502fcf382e2SArnaud Pouliquen 	res = get_rproc_pta_capabilities(ctx);
503fcf382e2SArnaud Pouliquen 	if (res)
504fcf382e2SArnaud Pouliquen 		return res;
505fcf382e2SArnaud Pouliquen 
506fcf382e2SArnaud Pouliquen 	/* Secure the firmware image depending on strategy */
507fcf382e2SArnaud Pouliquen 	if (!(ctx->hw_img_prot & PTA_RPROC_HWCAP_PROT_HASH_TABLE) ||
508fcf382e2SArnaud Pouliquen 	    ctx->hw_fmt != PTA_RPROC_HWCAP_FMT_ELF) {
509fcf382e2SArnaud Pouliquen 		/*
510fcf382e2SArnaud Pouliquen 		 * Only hash table for ELF format support implemented
511fcf382e2SArnaud Pouliquen 		 * in a first step.
512fcf382e2SArnaud Pouliquen 		 */
513fcf382e2SArnaud Pouliquen 		return TEE_ERROR_NOT_IMPLEMENTED;
514fcf382e2SArnaud Pouliquen 	}
515fcf382e2SArnaud Pouliquen 
516fcf382e2SArnaud Pouliquen 	res = remoteproc_save_fw_header_and_tlvs(ctx, fw_orig, fw_orig_size);
517fcf382e2SArnaud Pouliquen 	if (res)
518fcf382e2SArnaud Pouliquen 		return res;
519fcf382e2SArnaud Pouliquen 
520fcf382e2SArnaud Pouliquen 	res = remoteproc_verify_header(ctx, fw_orig_size);
521fcf382e2SArnaud Pouliquen 	if (res)
522fcf382e2SArnaud Pouliquen 		goto free_sec_cpy;
523fcf382e2SArnaud Pouliquen 
524fcf382e2SArnaud Pouliquen 	hdr = (void *)ctx->sec_cpy;
525fcf382e2SArnaud Pouliquen 	ctx->tlvs_sz = hdr->tlv_len;
526fcf382e2SArnaud Pouliquen 	ctx->tlvs = FW_TLV_PTR(ctx->sec_cpy, hdr);
527fcf382e2SArnaud Pouliquen 
528fcf382e2SArnaud Pouliquen 	res = remoteproc_verify_signature(ctx);
529fcf382e2SArnaud Pouliquen 	if (res)
530fcf382e2SArnaud Pouliquen 		goto free_sec_cpy;
531fcf382e2SArnaud Pouliquen 
532fcf382e2SArnaud Pouliquen 	/* Store location of the loadable binary in non-secure memory */
533fcf382e2SArnaud Pouliquen 	ctx->fw_img_sz = hdr->img_len;
534fcf382e2SArnaud Pouliquen 	ctx->fw_img = FW_IMG_PTR(fw_orig, hdr);
535fcf382e2SArnaud Pouliquen 
536fcf382e2SArnaud Pouliquen 	DMSG("Firmware images addr: %p size: %zu", ctx->fw_img,
537fcf382e2SArnaud Pouliquen 	     ctx->fw_img_sz);
538fcf382e2SArnaud Pouliquen 
539fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
540fcf382e2SArnaud Pouliquen 
541fcf382e2SArnaud Pouliquen free_sec_cpy:
542fcf382e2SArnaud Pouliquen 	TEE_Free(ctx->sec_cpy);
543fcf382e2SArnaud Pouliquen 	ctx->sec_cpy = NULL;
544fcf382e2SArnaud Pouliquen 
545fcf382e2SArnaud Pouliquen 	return res;
546fcf382e2SArnaud Pouliquen }
547fcf382e2SArnaud Pouliquen 
remoteproc_da_to_pa(uint32_t da,size_t size,struct remoteproc_context * ctx)5481a442a9fSArnaud Pouliquen static paddr_t remoteproc_da_to_pa(uint32_t da, size_t size,
5491a442a9fSArnaud Pouliquen 				   struct remoteproc_context *ctx)
5501a442a9fSArnaud Pouliquen {
5511a442a9fSArnaud Pouliquen 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
5521a442a9fSArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_INPUT,
5531a442a9fSArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_INPUT,
5541a442a9fSArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_OUTPUT);
5551a442a9fSArnaud Pouliquen 	TEE_Param params[TEE_NUM_PARAMS] = { };
5561a442a9fSArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
5571a442a9fSArnaud Pouliquen 	paddr_t pa = 0;
5581a442a9fSArnaud Pouliquen 
5591a442a9fSArnaud Pouliquen 	/*
5601a442a9fSArnaud Pouliquen 	 * The ELF file contains remote processor device addresses, that refer
5611a442a9fSArnaud Pouliquen 	 * to the remote processor memory space.
5621a442a9fSArnaud Pouliquen 	 * A translation is needed to get the corresponding physical address.
5631a442a9fSArnaud Pouliquen 	 */
5641a442a9fSArnaud Pouliquen 
5651a442a9fSArnaud Pouliquen 	params[0].value.a = ctx->rproc_id;
5661a442a9fSArnaud Pouliquen 	params[1].value.a = da;
5671a442a9fSArnaud Pouliquen 	params[2].value.a = size;
5681a442a9fSArnaud Pouliquen 
5691a442a9fSArnaud Pouliquen 	res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
5701a442a9fSArnaud Pouliquen 				  PTA_RPROC_FIRMWARE_DA_TO_PA,
5711a442a9fSArnaud Pouliquen 				  param_types, params, NULL);
5721a442a9fSArnaud Pouliquen 	if (res != TEE_SUCCESS) {
5731a442a9fSArnaud Pouliquen 		EMSG("Failed to translate device address %#"PRIx32, da);
5741a442a9fSArnaud Pouliquen 		return 0;
5751a442a9fSArnaud Pouliquen 	}
5761a442a9fSArnaud Pouliquen 
5771a442a9fSArnaud Pouliquen 	pa = (paddr_t)reg_pair_to_64(params[3].value.b, params[3].value.a);
5781a442a9fSArnaud Pouliquen 
5791a442a9fSArnaud Pouliquen 	/* Assert that the pa address is not 0 */
5801a442a9fSArnaud Pouliquen 	assert(pa);
5811a442a9fSArnaud Pouliquen 
5821a442a9fSArnaud Pouliquen 	return pa;
5831a442a9fSArnaud Pouliquen }
5841a442a9fSArnaud Pouliquen 
remoteproc_parse_rsc_table(struct remoteproc_context * ctx,uint8_t * fw_img,size_t fw_img_sz,paddr_t * rsc_pa,size_t * rsc_size)5851a442a9fSArnaud Pouliquen static TEE_Result remoteproc_parse_rsc_table(struct remoteproc_context *ctx,
5861a442a9fSArnaud Pouliquen 					     uint8_t *fw_img, size_t fw_img_sz,
5871a442a9fSArnaud Pouliquen 					     paddr_t *rsc_pa,
5881a442a9fSArnaud Pouliquen 					     size_t *rsc_size)
5891a442a9fSArnaud Pouliquen {
5901a442a9fSArnaud Pouliquen 	uint32_t da = 0;
5911a442a9fSArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
5921a442a9fSArnaud Pouliquen 	Elf32_Word size = 0;
5931a442a9fSArnaud Pouliquen 
5941a442a9fSArnaud Pouliquen 	res = e32_parser_find_rsc_table(fw_img, fw_img_sz, &da, &size);
5951a442a9fSArnaud Pouliquen 	if (res)
5961a442a9fSArnaud Pouliquen 		return res;
5971a442a9fSArnaud Pouliquen 
5981a442a9fSArnaud Pouliquen 	DMSG("Resource table device address %#"PRIx32" size %#"PRIx32,
5991a442a9fSArnaud Pouliquen 	     da, size);
6001a442a9fSArnaud Pouliquen 
6011a442a9fSArnaud Pouliquen 	*rsc_pa = remoteproc_da_to_pa(da, size, ctx);
6021a442a9fSArnaud Pouliquen 	if (!*rsc_pa)
6031a442a9fSArnaud Pouliquen 		return TEE_ERROR_ACCESS_DENIED;
6041a442a9fSArnaud Pouliquen 
6051a442a9fSArnaud Pouliquen 	*rsc_size = size;
6061a442a9fSArnaud Pouliquen 
6071a442a9fSArnaud Pouliquen 	return TEE_SUCCESS;
6081a442a9fSArnaud Pouliquen }
6091a442a9fSArnaud Pouliquen 
get_hash_table(struct remoteproc_context * ctx)610fcf382e2SArnaud Pouliquen static TEE_Result get_hash_table(struct remoteproc_context *ctx)
611fcf382e2SArnaud Pouliquen {
612fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
613fcf382e2SArnaud Pouliquen 	uint8_t *tlv_hash = NULL;
614fcf382e2SArnaud Pouliquen 	struct remoteproc_segment *hash_table = NULL;
615fcf382e2SArnaud Pouliquen 	size_t length = 0;
616fcf382e2SArnaud Pouliquen 
617fcf382e2SArnaud Pouliquen 	/* Get the segment's hash table from TLV data */
618fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, ctx->tlvs_sz, RPROC_TLV_HASHTABLE,
619fcf382e2SArnaud Pouliquen 				 &tlv_hash, &length);
620fcf382e2SArnaud Pouliquen 	if (res)
621fcf382e2SArnaud Pouliquen 		return res;
622fcf382e2SArnaud Pouliquen 
623fcf382e2SArnaud Pouliquen 	if (length % sizeof(struct remoteproc_segment))
624fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
625fcf382e2SArnaud Pouliquen 
626fcf382e2SArnaud Pouliquen 	/* We can not ensure that tlv_hash is memory aligned so make a copy */
627fcf382e2SArnaud Pouliquen 	hash_table = TEE_Malloc(length, TEE_MALLOC_FILL_ZERO);
628fcf382e2SArnaud Pouliquen 	if (!hash_table)
629fcf382e2SArnaud Pouliquen 		return TEE_ERROR_OUT_OF_MEMORY;
630fcf382e2SArnaud Pouliquen 
631fcf382e2SArnaud Pouliquen 	memcpy(hash_table, tlv_hash, length);
632fcf382e2SArnaud Pouliquen 
633fcf382e2SArnaud Pouliquen 	ctx->hash_table = hash_table;
634fcf382e2SArnaud Pouliquen 	ctx->nb_segment = length / sizeof(struct remoteproc_segment);
635fcf382e2SArnaud Pouliquen 
636fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
637fcf382e2SArnaud Pouliquen }
638fcf382e2SArnaud Pouliquen 
get_tlv_images_type(struct remoteproc_context * ctx,uint8_t num_img,uint8_t idx,uint8_t * img_type)639fcf382e2SArnaud Pouliquen static TEE_Result get_tlv_images_type(struct remoteproc_context *ctx,
640fcf382e2SArnaud Pouliquen 				      uint8_t num_img, uint8_t idx,
641fcf382e2SArnaud Pouliquen 				      uint8_t *img_type)
642fcf382e2SArnaud Pouliquen {
643fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
644fcf382e2SArnaud Pouliquen 	uint8_t *tlv_value = NULL;
645fcf382e2SArnaud Pouliquen 	size_t length = 0;
646fcf382e2SArnaud Pouliquen 
647fcf382e2SArnaud Pouliquen 	/* Get the type of the image to load, from TLV data */
648fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, ctx->tlvs_sz, RPROC_TLV_IMGTYPE,
649fcf382e2SArnaud Pouliquen 				 &tlv_value, &length);
650fcf382e2SArnaud Pouliquen 	if (res)
651fcf382e2SArnaud Pouliquen 		return res;
652fcf382e2SArnaud Pouliquen 
653fcf382e2SArnaud Pouliquen 	if (length != (sizeof(*img_type) * num_img))
654fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
655fcf382e2SArnaud Pouliquen 
656fcf382e2SArnaud Pouliquen 	*img_type = tlv_value[idx];
657fcf382e2SArnaud Pouliquen 
658fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
659fcf382e2SArnaud Pouliquen }
660fcf382e2SArnaud Pouliquen 
get_tlv_images_size(struct remoteproc_context * ctx,uint8_t num_img,uint8_t idx,uint32_t * img_size)661fcf382e2SArnaud Pouliquen static TEE_Result get_tlv_images_size(struct remoteproc_context *ctx,
662fcf382e2SArnaud Pouliquen 				      uint8_t num_img, uint8_t idx,
663fcf382e2SArnaud Pouliquen 				      uint32_t *img_size)
664fcf382e2SArnaud Pouliquen {
665fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
666fcf382e2SArnaud Pouliquen 	uint8_t *tlv_value = NULL;
667fcf382e2SArnaud Pouliquen 	uint32_t tlv_v = 0;
668fcf382e2SArnaud Pouliquen 	size_t length = 0;
669fcf382e2SArnaud Pouliquen 
670fcf382e2SArnaud Pouliquen 	/* Get the size of the image to load, from TLV data */
671fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, ctx->tlvs_sz, RPROC_TLV_IMGSIZE,
672fcf382e2SArnaud Pouliquen 				 &tlv_value, &length);
673fcf382e2SArnaud Pouliquen 	if (res)
674fcf382e2SArnaud Pouliquen 		return res;
675fcf382e2SArnaud Pouliquen 
676fcf382e2SArnaud Pouliquen 	if (length != (sizeof(*img_size) * num_img))
677fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
678fcf382e2SArnaud Pouliquen 
679fcf382e2SArnaud Pouliquen 	memcpy(&tlv_v, &tlv_value[sizeof(*img_size) * idx], sizeof(tlv_v));
680fcf382e2SArnaud Pouliquen 	*img_size = TEE_U32_FROM_LITTLE_ENDIAN(tlv_v);
681fcf382e2SArnaud Pouliquen 
682fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
683fcf382e2SArnaud Pouliquen }
684fcf382e2SArnaud Pouliquen 
get_segment_hash(struct remoteproc_context * ctx,uint8_t * src,uint32_t size,uint32_t da,uint32_t mem_size,uint8_t ** hash)685fcf382e2SArnaud Pouliquen static TEE_Result get_segment_hash(struct remoteproc_context *ctx, uint8_t *src,
686fcf382e2SArnaud Pouliquen 				   uint32_t size, uint32_t da,
687fcf382e2SArnaud Pouliquen 				   uint32_t mem_size, uint8_t **hash)
688fcf382e2SArnaud Pouliquen {
689fcf382e2SArnaud Pouliquen 	struct remoteproc_segment *peh = NULL;
690fcf382e2SArnaud Pouliquen 	unsigned int i = 0;
691fcf382e2SArnaud Pouliquen 	unsigned int nb_entry = ctx->nb_segment;
692fcf382e2SArnaud Pouliquen 
693fcf382e2SArnaud Pouliquen 	peh = (void *)(ctx->hash_table);
694fcf382e2SArnaud Pouliquen 
695fcf382e2SArnaud Pouliquen 	for (i = 0; i < nb_entry; peh++, i++) {
696fcf382e2SArnaud Pouliquen 		if (peh->phdr.p_paddr != da)
697fcf382e2SArnaud Pouliquen 			continue;
698fcf382e2SArnaud Pouliquen 
699fcf382e2SArnaud Pouliquen 		/*
700fcf382e2SArnaud Pouliquen 		 * Segment metadata are read from a non-secure memory.
701fcf382e2SArnaud Pouliquen 		 * Validate them using hash table data stored in secure memory.
702fcf382e2SArnaud Pouliquen 		 */
703fcf382e2SArnaud Pouliquen 		if (peh->phdr.p_type != PT_LOAD)
704fcf382e2SArnaud Pouliquen 			return TEE_ERROR_BAD_PARAMETERS;
705fcf382e2SArnaud Pouliquen 
706fcf382e2SArnaud Pouliquen 		if (peh->phdr.p_filesz != size || peh->phdr.p_memsz != mem_size)
707fcf382e2SArnaud Pouliquen 			return TEE_ERROR_BAD_PARAMETERS;
708fcf382e2SArnaud Pouliquen 
709fcf382e2SArnaud Pouliquen 		if (src < ctx->fw_img ||
710fcf382e2SArnaud Pouliquen 		    src >  (ctx->fw_img + ctx->fw_img_sz) ||
711fcf382e2SArnaud Pouliquen 		    (src + peh->phdr.p_filesz) > (ctx->fw_img + ctx->fw_img_sz))
712fcf382e2SArnaud Pouliquen 			return TEE_ERROR_BAD_PARAMETERS;
713fcf382e2SArnaud Pouliquen 
714fcf382e2SArnaud Pouliquen 		*hash = peh->hash;
715fcf382e2SArnaud Pouliquen 
716fcf382e2SArnaud Pouliquen 		return TEE_SUCCESS;
717fcf382e2SArnaud Pouliquen 	}
718fcf382e2SArnaud Pouliquen 
719fcf382e2SArnaud Pouliquen 	return TEE_ERROR_NO_DATA;
720fcf382e2SArnaud Pouliquen }
721fcf382e2SArnaud Pouliquen 
remoteproc_load_segment(uint8_t * src,uint32_t size,uint32_t da,uint32_t mem_size,void * priv)722fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_load_segment(uint8_t *src, uint32_t size,
723fcf382e2SArnaud Pouliquen 					  uint32_t da, uint32_t mem_size,
724fcf382e2SArnaud Pouliquen 					  void *priv)
725fcf382e2SArnaud Pouliquen {
726fcf382e2SArnaud Pouliquen 	struct remoteproc_context *ctx = priv;
727fcf382e2SArnaud Pouliquen 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
728fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_MEMREF_INPUT,
729fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_VALUE_INPUT,
730fcf382e2SArnaud Pouliquen 					       TEE_PARAM_TYPE_MEMREF_INPUT);
731fcf382e2SArnaud Pouliquen 	TEE_Param params[TEE_NUM_PARAMS] = { };
732fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
733fcf382e2SArnaud Pouliquen 	uint8_t *hash = NULL;
734fcf382e2SArnaud Pouliquen 
735fcf382e2SArnaud Pouliquen 	/*
736fcf382e2SArnaud Pouliquen 	 * Invoke platform remoteproc PTA to load the segment in remote
737fcf382e2SArnaud Pouliquen 	 * processor memory which is not mapped in the TA space.
738fcf382e2SArnaud Pouliquen 	 */
739fcf382e2SArnaud Pouliquen 
740fcf382e2SArnaud Pouliquen 	DMSG("Load segment %#"PRIx32" size %"PRIu32" (%"PRIu32")", da, size,
741fcf382e2SArnaud Pouliquen 	     mem_size);
742fcf382e2SArnaud Pouliquen 
743fcf382e2SArnaud Pouliquen 	res = get_segment_hash(ctx, src, size, da, mem_size, &hash);
744fcf382e2SArnaud Pouliquen 	if (res)
745fcf382e2SArnaud Pouliquen 		return res;
746fcf382e2SArnaud Pouliquen 
747fcf382e2SArnaud Pouliquen 	params[0].value.a = ctx->rproc_id;
748fcf382e2SArnaud Pouliquen 	params[1].memref.buffer = src;
749fcf382e2SArnaud Pouliquen 	params[1].memref.size = size;
750fcf382e2SArnaud Pouliquen 	params[2].value.a = da;
751fcf382e2SArnaud Pouliquen 	params[3].memref.buffer = hash;
752fcf382e2SArnaud Pouliquen 	params[3].memref.size = TEE_SHA256_HASH_SIZE;
753fcf382e2SArnaud Pouliquen 
754fcf382e2SArnaud Pouliquen 	if (size) {
755fcf382e2SArnaud Pouliquen 		res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
756fcf382e2SArnaud Pouliquen 					  PTA_RPROC_LOAD_SEGMENT_SHA256,
757fcf382e2SArnaud Pouliquen 					  param_types, params, NULL);
758fcf382e2SArnaud Pouliquen 		if (res != TEE_SUCCESS) {
759fcf382e2SArnaud Pouliquen 			EMSG("Fails to load segment, res = 0x%#"PRIx32, res);
760fcf382e2SArnaud Pouliquen 			return res;
761fcf382e2SArnaud Pouliquen 		}
762fcf382e2SArnaud Pouliquen 	}
763fcf382e2SArnaud Pouliquen 
764fcf382e2SArnaud Pouliquen 	/* Fill the rest of the memory with 0 */
765fcf382e2SArnaud Pouliquen 	if (size < mem_size) {
766fcf382e2SArnaud Pouliquen 		param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
767fcf382e2SArnaud Pouliquen 					      TEE_PARAM_TYPE_VALUE_INPUT,
768fcf382e2SArnaud Pouliquen 					      TEE_PARAM_TYPE_VALUE_INPUT,
769fcf382e2SArnaud Pouliquen 					      TEE_PARAM_TYPE_VALUE_INPUT);
770fcf382e2SArnaud Pouliquen 		params[1].value.a = da + size;
771fcf382e2SArnaud Pouliquen 		params[2].value.a = mem_size - size;
772fcf382e2SArnaud Pouliquen 		params[3].value.a = 0;
773fcf382e2SArnaud Pouliquen 
774fcf382e2SArnaud Pouliquen 		res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
775fcf382e2SArnaud Pouliquen 					  PTA_RPROC_SET_MEMORY,
776fcf382e2SArnaud Pouliquen 					  param_types, params, NULL);
777fcf382e2SArnaud Pouliquen 		if (res != TEE_SUCCESS)
778fcf382e2SArnaud Pouliquen 			EMSG("Fails to clear segment, res = %#"PRIx32, res);
779fcf382e2SArnaud Pouliquen 	}
780fcf382e2SArnaud Pouliquen 
781fcf382e2SArnaud Pouliquen 	return res;
782fcf382e2SArnaud Pouliquen }
783fcf382e2SArnaud Pouliquen 
remoteproc_load_elf(struct remoteproc_context * ctx)784fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_load_elf(struct remoteproc_context *ctx)
785fcf382e2SArnaud Pouliquen {
786fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
787fcf382e2SArnaud Pouliquen 	unsigned int num_img = 0;
788fcf382e2SArnaud Pouliquen 	unsigned int i = 0;
789fcf382e2SArnaud Pouliquen 	uint8_t img_type = REMOTEPROC_INVALID_TYPE;
790fcf382e2SArnaud Pouliquen 	uint32_t img_size = 0;
791fcf382e2SArnaud Pouliquen 	uint8_t *tlv = NULL;
792fcf382e2SArnaud Pouliquen 	int32_t offset = 0;
793fcf382e2SArnaud Pouliquen 	size_t length = 0;
7941a442a9fSArnaud Pouliquen 	paddr_t rsc_pa = 0;
7951a442a9fSArnaud Pouliquen 	size_t rsc_size = 0;
796fcf382e2SArnaud Pouliquen 
797fcf382e2SArnaud Pouliquen 	res = e32_parse_ehdr(ctx->fw_img, ctx->fw_img_sz);
798fcf382e2SArnaud Pouliquen 	if (res) {
799fcf382e2SArnaud Pouliquen 		EMSG("Failed to parse firmware, res = %#"PRIx32, res);
800fcf382e2SArnaud Pouliquen 		return res;
801fcf382e2SArnaud Pouliquen 	}
802fcf382e2SArnaud Pouliquen 
803fcf382e2SArnaud Pouliquen 	res = get_hash_table(ctx);
804fcf382e2SArnaud Pouliquen 	if (res)
805fcf382e2SArnaud Pouliquen 		return res;
806fcf382e2SArnaud Pouliquen 
807fcf382e2SArnaud Pouliquen 	/* Get the number of firmware images to load */
808fcf382e2SArnaud Pouliquen 	res = remoteproc_get_tlv(ctx->tlvs, ctx->tlvs_sz, RPROC_TLV_NUM_IMG,
809fcf382e2SArnaud Pouliquen 				 &tlv, &length);
810fcf382e2SArnaud Pouliquen 	if (res)
811fcf382e2SArnaud Pouliquen 		goto out;
812fcf382e2SArnaud Pouliquen 	if (length != sizeof(uint8_t)) {
813fcf382e2SArnaud Pouliquen 		res = TEE_ERROR_BAD_FORMAT;
814fcf382e2SArnaud Pouliquen 		goto out;
815fcf382e2SArnaud Pouliquen 	}
816fcf382e2SArnaud Pouliquen 
817fcf382e2SArnaud Pouliquen 	num_img = *tlv;
818fcf382e2SArnaud Pouliquen 	if (!num_img) {
819fcf382e2SArnaud Pouliquen 		res = TEE_ERROR_NO_DATA;
820fcf382e2SArnaud Pouliquen 		goto out;
821fcf382e2SArnaud Pouliquen 	}
822fcf382e2SArnaud Pouliquen 
8231a442a9fSArnaud Pouliquen 	/*
8241a442a9fSArnaud Pouliquen 	 * Initialize resource table with zero. These values will be returned if
8251a442a9fSArnaud Pouliquen 	 * no optional resource table is found in images.
8261a442a9fSArnaud Pouliquen 	 */
8271a442a9fSArnaud Pouliquen 	ctx->rsc_pa = 0;
8281a442a9fSArnaud Pouliquen 	ctx->rsc_size = 0;
8291a442a9fSArnaud Pouliquen 
830fcf382e2SArnaud Pouliquen 	for (i = 0; i < num_img; i++) {
831fcf382e2SArnaud Pouliquen 		res = get_tlv_images_type(ctx, num_img, i, &img_type);
832fcf382e2SArnaud Pouliquen 		if (res)
833fcf382e2SArnaud Pouliquen 			goto out;
834fcf382e2SArnaud Pouliquen 		if (img_type != REMOTEPROC_ELF_TYPE) {
835fcf382e2SArnaud Pouliquen 			res = TEE_ERROR_BAD_FORMAT;
836fcf382e2SArnaud Pouliquen 			goto out;
837fcf382e2SArnaud Pouliquen 		}
838fcf382e2SArnaud Pouliquen 
839fcf382e2SArnaud Pouliquen 		res = get_tlv_images_size(ctx, num_img, i, &img_size);
840fcf382e2SArnaud Pouliquen 		if (res)
841fcf382e2SArnaud Pouliquen 			goto out;
842fcf382e2SArnaud Pouliquen 
843fcf382e2SArnaud Pouliquen 		res = e32_parser_load_elf_image(ctx->fw_img + offset, img_size,
844fcf382e2SArnaud Pouliquen 						remoteproc_load_segment, ctx);
845fcf382e2SArnaud Pouliquen 		if (res)
846fcf382e2SArnaud Pouliquen 			goto out;
847fcf382e2SArnaud Pouliquen 
8481a442a9fSArnaud Pouliquen 		/* Take opportunity to get the resource table address */
8491a442a9fSArnaud Pouliquen 		res = remoteproc_parse_rsc_table(ctx, ctx->fw_img + offset,
8501a442a9fSArnaud Pouliquen 						 img_size, &rsc_pa, &rsc_size);
8511a442a9fSArnaud Pouliquen 		if (res != TEE_SUCCESS && res != TEE_ERROR_NO_DATA)
8521a442a9fSArnaud Pouliquen 			goto out;
8531a442a9fSArnaud Pouliquen 
8541a442a9fSArnaud Pouliquen 		if (res == TEE_SUCCESS) {
8551a442a9fSArnaud Pouliquen 			/*
8561a442a9fSArnaud Pouliquen 			 * Only one resource table is supported, check that no
8571a442a9fSArnaud Pouliquen 			 * other one has been declared in a previously loaded
8581a442a9fSArnaud Pouliquen 			 * firmware.
8591a442a9fSArnaud Pouliquen 			 */
8601a442a9fSArnaud Pouliquen 			if (ctx->rsc_pa || ctx->rsc_size) {
8611a442a9fSArnaud Pouliquen 				EMSG("More than one resource table found");
8621a442a9fSArnaud Pouliquen 				res = TEE_ERROR_BAD_FORMAT;
8631a442a9fSArnaud Pouliquen 				goto out;
8641a442a9fSArnaud Pouliquen 			}
8651a442a9fSArnaud Pouliquen 			ctx->rsc_pa = rsc_pa;
8661a442a9fSArnaud Pouliquen 			ctx->rsc_size = rsc_size;
8671a442a9fSArnaud Pouliquen 		} else {
8681a442a9fSArnaud Pouliquen 			/*
8691a442a9fSArnaud Pouliquen 			 * No resource table found. Force to TEE_SUCCESS as the
8701a442a9fSArnaud Pouliquen 			 * resource table is optional.
8711a442a9fSArnaud Pouliquen 			 */
8721a442a9fSArnaud Pouliquen 			res = TEE_SUCCESS;
8731a442a9fSArnaud Pouliquen 		}
874fcf382e2SArnaud Pouliquen 		offset += img_size;
875fcf382e2SArnaud Pouliquen 	}
876fcf382e2SArnaud Pouliquen 
877fcf382e2SArnaud Pouliquen out:
878fcf382e2SArnaud Pouliquen 	/* Should we clean-up the memories in case of fail ? */
879fcf382e2SArnaud Pouliquen 	TEE_Free(ctx->hash_table);
880fcf382e2SArnaud Pouliquen 	ctx->hash_table = NULL;
881fcf382e2SArnaud Pouliquen 
882fcf382e2SArnaud Pouliquen 	return res;
883fcf382e2SArnaud Pouliquen }
884fcf382e2SArnaud Pouliquen 
remoteproc_load_fw(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])885fcf382e2SArnaud Pouliquen static TEE_Result remoteproc_load_fw(uint32_t pt,
886fcf382e2SArnaud Pouliquen 				     TEE_Param params[TEE_NUM_PARAMS])
887fcf382e2SArnaud Pouliquen {
888fcf382e2SArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
889fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_MEMREF_INPUT,
890fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
891fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
892fcf382e2SArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
893fcf382e2SArnaud Pouliquen 	uint32_t rproc_id = params[0].value.a;
894fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
895fcf382e2SArnaud Pouliquen 
896fcf382e2SArnaud Pouliquen 	if (pt != exp_pt)
897fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
898fcf382e2SArnaud Pouliquen 
899fcf382e2SArnaud Pouliquen 	ctx = remoteproc_find_firmware(rproc_id);
900fcf382e2SArnaud Pouliquen 	if (!ctx)
901fcf382e2SArnaud Pouliquen 		ctx = remoteproc_add_firmware(rproc_id);
902fcf382e2SArnaud Pouliquen 	if (!ctx)
903fcf382e2SArnaud Pouliquen 		return TEE_ERROR_OUT_OF_MEMORY;
904fcf382e2SArnaud Pouliquen 
905ad50321fSArnaud Pouliquen 	/* The firmware is already loaded, do nothing */
906ad50321fSArnaud Pouliquen 	if (ctx->state == REMOTEPROC_LOADED)
907ad50321fSArnaud Pouliquen 		return TEE_SUCCESS;
908ad50321fSArnaud Pouliquen 
909fcf382e2SArnaud Pouliquen 	if (ctx->state != REMOTEPROC_OFF)
910fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_STATE;
911fcf382e2SArnaud Pouliquen 
912fcf382e2SArnaud Pouliquen 	if (!params[1].memref.buffer || !params[1].memref.size)
913fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
914fcf382e2SArnaud Pouliquen 
915fcf382e2SArnaud Pouliquen 	DMSG("Got base addr: %p size %#zx", params[1].memref.buffer,
916fcf382e2SArnaud Pouliquen 	     params[1].memref.size);
917fcf382e2SArnaud Pouliquen 
918fcf382e2SArnaud Pouliquen 	res = remoteproc_verify_firmware(ctx, params[1].memref.buffer,
919fcf382e2SArnaud Pouliquen 					 params[1].memref.size);
920fcf382e2SArnaud Pouliquen 	if (res) {
921fcf382e2SArnaud Pouliquen 		EMSG("Can't Authenticate the firmware (res = %#"PRIx32")", res);
922fcf382e2SArnaud Pouliquen 		goto out;
923fcf382e2SArnaud Pouliquen 	}
924fcf382e2SArnaud Pouliquen 
925fcf382e2SArnaud Pouliquen 	res = remoteproc_load_elf(ctx);
926fcf382e2SArnaud Pouliquen 	if (res)
927fcf382e2SArnaud Pouliquen 		goto out;
928fcf382e2SArnaud Pouliquen 
929fcf382e2SArnaud Pouliquen 	ctx->state = REMOTEPROC_LOADED;
930fcf382e2SArnaud Pouliquen 
931fcf382e2SArnaud Pouliquen out:
932fcf382e2SArnaud Pouliquen 	/* Clear reference to firmware image from shared memory */
933fcf382e2SArnaud Pouliquen 	ctx->fw_img = NULL;
934fcf382e2SArnaud Pouliquen 	ctx->fw_img_sz = 0;
935fcf382e2SArnaud Pouliquen 	ctx->nb_segment = 0;
936fcf382e2SArnaud Pouliquen 
937fcf382e2SArnaud Pouliquen 	/* Free allocated memories */
938fcf382e2SArnaud Pouliquen 	TEE_Free(ctx->sec_cpy);
939fcf382e2SArnaud Pouliquen 	ctx->sec_cpy = NULL;
940fcf382e2SArnaud Pouliquen 
941fcf382e2SArnaud Pouliquen 	return res;
942fcf382e2SArnaud Pouliquen }
943fcf382e2SArnaud Pouliquen 
remoteproc_start_fw(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])94456a69fb4SArnaud Pouliquen static TEE_Result remoteproc_start_fw(uint32_t pt,
94556a69fb4SArnaud Pouliquen 				      TEE_Param params[TEE_NUM_PARAMS])
94656a69fb4SArnaud Pouliquen {
94756a69fb4SArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
94856a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
94956a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
95056a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
95156a69fb4SArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
95256a69fb4SArnaud Pouliquen 	uint32_t rproc_id = params[0].value.a;
95356a69fb4SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
95456a69fb4SArnaud Pouliquen 
95556a69fb4SArnaud Pouliquen 	if (pt != exp_pt)
95656a69fb4SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
95756a69fb4SArnaud Pouliquen 
95856a69fb4SArnaud Pouliquen 	ctx = remoteproc_find_firmware(rproc_id);
95956a69fb4SArnaud Pouliquen 	if (!ctx)
96056a69fb4SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
96156a69fb4SArnaud Pouliquen 
96256a69fb4SArnaud Pouliquen 	switch (ctx->state) {
96356a69fb4SArnaud Pouliquen 	case REMOTEPROC_OFF:
96456a69fb4SArnaud Pouliquen 		res = TEE_ERROR_BAD_STATE;
96556a69fb4SArnaud Pouliquen 		break;
96656a69fb4SArnaud Pouliquen 	case REMOTEPROC_STARTED:
96756a69fb4SArnaud Pouliquen 		res = TEE_SUCCESS;
96856a69fb4SArnaud Pouliquen 		break;
96956a69fb4SArnaud Pouliquen 	case REMOTEPROC_LOADED:
97056a69fb4SArnaud Pouliquen 		res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
97156a69fb4SArnaud Pouliquen 					  PTA_RPROC_FIRMWARE_START,
97256a69fb4SArnaud Pouliquen 					  pt, params, NULL);
97356a69fb4SArnaud Pouliquen 		if (res == TEE_SUCCESS)
97456a69fb4SArnaud Pouliquen 			ctx->state = REMOTEPROC_STARTED;
97556a69fb4SArnaud Pouliquen 		break;
97656a69fb4SArnaud Pouliquen 	default:
97756a69fb4SArnaud Pouliquen 		res = TEE_ERROR_BAD_STATE;
97856a69fb4SArnaud Pouliquen 	}
97956a69fb4SArnaud Pouliquen 
98056a69fb4SArnaud Pouliquen 	return res;
98156a69fb4SArnaud Pouliquen }
98256a69fb4SArnaud Pouliquen 
remoteproc_stop_fw(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])98356a69fb4SArnaud Pouliquen static TEE_Result remoteproc_stop_fw(uint32_t pt,
98456a69fb4SArnaud Pouliquen 				     TEE_Param params[TEE_NUM_PARAMS])
98556a69fb4SArnaud Pouliquen {
98656a69fb4SArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
98756a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
98856a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
98956a69fb4SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
99056a69fb4SArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
99156a69fb4SArnaud Pouliquen 	uint32_t rproc_id = params[0].value.a;
99256a69fb4SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
99356a69fb4SArnaud Pouliquen 
99456a69fb4SArnaud Pouliquen 	if (pt != exp_pt)
99556a69fb4SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
99656a69fb4SArnaud Pouliquen 
99756a69fb4SArnaud Pouliquen 	ctx = remoteproc_find_firmware(rproc_id);
99856a69fb4SArnaud Pouliquen 	if (!ctx)
99956a69fb4SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
100056a69fb4SArnaud Pouliquen 
100156a69fb4SArnaud Pouliquen 	switch (ctx->state) {
100256a69fb4SArnaud Pouliquen 	case REMOTEPROC_LOADED:
100356a69fb4SArnaud Pouliquen 		res = TEE_ERROR_BAD_STATE;
100456a69fb4SArnaud Pouliquen 		break;
100556a69fb4SArnaud Pouliquen 	case REMOTEPROC_OFF:
100656a69fb4SArnaud Pouliquen 		res = TEE_SUCCESS;
100756a69fb4SArnaud Pouliquen 		break;
100856a69fb4SArnaud Pouliquen 	case REMOTEPROC_STARTED:
100956a69fb4SArnaud Pouliquen 		res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
101056a69fb4SArnaud Pouliquen 					  PTA_RPROC_FIRMWARE_STOP,
101156a69fb4SArnaud Pouliquen 					  pt, params, NULL);
101256a69fb4SArnaud Pouliquen 		if (res == TEE_SUCCESS)
101356a69fb4SArnaud Pouliquen 			ctx->state = REMOTEPROC_OFF;
101456a69fb4SArnaud Pouliquen 		break;
101556a69fb4SArnaud Pouliquen 	default:
101656a69fb4SArnaud Pouliquen 		res = TEE_ERROR_BAD_STATE;
101756a69fb4SArnaud Pouliquen 	}
101856a69fb4SArnaud Pouliquen 
101956a69fb4SArnaud Pouliquen 	return res;
102056a69fb4SArnaud Pouliquen }
102156a69fb4SArnaud Pouliquen 
remoteproc_get_rsc_table(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])10221a442a9fSArnaud Pouliquen static TEE_Result remoteproc_get_rsc_table(uint32_t pt,
10231a442a9fSArnaud Pouliquen 					   TEE_Param params[TEE_NUM_PARAMS])
10241a442a9fSArnaud Pouliquen {
10251a442a9fSArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
10261a442a9fSArnaud Pouliquen 						TEE_PARAM_TYPE_VALUE_OUTPUT,
10271a442a9fSArnaud Pouliquen 						TEE_PARAM_TYPE_VALUE_OUTPUT,
10281a442a9fSArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
10291a442a9fSArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
10301a442a9fSArnaud Pouliquen 
10311a442a9fSArnaud Pouliquen 	if (pt != exp_pt)
10321a442a9fSArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
10331a442a9fSArnaud Pouliquen 
10341a442a9fSArnaud Pouliquen 	ctx = remoteproc_find_firmware(params[0].value.a);
10351a442a9fSArnaud Pouliquen 	if (!ctx)
10361a442a9fSArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
10371a442a9fSArnaud Pouliquen 
10381a442a9fSArnaud Pouliquen 	if (ctx->state == REMOTEPROC_OFF)
10391a442a9fSArnaud Pouliquen 		return TEE_ERROR_BAD_STATE;
10401a442a9fSArnaud Pouliquen 
10411a442a9fSArnaud Pouliquen 	reg_pair_from_64((uint64_t)ctx->rsc_pa,
10421a442a9fSArnaud Pouliquen 			 &params[1].value.b, &params[1].value.a);
10431a442a9fSArnaud Pouliquen 	reg_pair_from_64((uint64_t)ctx->rsc_size,
10441a442a9fSArnaud Pouliquen 			 &params[2].value.b, &params[2].value.a);
10451a442a9fSArnaud Pouliquen 
10461a442a9fSArnaud Pouliquen 	return TEE_SUCCESS;
10471a442a9fSArnaud Pouliquen }
10481a442a9fSArnaud Pouliquen 
remoteproc_release_fw(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])10495c669b6dSArnaud Pouliquen static TEE_Result remoteproc_release_fw(uint32_t pt,
10505c669b6dSArnaud Pouliquen 					TEE_Param params[TEE_NUM_PARAMS])
10515c669b6dSArnaud Pouliquen {
10525c669b6dSArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
10535c669b6dSArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
10545c669b6dSArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
10555c669b6dSArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
10565c669b6dSArnaud Pouliquen 	struct remoteproc_context *ctx = NULL;
10575c669b6dSArnaud Pouliquen 	uint32_t rproc_id = params[0].value.a;
10585c669b6dSArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
10595c669b6dSArnaud Pouliquen 
10605c669b6dSArnaud Pouliquen 	if (pt != exp_pt)
10615c669b6dSArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
10625c669b6dSArnaud Pouliquen 
10635c669b6dSArnaud Pouliquen 	ctx = remoteproc_find_firmware(rproc_id);
10645c669b6dSArnaud Pouliquen 	if (!ctx)
10655c669b6dSArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
10665c669b6dSArnaud Pouliquen 
10675c669b6dSArnaud Pouliquen 	if (ctx->state == REMOTEPROC_STARTED)
10685c669b6dSArnaud Pouliquen 		return TEE_ERROR_BAD_STATE;
10695c669b6dSArnaud Pouliquen 
10705c669b6dSArnaud Pouliquen 	res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE,
10715c669b6dSArnaud Pouliquen 				  PTA_REMOTEPROC_RELEASE, pt, params, NULL);
10725c669b6dSArnaud Pouliquen 	if (res == TEE_SUCCESS)
10735c669b6dSArnaud Pouliquen 		ctx->state = REMOTEPROC_OFF;
10745c669b6dSArnaud Pouliquen 
10755c669b6dSArnaud Pouliquen 	return res;
10765c669b6dSArnaud Pouliquen }
10775c669b6dSArnaud Pouliquen 
TA_CreateEntryPoint(void)1078fcf382e2SArnaud Pouliquen TEE_Result TA_CreateEntryPoint(void)
1079fcf382e2SArnaud Pouliquen {
1080fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
1081fcf382e2SArnaud Pouliquen }
1082fcf382e2SArnaud Pouliquen 
TA_DestroyEntryPoint(void)1083fcf382e2SArnaud Pouliquen void TA_DestroyEntryPoint(void)
1084fcf382e2SArnaud Pouliquen {
1085fcf382e2SArnaud Pouliquen }
1086fcf382e2SArnaud Pouliquen 
1087fcf382e2SArnaud Pouliquen /*
1088fcf382e2SArnaud Pouliquen  * TA_OpenSessionEntryPoint: open a TA session associated to a remote processor
1089fcf382e2SArnaud Pouliquen  * to manage.
1090fcf382e2SArnaud Pouliquen  *
1091fcf382e2SArnaud Pouliquen  * [in] params[0].value.a:	Unique 32bit remote processor identifier
1092fcf382e2SArnaud Pouliquen  */
TA_OpenSessionEntryPoint(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS],void ** sess __unused)1093fcf382e2SArnaud Pouliquen TEE_Result TA_OpenSessionEntryPoint(uint32_t pt,
1094fcf382e2SArnaud Pouliquen 				    TEE_Param params[TEE_NUM_PARAMS],
1095fcf382e2SArnaud Pouliquen 				    void **sess __unused)
1096fcf382e2SArnaud Pouliquen {
1097fcf382e2SArnaud Pouliquen 	static const TEE_UUID uuid = PTA_RPROC_UUID;
1098fcf382e2SArnaud Pouliquen 	TEE_Result res = TEE_ERROR_GENERIC;
1099fcf382e2SArnaud Pouliquen 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1100fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
1101fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE,
1102fcf382e2SArnaud Pouliquen 						TEE_PARAM_TYPE_NONE);
1103fcf382e2SArnaud Pouliquen 
1104fcf382e2SArnaud Pouliquen 	if (pt != exp_pt)
1105fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
1106fcf382e2SArnaud Pouliquen 
1107fcf382e2SArnaud Pouliquen 	if (!session_refcount) {
1108fcf382e2SArnaud Pouliquen 		res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, pt, params,
1109fcf382e2SArnaud Pouliquen 					&pta_session, NULL);
1110fcf382e2SArnaud Pouliquen 		if (res)
1111fcf382e2SArnaud Pouliquen 			return res;
1112fcf382e2SArnaud Pouliquen 	}
1113fcf382e2SArnaud Pouliquen 
1114fcf382e2SArnaud Pouliquen 	session_refcount++;
1115fcf382e2SArnaud Pouliquen 
1116fcf382e2SArnaud Pouliquen 	return TEE_SUCCESS;
1117fcf382e2SArnaud Pouliquen }
1118fcf382e2SArnaud Pouliquen 
TA_CloseSessionEntryPoint(void * sess __unused)1119fcf382e2SArnaud Pouliquen void TA_CloseSessionEntryPoint(void *sess __unused)
1120fcf382e2SArnaud Pouliquen {
1121fcf382e2SArnaud Pouliquen 	session_refcount--;
1122fcf382e2SArnaud Pouliquen 
1123fcf382e2SArnaud Pouliquen 	if (!session_refcount)
1124fcf382e2SArnaud Pouliquen 		TEE_CloseTASession(pta_session);
1125fcf382e2SArnaud Pouliquen }
1126fcf382e2SArnaud Pouliquen 
TA_InvokeCommandEntryPoint(void * sess __unused,uint32_t cmd_id,uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])1127fcf382e2SArnaud Pouliquen TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd_id,
1128fcf382e2SArnaud Pouliquen 				      uint32_t pt,
1129fcf382e2SArnaud Pouliquen 				      TEE_Param params[TEE_NUM_PARAMS])
1130fcf382e2SArnaud Pouliquen {
1131fcf382e2SArnaud Pouliquen 	switch (cmd_id) {
1132fcf382e2SArnaud Pouliquen 	case TA_RPROC_CMD_LOAD_FW:
1133fcf382e2SArnaud Pouliquen 		return remoteproc_load_fw(pt, params);
1134fcf382e2SArnaud Pouliquen 	case TA_RPROC_CMD_START_FW:
113556a69fb4SArnaud Pouliquen 		return remoteproc_start_fw(pt, params);
1136fcf382e2SArnaud Pouliquen 	case TA_RPROC_CMD_STOP_FW:
113756a69fb4SArnaud Pouliquen 		return remoteproc_stop_fw(pt, params);
1138fcf382e2SArnaud Pouliquen 	case TA_RPROC_CMD_GET_RSC_TABLE:
11391a442a9fSArnaud Pouliquen 		return remoteproc_get_rsc_table(pt, params);
1140fcf382e2SArnaud Pouliquen 	case TA_RPROC_CMD_GET_COREDUMP:
1141fcf382e2SArnaud Pouliquen 		return TEE_ERROR_NOT_IMPLEMENTED;
11425c669b6dSArnaud Pouliquen 	case TA_RPROC_CMD_RELEASE_FW:
11435c669b6dSArnaud Pouliquen 		return remoteproc_release_fw(pt, params);
1144fcf382e2SArnaud Pouliquen 	default:
1145fcf382e2SArnaud Pouliquen 		return TEE_ERROR_BAD_PARAMETERS;
1146fcf382e2SArnaud Pouliquen 	}
1147fcf382e2SArnaud Pouliquen }
1148