# Copyright 2018 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
"""Implements commands for running and interacting with Fuchsia on QEMU."""
from common import GetHostArchFromPlatform, GetEmuRootForPlatform from common import EnsurePathExists from qemu_image import ExecQemuImgWithRetry from target import FuchsiaTargetException
# Virtual networking configuration data for QEMU.
HOST_IP_ADDRESS = '10.0.2.2'
GUEST_MAC_ADDRESS = '52:54:00:63:5e:7b'
# Capacity of the system's blobstore volume.
EXTENDED_BLOBSTORE_SIZE = 1073741824 # 1GB
def GetTargetType(): return QemuTarget
class QemuTarget(emu_target.EmuTarget):
EMULATOR_NAME = 'qemu'
def _IsKvmEnabled(self):
kvm_supported = sys.platform.startswith('linux') and \
os.access('/dev/kvm', os.R_OK | os.W_OK)
same_arch = \
(self._target_cpu == 'arm64'and platform.machine() == 'aarch64') or \
(self._target_cpu == 'x64'and platform.machine() == 'x86_64') if kvm_supported and same_arch: returnTrue elif self._require_kvm: if same_arch: ifnot os.path.exists('/dev/kvm'):
kvm_error = 'File /dev/kvm does not exist. Please install KVM first.' else:
kvm_error = 'To use KVM acceleration, add user to the kvm group '\ 'with "sudo usermod -a -G kvm $USER". Log out and back '\ 'in for the change to take effect.' raise FuchsiaTargetException(kvm_error) else: raise FuchsiaTargetException('KVM unavailable when CPU architecture '\ 'of host is different from that of'\ ' target. See --allow-no-kvm.') else: returnFalse
# 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._out_dir,
self._GetTargetSdkArch()), '-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',
]) else:
emu_command.extend([ '-machine', 'q35',
])
# 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,+invtsc') else:
logging.warning('Unable to launch %s with KVM acceleration. ' 'The guest VM will be slow.' % (self.EMULATOR_NAME)) if self._target_cpu == 'arm64':
kvm_command = ['-cpu', 'cortex-a53'] else:
kvm_command = ['-cpu', 'Haswell,+smap,-check,-fsgsbase']
# 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')
def _ComputeFileHash(filename):
hasher = hashlib.md5() with open(filename, 'rb') as f:
buf = f.read(4096) while buf:
hasher.update(buf)
buf = f.read(4096)
return hasher.hexdigest()
def _EnsureBlobstoreQcowAndReturnPath(out_dir, target_arch): """Returns a file containing the Fuchsia blobstore in a QCOW format, with extra buffer space added for growth."""
# 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(out_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)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.