aos/tools/harness/machines/qemu.py
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

378 lines
13 KiB
Python

##########################################################################
# Copyright (c) 2009-2016 ETH Zurich.
# All rights reserved.
#
# This file is distributed under the terms in the attached LICENSE file.
# If you do not find this file, copies can be found by writing to:
# ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
##########################################################################
import os, signal, tempfile, subprocess, shutil
import debug
from machines import Machine, ARMMachineBase, MachineFactory, MachineOperations
import efiimage
QEMU_SCRIPT_PATH = 'tools/qemu-wrapper.sh' # relative to source tree
class QEMUMachineBase(Machine):
def __init__(self, options, operations, **kwargs):
super(QEMUMachineBase, self).__init__(options, operations, **kwargs)
def get_tickrate(self):
return None
def get_buildall_target(self):
return self.get_bootarch().upper() + "_Full"
def get_boot_timeout(self):
# shorter time limit for running a qemu test
# FIXME: ideally this should somehow be expressed in CPU time / cycles
return 60
def get_pci_args(self):
return ["skb_bridge_program=bridge_bios"]
def get_machine_name(self):
return self._name
def get_serial_binary(self):
return "serial_pc16550d"
class QEMUMachineBaseOperations(MachineOperations):
def __init__(self, machine):
super(QEMUMachineBaseOperations, self).__init__(machine)
self.child = None
self.tftp_dir = None
def setup(self):
pass
def force_write(self, consolectrl):
pass
def get_tftp_dir(self):
if self.tftp_dir is None:
debug.verbose('creating temporary directory for QEMU TFTP files')
self.tftp_dir = tempfile.mkdtemp(prefix='harness_qemu_')
debug.verbose('QEMU TFTP directory is %s' % self.tftp_dir)
return self.tftp_dir
def _write_menu_lst(self, data, path):
debug.verbose('writing %s' % path)
debug.debug(data)
f = open(path, 'w')
f.write(data)
f.close()
def set_bootmodules(self, modules):
path = os.path.join(self.get_tftp_dir(), 'menu.lst')
self._write_menu_lst(modules.get_menu_data('/'), path)
def lock(self):
pass
def unlock(self):
pass
def _get_cmdline(self):
raise NotImplementedError
def _kill_child(self):
# terminate child if running
if self.child:
os.kill(self.child.pid, signal.SIGTERM)
self.child.wait()
self.child = None
self.masterfd = None
def reboot(self):
self._kill_child()
cmd = self._get_cmdline()
debug.verbose('starting "%s"' % ' '.join(cmd))
import pty
(self.masterfd, slavefd) = pty.openpty()
self.child = subprocess.Popen(cmd, close_fds=True,
stdout=slavefd,
stdin=slavefd)
os.close(slavefd)
# open in binary mode w/o buffering
self.qemu_out = os.fdopen(self.masterfd, 'rb', 0)
def shutdown(self):
self._kill_child()
# try to cleanup tftp tree if needed
if self.tftp_dir and os.path.isdir(self.tftp_dir):
shutil.rmtree(self.tftp_dir, ignore_errors=True)
self.tftp_dir = None
def get_output(self):
return self.qemu_out
class QEMUMachineX64Operations(QEMUMachineBaseOperations):
def _get_cmdline(self):
qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
menu_lst = os.path.join(self.get_tftp_dir(), 'menu.lst')
return [ qemu_wrapper, "--menu", menu_lst, "--arch", "x86_64",
"--smp", "%s" % self._machine.get_ncores() ]
def set_bootmodules(self, modules):
path = os.path.join(self.get_tftp_dir(), 'menu.lst')
self._write_menu_lst(modules.get_menu_data('/', self.get_tftp_dir()), path)
# create 1, 2 and 4 core x86_64 qemu machines
class TmpMachine(QEMUMachineBase):
name = 'qemu_x86_64'
def __init__(self, options, _class=None, **kwargs):
super(_class, self).__init__(options, QEMUMachineX64Operations(self), **kwargs)
# 60 seconds per core
def get_boot_timeout(self):
return self.get_ncores() * 60
# 120 seconds per core
def get_test_timeout(self):
return self.get_ncores() * 240
for n in [1, 2, 4]:
MachineFactory.addMachine('qemu_x86_64_c%d' % n, TmpMachine,
ncores=n,
bootarch='x86_64',
_class=TmpMachine)
class QEMUMachineARMv7(ARMMachineBase):
'''ARMv7 QEMU'''
name = 'qemu_armv7'
imagename = "armv7_a15ve_4_image"
def __init__(self, options, **kwargs):
super(QEMUMachineARMv7, self).__init__(options, QEMUMAchineARMv7Operations(self), **kwargs)
self._set_kernel_image()
# 60 seconds per core
def get_boot_timeout(self):
return self.get_ncores() * 60
# 120 seconds per core
def get_test_timeout(self):
return self.get_ncores() * 240
def get_buildall_target(self):
return "VExpressEMM-A15"
def get_bootarch(self):
return "armv7"
def get_platform(self):
return 'a15ve'
class QEMUMAchineARMv7Operations(QEMUMachineBaseOperations):
def _write_menu_lst(self, data, path):
self._machine._write_menu_lst(data, path)
def set_bootmodules(self, modules):
# write menu.lst
debug.verbose("Writing menu.lst in build directory.")
menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
"platforms", "arm", "menu.lst.armv7_a15ve_4")
self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
# produce ROM image
debug.verbose("Building QEMU image.")
debug.checkcmd(["make", self._machine.imagename],
cwd=self._machine.options.builds[0].build_dir)
def _get_cmdline(self):
qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
return ([qemu_wrapper, '--arch', 'a15ve', '--image', self._machine.kernel_img,
"--smp", "%s" % self._machine.get_ncores()])
for n in [1, 2, 4]:
MachineFactory.addMachine(QEMUMachineARMv7.name + ("_c%d" % n),
QEMUMachineARMv7,
bootarch = "armv7",
platform = "a15ve",
ncores = n)
class QEMUMachineZynq7(ARMMachineBase):
'''Zynq7000 as modelled by QEMU'''
name = 'qemu_armv7_zynq7'
imagename = "armv7_zynq7_image"
def __init__(self, options, **kwargs):
super(QEMUMachineZynq7, self).__init__(options, QEMUMachineZync7Operations(self), **kwargs)
self._set_kernel_image()
# XXX: change this once we have proper zynq7 configurations
self.menulst_template = "menu.lst.armv7_zynq7"
def get_buildall_target(self):
return "Zynq7000"
def get_ncores(self):
return 1
def get_platform(self):
return 'zynq7'
class QEMUMachineZync7Operations(QEMUMachineBaseOperations):
def _write_menu_lst(self, data, path):
self._machine._write_menu_lst(data, path)
def set_bootmodules(self, modules):
# write menu.lst
debug.verbose("Writing menu.lst in build directory.")
menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
"platforms", "arm", "menu.lst.armv7_zynq7")
self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
# produce ROM image
debug.verbose("Building QEMU image.")
debug.checkcmd(["make", self._machine.imagename],
cwd=self._machine.options.builds[0].build_dir)
def _get_cmdline(self):
qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
return ([qemu_wrapper, '--arch', 'zynq7', '--image', self._machine.kernel_img])
MachineFactory.addMachine(QEMUMachineZynq7.name + "_c1", QEMUMachineZynq7,
bootarch="armv7",
platform='zynq7')
class QEMUMachineARMv8(ARMMachineBase):
'''ARMv8 QEMU'''
name = 'qemu_armv8'
imagename = "armv8_efi"
def __init__(self, options, **kwargs):
super(QEMUMachineARMv8, self).__init__(options, QEMUMAchineARMv8Operations(self), **kwargs)
self._set_kernel_image()
self.menulst_template = "menu.lst.armv8_a57_qemu"
# 60 seconds per core
def get_boot_timeout(self):
return self.get_ncores() * 60
# 120 seconds per core
def get_test_timeout(self):
return self.get_ncores() * 240
def get_buildall_target(self):
return "QEMU"
def get_bootarch(self):
return "armv8"
def get_platform(self):
return 'a57_qemu'
class QEMUMAchineARMv8Operations(QEMUMachineBaseOperations):
def _write_menu_lst(self, data, path):
self._machine._write_menu_lst(data, path)
def set_bootmodules(self, modules):
# write menu.lst
debug.verbose("Writing menu.lst in build directory.")
menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
"platforms", "arm", "menu.lst.armv8_base")
self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
# produce ROM image
debug.verbose("Building QEMU EFI image.")
# debug.checkcmd(["make", self._machine.imagename],
# cwd=self._machine.options.builds[0].build_dir)
debug.checkcmd(["make"] + modules.get_build_targets(), cwd=self._machine.options.builds[0].build_dir)
efiimage.build_bf_efi_img(
self._machine.kernel_img,
self._machine.options.builds[0].build_dir,
modules.get_build_targets(),
menulst_fullpath,
None)
#efi = efiimage.EFIImage(self._machine.kernel_img, 200)
#efi.create()
#for module in modules.get_build_targets():
# efi.addFile(os.path.join(self._machine.options.builds[0].build_dir, module), module)
#efi.writeFile("startup.nsh", "Hagfish.efi hagfish.cfg")
#efi.addFile("/home/netos/tftpboot/Hagfish.efi", "Hagfish.efi")
#efi.addFile(menulst_fullpath, "hagfish.cfg")
def _get_cmdline(self):
qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
return [qemu_wrapper, '--arch', 'armv8', '--image', self._machine.kernel_img,
"--smp", "%s" % self._machine.get_ncores()]
for n in [1, 2, 4]:
MachineFactory.addMachine(QEMUMachineARMv8.name + ('_c%d' % n),
QEMUMachineARMv8,
boot_driver = 'boot_armv8_generic',
bootarch = "armv8",
ncores = n,
platform = "a57_qemu")
class QEMUMachineARMv8UBoot(ARMMachineBase):
'''ARMv8 QEMU with U-Boot'''
name = 'qemu_armv8_uboot'
imagename = "armv8_a57_qemu_image.efi"
def __init__(self, options, **kwargs):
super(QEMUMachineARMv8UBoot, self).__init__(options, QEMUMAchineARMv8UBootOperations(self), **kwargs)
self._set_kernel_image()
self.menulst_template = "menu.lst.armv8_a57_qemu"
def get_buildall_target(self):
return "QEMU"
def get_bootarch(self):
return "armv8"
def get_platform(self):
return 'a57_qemu'
class QEMUMAchineARMv8UBootOperations(QEMUMachineBaseOperations):
def _write_menu_lst(self, data, path):
self._machine._write_menu_lst(data, path)
def set_bootmodules(self, modules):
# write menu.lst
debug.verbose("Writing menu.lst in build directory.")
menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
"platforms", "arm", "menu.lst.armv8_a57_qemu")
self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
# produce ROM image
debug.verbose("Building QEMU image.")
debug.checkcmd(["make", self._machine.imagename],
cwd=self._machine.options.builds[0].build_dir)
def _get_cmdline(self):
qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
return ([qemu_wrapper, '--arch', 'armv8', '--uboot', '--image', self._machine.kernel_img,
"--smp", "%s" % self._machine.get_ncores()])
for n in [1, 2, 4]:
MachineFactory.addMachine(QEMUMachineARMv8UBoot.name + ('_c%d' % n),
QEMUMachineARMv8UBoot,
boot_driver = 'boot_armv8_generic',
bootarch = "armv8",
ncores = n,
qemu = True,
platform = "a57_qemu")