1 /*--------------------------------------------------------------------------
2 Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above
10       copyright notice, this list of conditions and the following
11       disclaimer in the documentation and/or other materials provided
12       with the distribution.
13     * Neither the name of The Linux Foundation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 --------------------------------------------------------------------------*/
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <dlfcn.h>
35 #include <sys/ioctl.h>
36 #include <pthread.h>
37 #include <time.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <sys/mman.h>
41 #include "hypv_intercept.h"
42 #ifdef _ANDROID_
43 #include <cutils/properties.h>
44 #endif
45 
46 #define MAX_HVFE_HANDLE             32
47 #define HYPV_HANDLE_SIGNATURE       0x2bcd0000
48 #define HYPV_HANDLE_SIGNATURE_MASK  0xffff0000
49 #define HYPV_HANDLE_MASK            0x0000ffff
50 #define POLL_TIMEOUT                0xffffffff
51 #define MAX_EVENTS                  32
52 
53 #define IS_HYPERVISOR_VIDEO_HANDLE(fd) ((fd & HYPV_HANDLE_SIGNATURE_MASK)==HYPV_HANDLE_SIGNATURE)
54 #define HYP_INITIALIZED  (g_hvfe_handle_count > 0)
55 #define NUM_PENDING_EVENTS(a, b) ((a > b) ? (a - b) : (b - a))
56 
57 typedef void* HVFE_HANDLE;
58 typedef int (*hvfe_callback_handler_t)(void *context, void *message);
59 
60 struct hypv_intercept {
61     HVFE_HANDLE  handle;
62     short event_flags[MAX_EVENTS];
63     bool exit_flag;
64     unsigned int event_q_front;
65     unsigned int event_q_rear;
66     pthread_t thread_id;
67     pthread_cond_t cond;
68     pthread_mutex_t lock;
69 };
70 
71 struct hvfe_callback_t
72 {
73     hvfe_callback_handler_t handler;
74     void* context;
75 };
76 
77 typedef void (*cb)(int flag);
78 typedef HVFE_HANDLE (*video_fe_open_func)(const char*, int, hvfe_callback_t*);
79 typedef int (*video_fe_ioctl_func)(HVFE_HANDLE, int, void*);
80 typedef int (*video_fe_close_func)(HVFE_HANDLE);
81 
82 static void *hvfe_lib_handle = NULL;
83 static video_fe_open_func video_fe_open = NULL;
84 static video_fe_ioctl_func video_fe_ioctl = NULL;
85 static video_fe_close_func video_fe_close = NULL;
86 static pthread_mutex_t g_hvfe_handle_lock = PTHREAD_MUTEX_INITIALIZER;
87 static struct hypv_intercept g_hvfe_handle[MAX_HVFE_HANDLE];
88 static int g_hvfe_handle_count  = 0;
89 static int event_notify(void *context, void *messages);
90 int debug_level = 0x1;
91 
add_handle_to_index(HVFE_HANDLE handle,int index)92 static int add_handle_to_index(HVFE_HANDLE handle, int index)
93 {
94     int rc = 0;
95 
96     memset(&g_hvfe_handle[index], 0, sizeof(struct hypv_intercept));
97     if (pthread_mutex_init(&g_hvfe_handle[index].lock, NULL) != 0) {
98         HYP_VIDEO_MSG_ERROR("error initializing pthread lock");
99         rc = -1;
100     } else if (pthread_cond_init(&g_hvfe_handle[index].cond, NULL) != 0) {
101         HYP_VIDEO_MSG_ERROR("error initializing pthread cond");
102         rc = -1;
103     } else {
104         g_hvfe_handle[index].handle = handle;
105         g_hvfe_handle_count++;
106     }
107 
108     return rc;
109 }
110 
find_empty_handle_index(void)111 static int find_empty_handle_index(void)
112 {
113     int rc = 0;
114 
115     if (g_hvfe_handle_count >= MAX_HVFE_HANDLE) {
116         HYP_VIDEO_MSG_ERROR("reached max handle count. handle count %d",
117                              g_hvfe_handle_count);
118         rc = -1;
119     } else {
120         int i;
121 
122         for (i = 0; i < MAX_HVFE_HANDLE; i++) {
123             if (g_hvfe_handle[i].handle == 0) {
124                 rc = i;
125                 break;
126             }
127         }
128 
129         if (i >= MAX_HVFE_HANDLE) {
130             HYP_VIDEO_MSG_ERROR("failed to find empty slot");
131             rc = -1;
132         }
133     }
134 
135     return rc;
136 }
137 
hypv_init(void)138 static int hypv_init(void)
139 {
140     int rc = 0;
141 
142     hvfe_lib_handle = dlopen("libhyp_video_fe.so", RTLD_NOW);
143     if (hvfe_lib_handle == NULL) {
144         HYP_VIDEO_MSG_ERROR("failed to open libhyp_video_fe");
145         rc = -1;
146     } else {
147         video_fe_open = (video_fe_open_func)dlsym(hvfe_lib_handle, "video_fe_open");
148         if (video_fe_open == NULL) {
149             HYP_VIDEO_MSG_ERROR("failed to get video_fe_open handle");
150             rc = -1;
151         } else {
152             video_fe_ioctl = (video_fe_ioctl_func)dlsym(hvfe_lib_handle, "video_fe_ioctl");
153             if (video_fe_ioctl == NULL) {
154                 HYP_VIDEO_MSG_ERROR("failed to get video_fe_ioctl handle");
155                 rc = -1;
156             } else {
157                 video_fe_close = (video_fe_close_func)dlsym(hvfe_lib_handle, "video_fe_close");
158                 if (video_fe_close == 0) {
159                     HYP_VIDEO_MSG_ERROR("failed to get video_fe_close handle");
160                     rc = -1;
161                 }//video_fe_close
162             } //video_fe_ioctl
163         } //video_fe_open
164     } //hvfe_lib_handle
165 
166     if (rc < 0 && hvfe_lib_handle) {
167         dlclose(hvfe_lib_handle);
168         hvfe_lib_handle = NULL;
169     }
170 
171     return rc;
172 }
173 
hypv_deinit(void)174 static void hypv_deinit(void)
175 {
176     dlclose(hvfe_lib_handle);
177     hvfe_lib_handle = NULL;
178 
179     return;
180 }
181 
hypv_open(const char * str,int flag)182 int hypv_open(const char *str, int flag)
183 {
184     int rc = 0;
185 
186 #ifdef _LINUX_
187     char *env_ptr = getenv("HYPV_DEBUG_LEVEL");
188     debug_level = env_ptr ? atoi(env_ptr) : 0;
189 #elif defined _ANDROID_
190     char property_value[PROPERTY_VALUE_MAX] = {0};
191 
192     property_get("vendor.hypv.debug.level", property_value, "1");
193     debug_level = atoi(property_value);
194 #endif
195 
196     pthread_mutex_lock(&g_hvfe_handle_lock);
197 
198     if (!HYP_INITIALIZED) {
199         if ((rc = hypv_init()) < 0) {
200             HYP_VIDEO_MSG_ERROR("hypervisor init failed");
201             pthread_mutex_unlock(&g_hvfe_handle_lock);
202             return rc;
203         }
204     }
205 
206     int index = find_empty_handle_index();
207     if (index < 0) {
208         rc = -1;
209     } else {
210         struct hvfe_callback_t cb;
211 
212         cb.handler = event_notify;
213         cb.context = &g_hvfe_handle[index];
214         HVFE_HANDLE hvfe_handle = video_fe_open(str, flag, &cb);
215         HYP_VIDEO_MSG_INFO("video fe open handle = %p", hvfe_handle);
216 
217         if (hvfe_handle == NULL) {
218             HYP_VIDEO_MSG_ERROR("video fe open failed");
219             rc = -1;
220         } else {
221             if (add_handle_to_index(hvfe_handle, index) < 0) {
222                 HYP_VIDEO_MSG_ERROR("failed to add hvfe handle");
223                 video_fe_close(hvfe_handle);
224                 rc = -1;
225             } else {
226                 rc = (HYPV_HANDLE_SIGNATURE | index);
227             }
228         }
229     }
230 
231     pthread_mutex_unlock(&g_hvfe_handle_lock);
232 
233     if (rc < 0)
234         hypv_deinit();
235 
236     return rc;
237 }
238 
hypv_ioctl(int fd,int cmd,void * data)239 int hypv_ioctl(int fd, int cmd, void *data)
240 {
241     int rc = 0;
242 
243     if (!HYP_INITIALIZED) {
244         HYP_VIDEO_MSG_ERROR("hypervisor not initialized");
245         return -1;
246     }
247 
248     if (IS_HYPERVISOR_VIDEO_HANDLE(fd)) {
249         int fd_index = fd & HYPV_HANDLE_MASK;
250         if (fd_index >= MAX_HVFE_HANDLE) {
251             HYP_VIDEO_MSG_ERROR("invalid fd_index = %d", fd_index);
252             rc = -1;
253         } else {
254             rc = video_fe_ioctl(g_hvfe_handle[fd_index].handle, cmd, data);
255             HYP_VIDEO_MSG_INFO("fd %d, fd_index %d, cmd 0x%x, data 0x%p, rc %d",
256                               fd, fd_index, cmd, data, rc);
257         }
258     } else {
259         HYP_VIDEO_MSG_ERROR("native ioctl: fd %d, cmd 0x%x, data 0x%p",
260                              fd, cmd, data);
261         rc = ioctl(fd, cmd, data);
262     }
263 
264     return rc;
265 }
266 
event_notify(void * context,void * messages)267 static int event_notify(void *context, void *messages)
268 {
269     struct hypv_intercept *handle = (struct hypv_intercept *)context;
270     int flags = *(int *)messages;
271 
272     HYP_VIDEO_MSG_INFO("event flag 0x%x", flags);
273     pthread_mutex_lock(&handle->lock);
274     handle->event_flags[handle->event_q_rear++] = flags;
275     handle->event_q_rear %= MAX_EVENTS;
276     HYP_VIDEO_MSG_INFO("cond signal. num_pending_events %d event_q_front %d event_q_rear %d",
277                         NUM_PENDING_EVENTS(handle->event_q_front, handle->event_q_rear),
278                         handle->event_q_front, handle->event_q_rear);
279     pthread_cond_signal(&handle->cond);
280     pthread_mutex_unlock(&handle->lock);
281 
282     return 0;
283 }
284 
exit_thread(void * fds)285 static void* exit_thread(void *fds)
286 {
287     struct pollfd *pfds = (struct pollfd *)fds;
288     int fd_index = pfds[0].fd & HYPV_HANDLE_MASK;
289     struct hypv_intercept *handle = &g_hvfe_handle[fd_index];
290     struct pollfd exit_fd;
291 
292     HYP_VIDEO_MSG_INFO("exit thread created. fd = %d", fd_index);
293     exit_fd.events = POLLIN | POLLERR;
294     exit_fd.fd = pfds[1].fd;
295 
296     poll(&exit_fd, 1, POLL_TIMEOUT);
297 
298     if ((exit_fd.revents & POLLIN) || (exit_fd.revents & POLLERR)) {
299        handle->exit_flag = true;
300        pthread_cond_signal(&handle->cond);
301     }
302 
303     return NULL;
304 }
305 
hypv_poll(struct pollfd * fds,nfds_t nfds,int timeout)306 int hypv_poll(struct pollfd *fds, nfds_t nfds, int timeout)
307 {
308     struct timespec ts;
309     int ret = 0;
310 
311     if (nfds == 0)
312         return -1;
313 
314     if (!HYP_INITIALIZED) {
315         HYP_VIDEO_MSG_ERROR("hypervisor not initialized");
316         return -1;
317     }
318 
319     if (IS_HYPERVISOR_VIDEO_HANDLE(fds[0].fd)) {
320         int fd_index = fds[0].fd & HYPV_HANDLE_MASK;
321 
322         if (fd_index >= MAX_HVFE_HANDLE) {
323             HYP_VIDEO_MSG_ERROR("invalid fd index %d", fd_index);
324             ret = -1;
325         } else {
326             struct hypv_intercept *handle = &g_hvfe_handle[fd_index];
327 
328             clock_gettime(CLOCK_REALTIME, &ts);
329             ts.tv_sec += timeout / 1000;
330             ts.tv_nsec = 0;
331             fds[1].revents = fds[0].revents = 0;
332 
333             if (handle->thread_id == 0) {
334                 if (pthread_create(&handle->thread_id, 0, exit_thread, fds)) {
335                     handle->thread_id = 0;
336                     return -1;
337                 }
338             }
339 
340             pthread_mutex_lock(&handle->lock);
341             if (!NUM_PENDING_EVENTS(handle->event_q_front, handle->event_q_rear) &&
342                 !handle->exit_flag) {
343                 ret = pthread_cond_timedwait(&handle->cond, &handle->lock, &ts);
344             }
345             else
346             {
347                 HYP_VIDEO_MSG_INFO("hypv_poll: process pending flag");
348             }
349 
350             if (ret == ETIMEDOUT) {
351                 HYP_VIDEO_MSG_INFO("hyp poll timeout");
352                 ret = 0;
353             } else if (ret == 0) {
354                 if (handle->exit_flag == true) {
355                     HYP_VIDEO_MSG_INFO("hyp poll exit");
356                     fds[1].revents = POLLIN;
357                     handle->exit_flag = false;
358                     handle->thread_id = 0;
359                 } else {
360                     fds[0].revents = handle->event_flags[handle->event_q_front++];
361                     handle->event_q_front %= MAX_EVENTS;
362                     HYP_VIDEO_MSG_INFO("hyp poll fd %d events 0x%x pending events %d",
363                                         fds[0].fd, fds[0].revents,
364                                         NUM_PENDING_EVENTS(handle->event_q_front, handle->event_q_rear));
365                 }
366                 ret = 1;
367             }
368 
369             pthread_mutex_unlock(&handle->lock);
370         }
371     } else {
372         HYP_VIDEO_MSG_ERROR("unknown fd = %d", fds[0].fd);
373     }
374 
375     return ret;
376 }
377 
hypv_close(int fd)378 int hypv_close(int fd)
379 {
380     int rc = 0;
381 
382     if (!HYP_INITIALIZED) {
383         HYP_VIDEO_MSG_ERROR("hypervisor not initialized");
384         return -1;
385     }
386 
387     if (IS_HYPERVISOR_VIDEO_HANDLE(fd)) {
388         int fd_index = fd & HYPV_HANDLE_MASK;
389 
390         if ((fd_index >= MAX_HVFE_HANDLE) || (fd_index < 0)) {
391             HYP_VIDEO_MSG_ERROR("invalid fd %d", fd_index);
392             rc = -1;
393         } else {
394             pthread_mutex_lock(&g_hvfe_handle_lock);
395             rc = video_fe_close(g_hvfe_handle[fd_index].handle);
396             g_hvfe_handle[fd_index].handle = 0;
397             pthread_cond_destroy(&g_hvfe_handle[fd_index].cond);
398             pthread_mutex_destroy(&g_hvfe_handle[fd_index].lock);
399             if (--g_hvfe_handle_count == 0)
400                 hypv_deinit();
401             pthread_mutex_unlock(&g_hvfe_handle_lock);
402         }
403     } else {
404         rc = close(fd);
405     }
406 
407     return rc;
408 }
409