1// Copyright 2014 The Android Open Source Project
2//
3// This software is licensed under the terms of the GNU General Public
4// License version 2, as published by the Free Software Foundation, and
5// may be copied, distributed, and modified under those terms.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10// GNU General Public License for more details.
11
12// This source file implements emulator-arm64 and emulator64-arm64
13// which are used to launch QEMU binaries located under
14// $PROGRAM_DIR/qemu/<host>/qemu-system-aarch64<exe>
15
16#include "android/base/containers/StringVector.h"
17#include "android/base/files/PathUtils.h"
18#include "android/base/Limits.h"
19#include "android/base/Log.h"
20#include "android/base/String.h"
21#include "android/base/StringFormat.h"
22
23#include "android/cmdline-option.h"
24#include "android/globals.h"
25#include "android/help.h"
26#include "android/kernel/kernel_utils.h"
27#include "android/main-common.h"
28#include "android/utils/bufprint.h"
29#include "android/utils/debug.h"
30#include "android/utils/path.h"
31#include "android/utils/stralloc.h"
32#include "android/utils/win32_cmdline_quote.h"
33
34#include <limits.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38
39#define  STRINGIFY(x)   _STRINGIFY(x)
40#define  _STRINGIFY(x)  #x
41
42#ifdef ANDROID_SDK_TOOLS_REVISION
43#  define  VERSION_STRING  STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
44#else
45#  define  VERSION_STRING  "standalone"
46#endif
47
48#define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
49
50/* The execv() definition in older mingw is slightly bogus.
51 * It takes a second argument of type 'const char* const*'
52 * while POSIX mandates char** instead.
53 *
54 * To avoid compiler warnings, define the safe_execv macro
55 * to perform an explicit cast with mingw.
56 */
57#if defined(_WIN32) && !ANDROID_GCC_PREREQ(4,4)
58#  define safe_execv(_filepath,_argv)  execv((_filepath),(const char* const*)(_argv))
59#else
60#  define safe_execv(_filepath,_argv)  execv((_filepath),(_argv))
61#endif
62
63using namespace android::base;
64
65namespace {
66
67// The host CPU architecture.
68#ifdef __i386__
69const char kHostArch[] = "x86";
70#elif defined(__x86_64__)
71const char kHostArch[] = "x86_64";
72#else
73#error "Your host CPU is not supported!"
74#endif
75
76// The host operating system name.
77#ifdef __linux__
78static const char kHostOs[] = "linux";
79#elif defined(__APPLE__)
80static const char kHostOs[] = "darwin";
81#elif defined(_WIN32)
82static const char kHostOs[] = "windows";
83#endif
84
85// The target CPU architecture.
86const char kTargetArch[] = "aarch64";
87
88// Return the path of the QEMU executable
89String getQemuExecutablePath(const char* programPath) {
90    StringVector path = PathUtils::decompose(programPath);
91    if (path.size() < 1) {
92        return String();
93    }
94    // Remove program from path.
95    path.resize(path.size() - 1U);
96
97    // Add sub-directories.
98    path.append(String("qemu"));
99
100    String host = kHostOs;
101    host += "-";
102    host += kHostArch;
103    path.append(host);
104
105    String qemuProgram = "qemu-system-";
106    qemuProgram += kTargetArch;
107#ifdef _WIN32
108    qemuProgram += ".exe";
109#endif
110    path.append(qemuProgram);
111
112    return PathUtils::recompose(path);
113}
114
115void emulator_help( void ) {
116    STRALLOC_DEFINE(out);
117    android_help_main(out);
118    printf("%.*s", out->n, out->s);
119    stralloc_reset(out);
120    exit(1);
121}
122
123/* TODO: Put in shared source file */
124char* _getFullFilePath(const char* rootPath, const char* fileName) {
125    if (path_is_absolute(fileName)) {
126        return ASTRDUP(fileName);
127    } else {
128        char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
129
130        p = bufprint(temp, end, "%s/%s", rootPath, fileName);
131        if (p >= end) {
132            return NULL;
133        }
134        return ASTRDUP(temp);
135    }
136}
137
138uint64_t _adjustPartitionSize(const char*  description,
139                              uint64_t     imageBytes,
140                              uint64_t     defaultBytes,
141                              int          inAndroidBuild ) {
142    char      temp[64];
143    unsigned  imageMB;
144    unsigned  defaultMB;
145
146    if (imageBytes <= defaultBytes)
147        return defaultBytes;
148
149    imageMB   = convertBytesToMB(imageBytes);
150    defaultMB = convertBytesToMB(defaultBytes);
151
152    if (imageMB > defaultMB) {
153        snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
154    } else {
155        snprintf(temp, sizeof temp, "(%" PRIu64 "  bytes > %" PRIu64 " bytes)", imageBytes, defaultBytes);
156    }
157
158    if (inAndroidBuild) {
159        dwarning("%s partition size adjusted to match image file %s\n", description, temp);
160    }
161
162    return convertMBToBytes(imageMB);
163}
164
165bool android_op_wipe_data;
166
167}  // namespace
168
169extern "C" int main(int argc, char **argv, char **envp) {
170    if (argc < 1) {
171        fprintf(stderr, "Invalid invokation (no program path)\n");
172        return 1;
173    }
174
175    AndroidOptions opts[1];
176
177    if (android_parse_options(&argc, &argv, opts) < 0) {
178        return 1;
179    }
180
181    // TODO(digit): This code is very similar to the one in main.c,
182    // refactor everything so that it fits into a single shared source
183    // file, if possible, with the least amount of dependencies.
184
185    while (argc-- > 1) {
186        const char* opt = (++argv)[0];
187
188        if(!strcmp(opt, "-qemu")) {
189            argc--;
190            argv++;
191            break;
192        }
193
194        if (!strcmp(opt, "-help")) {
195            emulator_help();
196        }
197
198        if (!strncmp(opt, "-help-",6)) {
199            STRALLOC_DEFINE(out);
200            opt += 6;
201
202            if (!strcmp(opt, "all")) {
203                android_help_all(out);
204            }
205            else if (android_help_for_option(opt, out) == 0) {
206                /* ok */
207            }
208            else if (android_help_for_topic(opt, out) == 0) {
209                /* ok */
210            }
211            if (out->n > 0) {
212                printf("\n%.*s", out->n, out->s);
213                exit(0);
214            }
215
216            fprintf(stderr, "unknown option: -help-%s\n", opt);
217            fprintf(stderr, "please use -help for a list of valid topics\n");
218            exit(1);
219        }
220
221        if (opt[0] == '-') {
222            fprintf(stderr, "unknown option: %s\n", opt);
223            fprintf(stderr, "please use -help for a list of valid options\n");
224            exit(1);
225        }
226
227        fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
228        fprintf(stderr, "Hint: use '@foo' to launch a virtual device named 'foo'.\n");
229        fprintf(stderr, "please use -help for more information\n");
230        exit(1);
231    }
232
233    if (opts->version) {
234        printf("Android emulator version %s\n"
235               "Copyright (C) 2006-2011 The Android Open Source Project and many others.\n"
236               "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
237#if defined ANDROID_BUILD_ID
238               VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
239#else
240               VERSION_STRING);
241#endif
242        printf("  This software is licensed under the terms of the GNU General Public\n"
243               "  License version 2, as published by the Free Software Foundation, and\n"
244               "  may be copied, distributed, and modified under those terms.\n\n"
245               "  This program is distributed in the hope that it will be useful,\n"
246               "  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
247               "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
248               "  GNU General Public License for more details.\n\n");
249
250        exit(0);
251    }
252
253    sanitizeOptions(opts);
254
255    // Ignore snapshot storage here.
256
257    int inAndroidBuild = 0;
258    AvdInfo* avd = createAVD(opts, &inAndroidBuild);
259
260    // Ignore skin options here.
261
262    // Read hardware configuration, apply overrides from options.
263    AndroidHwConfig* hw = android_hw;
264    if (avdInfo_initHwConfig(avd, hw) < 0) {
265        derror("could not read hardware configuration ?");
266        exit(1);
267    }
268
269    /* Update CPU architecture for HW configs created from build dir. */
270    if (inAndroidBuild) {
271#if defined(TARGET_ARM)
272        reassign_string(&android_hw->hw_cpu_arch, "arm");
273#elif defined(TARGET_I386)
274        reassign_string(&android_hw->hw_cpu_arch, "x86");
275#elif defined(TARGET_MIPS)
276        reassign_string(&android_hw->hw_cpu_arch, "mips");
277#elif defined(TARGET_ARM64)
278        reassign_string(&android_hw->hw_cpu_arch, "arm64");
279#endif
280    }
281
282    /* generate arguments for the underlying qemu main() */
283    {
284        char*  kernelFile    = opts->kernel;
285
286        if (kernelFile == NULL) {
287            kernelFile = avdInfo_getKernelPath(avd);
288            if (kernelFile == NULL) {
289                derror( "This AVD's configuration is missing a kernel file!!" );
290                exit(2);
291            }
292            D("autoconfig: -kernel %s", kernelFile);
293        }
294        if (!path_exists(kernelFile)) {
295            derror( "Invalid or missing kernel image file: %s", kernelFile );
296            exit(2);
297        }
298
299        hw->kernel_path = kernelFile;
300    }
301
302    KernelType kernelType = KERNEL_TYPE_LEGACY;
303    if (!android_pathProbeKernelType(hw->kernel_path, &kernelType)) {
304        D("WARNING: Could not determine kernel device naming scheme. Assuming legacy\n"
305            "If this AVD doesn't boot, and uses a recent kernel (3.10 or above) try setting\n"
306            "'kernel.newDeviceNaming' to 'yes' in its configuration.\n");
307    }
308
309    // Auto-detect kernel device naming scheme if needed.
310    if (androidHwConfig_getKernelDeviceNaming(hw) < 0) {
311        const char* newDeviceNaming = "no";
312        if (kernelType == KERNEL_TYPE_3_10_OR_ABOVE) {
313            D("Auto-detect: Kernel image requires new device naming scheme.");
314            newDeviceNaming = "yes";
315        } else {
316            D("Auto-detect: Kernel image requires legacy device naming scheme.");
317        }
318        AFREE(hw->kernel_newDeviceNaming);
319        hw->kernel_newDeviceNaming = ASTRDUP(newDeviceNaming);
320    }
321
322    // Auto-detect YAFFS2 partition support if needed.
323    if (androidHwConfig_getKernelYaffs2Support(hw) < 0) {
324        // Essentially, anything before API level 20 supports Yaffs2
325        const char* newYaffs2Support = "no";
326        if (avdInfo_getApiLevel(avd) < 20) {
327            newYaffs2Support = "yes";
328            D("Auto-detect: Kernel does support YAFFS2 partitions.");
329        } else {
330            D("Auto-detect: Kernel does not support YAFFS2 partitions.");
331        }
332        AFREE(hw->kernel_supportsYaffs2);
333        hw->kernel_supportsYaffs2 = ASTRDUP(newYaffs2Support);
334    }
335
336
337    /* opts->ramdisk is never NULL (see createAVD) here */
338    if (opts->ramdisk) {
339        reassign_string(&hw->disk_ramdisk_path, opts->ramdisk);
340    }
341    else if (!hw->disk_ramdisk_path[0]) {
342        hw->disk_ramdisk_path = avdInfo_getRamdiskPath(avd);
343        D("autoconfig: -ramdisk %s", hw->disk_ramdisk_path);
344    }
345
346    /* -partition-size is used to specify the max size of both the system
347     * and data partition sizes.
348     */
349    uint64_t defaultPartitionSize = convertMBToBytes(200);
350
351    if (opts->partition_size) {
352        char*  end;
353        long   sizeMB = strtol(opts->partition_size, &end, 0);
354        long   minSizeMB = 10;
355        long   maxSizeMB = LONG_MAX / ONE_MB;
356
357        if (sizeMB < 0 || *end != 0) {
358            derror( "-partition-size must be followed by a positive integer" );
359            exit(1);
360        }
361        if (sizeMB < minSizeMB || sizeMB > maxSizeMB) {
362            derror( "partition-size (%d) must be between %dMB and %dMB",
363                    sizeMB, minSizeMB, maxSizeMB );
364            exit(1);
365        }
366        defaultPartitionSize = (uint64_t) sizeMB * ONE_MB;
367    }
368
369    /** SYSTEM PARTITION **/
370
371    if (opts->sysdir == NULL) {
372        if (avdInfo_inAndroidBuild(avd)) {
373            opts->sysdir = ASTRDUP(avdInfo_getContentPath(avd));
374            D("autoconfig: -sysdir %s", opts->sysdir);
375        }
376    }
377
378    if (opts->sysdir != NULL) {
379        if (!path_exists(opts->sysdir)) {
380            derror("Directory does not exist: %s", opts->sysdir);
381            exit(1);
382        }
383    }
384
385    {
386        char*  rwImage   = NULL;
387        char*  initImage = NULL;
388
389        do {
390            if (opts->system == NULL) {
391                /* If -system is not used, try to find a runtime system image
392                * (i.e. system-qemu.img) in the content directory.
393                */
394                rwImage = avdInfo_getSystemImagePath(avd);
395                if (rwImage != NULL) {
396                    break;
397                }
398                /* Otherwise, try to find the initial system image */
399                initImage = avdInfo_getSystemInitImagePath(avd);
400                if (initImage == NULL) {
401                    derror("No initial system image for this configuration!");
402                    exit(1);
403                }
404                break;
405            }
406
407            /* If -system <name> is used, use it to find the initial image */
408            if (opts->sysdir != NULL && !path_exists(opts->system)) {
409                initImage = _getFullFilePath(opts->sysdir, opts->system);
410            } else {
411                initImage = ASTRDUP(opts->system);
412            }
413            if (!path_exists(initImage)) {
414                derror("System image file doesn't exist: %s", initImage);
415                exit(1);
416            }
417
418        } while (0);
419
420        if (rwImage != NULL) {
421            /* Use the read/write image file directly */
422            hw->disk_systemPartition_path     = rwImage;
423            hw->disk_systemPartition_initPath = NULL;
424            D("Using direct system image: %s", rwImage);
425        } else if (initImage != NULL) {
426            hw->disk_systemPartition_path = NULL;
427            hw->disk_systemPartition_initPath = initImage;
428            D("Using initial system image: %s", initImage);
429        }
430
431        /* Check the size of the system partition image.
432        * If we have an AVD, it must be smaller than
433        * the disk.systemPartition.size hardware property.
434        *
435        * Otherwise, we need to adjust the systemPartitionSize
436        * automatically, and print a warning.
437        *
438        */
439        const char* systemImage = hw->disk_systemPartition_path;
440        uint64_t    systemBytes;
441
442        if (systemImage == NULL)
443            systemImage = hw->disk_systemPartition_initPath;
444
445        if (path_get_size(systemImage, &systemBytes) < 0) {
446            derror("Missing system image: %s", systemImage);
447            exit(1);
448        }
449
450        hw->disk_systemPartition_size =
451            _adjustPartitionSize("system", systemBytes, defaultPartitionSize,
452                                 avdInfo_inAndroidBuild(avd));
453    }
454
455    /** DATA PARTITION **/
456
457    if (opts->datadir) {
458        if (!path_exists(opts->datadir)) {
459            derror("Invalid -datadir directory: %s", opts->datadir);
460        }
461    }
462
463    {
464        char*  dataImage = NULL;
465        char*  initImage = NULL;
466
467        do {
468            if (!opts->data) {
469                dataImage = avdInfo_getDataImagePath(avd);
470                if (dataImage != NULL) {
471                    D("autoconfig: -data %s", dataImage);
472                    break;
473                }
474                dataImage = avdInfo_getDefaultDataImagePath(avd);
475                if (dataImage == NULL) {
476                    derror("No data image path for this configuration!");
477                    exit (1);
478                }
479                opts->wipe_data = 1;
480                break;
481            }
482
483            if (opts->datadir) {
484                dataImage = _getFullFilePath(opts->datadir, opts->data);
485            } else {
486                dataImage = ASTRDUP(opts->data);
487            }
488        } while (0);
489
490        if (opts->initdata != NULL) {
491            initImage = ASTRDUP(opts->initdata);
492            if (!path_exists(initImage)) {
493                derror("Invalid initial data image path: %s", initImage);
494                exit(1);
495            }
496        } else {
497            initImage = avdInfo_getDataInitImagePath(avd);
498            D("autoconfig: -initdata %s", initImage);
499        }
500
501        hw->disk_dataPartition_path = dataImage;
502        if (opts->wipe_data) {
503            hw->disk_dataPartition_initPath = initImage;
504        } else {
505            hw->disk_dataPartition_initPath = NULL;
506        }
507        android_op_wipe_data = opts->wipe_data;
508
509        uint64_t     defaultBytes =
510                hw->disk_dataPartition_size == 0 ?
511                defaultPartitionSize :
512                hw->disk_dataPartition_size;
513        uint64_t     dataBytes;
514        const char*  dataPath = hw->disk_dataPartition_initPath;
515
516        if (dataPath == NULL)
517            dataPath = hw->disk_dataPartition_path;
518
519        path_get_size(dataPath, &dataBytes);
520
521        hw->disk_dataPartition_size =
522            _adjustPartitionSize("data", dataBytes, defaultBytes,
523                                 avdInfo_inAndroidBuild(avd));
524    }
525
526    /** CACHE PARTITION **/
527
528    if (opts->no_cache) {
529        /* No cache partition at all */
530        hw->disk_cachePartition = 0;
531    }
532    else if (!hw->disk_cachePartition) {
533        if (opts->cache) {
534            dwarning( "Emulated hardware doesn't support a cache partition. -cache option ignored!" );
535            opts->cache = NULL;
536        }
537    }
538    else
539    {
540        if (!opts->cache) {
541            /* Find the current cache partition file */
542            opts->cache = avdInfo_getCachePath(avd);
543            if (opts->cache == NULL) {
544                /* The file does not exists, we will force its creation
545                 * if we are not in the Android build system. Otherwise,
546                 * a temporary file will be used.
547                 */
548                if (!avdInfo_inAndroidBuild(avd)) {
549                    opts->cache = avdInfo_getDefaultCachePath(avd);
550                }
551            }
552            if (opts->cache) {
553                D("autoconfig: -cache %s", opts->cache);
554            }
555        }
556
557        if (opts->cache) {
558            hw->disk_cachePartition_path = ASTRDUP(opts->cache);
559        }
560    }
561
562    if (hw->disk_cachePartition_path && opts->cache_size) {
563        /* Set cache partition size per user options. */
564        char*  end;
565        long   sizeMB = strtol(opts->cache_size, &end, 0);
566
567        if (sizeMB < 0 || *end != 0) {
568            derror( "-cache-size must be followed by a positive integer" );
569            exit(1);
570        }
571        hw->disk_cachePartition_size = (uint64_t) sizeMB * ONE_MB;
572    }
573
574    /** SD CARD PARTITION */
575
576    if (!hw->hw_sdCard) {
577        /* No SD Card emulation, so -sdcard will be ignored */
578        if (opts->sdcard) {
579            dwarning( "Emulated hardware doesn't support SD Cards. -sdcard option ignored." );
580            opts->sdcard = NULL;
581        }
582    } else {
583        /* Auto-configure -sdcard if it is not available */
584        if (!opts->sdcard) {
585            do {
586                /* If -datadir <path> is used, look for a sdcard.img file here */
587                if (opts->datadir) {
588                    char tmp[PATH_MAX], *tmpend = tmp + sizeof(tmp);
589                    bufprint(tmp, tmpend, "%s/%s", opts->datadir, "system.img");
590                    if (path_exists(tmp)) {
591                        opts->sdcard = strdup(tmp);
592                        break;
593                    }
594                }
595
596                /* Otherwise, look at the AVD's content */
597                opts->sdcard = avdInfo_getSdCardPath(avd);
598                if (opts->sdcard != NULL) {
599                    break;
600                }
601
602                /* Nothing */
603            } while (0);
604
605            if (opts->sdcard) {
606                D("autoconfig: -sdcard %s", opts->sdcard);
607            }
608        }
609    }
610
611    if(opts->sdcard) {
612        uint64_t  size;
613        if (path_get_size(opts->sdcard, &size) == 0) {
614            /* see if we have an sdcard image.  get its size if it exists */
615            /* due to what looks like limitations of the MMC protocol, one has
616             * to use an SD Card image that is equal or larger than 9 MB
617             */
618            if (size < 9*1024*1024ULL) {
619                fprintf(stderr, "### WARNING: SD Card files must be at least 9MB, ignoring '%s'\n", opts->sdcard);
620            } else {
621                hw->hw_sdCard_path = ASTRDUP(opts->sdcard);
622            }
623        } else {
624            dwarning("no SD Card image at '%s'", opts->sdcard);
625        }
626    }
627
628    if (opts->memory) {
629        char*  end;
630        long   ramSize = strtol(opts->memory, &end, 0);
631        if (ramSize < 0 || *end != 0) {
632            derror( "-memory must be followed by a positive integer" );
633            exit(1);
634        }
635        if (ramSize < 32 || ramSize > 4096) {
636            derror( "physical memory size must be between 32 and 4096 MB" );
637            exit(1);
638        }
639        hw->hw_ramSize = ramSize;
640    } else {
641        int ramSize = hw->hw_ramSize;
642        if (ramSize <= 0) {
643#if 1
644            // For ARM64, use 1GB by default.
645            ramSize = 1024 * 1024ULL;
646#else
647            /* Compute the default RAM size based on the size of screen.
648             * This is only used when the skin doesn't provide the ram
649             * size through its hardware.ini (i.e. legacy ones) or when
650             * in the full Android build system.
651             */
652            int64_t pixels  = hw->hw_lcd_width * hw->hw_lcd_height;
653            /* The following thresholds are a bit liberal, but we
654             * essentially want to ensure the following mappings:
655             *
656             *   320x480 -> 96
657             *   800x600 -> 128
658             *  1024x768 -> 256
659             *
660             * These are just simple heuristics, they could change in
661             * the future.
662             */
663            if (pixels <= 250000)
664                ramSize = 96;
665            else if (pixels <= 500000)
666                ramSize = 128;
667            else
668                ramSize = 256;
669        }
670#endif
671        hw->hw_ramSize = ramSize;
672    }
673
674    D("Physical RAM size: %dMB\n", hw->hw_ramSize);
675
676    if (opts->gpu) {
677        const char* gpu = opts->gpu;
678        if (!strcmp(gpu,"on") || !strcmp(gpu,"enable")) {
679            hw->hw_gpu_enabled = 1;
680        } else if (!strcmp(gpu,"off") || !strcmp(gpu,"disable")) {
681            hw->hw_gpu_enabled = 0;
682        } else if (!strcmp(gpu,"auto")) {
683            /* Nothing to do */
684        } else {
685            derror("Invalid value for -gpu <mode> parameter: %s\n", gpu);
686            derror("Valid values are: on, off or auto\n");
687            exit(1);
688        }
689    }
690
691    hw->avd_name = ASTRDUP(avdInfo_getName(avd));
692
693    String qemuExecutable = getQemuExecutablePath(argv[0]);
694    D("QEMU EXECUTABLE=%s\n", qemuExecutable.c_str());
695
696    // Now build the QEMU parameters.
697    const char* args[128];
698    int n = 0;
699
700    args[n++] = qemuExecutable.c_str();
701
702    args[n++] = "-cpu";
703    args[n++] = "cortex-a57";
704    args[n++] = "-machine";
705    args[n++] = "type=ranchu";
706
707    // Memory size
708    args[n++] = "-m";
709    String memorySize = StringFormat("%ld", hw->hw_ramSize);
710    args[n++] = memorySize.c_str();
711
712    // Command-line
713    args[n++] = "-append";
714    String kernelCommandLine =
715            "console=ttyAMA0,38400 keep_bootcon earlyprintk=ttyAMA0";
716    args[n++] = kernelCommandLine.c_str();
717
718    args[n++] = "-serial";
719    args[n++] = "mon:stdio";
720
721    // Kernel image
722    args[n++] = "-kernel";
723    args[n++] = hw->kernel_path;
724
725    // Ramdisk
726    args[n++] = "-initrd";
727    args[n++] = hw->disk_ramdisk_path;
728
729    // Data partition.
730    args[n++] = "-drive";
731    String userDataParam =
732            StringFormat("index=2,id=userdata,file=%s",
733                         hw->disk_dataPartition_path);
734    args[n++] = userDataParam.c_str();
735    args[n++] = "-device";
736    args[n++] = "virtio-blk-device,drive=userdata";
737
738    // Cache partition.
739    args[n++] = "-drive";
740    String cacheParam =
741            StringFormat("index=1,id=cache,file=%s",
742                         hw->disk_cachePartition_path);
743    args[n++] = cacheParam.c_str();
744    args[n++] = "-device";
745    args[n++] = "virtio-blk-device,drive=cache";
746
747    // System partition.
748    args[n++] = "-drive";
749    String systemParam =
750            StringFormat("index=0,id=system,file=%s",
751                         hw->disk_systemPartition_initPath);
752    args[n++] = systemParam.c_str();
753    args[n++] = "-device";
754    args[n++] = "virtio-blk-device,drive=system";
755
756    // Network
757    args[n++] = "-netdev";
758    args[n++] = "user,id=mynet";
759    args[n++] = "-device";
760    args[n++] = "virtio-net-device,netdev=mynet";
761    args[n++] = "-show-cursor";
762
763    if(VERBOSE_CHECK(init)) {
764        int i;
765        printf("QEMU options list:\n");
766        for(i = 0; i < n; i++) {
767            printf("emulator: argv[%02d] = \"%s\"\n", i, args[i]);
768        }
769        /* Dump final command-line option to make debugging the core easier */
770        printf("Concatenated QEMU options:\n");
771        for (i = 0; i < n; i++) {
772            /* To make it easier to copy-paste the output to a command-line,
773             * quote anything that contains spaces.
774             */
775            if (strchr(args[i], ' ') != NULL) {
776                printf(" '%s'", args[i]);
777            } else {
778                printf(" %s", args[i]);
779            }
780        }
781        printf("\n");
782    }
783
784    if (!path_exists(qemuExecutable.c_str())) {
785        fprintf(stderr, "Missing QEMU executable: %s\n",
786                qemuExecutable.c_str());
787        return 1;
788    }
789
790    // Now launch executable.
791#ifdef _WIN32
792    // Take care of quoting all parameters before sending them to execv().
793    // See the "Eveyone quotes command line arguments the wrong way" on
794    // MSDN.
795    int i;
796    for (i = 0; i < n; ++i) {
797        // Technically, this leaks the quoted strings, but we don't care
798        // since this process will terminate after the execv() anyway.
799        args[i] = win32_cmdline_quote(args[i]);
800        D("Quoted param: [%s]\n", args[i]);
801    }
802#endif
803
804    safe_execv(qemuExecutable.c_str(), (char* const*)args);
805
806    fprintf(stderr,
807            "Could not launch QEMU [%s]: %s\n",
808            qemuExecutable.c_str(),
809            strerror(errno));
810
811    return errno;
812}
813}
814}
815}
816