• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
63 using namespace android::base;
64 
65 namespace {
66 
67 // The host CPU architecture.
68 #ifdef __i386__
69 const char kHostArch[] = "x86";
70 #elif defined(__x86_64__)
71 const 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__
78 static const char kHostOs[] = "linux";
79 #elif defined(__APPLE__)
80 static const char kHostOs[] = "darwin";
81 #elif defined(_WIN32)
82 static const char kHostOs[] = "windows";
83 #endif
84 
85 // The target CPU architecture.
86 const char kTargetArch[] = "aarch64";
87 
88 // Return the path of the QEMU executable
getQemuExecutablePath(const char * programPath)89 String 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 
emulator_help(void)115 void 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 */
_getFullFilePath(const char * rootPath,const char * fileName)124 char* _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 
_adjustPartitionSize(const char * description,uint64_t imageBytes,uint64_t defaultBytes,int inAndroidBuild)138 uint64_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 
165 bool android_op_wipe_data;
166 
167 }  // namespace
168 
main(int argc,char ** argv,char ** envp)169 extern "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