1 ##########################################################################
2 # Copyright (c) 2009-2016 ETH Zurich.
5 # This file is distributed under the terms in the attached LICENSE file.
6 # If you do not find this file, copies can be found by writing to:
7 # ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
8 ##########################################################################
10 import os, signal, tempfile, subprocess, shutil
12 from machines import Machine, ARMMachineBase, MachineFactory, MachineOperations
14 QEMU_SCRIPT_PATH = 'tools/qemu-wrapper.sh' # relative to source tree
15 GRUB_IMAGE_PATH = 'tools/grub-qemu.img' # relative to source tree
16 QEMU_CMD_X64 = 'qemu-system-x86_64'
17 QEMU_CMD_X32 = 'qemu-system-i386'
18 QEMU_CMD_ARM = 'qemu-system-arm'
19 QEMU_ARGS_GENERIC = '-nographic -no-reboot'.split()
20 QEMU_ARGS_X64 = '-net nic,model=ne2k_pci -net user -m 3084'.split()
21 QEMU_ARGS_X32 = '-net nic,model=ne2k_pci -net user -m 512'.split()
23 class QEMUMachineBase(Machine):
24 def __init__(self, options, operations, **kwargs):
25 super(QEMUMachineBase, self).__init__(options, operations, **kwargs)
27 def get_tickrate(self):
30 def get_buildall_target(self):
31 return self.get_bootarch().upper() + "_Full"
33 def get_boot_timeout(self):
34 # shorter time limit for running a qemu test
35 # FIXME: ideally this should somehow be expressed in CPU time / cycles
38 def get_machine_name(self):
41 def get_serial_binary(self):
42 return "serial_pc16550d"
44 class QEMUMachineBaseOperations(MachineOperations):
46 def __init__(self, machine):
47 super(QEMUMachineBaseOperations, self).__init__(machine)
55 def force_write(self, consolectrl):
58 def get_tftp_dir(self):
59 if self.tftp_dir is None:
60 debug.verbose('creating temporary directory for QEMU TFTP files')
61 self.tftp_dir = tempfile.mkdtemp(prefix='harness_qemu_')
62 debug.verbose('QEMU TFTP directory is %s' % self.tftp_dir)
65 def _write_menu_lst(self, data, path):
66 debug.verbose('writing %s' % path)
72 def set_bootmodules(self, modules):
73 path = os.path.join(self.get_tftp_dir(), 'menu.lst')
74 self._write_menu_lst(modules.get_menu_data('/'), path)
82 def _get_cmdline(self):
83 raise NotImplementedError
85 def _kill_child(self):
86 # terminate child if running
88 os.kill(self.child.pid, signal.SIGTERM)
95 cmd = self._get_cmdline()
96 debug.verbose('starting "%s"' % ' '.join(cmd))
98 (self.masterfd, slavefd) = pty.openpty()
99 self.child = subprocess.Popen(cmd, close_fds=True,
103 # open in binary mode w/o buffering
104 self.qemu_out = os.fdopen(self.masterfd, 'rb', 0)
108 # try to cleanup tftp tree if needed
109 if self.tftp_dir and os.path.isdir(self.tftp_dir):
110 shutil.rmtree(self.tftp_dir, ignore_errors=True)
113 def get_output(self):
116 class QEMUMachineX64Operations(QEMUMachineBaseOperations):
117 def _get_cmdline(self):
118 qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
119 menu_lst = os.path.join(self.get_tftp_dir(), 'menu.lst')
120 return [ qemu_wrapper, "--menu", menu_lst, "--arch", "x86_64",
121 "--smp", "%s" % self._machine.get_ncores() ]
123 def set_bootmodules(self, modules):
124 path = os.path.join(self.get_tftp_dir(), 'menu.lst')
125 self._write_menu_lst(modules.get_menu_data('/', self.get_tftp_dir()), path)
127 class QEMUMachineX32Operations(QEMUMachineBaseOperations):
128 def _get_cmdline(self):
129 grub_image = os.path.join(self.options.sourcedir, GRUB_IMAGE_PATH)
130 s = '-smp %d -fda %s -tftp %s' % (self.get_ncores(), grub_image,
132 return [QEMU_CMD_X32] + QEMU_ARGS_GENERIC + QEMU_ARGS_X32 + s.split()
134 # create 1, 2 and 4 core x86_64 qemu machines
137 class TmpMachine(QEMUMachineBase):
138 def __init__(self, options, _class=None, **kwargs):
139 super(_class, self).__init__(options, QEMUMachineX64Operations(self), **kwargs)
141 # 60 seconds per core
142 def get_boot_timeout(self):
143 return self.get_ncores() * 60
145 # 120 seconds per core
146 def get_test_timeout(self):
147 return self.get_ncores() * 120
149 MachineFactory.addMachine('qemu%d' % n, TmpMachine,
154 class QEMUMachineARMv7Uniproc(ARMMachineBase):
155 '''Uniprocessor ARMv7 QEMU'''
158 imagename = "armv7_a15ve_1_image"
160 def __init__(self, options, **kwargs):
161 super(QEMUMachineARMv7Uniproc, self).__init__(options, QEMUMAchineARMv7UniprocOperations(self), **kwargs)
162 self._set_kernel_image()
164 def get_ncores(self):
167 def get_buildall_target(self):
168 return "VExpressEMM-A15"
170 def get_bootarch(self):
173 def get_platform(self):
176 class QEMUMAchineARMv7UniprocOperations(QEMUMachineBaseOperations):
178 def _write_menu_lst(self, data, path):
179 self._machine._write_menu_lst(data, path)
181 def set_bootmodules(self, modules):
183 debug.verbose("Writing menu.lst in build directory.")
184 menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
185 "platforms", "arm", "menu.lst.armv7_a15ve_1")
186 self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
189 debug.verbose("Building QEMU image.")
190 debug.checkcmd(["make", self._machine.imagename],
191 cwd=self._machine.options.builds[0].build_dir)
193 def _get_cmdline(self):
194 qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
196 return ([qemu_wrapper, '--arch', 'a15ve', '--image', self._machine.kernel_img])
198 MachineFactory.addMachine(QEMUMachineARMv7Uniproc.name, QEMUMachineARMv7Uniproc,
202 class QEMUMachineZynq7(ARMMachineBase):
203 '''Zynq7000 as modelled by QEMU'''
204 name = 'qemu_armv7_zynq7'
206 imagename = "armv7_zynq7_image"
208 def __init__(self, options, **kwargs):
209 super(QEMUMachineZynq7, self).__init__(options, QEMUMachineZync7Operations(self), **kwargs)
210 self._set_kernel_image()
211 # XXX: change this once we have proper zynq7 configurations
212 self.menulst_template = "menu.lst.armv7_zynq7"
214 def get_buildall_target(self):
217 def get_ncores(self):
220 def get_platform(self):
223 class QEMUMachineZync7Operations(QEMUMachineBaseOperations):
225 def _write_menu_lst(self, data, path):
226 self._machine._write_menu_lst(data, path)
228 def set_bootmodules(self, modules):
230 debug.verbose("Writing menu.lst in build directory.")
231 menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
232 "platforms", "arm", "menu.lst.armv7_zynq7")
233 self._write_menu_lst(modules.get_menu_data('/'), menulst_fullpath)
236 debug.verbose("Building QEMU image.")
237 debug.checkcmd(["make", self._machine.imagename],
238 cwd=self._machine.options.builds[0].build_dir)
240 def _get_cmdline(self):
241 qemu_wrapper = os.path.join(self._machine.options.sourcedir, QEMU_SCRIPT_PATH)
243 return ([qemu_wrapper, '--arch', 'zynq7', '--image', self._machine.kernel_img])
245 MachineFactory.addMachine(QEMUMachineZynq7.name, QEMUMachineZynq7,