1 /*
2 * Copyright 2020, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "secure_fb_ipc"
18
19 #include <lib/secure_fb/secure_fb.h>
20
21 #include <assert.h>
22 #include <inttypes.h>
23 #include <lib/tipc/tipc.h>
24 #include <lk/compiler.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/mman.h>
28 #include <trusty_ipc.h>
29 #include <trusty_log.h>
30 #include <uapi/err.h>
31
32 struct secure_fb_session {
33 handle_t chan;
34 size_t next_fb;
35 size_t num_fbs;
36 struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
37 };
38
new_secure_fb_session(void)39 static struct secure_fb_session* new_secure_fb_session(void) {
40 struct secure_fb_session* s = calloc(1, sizeof(*s));
41 if (s == NULL) {
42 return NULL;
43 }
44
45 s->chan = INVALID_IPC_HANDLE;
46 return s;
47 }
48
free_secure_fb_session(struct secure_fb_session * s)49 static void free_secure_fb_session(struct secure_fb_session* s) {
50 for (size_t i = 0; i < SECURE_FB_MAX_FBS; ++i) {
51 uint8_t** buffer = &s->fbs[i].fb_info.buffer;
52 if (*buffer) {
53 int rc = munmap(*buffer, s->fbs[i].fb_info.size);
54 if (rc != NO_ERROR) {
55 TLOGW("munmap() failed: %d\n", rc);
56 }
57 *buffer = NULL;
58 }
59 }
60 free(s);
61 }
62
new_connected_session(uint32_t idx)63 static struct secure_fb_session* new_connected_session(uint32_t idx) {
64 char port_name[SECURE_FB_MAX_PORT_NAME_SIZE] = {0};
65 struct secure_fb_session* s;
66 int rc;
67
68 if (idx >= SECURE_FB_MAX_INST) {
69 TLOGE("Invalid index %" PRIu32 "\n", idx);
70 return NULL;
71 }
72
73 int n = snprintf(port_name, sizeof(port_name), "%s.%d", SECURE_FB_PORT_NAME,
74 idx);
75 if (n != SECURE_FB_MAX_PORT_NAME_SIZE - 1) {
76 TLOGE("Failed to create port name\n");
77 return NULL;
78 }
79
80 s = new_secure_fb_session();
81 if (s == NULL) {
82 TLOGE("Failed to create session\n");
83 return NULL;
84 }
85
86 rc = tipc_connect(&s->chan, port_name);
87 if (rc != NO_ERROR) {
88 TLOGE("Failed to connect to \"%s_%d\" (%d)\n", SECURE_FB_PORT_NAME, idx,
89 rc);
90 free_secure_fb_session(s);
91 return NULL;
92 }
93
94 return s;
95 }
96
free_connected_session(struct secure_fb_session * s)97 static void free_connected_session(struct secure_fb_session* s) {
98 if (s->chan != INVALID_IPC_HANDLE) {
99 close(s->chan);
100 }
101 free_secure_fb_session(s);
102 }
103
await_resp(handle_t chan,struct ipc_msg * msg)104 static int await_resp(handle_t chan, struct ipc_msg* msg) {
105 int rc;
106 uevent_t event;
107
108 rc = wait(chan, &event, INFINITE_TIME);
109 if (rc < 0) {
110 TLOGE("Failed to wait for response (%d)\n", rc);
111 return rc;
112 }
113
114 ipc_msg_info_t msg_info;
115 rc = get_msg(chan, &msg_info);
116 if (rc != 0) {
117 TLOGE("Failed to get_msg (%d)\n", rc);
118 return rc;
119 }
120
121 rc = read_msg(chan, msg_info.id, 0, msg);
122 put_msg(chan, msg_info.id);
123 return rc;
124 }
125
mmap_fbs(struct secure_fb_desc * fbs,size_t num_fbs,handle_t * handles)126 static int mmap_fbs(struct secure_fb_desc* fbs,
127 size_t num_fbs,
128 handle_t* handles) {
129 struct secure_fb_desc* fb;
130
131 for (size_t i = 0; i < num_fbs; i++) {
132 fb = &fbs[i];
133 fb->fb_info.buffer =
134 mmap(NULL, fb->fb_info.size, PROT_READ | PROT_WRITE, 0,
135 handles[fb->handle_index], fb->offset);
136 if (fb->fb_info.buffer == MAP_FAILED) {
137 goto err;
138 }
139 }
140 return NO_ERROR;
141
142 err:
143 for (size_t i = 0; i < num_fbs; i++) {
144 fb = &fbs[i];
145 if (fb->fb_info.buffer) {
146 int rc = munmap(fb->fb_info.buffer, fb->fb_info.size);
147 if (rc != NO_ERROR) {
148 TLOGW("munmap() failed: %d\n", rc);
149 }
150 }
151 memset(fb, 0, sizeof(*fb));
152 }
153 return ERR_BAD_HANDLE;
154 }
155
handle_get_fbs_resp(struct secure_fb_session * s)156 static int handle_get_fbs_resp(struct secure_fb_session* s) {
157 int rc;
158 struct secure_fb_resp hdr;
159 struct secure_fb_get_fbs_resp args;
160 struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
161 size_t fbs_len;
162 handle_t handles[SECURE_FB_MAX_FBS] = {[0 ... SECURE_FB_MAX_FBS - 1] =
163 INVALID_IPC_HANDLE};
164 struct iovec iovs[] = {
165 {
166 .iov_base = &hdr,
167 .iov_len = sizeof(hdr),
168 },
169 {
170 .iov_base = &args,
171 .iov_len = sizeof(args),
172 },
173 {
174 .iov_base = fbs,
175 .iov_len = sizeof(fbs),
176 },
177 };
178 struct ipc_msg msg = {
179 .num_iov = countof(iovs),
180 .iov = iovs,
181 .num_handles = SECURE_FB_MAX_FBS,
182 .handles = handles,
183 };
184
185 rc = await_resp(s->chan, &msg);
186 if (rc < 0) {
187 return rc;
188 }
189
190 if (rc < (int)(sizeof(hdr) + sizeof(args))) {
191 return ERR_BAD_LEN;
192 }
193
194 fbs_len = sizeof(fbs[0]) * args.num_fbs;
195
196 if (rc != (int)(sizeof(hdr) + sizeof(args) + fbs_len)) {
197 if (rc >= 0) {
198 return ERR_BAD_LEN;
199 }
200 return rc;
201 }
202
203 if (hdr.cmd != (SECURE_FB_CMD_GET_FBS | SECURE_FB_CMD_RESP_BIT)) {
204 return ERR_CMD_UNKNOWN;
205 }
206
207 if (hdr.status != SECURE_FB_ERROR_OK) {
208 TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB request (%d)\n", hdr.status);
209 return ERR_GENERIC;
210 }
211
212 rc = mmap_fbs(fbs, args.num_fbs, handles);
213 /* Close all received handles. We don't need to keep them around. */
214 for (size_t i = 0; i < SECURE_FB_MAX_FBS; ++i) {
215 if (handles[i] != INVALID_IPC_HANDLE) {
216 close(handles[i]);
217 }
218 }
219
220 if (rc != NO_ERROR) {
221 TLOGE("Failed to mmap() framebuffers (%d)\n", hdr.status);
222 return rc;
223 }
224
225 for (size_t i = 0; i < (size_t)args.num_fbs; ++i) {
226 s->fbs[i] = fbs[i];
227 }
228 s->num_fbs = args.num_fbs;
229 s->next_fb = 0;
230 return NO_ERROR;
231 }
232
get_fbs(struct secure_fb_session * s)233 static int get_fbs(struct secure_fb_session* s) {
234 int rc;
235 struct secure_fb_req req;
236
237 assert(s->chan != INVALID_IPC_HANDLE);
238
239 req.cmd = SECURE_FB_CMD_GET_FBS;
240 rc = tipc_send1(s->chan, &req, sizeof(req));
241 if (rc != (int)sizeof(req)) {
242 TLOGE("Failed to send SECURE_FB_CMD_GET_FBS request (%d)\n", rc);
243 if (rc >= 0) {
244 rc = ERR_BAD_LEN;
245 }
246 return rc;
247 }
248
249 return handle_get_fbs_resp(s);
250 }
251
handle_display_fb_resp(handle_t chan)252 static int handle_display_fb_resp(handle_t chan) {
253 int rc;
254 struct uevent evt;
255 struct secure_fb_resp hdr;
256
257 rc = wait(chan, &evt, INFINITE_TIME);
258 if (rc != NO_ERROR) {
259 TLOGE("Error waiting for response (%d)\n", rc);
260 return rc;
261 }
262
263 rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
264 if (rc < 0) {
265 TLOGE("Failed to receive SECURE_FB_CMD_DISPLAY_FB response (%d)\n", rc);
266 return rc;
267 }
268
269 if (hdr.cmd != (SECURE_FB_CMD_DISPLAY_FB | SECURE_FB_CMD_RESP_BIT)) {
270 return ERR_CMD_UNKNOWN;
271 }
272
273 if (hdr.status != SECURE_FB_ERROR_OK) {
274 TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB (%d)\n", hdr.status);
275 return ERR_GENERIC;
276 }
277
278 return NO_ERROR;
279 }
280
display_fb(handle_t chan,uint32_t buffer_id)281 static int display_fb(handle_t chan, uint32_t buffer_id) {
282 int rc;
283 struct secure_fb_req hdr;
284 struct secure_fb_display_fb_req args;
285
286 hdr.cmd = SECURE_FB_CMD_DISPLAY_FB;
287 args.buffer_id = buffer_id;
288
289 rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
290 if (rc != (int)(sizeof(hdr) + sizeof(args))) {
291 TLOGE("Failed to send SECURE_FB_CMD_DISPLAY_FB request (%d)\n", rc);
292 return rc;
293 }
294
295 return handle_display_fb_resp(chan);
296 }
297
secure_fb_open(secure_fb_handle_t * session,struct secure_fb_info * fb_info,uint32_t idx)298 secure_fb_error secure_fb_open(secure_fb_handle_t* session,
299 struct secure_fb_info* fb_info,
300 uint32_t idx) {
301 int rc;
302 struct secure_fb_session* s;
303
304 if (!session) {
305 return TTUI_ERROR_UNEXPECTED_NULL_PTR;
306 }
307
308 s = new_connected_session(idx);
309 if (s == NULL) {
310 return TTUI_ERROR_NO_SERVICE;
311 }
312
313 rc = get_fbs(s);
314 if (rc != NO_ERROR) {
315 free_connected_session(s);
316 return TTUI_ERROR_MEMORY_ALLOCATION_FAILED;
317 }
318
319 *fb_info = s->fbs[s->next_fb].fb_info;
320 *session = (secure_fb_handle_t)s;
321 return TTUI_ERROR_OK;
322 }
323
secure_fb_display_next(secure_fb_handle_t session,struct secure_fb_info * fb_info)324 secure_fb_error secure_fb_display_next(secure_fb_handle_t session,
325 struct secure_fb_info* fb_info) {
326 int rc;
327 uint32_t buffer_id;
328 struct secure_fb_session* s = (struct secure_fb_session*)session;
329
330 if (!fb_info || !s) {
331 return TTUI_ERROR_UNEXPECTED_NULL_PTR;
332 }
333
334 buffer_id = s->fbs[s->next_fb].buffer_id;
335 rc = display_fb(s->chan, buffer_id);
336 if (rc != NO_ERROR) {
337 return TTUI_ERROR_NO_FRAMEBUFFER;
338 }
339
340 s->next_fb = (s->next_fb + 1) % s->num_fbs;
341 *fb_info = s->fbs[s->next_fb].fb_info;
342 return TTUI_ERROR_OK;
343 }
344
secure_fb_close(secure_fb_handle_t session)345 void secure_fb_close(secure_fb_handle_t session) {
346 int rc;
347 struct secure_fb_req req;
348 struct secure_fb_session* s = (struct secure_fb_session*)session;
349
350 if (!s || s->chan == INVALID_IPC_HANDLE) {
351 return;
352 }
353
354 req.cmd = SECURE_FB_CMD_RELEASE;
355 rc = tipc_send1(s->chan, &req, sizeof(req));
356 if (rc != (int)sizeof(req)) {
357 TLOGE("Failed to send SECURE_FB_CMD_RELEASE request (%d)\n", rc);
358 }
359
360 free_connected_session(s);
361 }
362