Home | History | Annotate | Download | only in qemu-launcher
      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
     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 
    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 */
    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 
    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 
    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