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)
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();
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)
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()
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)
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)
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)
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
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
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()
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()
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
def _GetTargetKernelPath(self): kernel_name = 'zircon.bin' if self._GetTargetSdkArch() == 'arm64': kernel_name = 'qemu-zircon.bin' return boot_data.GetTargetFile(self._GetTargetSdkArch(), kernel_name)