9da7bc80ad67bfbce887648c323bafc24dbc726e
[firefly-linux-kernel-4.4.55.git] / security / optee_linuxdriver / core / tee_kernel_api.c
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License Version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  */
13 #include <linux/module.h>
14 #include <linux/device.h>
15 #include <linux/miscdevice.h>
16 #include <linux/io.h>
17 #include <linux/vmalloc.h>
18
19 #include "linux/tee_kernel_api.h"
20 #include "linux/tee_core.h"
21 #include "linux/tee_ioc.h"
22
23 #include "tee_core_priv.h"
24 #include "tee_shm.h"
25 #include "tee_supp_com.h"
26
27 #define TEE_TZ_DEVICE_NAME      "opteearmtz00"
28
29 static void reset_tee_cmd(struct tee_cmd_io *cmd)
30 {
31         cmd->fd_sess = -1;
32         cmd->cmd = 0;
33         cmd->uuid = NULL;
34         cmd->origin = TEEC_ORIGIN_API;
35         cmd->err = TEEC_SUCCESS;
36         cmd->data = NULL;
37         cmd->data_size = 0;
38         cmd->op = NULL;
39 }
40
41 TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
42 {
43         struct tee *tee;
44         struct tee_context *ctx;
45         pr_cont("%s: > name=\"%s\"\n", __func__, name);
46
47         if (!context)
48                 return TEEC_ERROR_BAD_PARAMETERS;
49
50         context->fd = 0;
51
52         if (name == NULL)
53                 strncpy(context->devname, TEE_TZ_DEVICE_NAME,
54                         sizeof(context->devname));
55         else
56                 strncpy(context->devname, name, sizeof(context->devname));
57
58         tee = tee_get_tee(context->devname);
59         if (!tee) {
60                 pr_err("%s - can't get device [%s]\n", __func__, name);
61                 return TEEC_ERROR_BAD_PARAMETERS;
62         }
63
64         ctx = tee_context_create(tee);
65         if (IS_ERR_OR_NULL(ctx))
66                 return TEEC_ERROR_BAD_PARAMETERS;
67
68         ctx->usr_client = 0;
69
70         /* TODO fixme will not work on 64-bit platform */
71         context->fd = (int)(uintptr_t)ctx;
72         BUG_ON(ctx != (struct tee_context *)(uintptr_t)context->fd);
73
74         pr_cont("%s: < ctx=%p is created\n", __func__, (void *)ctx);
75         return TEEC_SUCCESS;
76 }
77 EXPORT_SYMBOL(TEEC_InitializeContext);
78
79 void TEEC_FinalizeContext(TEEC_Context *context)
80 {
81         if (!context || !context->fd) {
82                 pr_err("%s - can't release context %p:[%s]\n", __func__,
83                        context, (context
84                                  && context->devname) ? context->devname : "");
85                 return;
86         }
87         /* TODO fixme will not work on 64-bit platform */
88         tee_context_destroy((struct tee_context *)(uintptr_t)context->fd);
89         return;
90 }
91 EXPORT_SYMBOL(TEEC_FinalizeContext);
92
93 TEEC_Result TEEC_OpenSession(TEEC_Context *context,
94                              TEEC_Session *session,
95                              const TEEC_UUID *destination,
96                              uint32_t connectionMethod,
97                              const void *connectionData,
98                              TEEC_Operation *operation,
99                              uint32_t *return_origin)
100 {
101         TEEC_Operation dummy_op;
102         struct tee_cmd_io cmd;
103         struct tee_session *sess;
104         struct tee_context *ctx;
105
106         if (!operation) {
107                 /*
108                  * The code here exist because Global Platform API states that
109                  * it is allowed to give operation as a NULL pointer.
110                  * In kernel and secure world we in most cases don't want
111                  * this to be NULL, hence we use this dummy operation when
112                  * a client doesn't provide any operation.
113                  */
114                 memset(&dummy_op, 0, sizeof(TEEC_Operation));
115                 operation = &dummy_op;
116         }
117
118         if (!context || !session || !destination || !operation
119             || !return_origin)
120                 return TEEC_ERROR_BAD_PARAMETERS;
121
122         session->fd = 0;
123
124         /* TODO fixme will not work on 64-bit platform */
125         ctx = (struct tee_context *)(uintptr_t)context->fd;
126         reset_tee_cmd(&cmd);
127         cmd.op = operation;
128         cmd.uuid = (TEEC_UUID *) destination;
129
130         sess = tee_session_create_and_open(ctx, &cmd);
131         if (IS_ERR_OR_NULL(sess)) {
132                 if (cmd.origin)
133                         *return_origin = cmd.origin;
134                 else
135                         *return_origin = TEEC_ORIGIN_COMMS;
136                 if (cmd.err)
137                         return cmd.err;
138                 else
139                         return TEEC_ERROR_COMMUNICATION;
140         } else {
141                 *return_origin = cmd.origin;
142                 /* TODO fixme will not work on 64-bit platform */
143                 session->fd = (int)(uintptr_t)sess;
144                 BUG_ON(sess != (struct tee_session *)(uintptr_t)session->fd);
145                 return cmd.err;
146         }
147 }
148 EXPORT_SYMBOL(TEEC_OpenSession);
149
150 void TEEC_CloseSession(TEEC_Session *session)
151 {
152         if (session && session->fd) {
153                 /* TODO fixme will not work on 64-bit platform */
154                 struct tee_session *sess =
155                         (struct tee_session *)(uintptr_t)session->fd;
156                 tee_session_close_and_destroy(sess);
157         }
158 }
159 EXPORT_SYMBOL(TEEC_CloseSession);
160
161 TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
162                                uint32_t commandID,
163                                TEEC_Operation *operation,
164                                uint32_t *return_origin)
165 {
166         int ret = 0;
167         struct tee_cmd_io cmd;
168         struct tee_session *sess;
169
170         if (!session || !operation || !return_origin || !session->fd)
171                 return TEEC_ERROR_BAD_PARAMETERS;
172
173         /* TODO fixme will not work on 64-bit platform */
174         sess = (struct tee_session *)(uintptr_t)session->fd;
175         reset_tee_cmd(&cmd);
176         cmd.cmd = commandID;
177         cmd.op = operation;
178
179         ret = tee_session_invoke_be(sess, &cmd);
180         if (ret) {
181                 if (cmd.origin)
182                         *return_origin = cmd.origin;
183                 else
184                         *return_origin = TEEC_ORIGIN_COMMS;
185                 if (cmd.err)
186                         return cmd.err;
187                 else
188                         return TEEC_ERROR_COMMUNICATION;
189         } else {
190                 *return_origin = cmd.origin;
191                 return cmd.err;
192         }
193 }
194 EXPORT_SYMBOL(TEEC_InvokeCommand);
195
196 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
197                                       TEEC_SharedMemory *sharedMem)
198 {
199         if (!sharedMem)
200                 return TEEC_ERROR_BAD_PARAMETERS;
201
202         sharedMem->registered = 1;
203         return TEEC_SUCCESS;
204 }
205 EXPORT_SYMBOL(TEEC_RegisterSharedMemory);
206
207 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
208                                       TEEC_SharedMemory *shared_memory)
209 {
210         struct tee_shm_io shm_io;
211         int ret;
212         struct tee_shm *shm;
213
214         if (!context || !context->ctx || !shared_memory)
215                 return TEEC_ERROR_BAD_PARAMETERS;
216
217         shm_io.size = shared_memory->size;
218         shm_io.flags = shared_memory->flags | TEEC_MEM_KAPI;
219         ret = tee_shm_alloc_io(context->ctx, &shm_io);
220         if (ret) {
221                 pr_err("%s: tee_shm_alloc_io(%zd) failed\n", __func__,
222                        shared_memory->size);
223                 return TEEC_ERROR_OUT_OF_MEMORY;
224         }
225
226         shared_memory->registered = 0;
227         shared_memory->flags = shm_io.flags;
228         shared_memory->d.fd = shm_io.fd_shm;
229
230         shm = (struct tee_shm *)(long)shm_io.fd_shm;
231         shared_memory->buffer = shm->kaddr;
232
233         pr_debug("%s(%zd) => fd=%d, kaddr=%p\n", __func__,
234                  shm_io.size, shm_io.fd_shm, (void *)shared_memory->buffer);
235
236         return TEEC_SUCCESS;
237 }
238 EXPORT_SYMBOL(TEEC_AllocateSharedMemory);
239
240 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shared_memory)
241 {
242         struct tee_shm *shm;
243
244         if (!shared_memory || shared_memory->registered)
245                 return;
246
247         pr_debug("%s (vaddr = %p)\n", __func__, shared_memory->buffer);
248
249         shm = (struct tee_shm *)(long)shared_memory->d.fd;
250         tee_shm_free_io(shm);
251
252         shared_memory->buffer = NULL;
253         shared_memory->d.fd = 0;
254 }
255 EXPORT_SYMBOL(TEEC_ReleaseSharedMemory);