sync with latest
[sdk/emulator/qemu.git] / tizen / src / emulator.c
1 /*
2  * Emulator
3  *
4  * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * SeokYeon Hwang <syeon.hwang@samsung.com>
8  * MunKyu Im <munkyu.im@samsung.com>
9  * GiWoong Kim <giwoong.kim@samsung.com>
10  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11  * HyunJun Son
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26  * MA 02110-1301, USA.
27  *
28  * Contributors:
29  * - S-Core Co., Ltd
30  *
31  */
32
33
34 #include "maru_common.h"
35 #include "emulator.h"
36 #include "osutil.h"
37 #include "guest_debug.h"
38 #include "sdb.h"
39 #include "string.h"
40 #include "skin/maruskin_server.h"
41 #include "skin/maruskin_client.h"
42 #include "guest_server.h"
43 #include "emul_state.h"
44 #include "qemu_socket.h"
45 #include "build_info.h"
46 #include "maru_err_table.h"
47 #include "maru_display.h"
48 #include "qemu-config.h"
49 #include "mloop_event.h"
50 #include "hw/maru_camera_common.h"
51 #include "hw/gloffscreen_test.h"
52 #include "debug_ch.h"
53
54 #include <stdlib.h>
55 #ifdef CONFIG_SDL
56 #include <SDL.h>
57 #endif
58
59 #ifdef CONFIG_DARWIN
60 #include "ns_event.h"
61 #endif
62
63 MULTI_DEBUG_CHANNEL(qemu, main);
64
65 #define QEMU_ARGS_PREFIX "--qemu-args"
66 #define SKIN_ARGS_PREFIX "--skin-args"
67 #define IMAGE_PATH_PREFIX   "file="
68 //#define IMAGE_PATH_SUFFIX   ",if=virtio"
69 #define IMAGE_PATH_SUFFIX   ",if=virtio,index=1"
70 #define SDB_PORT_PREFIX     "sdb_port="
71 #define LOGS_SUFFIX         "/logs/"
72 #define LOGFILE             "emulator.log"
73 #define LCD_WIDTH_PREFIX "width="
74 #define LCD_HEIGHT_PREFIX "height="
75
76 #define MIDBUF  128
77
78 gchar bin_path[PATH_MAX] = { 0, };
79 gchar log_path[PATH_MAX] = { 0, };
80
81 int tizen_base_port;
82 char tizen_target_path[PATH_MAX];
83 char tizen_target_img_path[PATH_MAX];
84
85 int enable_gl = 0;
86 int enable_yagl = 0;
87
88 int is_webcam_enabled;
89
90 #define LEN_MARU_KERNEL_CMDLINE 512
91 gchar maru_kernel_cmdline[LEN_MARU_KERNEL_CMDLINE];
92
93 static int _skin_argc;
94 static char **_skin_argv;
95 static int _qemu_argc;
96 static char **_qemu_argv;
97
98 #if defined(CONFIG_LINUX)
99 #include <sys/shm.h>
100 extern int g_shmid;
101 #endif
102
103 #ifdef CONFIG_DARWIN
104 int thread_running = 1; /* Check if we need exit main */
105 #endif
106
107 const gchar *get_log_path(void)
108 {
109     return log_path;
110 }
111
112 void exit_emulator(void)
113 {
114     mloop_ev_stop();
115     shutdown_skin_server();
116     shutdown_guest_server();
117
118 #if defined(CONFIG_LINUX)
119     /* clean up the vm lock memory by munkyu */
120     if (shmctl(g_shmid, IPC_RMID, 0) == -1) {
121         ERR("shmctl failed\n");
122         perror("emulator.c: ");
123     }
124 #endif
125
126     maru_display_fini();
127 }
128
129 static void construct_main_window(int skin_argc, char *skin_argv[],
130                                 int qemu_argc, char *qemu_argv[])
131 {
132     INFO("construct main window\n");
133
134     start_skin_server(skin_argc, skin_argv, qemu_argc, qemu_argv);
135
136     /* the next line checks for debugging and etc.. */
137     if (get_emul_skin_enable() == 1) {
138         if (0 > start_skin_client(skin_argc, skin_argv)) {
139             maru_register_exit_msg(MARU_EXIT_SKIN_SERVER_FAILED, NULL);
140             exit(-1);
141         }
142     }
143
144     set_emul_caps_lock_state(0);
145     set_emul_num_lock_state(0);
146 }
147
148 static void parse_options(int argc, char *argv[], int *skin_argc,
149                         char ***skin_argv, int *qemu_argc, char ***qemu_argv)
150 {
151     int i = 0;
152     int skin_args_index = 0;
153
154     if (argc <= 1) {
155         fprintf(stderr, "Arguments are not enough to launch Emulator. "
156                 "Please try to use Emulator Manager.\n");
157         exit(1);
158     }
159
160     /* classification */
161     for (i = 1; i < argc; ++i) {
162         if (strstr(argv[i], SKIN_ARGS_PREFIX)) {
163             *skin_argv = &(argv[i + 1]);
164             break;
165         }
166     }
167
168     for (skin_args_index = i; skin_args_index < argc; ++skin_args_index) {
169         if (strstr(argv[skin_args_index], QEMU_ARGS_PREFIX)) {
170             *skin_argc = skin_args_index - i - 1;
171
172             *qemu_argc = argc - skin_args_index - i + 1;
173             *qemu_argv = &(argv[skin_args_index]);
174
175             argv[skin_args_index] = argv[0];
176         }
177     }
178 }
179
180 static void get_host_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
181 {
182     get_host_proxy_os(http_proxy, https_proxy, ftp_proxy, socks_proxy);
183 }
184
185 static void set_bin_path(gchar * exec_argv)
186 {
187     set_bin_path_os(exec_argv);
188 }
189
190 gchar * get_bin_path(void)
191 {
192     return bin_path;
193 }
194
195 static void check_vm_lock(void)
196 {
197     check_vm_lock_os();
198 }
199
200 static void make_vm_lock(void)
201 {
202     make_vm_lock_os();
203 }
204
205 static void set_image_and_log_path(char *qemu_argv)
206 {
207     int i, j = 0;
208     int name_len = 0;
209     int prefix_len = 0;
210     int suffix_len = 0;
211     int max = 0;
212     char *path = malloc(PATH_MAX);
213     name_len = strlen(qemu_argv);
214     prefix_len = strlen(IMAGE_PATH_PREFIX);
215     suffix_len = strlen(IMAGE_PATH_SUFFIX);
216     max = name_len - suffix_len;
217     for (i = prefix_len , j = 0; i < max; i++) {
218         path[j++] = qemu_argv[i];
219     }
220     path[j] = '\0';
221     if (!g_path_is_absolute(path)) {
222         strcpy(tizen_target_path, g_get_current_dir());
223     } else {
224         strcpy(tizen_target_path, g_path_get_dirname(path));
225     }
226
227     strcpy(tizen_target_img_path, path);
228     free(path);
229
230     strcpy(log_path, tizen_target_path);
231     strcat(log_path, LOGS_SUFFIX);
232 #ifdef CONFIG_WIN32
233     if (access(g_win32_locale_filename_from_utf8(log_path), R_OK) != 0) {
234         g_mkdir(g_win32_locale_filename_from_utf8(log_path), 0755);
235     }
236 #else
237     if (access(log_path, R_OK) != 0) {
238         g_mkdir(log_path, 0755);
239     }
240 #endif
241     strcat(log_path, LOGFILE);
242 }
243
244 static void redir_output(void)
245 {
246     FILE *fp;
247
248     fp = freopen(log_path, "a+", stdout);
249     if (fp == NULL) {
250         fprintf(stderr, "log file open error\n");
251     }
252
253     fp = freopen(log_path, "a+", stderr);
254     if (fp == NULL) {
255         fprintf(stderr, "log file open error\n");
256     }
257     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
258     setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
259 }
260
261 static void extract_qemu_info(int qemu_argc, char **qemu_argv)
262 {
263     int i = 0;
264
265     for (i = 0; i < qemu_argc; ++i) {
266         if (strstr(qemu_argv[i], IMAGE_PATH_PREFIX) != NULL) {
267             set_image_and_log_path(qemu_argv[i]);
268             break;
269         }
270     }
271
272 }
273
274 static void extract_skin_info(int skin_argc, char **skin_argv)
275 {
276     int i = 0;
277     int w = 0, h = 0;
278
279     for (i = 0; i < skin_argc; ++i) {
280         if (strstr(skin_argv[i], LCD_WIDTH_PREFIX) != NULL) {
281             char *width_arg = skin_argv[i] + strlen(LCD_WIDTH_PREFIX);
282             w = atoi(width_arg);
283
284             INFO("lcd width option = %d\n", w);
285         } else if (strstr(skin_argv[i], LCD_HEIGHT_PREFIX) != NULL) {
286             char *height_arg = skin_argv[i] + strlen(LCD_HEIGHT_PREFIX);
287             h = atoi(height_arg);
288
289             INFO("lcd height option = %d\n", h);
290         }
291
292         if (w != 0 && h != 0) {
293             set_emul_lcd_size(w, h);
294             break;
295         }
296     }
297 }
298
299
300 static void print_system_info(void)
301 {
302 #define DIV 1024
303
304     char timeinfo[64] = {0, };
305     struct tm *tm_time;
306     struct timeval tval;
307
308     INFO("* Board name : %s\n", build_version);
309     INFO("* Package %s\n", pkginfo_version);
310     INFO("* Package %s\n", pkginfo_maintainer);
311     INFO("* Git Head : %s\n", pkginfo_githead);
312     INFO("* User name : %s\n", g_get_real_name());
313     INFO("* Host name : %s\n", g_get_host_name());
314
315     /* timestamp */
316     INFO("* Build date : %s\n", build_date);
317     gettimeofday(&tval, NULL);
318     tm_time = localtime(&(tval.tv_sec));
319     strftime(timeinfo, sizeof(timeinfo), "%Y/%m/%d %H:%M:%S", tm_time);
320     INFO("* Current time : %s\n", timeinfo);
321
322 #ifdef CONFIG_SDL
323     /* Gets the version of the dynamically linked SDL library */
324     INFO("* Host sdl version : (%d, %d, %d)\n",
325         SDL_Linked_Version()->major,
326         SDL_Linked_Version()->minor,
327         SDL_Linked_Version()->patch);
328 #endif
329     print_system_info_os();
330 }
331
332 typedef struct {
333     const char *device_name;
334     int found;
335 } device_opt_finding_t;
336
337 static int find_device_opt (QemuOpts *opts, void *opaque)
338 {
339     device_opt_finding_t *devp = (device_opt_finding_t *) opaque;
340     if (devp->found == 1) {
341         return 0;
342     }
343
344     const char *str = qemu_opt_get (opts, "driver");
345     if (strcmp (str, devp->device_name) == 0) {
346         devp->found = 1;
347     }
348     return 0;
349 }
350
351 #define DEFAULT_QEMU_DNS_IP "10.0.2.3"
352 static void prepare_basic_features(void)
353 {
354     char http_proxy[MIDBUF] ={0}, https_proxy[MIDBUF] = {0,},
355         ftp_proxy[MIDBUF] = {0,}, socks_proxy[MIDBUF] = {0,},
356         dns[MIDBUF] = {0};
357
358     tizen_base_port = get_sdb_base_port();
359
360     get_host_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
361     /* using "DNS" provided by default QEMU */
362     g_strlcpy(dns, DEFAULT_QEMU_DNS_IP, strlen(DEFAULT_QEMU_DNS_IP) + 1);
363
364     check_vm_lock();
365     socket_init();
366     make_vm_lock();
367
368     sdb_setup(); /* determine the base port for emulator */
369     set_emul_vm_base_port(tizen_base_port);
370
371     gchar * const tmp_str = g_strdup_printf(" sdb_port=%d,"
372         " http_proxy=%s https_proxy=%s ftp_proxy=%s socks_proxy=%s"
373         " dns1=%s", get_emul_vm_base_port(),
374         http_proxy, https_proxy, ftp_proxy, socks_proxy, dns);
375
376     g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
377
378     g_free(tmp_str);
379 }
380
381 #define VIRTIOGL_DEV_NAME "virtio-gl-pci"
382 #ifdef CONFIG_GL_BACKEND
383 static void prepare_opengl_acceleration(void)
384 {
385     int capability_check_gl = 0;
386
387     if (enable_gl && enable_yagl) {
388         ERR("Error: only one openGL passthrough device can be used at one time!\n");
389         exit(1);
390     }
391
392
393     if (enable_gl || enable_yagl) {
394         capability_check_gl = gl_acceleration_capability_check();
395
396         if (capability_check_gl != 0) {
397             enable_gl = enable_yagl = 0;
398             WARN("Warn: GL acceleration was disabled due to the fail of GL check!\n");
399         }
400     }
401     if (enable_gl) {
402         device_opt_finding_t devp = {VIRTIOGL_DEV_NAME, 0};
403         qemu_opts_foreach(qemu_find_opts("device"), find_device_opt, &devp, 0);
404         if (devp.found == 0) {
405             if (!qemu_opts_parse(qemu_find_opts("device"), VIRTIOGL_DEV_NAME, 1)) {
406                 exit(1);
407             }
408         }
409     }
410
411     gchar * const tmp_str = g_strdup_printf(" gles=%d yagl=%d", enable_gl, enable_yagl);
412
413     g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
414
415     g_free(tmp_str);
416 }
417 #endif
418
419 #define MARUCAM_DEV_NAME "maru_camera_pci"
420 #define WEBCAM_INFO_IGNORE 0x00
421 #define WEBCAM_INFO_WRITE 0x04
422 static void prepare_host_webcam(void)
423 {
424     is_webcam_enabled = marucam_device_check(WEBCAM_INFO_WRITE);
425
426     if (!is_webcam_enabled) {
427         INFO("[Webcam] <WARNING> Webcam support was disabled "
428                          "due to the fail of webcam capability check!\n");
429     }
430     else {
431         device_opt_finding_t devp = {MARUCAM_DEV_NAME, 0};
432         qemu_opts_foreach(qemu_find_opts("device"), find_device_opt, &devp, 0);
433         if (devp.found == 0) {
434             if (!qemu_opts_parse(qemu_find_opts("device"), MARUCAM_DEV_NAME, 1)) {
435                 INFO("Failed to initialize the marucam device.\n");
436                 exit(1);
437             }
438         }
439         INFO("[Webcam] Webcam support was enabled.\n");
440     }
441
442     gchar * const tmp_str = g_strdup_printf(" enable_cam=%d", is_webcam_enabled);
443
444     g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
445
446     g_free(tmp_str);
447 }
448
449 const gchar * prepare_maru_devices(const gchar *kernel_cmdline)
450 {
451     INFO("Prepare maru specified kernel command line\n");
452
453     g_strlcpy(maru_kernel_cmdline, kernel_cmdline, LEN_MARU_KERNEL_CMDLINE);
454
455     // Prepare basic features
456     prepare_basic_features();
457
458     // Prepare GL acceleration
459 #ifdef CONFIG_GL_BACKEND
460     prepare_opengl_acceleration();
461 #endif
462
463     // Prepare host webcam
464     prepare_host_webcam();
465
466     INFO("kernel command : %s\n", maru_kernel_cmdline);
467
468     return maru_kernel_cmdline;
469 }
470
471 int maru_device_check(QemuOpts *opts)
472 {
473 #if defined(CONFIG_GL_BACKEND)
474     // virtio-gl pci device
475     if (!enable_gl) {
476         // ignore virtio-gl-pci device, even if users set it in option.
477         const char *driver = qemu_opt_get(opts, "driver");
478         if (driver && (strcmp (driver, VIRTIOGL_DEV_NAME) == 0)) {
479             return -1;
480         }
481     }
482 #endif
483     if (!is_webcam_enabled) {
484         const char *driver = qemu_opt_get(opts, "driver");
485         if (driver && (strcmp (driver, MARUCAM_DEV_NAME) == 0)) {
486             return -1;
487         }
488     }
489
490     return 0;
491 }
492
493 void prepare_maru(void)
494 {
495     INFO("Prepare maru specified feature\n");
496
497     INFO("call construct_main_window\n");
498
499     construct_main_window(_skin_argc, _skin_argv, _qemu_argc, _qemu_argv);
500
501     int guest_server_port = tizen_base_port + SDB_UDP_SENSOR_INDEX;
502     start_guest_server(guest_server_port);
503
504     mloop_ev_init();
505 }
506
507 int qemu_main(int argc, char **argv, char **envp);
508
509 static int emulator_main(int argc, char *argv[])
510 {
511     parse_options(argc, argv, &_skin_argc,
512                 &_skin_argv, &_qemu_argc, &_qemu_argv);
513     set_bin_path(_qemu_argv[0]);
514     extract_qemu_info(_qemu_argc, _qemu_argv);
515
516     INFO("Emulator start !!!\n");
517     atexit(maru_atexit);
518
519     extract_skin_info(_skin_argc, _skin_argv);
520
521     print_system_info();
522
523     INFO("Prepare running...\n");
524     /* Redirect stdout and stderr after debug_ch is initialized. */
525     redir_output();
526     INFO("tizen_target_img_path: %s\n", tizen_target_img_path);
527     int i;
528
529     fprintf(stdout, "qemu args: =========================================\n");
530     for (i = 0; i < _qemu_argc; ++i) {
531         fprintf(stdout, "%s ", _qemu_argv[i]);
532     }
533     fprintf(stdout, "\nqemu args: =========================================\n");
534
535     fprintf(stdout, "skin args: =========================================\n");
536     for (i = 0; i < _skin_argc; ++i) {
537         fprintf(stdout, "%s ", _skin_argv[i]);
538     }
539     fprintf(stdout, "\nskin args: =========================================\n");
540
541     INFO("qemu main start!\n");
542     qemu_main(_qemu_argc, _qemu_argv, NULL);
543
544     exit_emulator();
545
546     return 0;
547 }
548
549 #ifndef CONFIG_DARWIN
550 int main(int argc, char *argv[])
551 {
552     return emulator_main(argc, argv);
553 }
554 #else
555 int g_argc;
556
557 static void* main_thread(void* args)
558 {
559     char** argv;
560     int argc = g_argc;
561     argv = (char**) args;
562
563     emulator_main(argc, argv);
564
565     thread_running = 0;
566     pthread_exit(NULL);
567 }
568
569 int main(int argc, char *argv[])
570 {
571     char** args;
572     pthread_t main_thread_id;
573
574     g_argc = argc;
575     args = argv;
576
577     if (0 != pthread_create(&main_thread_id, NULL, main_thread, args)) {
578         INFO("Create main thread failed\n");
579         return -1;
580     }
581
582     ns_event_loop(&thread_running);
583
584     return 0;
585 }
586 #endif
587