Example #1
0
  def Start(self):
    if self._auto:
      logging.debug('Starting automatic device deployment.')
      node_name = boot_data.GetNodeName(self._output_dir)
      self._host = self.__Discover(node_name)
      if self._host and self._WaitUntilReady(retries=0):
        if not self._SDKHashMatches():
          logging.info('SDK hash does not match, rebooting.')
          self.RunCommand(['dm', 'reboot'])
          self._started = False
        else:
          logging.info('Connected to an already booted device.')
          self._new_instance = False
          return

      logging.info('Netbooting Fuchsia. ' +
                   'Please ensure that your device is in bootloader mode.')
      bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver')
      bootserver_command = [
          bootserver_path,
          '-1',
          '--efi',
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'local.esp.blk')),
          '--fvm',
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'fvm.sparse.blk')),
          '--fvm',
          EnsurePathExists(
              boot_data.ConfigureDataFVM(self._output_dir,
                                         boot_data.FVM_TYPE_SPARSE)),
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'fuchsia.zbi')),
          '--'] + boot_data.GetKernelArgs(self._output_dir)
      logging.debug(' '.join(bootserver_command))
      subprocess.check_call(bootserver_command)

      # Start loglistener to save system logs.
      if self._system_log_file:
        loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener')
        self._loglistener = subprocess.Popen(
            [loglistener_path, node_name],
            stdout=self._system_log_file,
            stderr=subprocess.STDOUT, stdin=open(os.devnull))

      logging.debug('Waiting for device to join network.')
      for retry in xrange(CONNECT_RETRY_COUNT):
        self._host = self.__Discover(node_name)
        if self._host:
          break
        time.sleep(CONNECT_RETRY_WAIT_SECS)
      if not self._host:
        raise Exception('Couldn\'t connect to device.')

      logging.debug('host=%s, port=%d' % (self._host, self._port))

    self._WaitUntilReady();

    # Update the target's hash to match the current tree's.
    self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
Example #2
0
  def Start(self):
    if self._auto:
      logging.debug('Starting automatic device deployment.')
      node_name = boot_data.GetNodeName(self._output_dir)
      self._host = self.__Discover(node_name)
      if self._host and self._WaitUntilReady(retries=0):
        logging.info('Connected to an already booted device.')
        self._new_instance = False
        return

      logging.info('Netbooting Fuchsia. ' +
                   'Please ensure that your device is in bootloader mode.')
      bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver')
      bootserver_command = [
          bootserver_path,
          '-1',
          '--efi',
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'local.esp.blk')),
          '--fvm',
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'fvm.sparse.blk')),
          '--fvm',
          EnsurePathExists(
              boot_data.ConfigureDataFVM(self._output_dir,
                                         boot_data.FVM_TYPE_SPARSE)),
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'zircon.bin')),
          EnsurePathExists(boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                   'bootdata-blob.bin')),
          '--'] + boot_data.GetKernelArgs(self._output_dir)
      logging.debug(' '.join(bootserver_command))
      subprocess.check_call(bootserver_command)

      # Setup loglistener. Logs will be redirected to stdout if the device takes
      # longer than expected to boot.
      loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener')
      loglistener = subprocess.Popen([loglistener_path, node_name],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT,
                                     stdin=open(os.devnull))
      self._SetSystemLogsReader(
          log_reader.LogReader(loglistener, loglistener.stdout))

      logging.debug('Waiting for device to join network.')
      for retry in xrange(CONNECT_RETRY_COUNT):
        if retry == CONNECT_RETRY_COUNT_BEFORE_LOGGING:
          self._system_logs_reader.RedirectTo(sys.stdout);
        self._host = self.__Discover(node_name)
        if self._host:
          break
        time.sleep(CONNECT_RETRY_WAIT_SECS)
      if not self._host:
        raise Exception('Couldn\'t connect to device.')

      logging.debug('host=%s, port=%d' % (self._host, self._port))

    self._WaitUntilReady();
Example #3
0
    def __ProvisionDevice(self, node_name):
        logging.info('Netbooting Fuchsia. ' +
                     'Please ensure that your device is in bootloader mode.')
        bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver')
        bootserver_command = [
            bootserver_path, '-1', '--fvm',
            EnsurePathExists(
                boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                        'fvm.sparse.blk')),
            EnsurePathExists(
                boot_data.GetBootImage(self._output_dir,
                                       self._GetTargetSdkArch()))
        ]

        if self._GetTargetSdkArch() == 'x64':
            bootserver_command += [
                '--efi',
                EnsurePathExists(
                    boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                            'local.esp.blk'))
            ]

        bootserver_command += ['--']
        bootserver_command += boot_data.GetKernelArgs(self._output_dir)

        logging.debug(' '.join(bootserver_command))
        subprocess.check_call(bootserver_command)

        # Start loglistener to save system logs.
        if self._system_log_file:
            loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener')
            self._loglistener = subprocess.Popen([loglistener_path, node_name],
                                                 stdout=self._system_log_file,
                                                 stderr=subprocess.STDOUT,
                                                 stdin=open(os.devnull))

        logging.debug('Waiting for device to join network.')
        for retry in xrange(CONNECT_RETRY_COUNT):
            self._host = self.__Discover(node_name)
            if self._host:
                break
            time.sleep(CONNECT_RETRY_WAIT_SECS)
        if not self._host:
            raise Exception('Couldn\'t connect to device.')

        logging.debug('host=%s, port=%d' % (self._host, self._port))

        self._WaitUntilReady()

        # Update the target's hash to match the current tree's.
        self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
Example #4
0
    def Start(self):
        if self._auto:
            logging.debug('Starting automatic device deployment.')
            node_name = boot_data.GetNodeName(self._output_dir)
            self._host = self.__Discover(node_name)
            if self._host and self._WaitUntilReady(retries=0):
                logging.info('Connected to an already booted device.')
                self._new_instance = False
                return

            logging.info(
                'Netbooting Fuchsia. ' +
                'Please ensure that your device is in bootloader mode.')
            bootserver_path = os.path.join(common.SDK_ROOT, 'tools',
                                           'bootserver')
            data_fvm_path = boot_data.ConfigureDataFVM(
                self._output_dir, boot_data.FVM_TYPE_SPARSE)
            bootserver_command = [bootserver_path,
                                  '-1',
                                  '--efi',
                                  boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                          'local.esp.blk'),
                                  '--fvm',
                                  boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                          'fvm.sparse.blk'),
                                  '--fvm',
                                  data_fvm_path,
                                  boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                          'zircon.bin'),
                                  boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                                          'bootdata-blob.bin'),
                                  '--'] + \
                                  boot_data.GetKernelArgs(self._output_dir)
            logging.debug(' '.join(bootserver_command))
            subprocess.check_call(bootserver_command)

            logging.debug('Waiting for device to join network.')
            for _ in xrange(CONNECT_RETRY_COUNT):
                self._host = self.__Discover(node_name)
                if self._host:
                    break
                time.sleep(CONNECT_RETRY_WAIT_SECS)
            if not self._host:
                raise Exception('Couldn\'t connect to device.')

            logging.debug('host=%s, port=%d' % (self._host, self._port))

        self._WaitUntilReady()
Example #5
0
  def _ProvisionDevice(self):
    """Pave a device with a generic image of Fuchsia."""

    bootserver_path = GetHostToolPathFromPlatform('bootserver')
    bootserver_command = [
        bootserver_path, '-1', '--fvm',
        EnsurePathExists(
            boot_data.GetTargetFile('storage-sparse.blk',
                                    self._GetTargetSdkArch(),
                                    boot_data.TARGET_TYPE_GENERIC)),
        EnsurePathExists(
            boot_data.GetBootImage(self._out_dir, self._GetTargetSdkArch(),
                                   boot_data.TARGET_TYPE_GENERIC))
    ]

    if self._node_name:
      bootserver_command += ['-n', self._node_name]

    bootserver_command += ['--']
    bootserver_command += boot_data.GetKernelArgs()

    logging.debug(' '.join(bootserver_command))
    _, stdout = SubprocessCallWithTimeout(bootserver_command,
                                          silent=False,
                                          timeout_secs=300)

    self._ParseNodename(stdout)

    # Update the target's hash to match the current tree's.
    self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
Example #6
0
    def __ProvisionDevice(self):
        """Netboots a device with Fuchsia. If |_node_name| is set, then only a
    device with a matching node name is used.

    The device is up and reachable via SSH when the function is successfully
    completes."""

        bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver')
        bootserver_command = [
            bootserver_path, '-1', '--fvm',
            EnsurePathExists(
                boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                        'fvm.sparse.blk')),
            EnsurePathExists(
                boot_data.GetBootImage(self._output_dir,
                                       self._GetTargetSdkArch()))
        ]

        if self._node_name:
            bootserver_command += ['-n', self._node_name]

        bootserver_command += ['--']
        bootserver_command += boot_data.GetKernelArgs(self._output_dir)

        logging.debug(' '.join(bootserver_command))
        stdout = subprocess.check_output(bootserver_command,
                                         stderr=subprocess.STDOUT)

        # Parse the nodename from bootserver stdout.
        m = re.search(r'.*Proceeding with nodename (?P<nodename>.*)$', stdout,
                      re.MULTILINE)
        if not m:
            raise Exception('Couldn\'t parse nodename from bootserver output.')
        self._node_name = m.groupdict()['nodename']
        logging.info('Booted device "%s".' % self._node_name)

        # Start loglistener to save system logs.
        if self._system_log_file:
            loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener')
            self._loglistener = subprocess.Popen(
                [loglistener_path, self._node_name],
                stdout=self._system_log_file,
                stderr=subprocess.STDOUT,
                stdin=open(os.devnull))

        # Repeatdly query mDNS until we find the device, or we hit the timeout of
        # DISCOVERY_TIMEOUT_SECS.
        logging.info('Waiting for device to join network.')
        for _ in xrange(_BOOT_DISCOVERY_ATTEMPTS):
            if self.__Discover():
                break

        if not self._host:
            raise Exception('Device %s couldn\'t be discovered via mDNS.' %
                            self._node_name)

        self._WaitUntilReady()

        # Update the target's hash to match the current tree's.
        self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
Example #7
0
def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch):
    """Returns a file containing the Fuchsia blobstore in a QCOW format,
  with extra buffer space added for growth."""

    qimg_tool = os.path.join(common.GetEmuRootForPlatform('qemu'), 'bin',
                             'qemu-img')
    fvm_tool = common.GetHostToolPathFromPlatform('fvm')
    blobstore_path = boot_data.GetTargetFile('storage-full.blk', target_arch,
                                             'qemu')
    qcow_path = os.path.join(output_dir, 'gen', 'blobstore.qcow')

    # Check a hash of the blobstore to determine if we can re-use an existing
    # extended version of it.
    blobstore_hash_path = os.path.join(output_dir, 'gen', 'blobstore.hash')
    current_blobstore_hash = _ComputeFileHash(blobstore_path)

    if os.path.exists(blobstore_hash_path) and os.path.exists(qcow_path):
        if current_blobstore_hash == open(blobstore_hash_path, 'r').read():
            return qcow_path

    # Add some extra room for growth to the Blobstore volume.
    # Fuchsia is unable to automatically extend FVM volumes at runtime so the
    # volume enlargement must be performed prior to QEMU startup.

    # The 'fvm' tool only supports extending volumes in-place, so make a
    # temporary copy of 'blobstore.bin' before it's mutated.
    extended_blobstore = tempfile.NamedTemporaryFile()
    shutil.copyfile(blobstore_path, extended_blobstore.name)
    subprocess.check_call([
        fvm_tool, extended_blobstore.name, 'extend', '--length',
        str(EXTENDED_BLOBSTORE_SIZE), blobstore_path
    ])

    # Construct a QCOW image from the extended, temporary FVM volume.
    # The result will be retained in the build output directory for re-use.
    qemu_img_cmd = [
        qimg_tool, 'convert', '-f', 'raw', '-O', 'qcow2', '-c',
        extended_blobstore.name, qcow_path
    ]
    # TODO(crbug.com/1046861): Remove arm64 call with retries when bug is fixed.
    if common.GetHostArchFromPlatform() == 'arm64':
        qemu_image.ExecQemuImgWithRetry(qemu_img_cmd)
    else:
        subprocess.check_call(qemu_img_cmd)

    # Write out a hash of the original blobstore file, so that subsequent runs
    # can trivially check if a cached extended FVM volume is available for reuse.
    with open(blobstore_hash_path, 'w') as blobstore_hash_file:
        blobstore_hash_file.write(current_blobstore_hash)

    return qcow_path
  def _ProvisionDevice(self):
    """Pave a device with a generic image of Fuchsia."""
    bootserver_path = GetHostToolPathFromPlatform('bootserver')
    bootserver_command = [
        bootserver_path, '-1', '--fvm',
        EnsurePathExists(
            boot_data.GetTargetFile('storage-sparse.blk',
                                    self._GetTargetSdkArch(),
                                    boot_data.TARGET_TYPE_GENERIC)),
        EnsurePathExists(
            boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch(),
                                   boot_data.TARGET_TYPE_GENERIC))
    ]

    if self._node_name:
      bootserver_command += ['-n', self._node_name]

    bootserver_command += ['--']
    bootserver_command += boot_data.GetKernelArgs(self._output_dir)

    logging.debug(' '.join(bootserver_command))
    _, stdout = SubprocessCallWithTimeout(bootserver_command,
                                          silent=False,
                                          timeout_secs=300)

    self._ParseNodename(stdout)

    # Start loglistener to save system logs.
    if self._system_log_file:
      self._StartLoglistener()

    # Repeatdly query mDNS until we find the device, or we hit
    # BOOT_DISCOVERY_ATTEMPTS
    logging.info('Waiting for device to join network.')
    for _ in xrange(device_target.BOOT_DISCOVERY_ATTEMPTS):
      if self.__Discover():
        break

    if not self._host:
      raise Exception("Device %s couldn't be discovered via mDNS." %
                      self._node_name)

    self._WaitUntilReady()

    # Update the target's hash to match the current tree's.
    self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
Example #9
0
  def Start(self):
    qemu_path = os.path.join(GetQemuRootForPlatform(), 'bin',
                             'qemu-system-' + self._GetTargetSdkLegacyArch())
    kernel_args = boot_data.GetKernelArgs(self._output_dir)

    # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
    # noisy ANSI spew from the user's terminal emulator.
    kernel_args.append('TERM=dumb')

    # Enable logging to the serial port. This is a temporary fix to investigate
    # the root cause for https://crbug.com/869753 .
    kernel_args.append('kernel.serial=legacy')

    qemu_command = [qemu_path,
        '-m', str(self._ram_size_mb),
        '-nographic',
        '-kernel', EnsurePathExists(
            boot_data.GetTargetFile('qemu-kernel.kernel',
                                    self._GetTargetSdkArch(),
                                    boot_data.TARGET_TYPE_QEMU)),
        '-initrd', EnsurePathExists(
            boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch(),
                                   boot_data.TARGET_TYPE_QEMU)),
        '-smp', str(self._cpu_cores),

        # Attach the blobstore and data volumes. Use snapshot mode to discard
        # any changes.
        '-snapshot',
        '-drive', 'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
                    EnsurePathExists(
                        os.path.join(self._output_dir, 'fvm.blk.qcow2')),
        '-device', 'virtio-blk-pci,drive=blobstore',

        # Use stdio for the guest OS only; don't attach the QEMU interactive
        # monitor.
        '-serial', 'stdio',
        '-monitor', 'none',

        '-append', ' '.join(kernel_args)
      ]

    # Configure the machine to emulate, based on the target architecture.
    if self._target_cpu == 'arm64':
      qemu_command.extend([
          '-machine','virt',
      ])
      netdev_type = 'virtio-net-pci'
    else:
      qemu_command.extend([
          '-machine', 'q35',
      ])
      netdev_type = 'e1000'

    # Configure the CPU to emulate.
    # On Linux, we can enable lightweight virtualization (KVM) if the host and
    # guest architectures are the same.
    enable_kvm = self._require_kvm or (sys.platform.startswith('linux') and (
        (self._target_cpu == 'arm64' and platform.machine() == 'aarch64') or
        (self._target_cpu == 'x64' and platform.machine() == 'x86_64')) and
      os.access('/dev/kvm', os.R_OK | os.W_OK))
    if enable_kvm:
      qemu_command.extend(['-enable-kvm', '-cpu', 'host,migratable=no'])
    else:
      logging.warning('Unable to launch QEMU with KVM acceleration.')
      if self._target_cpu == 'arm64':
        qemu_command.extend(['-cpu', 'cortex-a53'])
      else:
        qemu_command.extend(['-cpu', 'Haswell,+smap,-check,-fsgsbase'])

    # Configure virtual network. It is used in the tests to connect to
    # testserver running on the host.
    netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
            (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

    self._host_ssh_port = common.GetAvailableTcpPort()
    netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
    qemu_command.extend([
      '-netdev', netdev_config,
      '-device', '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
    ])

    # We pass a separate stdin stream to qemu. Sharing stdin across processes
    # leads to flakiness due to the OS prematurely killing the stream and the
    # Python script panicking and aborting.
    # The precise root cause is still nebulous, but this fix works.
    # See crbug.com/741194.
    logging.debug('Launching QEMU.')
    logging.debug(' '.join(qemu_command))

    # Zircon sends debug logs to serial port (see kernel.serial=legacy flag
    # above). Serial port is redirected to a file through QEMU stdout.
    # Unless a |_system_log_file| is explicitly set, we output the kernel serial
    # log to a temporary file, and print that out if we are unable to connect to
    # the QEMU guest, to make it easier to diagnose connectivity issues.
    temporary_system_log_file = None
    if self._system_log_file:
      stdout = self._system_log_file
      stderr = subprocess.STDOUT
    else:
      temporary_system_log_file = tempfile.NamedTemporaryFile('w')
      stdout = temporary_system_log_file
      stderr = sys.stderr

    self._qemu_process = subprocess.Popen(qemu_command, stdin=open(os.devnull),
                                          stdout=stdout, stderr=stderr)
    try:
      self._WaitUntilReady();
    except target.FuchsiaTargetException:
      if temporary_system_log_file:
        logging.info("Kernel logs:\n" +
                     open(temporary_system_log_file.name, 'r').read())
      raise
Example #10
0
  def _BuildCommand(self):
    boot_data.ProvisionSSH()
    self._host_ssh_port = common.GetAvailableTcpPort()
    kernel_image = common.EnsurePathExists(
        boot_data.GetTargetFile('qemu-kernel.kernel', self._image_arch,
                                self._image_type))
    zbi_image = common.EnsurePathExists(
        boot_data.GetTargetFile('zircon-a.zbi', self._image_arch,
                                self._image_type))
    fvm_image = common.EnsurePathExists(
        boot_data.GetTargetFile('storage-full.blk', self._image_arch,
                                self._image_type))
    aemu_path = common.EnsurePathExists(
        os.path.join(common.GetEmuRootForPlatform(self.EMULATOR_NAME),
                     'emulator'))

    emu_command = [
        self._FVDL_PATH,
        '--sdk',
        'start',
        '--nointeractive',

        # Host port mapping for user-networking mode.
        '--port-map',
        'hostfwd=tcp::{}-:22'.format(self._host_ssh_port),

        # no-interactive requires a --vdl-output flag to shutdown the emulator.
        '--vdl-output',
        self._vdl_output_file.name,
        '-c',
        ' '.join(boot_data.GetKernelArgs()),

        # Use existing images instead of downloading new ones.
        '--kernel-image',
        kernel_image,
        '--zbi-image',
        zbi_image,
        '--fvm-image',
        fvm_image,
        '--image-architecture',
        self._target_cpu,

        # Use an existing emulator checked out by Chromium.
        '--aemu-path',
        aemu_path,

        # Use this flag and temp file to define ram size.
        '--device-proto',
        self._device_proto_file.name,
        '--cpu-count',
        str(self._cpu_cores)
    ]
    self._ConfigureEmulatorLog(emu_command)

    if not self._require_kvm:
      emu_command.append('--noacceleration')
    if not self._enable_graphics:
      emu_command.append('--headless')
    if self._hardware_gpu:
      emu_command.append('--host-gpu')
    if self._with_network:
      emu_command.append('-N')

    return emu_command
Example #11
0
    def Start(self):
        qemu_path = os.path.join(common.SDK_ROOT, 'qemu', 'bin',
                                 'qemu-system-' + self._GetTargetSdkArch())
        kernel_args = boot_data.GetKernelArgs(self._output_dir)

        qemu_command = [
            qemu_path,
            '-m',
            str(self._ram_size_mb),
            '-nographic',
            '-kernel',
            boot_data.GetTargetFile(self._GetTargetSdkArch(), 'zircon.bin'),
            '-initrd',
            boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                    'bootdata-blob.bin'),
            '-smp',
            '4',

            # Attach the blobstore and data volumes. Use snapshot mode to discard
            # any changes.
            '-snapshot',
            '-drive',
            'file=%s,format=qcow2,if=none,id=data,snapshot=on' %
            os.path.join(self._output_dir, 'fvm.blk.qcow2'),
            '-drive',
            'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
            self._MakeQcowDisk(
                boot_data.ConfigureDataFVM(self._output_dir, False)),
            '-device',
            'virtio-blk-pci,drive=data',
            '-device',
            'virtio-blk-pci,drive=blobstore',

            # Use stdio for the guest OS only; don't attach the QEMU interactive
            # monitor.
            '-serial',
            'stdio',
            '-monitor',
            'none',

            # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
            # noisy ANSI spew from the user's terminal emulator.
            '-append',
            'TERM=dumb ' + ' '.join(kernel_args)
        ]

        # Configure the machine & CPU to emulate, based on the target architecture.
        # Enable lightweight virtualization (KVM) if the host and guest OS run on
        # the same architecture.
        if self._target_cpu == 'arm64':
            qemu_command.extend([
                '-machine',
                'virt',
                '-cpu',
                'cortex-a53',
            ])
            netdev_type = 'virtio-net-pci'
            if platform.machine() == 'aarch64':
                qemu_command.append('-enable-kvm')
        else:
            qemu_command.extend([
                '-machine',
                'q35',
                '-cpu',
                'host,migratable=no',
            ])
            netdev_type = 'e1000'
            if platform.machine() == 'x86_64':
                qemu_command.append('-enable-kvm')

        # Configure virtual network. It is used in the tests to connect to
        # testserver running on the host.
        netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
                (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

        self._host_ssh_port = _GetAvailableTcpPort()
        netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
        qemu_command.extend([
            '-netdev',
            netdev_config,
            '-device',
            '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
        ])

        # We pass a separate stdin stream to qemu. Sharing stdin across processes
        # leads to flakiness due to the OS prematurely killing the stream and the
        # Python script panicking and aborting.
        # The precise root cause is still nebulous, but this fix works.
        # See crbug.com/741194.
        logging.debug('Launching QEMU.')
        logging.debug(' '.join(qemu_command))

        stdio_flags = {'stdin': open(os.devnull)}
        if logging.getLogger().getEffectiveLevel() != logging.DEBUG:
            # Output the Fuchsia debug log.
            stdio_flags['stdout'] = open(os.devnull)
            stdio_flags['stderr'] = open(os.devnull)

        self._qemu_process = subprocess.Popen(qemu_command, **stdio_flags)
        self._WaitUntilReady()
Example #12
0
    def Start(self):
        qemu_path = os.path.join(
            QEMU_ROOT, 'bin', 'qemu-system-' + self._GetTargetSdkLegacyArch())
        kernel_args = boot_data.GetKernelArgs(self._output_dir)

        # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
        # noisy ANSI spew from the user's terminal emulator.
        kernel_args.append('TERM=dumb')

        # Enable logging to the serial port. This is a temporary fix to investigate
        # the root cause for https://crbug.com/869753 .
        kernel_args.append('kernel.serial=legacy')

        qemu_command = [
            qemu_path,
            '-m',
            str(self._ram_size_mb),
            '-nographic',
            '-kernel',
            EnsurePathExists(
                boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                        'zircon.bin')),
            '-initrd',
            EnsurePathExists(
                boot_data.GetTargetFile(self._GetTargetSdkArch(),
                                        'bootdata-blob.bin')),
            '-smp',
            '4',

            # Attach the blobstore and data volumes. Use snapshot mode to discard
            # any changes.
            '-snapshot',
            '-drive',
            'file=%s,format=qcow2,if=none,id=data,snapshot=on' %
            EnsurePathExists(os.path.join(self._output_dir, 'fvm.blk.qcow2')),
            '-drive',
            'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
            EnsurePathExists(
                boot_data.ConfigureDataFVM(self._output_dir,
                                           boot_data.FVM_TYPE_QCOW)),
            '-device',
            'virtio-blk-pci,drive=data',
            '-device',
            'virtio-blk-pci,drive=blobstore',

            # Use stdio for the guest OS only; don't attach the QEMU interactive
            # monitor.
            '-serial',
            'stdio',
            '-monitor',
            'none',
            '-append',
            ' '.join(kernel_args)
        ]

        # Configure the machine & CPU to emulate, based on the target architecture.
        # Enable lightweight virtualization (KVM) if the host and guest OS run on
        # the same architecture.
        if self._target_cpu == 'arm64':
            qemu_command.extend([
                '-machine',
                'virt',
                '-cpu',
                'cortex-a53',
            ])
            netdev_type = 'virtio-net-pci'
            if platform.machine() == 'aarch64':
                qemu_command.append('-enable-kvm')
        else:
            qemu_command.extend([
                '-machine',
                'q35',
                '-cpu',
                'host,migratable=no',
            ])
            netdev_type = 'e1000'
            if platform.machine() == 'x86_64':
                qemu_command.append('-enable-kvm')

        # Configure virtual network. It is used in the tests to connect to
        # testserver running on the host.
        netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
                (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

        self._host_ssh_port = _GetAvailableTcpPort()
        netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
        qemu_command.extend([
            '-netdev',
            netdev_config,
            '-device',
            '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
        ])

        # We pass a separate stdin stream to qemu. Sharing stdin across processes
        # leads to flakiness due to the OS prematurely killing the stream and the
        # Python script panicking and aborting.
        # The precise root cause is still nebulous, but this fix works.
        # See crbug.com/741194.
        logging.debug('Launching QEMU.')
        logging.debug(' '.join(qemu_command))

        # Zircon sends debug logs to serial port (see kernel.serial=legacy flag
        # above). Serial port is redirected to a file through QEMU stdout.
        # This approach is used instead of loglistener to debug
        # https://crbug.com/86975 .
        if self._system_log_file:
            stdout = self._system_log_file
            stderr = subprocess.STDOUT
        else:
            stdout = open(os.devnull)
            stderr = sys.stderr

        self._qemu_process = subprocess.Popen(qemu_command,
                                              stdin=open(os.devnull),
                                              stdout=stdout,
                                              stderr=stderr)
        self._WaitUntilReady()
Example #13
0
    def _BuildQemuConfig(self):
        boot_data.AssertBootImagesExist(self._GetTargetSdkArch(), 'qemu')

        emu_command = [
            '-kernel',
            EnsurePathExists(
                boot_data.GetTargetFile('qemu-kernel.kernel',
                                        self._GetTargetSdkArch(),
                                        boot_data.TARGET_TYPE_QEMU)),
            '-initrd',
            EnsurePathExists(
                boot_data.GetBootImage(self._output_dir,
                                       self._GetTargetSdkArch(),
                                       boot_data.TARGET_TYPE_QEMU)),
            '-m',
            str(self._ram_size_mb),
            '-smp',
            str(self._cpu_cores),

            # Attach the blobstore and data volumes. Use snapshot mode to discard
            # any changes.
            '-snapshot',
            '-drive',
            'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
            _EnsureBlobstoreQcowAndReturnPath(self._output_dir,
                                              self._GetTargetSdkArch(),
                                              self._qemu_img_retries),
            '-device',
            'virtio-blk-pci,drive=blobstore',

            # Use stdio for the guest OS only; don't attach the QEMU interactive
            # monitor.
            '-serial',
            'stdio',
            '-monitor',
            'none',
        ]

        # Configure the machine to emulate, based on the target architecture.
        if self._target_cpu == 'arm64':
            emu_command.extend([
                '-machine',
                'virt,gic_version=3',
            ])
            netdev_type = 'virtio-net-pci'
        else:
            emu_command.extend([
                '-machine',
                'q35',
            ])
            netdev_type = 'e1000'

        # Configure virtual network. It is used in the tests to connect to
        # testserver running on the host.
        netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
                (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

        self._host_ssh_port = common.GetAvailableTcpPort()
        netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
        emu_command.extend([
            '-netdev',
            netdev_config,
            '-device',
            '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
        ])

        # Configure the CPU to emulate.
        # On Linux, we can enable lightweight virtualization (KVM) if the host and
        # guest architectures are the same.
        if self._IsKvmEnabled():
            kvm_command = ['-enable-kvm', '-cpu']
            if self._target_cpu == 'arm64':
                kvm_command.append('host')
            else:
                kvm_command.append('host,migratable=no')
        else:
            logging.warning('Unable to launch %s with KVM acceleration.' %
                            (self._emu_type) + 'The guest VM will be slow.')
            if self._target_cpu == 'arm64':
                kvm_command = ['-cpu', 'cortex-a53']
            else:
                kvm_command = ['-cpu', 'Haswell,+smap,-check,-fsgsbase']

        emu_command.extend(kvm_command)

        kernel_args = boot_data.GetKernelArgs(self._output_dir)

        # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
        # noisy ANSI spew from the user's terminal emulator.
        kernel_args.append('TERM=dumb')

        # Construct kernel cmd line
        kernel_args.append('kernel.serial=legacy')

        # Don't 'reboot' the emulator if the kernel crashes
        kernel_args.append('kernel.halt-on-panic=true')

        emu_command.extend(['-append', ' '.join(kernel_args)])

        return emu_command
Example #14
0
 def _GetTargetKernelPath(self):
     kernel_name = 'zircon.bin'
     if self._GetTargetSdkArch() == 'arm64':
         kernel_name = 'qemu-zircon.bin'
     return boot_data.GetTargetFile(self._GetTargetSdkArch(), kernel_name)