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 munmap(*buffer, s->fbs[i].fb_info.size);
54 *buffer = NULL;
55 }
56 }
57 free(s);
58 }
59
new_connected_session(uint32_t idx)60 static struct secure_fb_session* new_connected_session(uint32_t idx) {
61 char port_name[SECURE_FB_MAX_PORT_NAME_SIZE] = {0};
62 struct secure_fb_session* s;
63 int rc;
64
65 if (idx >= SECURE_FB_MAX_INST) {
66 TLOGE("Invalid index %" PRIu32 "\n", idx);
67 return NULL;
68 }
69
70 int n = snprintf(port_name, sizeof(port_name), "%s.%d", SECURE_FB_PORT_NAME,
71 idx);
72 if (n != SECURE_FB_MAX_PORT_NAME_SIZE - 1) {
73 TLOGE("Failed to create port name\n");
74 return NULL;
75 }
76
77 s = new_secure_fb_session();
78 if (s == NULL) {
79 TLOGE("Failed to create session\n");
80 return NULL;
81 }
82
83 rc = tipc_connect(&s->chan, port_name);
84 if (rc != NO_ERROR) {
85 TLOGE("Failed to connect to \"%s_%d\" (%d)\n", SECURE_FB_PORT_NAME, idx,
86 rc);
87 free_secure_fb_session(s);
88 return NULL;
89 }
90
91 return s;
92 }
93
free_connected_session(struct secure_fb_session * s)94 static void free_connected_session(struct secure_fb_session* s) {
95 if (s->chan != INVALID_IPC_HANDLE) {
96 close(s->chan);
97 }
98 free_secure_fb_session(s);
99 }
100
await_resp(handle_t chan,struct ipc_msg * msg)101 static int await_resp(handle_t chan, struct ipc_msg* msg) {
102 int rc;
103 uevent_t event;
104
105 rc = wait(chan, &event, INFINITE_TIME);
106 if (rc < 0) {
107 TLOGE("Failed to wait for response (%d)\n", rc);
108 return rc;
109 }
110
111 ipc_msg_info_t msg_info;
112 rc = get_msg(chan, &msg_info);
113 if (rc != 0) {
114 TLOGE("Failed to get_msg (%d)\n", rc);
115 return rc;
116 }
117
118 rc = read_msg(chan, msg_info.id, 0, msg);
119 put_msg(chan, msg_info.id);
120 return rc;
121 }
122
mmap_fbs(struct secure_fb_desc * fbs,size_t num_fbs,handle_t * handles)123 static int mmap_fbs(struct secure_fb_desc* fbs,
124 size_t num_fbs,
125 handle_t* handles) {
126 struct secure_fb_desc* fb;
127
128 for (size_t i = 0; i < num_fbs; i++) {
129 fb = &fbs[i];
130 fb->fb_info.buffer =
131 mmap(NULL, fb->fb_info.size, PROT_READ | PROT_WRITE, 0,
132 handles[fb->handle_index], fb->offset);
133 if (fb->fb_info.buffer == MAP_FAILED) {
134 goto err;
135 }
136 }
137 return NO_ERROR;
138
139 err:
140 for (size_t i = 0; i < num_fbs; i++) {
141 fb = &fbs[i];
142 if (fb->fb_info.buffer) {
143 munmap(fb->fb_info.buffer, fb->fb_info.size);
144 }
145 memset(fb, 0, sizeof(*fb));
146 }
147 return ERR_BAD_HANDLE;
148 }
149
handle_get_fbs_resp(struct secure_fb_session * s)150 static int handle_get_fbs_resp(struct secure_fb_session* s) {
151 int rc;
152 struct secure_fb_resp hdr;
153 struct secure_fb_get_fbs_resp args;
154 struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
155 size_t fbs_len;
156 handle_t handles[SECURE_FB_MAX_FBS] = {[0 ... SECURE_FB_MAX_FBS - 1] =
157 INVALID_IPC_HANDLE};
158 struct iovec iovs[] = {
159 {
160 .iov_base = &hdr,
161 .iov_len = sizeof(hdr),
162 },
163 {
164 .iov_base = &args,
165 .iov_len = sizeof(args),
166 },
167 {
168 .iov_base = fbs,
169 .iov_len = sizeof(fbs),
170 },
171 };
172 struct ipc_msg msg = {
173 .num_iov = countof(iovs),
174 .iov = iovs,
175 .num_handles = SECURE_FB_MAX_FBS,
176 .handles = handles,
177 };
178
179 rc = await_resp(s->chan, &msg);
180 if (rc < 0) {
181 return rc;
182 }
183
184 if (rc < (int)(sizeof(hdr) + sizeof(args))) {
185 return ERR_BAD_LEN;
186 }
187
188 fbs_len = sizeof(fbs[0]) * args.num_fbs;
189
190 if (rc != (int)(sizeof(hdr) + sizeof(args) + fbs_len)) {
191 if (rc >= 0) {
192 return ERR_BAD_LEN;
193 }
194 return rc;
195 }
196
197 if (hdr.cmd != (SECURE_FB_CMD_GET_FBS | SECURE_FB_CMD_RESP_BIT)) {
198 return ERR_CMD_UNKNOWN;
199 }
200
201 if (hdr.status != SECURE_FB_ERROR_OK) {
202 TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB request (%d)\n", hdr.status);
203 return ERR_GENERIC;
204 }
205
206 rc = mmap_fbs(fbs, args.num_fbs, handles);
207 /* Close all received handles. We don't need to keep them around. */
208 for (size_t i = 0; i < SECURE_FB_MAX_FBS; ++i) {
209 if (handles[i] != INVALID_IPC_HANDLE) {
210 close(handles[i]);
211 }
212 }
213
214 if (rc != NO_ERROR) {
215 TLOGE("Failed to mmap() framebuffers (%d)\n", hdr.status);
216 return rc;
217 }
218
219 for (size_t i = 0; i < (size_t)args.num_fbs; ++i) {
220 s->fbs[i] = fbs[i];
221 }
222 s->num_fbs = args.num_fbs;
223 s->next_fb = 0;
224 return NO_ERROR;
225 }
226
get_fbs(struct secure_fb_session * s)227 static int get_fbs(struct secure_fb_session* s) {
228 int rc;
229 struct secure_fb_req req;
230
231 assert(s->chan != INVALID_IPC_HANDLE);
232
233 req.cmd = SECURE_FB_CMD_GET_FBS;
234 rc = tipc_send1(s->chan, &req, sizeof(req));
235 if (rc != (int)sizeof(req)) {
236 TLOGE("Failed to send SECURE_FB_CMD_GET_FBS request (%d)\n", rc);
237 if (rc >= 0) {
238 rc = ERR_BAD_LEN;
239 }
240 return rc;
241 }
242
243 return handle_get_fbs_resp(s);
244 }
245
handle_display_fb_resp(handle_t chan)246 static int handle_display_fb_resp(handle_t chan) {
247 int rc;
248 struct uevent evt;
249 struct secure_fb_resp hdr;
250
251 rc = wait(chan, &evt, INFINITE_TIME);
252 if (rc != NO_ERROR) {
253 TLOGE("Error waiting for response (%d)\n", rc);
254 return rc;
255 }
256
257 rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
258 if (rc < 0) {
259 TLOGE("Failed to receive SECURE_FB_CMD_DISPLAY_FB response (%d)\n", rc);
260 return rc;
261 }
262
263 if (hdr.cmd != (SECURE_FB_CMD_DISPLAY_FB | SECURE_FB_CMD_RESP_BIT)) {
264 return ERR_CMD_UNKNOWN;
265 }
266
267 if (hdr.status != SECURE_FB_ERROR_OK) {
268 TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB (%d)\n", hdr.status);
269 return ERR_GENERIC;
270 }
271
272 return NO_ERROR;
273 }
274
display_fb(handle_t chan,uint32_t buffer_id)275 static int display_fb(handle_t chan, uint32_t buffer_id) {
276 int rc;
277 struct secure_fb_req hdr;
278 struct secure_fb_display_fb_req args;
279
280 hdr.cmd = SECURE_FB_CMD_DISPLAY_FB;
281 args.buffer_id = buffer_id;
282
283 rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
284 if (rc != (int)(sizeof(hdr) + sizeof(args))) {
285 TLOGE("Failed to send SECURE_FB_CMD_DISPLAY_FB request (%d)\n", rc);
286 return rc;
287 }
288
289 return handle_display_fb_resp(chan);
290 }
291
secure_fb_open(secure_fb_handle_t * session,struct secure_fb_info * fb_info,uint32_t idx)292 secure_fb_error secure_fb_open(secure_fb_handle_t* session,
293 struct secure_fb_info* fb_info,
294 uint32_t idx) {
295 int rc;
296 struct secure_fb_session* s;
297
298 if (!session) {
299 return TTUI_ERROR_UNEXPECTED_NULL_PTR;
300 }
301
302 s = new_connected_session(idx);
303 if (s == NULL) {
304 return TTUI_ERROR_NO_SERVICE;
305 }
306
307 rc = get_fbs(s);
308 if (rc != NO_ERROR) {
309 free_connected_session(s);
310 return TTUI_ERROR_MEMORY_ALLOCATION_FAILED;
311 }
312
313 *fb_info = s->fbs[s->next_fb].fb_info;
314 *session = (secure_fb_handle_t)s;
315 return TTUI_ERROR_OK;
316 }
317
secure_fb_display_next(secure_fb_handle_t session,struct secure_fb_info * fb_info)318 secure_fb_error secure_fb_display_next(secure_fb_handle_t session,
319 struct secure_fb_info* fb_info) {
320 int rc;
321 uint32_t buffer_id;
322 struct secure_fb_session* s = (struct secure_fb_session*)session;
323
324 if (!fb_info || !s) {
325 return TTUI_ERROR_UNEXPECTED_NULL_PTR;
326 }
327
328 buffer_id = s->fbs[s->next_fb].buffer_id;
329 rc = display_fb(s->chan, buffer_id);
330 if (rc != NO_ERROR) {
331 return TTUI_ERROR_NO_FRAMEBUFFER;
332 }
333
334 s->next_fb = (s->next_fb + 1) % s->num_fbs;
335 *fb_info = s->fbs[s->next_fb].fb_info;
336 return TTUI_ERROR_OK;
337 }
338
secure_fb_close(secure_fb_handle_t session)339 void secure_fb_close(secure_fb_handle_t session) {
340 int rc;
341 struct secure_fb_req req;
342 struct secure_fb_session* s = (struct secure_fb_session*)session;
343
344 if (!s || s->chan == INVALID_IPC_HANDLE) {
345 return;
346 }
347
348 req.cmd = SECURE_FB_CMD_RELEASE;
349 rc = tipc_send1(s->chan, &req, sizeof(req));
350 if (rc != (int)sizeof(req)) {
351 TLOGE("Failed to send SECURE_FB_CMD_RELEASE request (%d)\n", rc);
352 }
353
354 free_connected_session(s);
355 }
356