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