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