4 * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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>
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.
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.
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,
34 #include "maru_common.h"
37 #include "guest_debug.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"
63 MULTI_DEBUG_CHANNEL(qemu, main);
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="
78 gchar bin_path[PATH_MAX] = { 0, };
79 gchar log_path[PATH_MAX] = { 0, };
82 char tizen_target_path[PATH_MAX];
83 char tizen_target_img_path[PATH_MAX];
88 int is_webcam_enabled;
90 #define LEN_MARU_KERNEL_CMDLINE 512
91 gchar maru_kernel_cmdline[LEN_MARU_KERNEL_CMDLINE];
93 static int _skin_argc;
94 static char **_skin_argv;
95 static int _qemu_argc;
96 static char **_qemu_argv;
98 #if defined(CONFIG_LINUX)
104 int thread_running = 1; /* Check if we need exit main */
107 const gchar *get_log_path(void)
112 void exit_emulator(void)
115 shutdown_skin_server();
116 shutdown_guest_server();
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: ");
129 static void construct_main_window(int skin_argc, char *skin_argv[],
130 int qemu_argc, char *qemu_argv[])
132 INFO("construct main window\n");
134 start_skin_server(skin_argc, skin_argv, qemu_argc, qemu_argv);
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);
144 set_emul_caps_lock_state(0);
145 set_emul_num_lock_state(0);
148 static void parse_options(int argc, char *argv[], int *skin_argc,
149 char ***skin_argv, int *qemu_argc, char ***qemu_argv)
152 int skin_args_index = 0;
155 fprintf(stderr, "Arguments are not enough to launch Emulator. "
156 "Please try to use Emulator Manager.\n");
161 for (i = 1; i < argc; ++i) {
162 if (strstr(argv[i], SKIN_ARGS_PREFIX)) {
163 *skin_argv = &(argv[i + 1]);
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;
172 *qemu_argc = argc - skin_args_index - i + 1;
173 *qemu_argv = &(argv[skin_args_index]);
175 argv[skin_args_index] = argv[0];
180 static void get_host_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
182 get_host_proxy_os(http_proxy, https_proxy, ftp_proxy, socks_proxy);
185 static void set_bin_path(gchar * exec_argv)
187 set_bin_path_os(exec_argv);
190 gchar * get_bin_path(void)
195 static void check_vm_lock(void)
200 static void make_vm_lock(void)
205 static void set_image_and_log_path(char *qemu_argv)
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];
221 if (!g_path_is_absolute(path)) {
222 strcpy(tizen_target_path, g_get_current_dir());
224 strcpy(tizen_target_path, g_path_get_dirname(path));
227 strcpy(tizen_target_img_path, path);
230 strcpy(log_path, tizen_target_path);
231 strcat(log_path, LOGS_SUFFIX);
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);
237 if (access(log_path, R_OK) != 0) {
238 g_mkdir(log_path, 0755);
241 strcat(log_path, LOGFILE);
244 static void redir_output(void)
248 fp = freopen(log_path, "a+", stdout);
250 fprintf(stderr, "log file open error\n");
253 fp = freopen(log_path, "a+", stderr);
255 fprintf(stderr, "log file open error\n");
257 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
258 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
261 static void extract_qemu_info(int qemu_argc, char **qemu_argv)
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]);
274 static void extract_skin_info(int skin_argc, char **skin_argv)
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);
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);
289 INFO("lcd height option = %d\n", h);
292 if (w != 0 && h != 0) {
293 set_emul_lcd_size(w, h);
300 static void print_system_info(void)
304 char timeinfo[64] = {0, };
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());
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);
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);
329 print_system_info_os();
333 const char *device_name;
335 } device_opt_finding_t;
337 static int find_device_opt (QemuOpts *opts, void *opaque)
339 device_opt_finding_t *devp = (device_opt_finding_t *) opaque;
340 if (devp->found == 1) {
344 const char *str = qemu_opt_get (opts, "driver");
345 if (strcmp (str, devp->device_name) == 0) {
351 #define DEFAULT_QEMU_DNS_IP "10.0.2.3"
352 static void prepare_basic_features(void)
354 char http_proxy[MIDBUF] ={0}, https_proxy[MIDBUF] = {0,},
355 ftp_proxy[MIDBUF] = {0,}, socks_proxy[MIDBUF] = {0,},
358 tizen_base_port = get_sdb_base_port();
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);
368 sdb_setup(); /* determine the base port for emulator */
369 set_emul_vm_base_port(tizen_base_port);
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);
376 g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
381 #define VIRTIOGL_DEV_NAME "virtio-gl-pci"
382 #ifdef CONFIG_GL_BACKEND
383 static void prepare_opengl_acceleration(void)
385 int capability_check_gl = 0;
387 if (enable_gl && enable_yagl) {
388 ERR("Error: only one openGL passthrough device can be used at one time!\n");
393 if (enable_gl || enable_yagl) {
394 capability_check_gl = gl_acceleration_capability_check();
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");
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)) {
411 gchar * const tmp_str = g_strdup_printf(" gles=%d yagl=%d", enable_gl, enable_yagl);
413 g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
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)
424 is_webcam_enabled = marucam_device_check(WEBCAM_INFO_WRITE);
426 if (!is_webcam_enabled) {
427 INFO("[Webcam] <WARNING> Webcam support was disabled "
428 "due to the fail of webcam capability check!\n");
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");
439 INFO("[Webcam] Webcam support was enabled.\n");
442 gchar * const tmp_str = g_strdup_printf(" enable_cam=%d", is_webcam_enabled);
444 g_strlcat(maru_kernel_cmdline, tmp_str, LEN_MARU_KERNEL_CMDLINE);
449 const gchar * prepare_maru_devices(const gchar *kernel_cmdline)
451 INFO("Prepare maru specified kernel command line\n");
453 g_strlcpy(maru_kernel_cmdline, kernel_cmdline, LEN_MARU_KERNEL_CMDLINE);
455 // Prepare basic features
456 prepare_basic_features();
458 // Prepare GL acceleration
459 #ifdef CONFIG_GL_BACKEND
460 prepare_opengl_acceleration();
463 // Prepare host webcam
464 prepare_host_webcam();
466 INFO("kernel command : %s\n", maru_kernel_cmdline);
468 return maru_kernel_cmdline;
471 int maru_device_check(QemuOpts *opts)
473 #if defined(CONFIG_GL_BACKEND)
474 // virtio-gl pci device
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)) {
483 if (!is_webcam_enabled) {
484 const char *driver = qemu_opt_get(opts, "driver");
485 if (driver && (strcmp (driver, MARUCAM_DEV_NAME) == 0)) {
493 void prepare_maru(void)
495 INFO("Prepare maru specified feature\n");
497 INFO("call construct_main_window\n");
499 construct_main_window(_skin_argc, _skin_argv, _qemu_argc, _qemu_argv);
501 int guest_server_port = tizen_base_port + SDB_UDP_SENSOR_INDEX;
502 start_guest_server(guest_server_port);
507 int qemu_main(int argc, char **argv, char **envp);
509 static int emulator_main(int argc, char *argv[])
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);
516 INFO("Emulator start !!!\n");
519 extract_skin_info(_skin_argc, _skin_argv);
523 INFO("Prepare running...\n");
524 /* Redirect stdout and stderr after debug_ch is initialized. */
526 INFO("tizen_target_img_path: %s\n", tizen_target_img_path);
529 fprintf(stdout, "qemu args: =========================================\n");
530 for (i = 0; i < _qemu_argc; ++i) {
531 fprintf(stdout, "%s ", _qemu_argv[i]);
533 fprintf(stdout, "\nqemu args: =========================================\n");
535 fprintf(stdout, "skin args: =========================================\n");
536 for (i = 0; i < _skin_argc; ++i) {
537 fprintf(stdout, "%s ", _skin_argv[i]);
539 fprintf(stdout, "\nskin args: =========================================\n");
541 INFO("qemu main start!\n");
542 qemu_main(_qemu_argc, _qemu_argv, NULL);
549 #ifndef CONFIG_DARWIN
550 int main(int argc, char *argv[])
552 return emulator_main(argc, argv);
557 static void* main_thread(void* args)
561 argv = (char**) args;
563 emulator_main(argc, argv);
569 int main(int argc, char *argv[])
572 pthread_t main_thread_id;
577 if (0 != pthread_create(&main_thread_id, NULL, main_thread, args)) {
578 INFO("Create main thread failed\n");
582 ns_event_loop(&thread_running);