tools/ew.py: Add support for virtio-net
[helenos.git] / tools / ew.py
blobf9d953e9d9cf11d75cddc45bb1159b05dc299b07
1 #!/usr/bin/env python
3 # Copyright (c) 2013 Jakub Jermar
4 # All rights reserved.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
10 # - Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # - Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # - The name of the author may not be used to endorse or promote products
16 # derived from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 """
32 Emulator wrapper for running HelenOS
33 """
35 import os
36 import sys
37 import subprocess
38 import autotool
39 import platform
40 import thread
41 import time
43 overrides = {}
45 def is_override(str):
46 if str in overrides.keys():
47 return overrides[str]
48 return False
50 def cfg_get(platform, machine, processor):
51 if machine == "" or emulators[platform].has_key("run"):
52 return emulators[platform]
53 elif processor == "" or emulators[platform][machine].has_key("run"):
54 return emulators[platform][machine]
55 else:
56 return emulators[platform][machine][processor]
58 def termemu_detect():
59 for termemu in ['xfce4-terminal', 'xterm']:
60 try:
61 subprocess.check_output('which ' + termemu, shell = True)
62 return termemu
63 except:
64 pass
66 def run_in_console(cmd, title):
67 ecmd = cmd.replace('"', '\\"')
68 cmdline = termemu_detect() + ' -T ' + '"' + title + '"' + ' -e "' + ecmd + '"'
69 print(cmdline)
70 if not is_override('dryrun'):
71 subprocess.call(cmdline, shell = True)
73 def get_host_native_width():
74 return int(platform.architecture()[0].strip('bit'))
76 def pc_options(guest_width):
77 opts = ''
79 # Do not enable KVM if running 64 bits HelenOS
80 # on 32 bits host
81 host_width = get_host_native_width()
82 if guest_width <= host_width and not is_override('nokvm'):
83 opts = opts + ' -enable-kvm'
85 # Remove the leading space
86 return opts[1:]
88 def malta_options():
89 return '-cpu 4Kc'
91 def platform_to_qemu_options(platform, machine, processor):
92 if platform == 'amd64':
93 return 'system-x86_64', pc_options(64)
94 elif platform == 'arm32':
95 return 'system-arm', '-M integratorcp'
96 elif platform == 'ia32':
97 return 'system-i386', pc_options(32)
98 elif platform == 'mips32':
99 if machine == 'lmalta':
100 return 'system-mipsel', malta_options()
101 elif machine == 'bmalta':
102 return 'system-mips', malta_options()
103 elif platform == 'ppc32':
104 return 'system-ppc', '-m 256'
105 elif platform == 'sparc64':
106 if machine != 'generic':
107 raise Exception
108 if processor == 'us':
109 return 'system-sparc64', '-M sun4u --prom-env boot-args="console=devices/\\hw\\pci0\\01:01.0\\com1\\a"'
110 elif processor == 'sun4v':
111 default_path = '/usr/local/opensparc/image/'
112 try:
113 if os.path.exists(default_path):
114 opensparc_bins = default_path
115 elif os.path.exists(os.environ['OPENSPARC_BINARIES']):
116 opensparc_bins = os.environ['OPENSPARC_BINARIES']
117 else:
118 raise Exception
119 except:
120 print("Cannot find OpenSPARC binary images!")
121 print("Either set OPENSPARC_BINARIES environment variable accordingly or place the images in %s." % (default_path))
122 raise Exception
124 return 'system-sparc64', '-M niagara -m 256 -L %s' % (opensparc_bins)
127 def hdisk_mk():
128 if not os.path.exists('hdisk.img'):
129 subprocess.call('tools/mkfat.py 1048576 uspace/dist/data hdisk.img', shell = True)
131 def qemu_bd_options():
132 if is_override('nohdd'):
133 return ''
135 hdisk_mk()
137 return ' -drive file=hdisk.img,index=0,media=disk,format=raw'
139 def qemu_nic_ne2k_options():
140 return ' -device ne2k_isa,irq=5,vlan=0'
142 def qemu_nic_e1k_options():
143 return ' -device e1000,vlan=0'
145 def qemu_nic_rtl8139_options():
146 return ' -device rtl8139,vlan=0'
148 def qemu_nic_virtio_options():
149 return ' -device virtio-net,vlan=0'
151 def qemu_net_options():
152 if is_override('nonet'):
153 return ''
155 nic_options = ''
156 if 'net' in overrides.keys():
157 if 'e1k' in overrides['net'].keys():
158 nic_options += qemu_nic_e1k_options()
159 if 'rtl8139' in overrides['net'].keys():
160 nic_options += qemu_nic_rtl8139_options()
161 if 'ne2k' in overrides['net'].keys():
162 nic_options += qemu_nic_ne2k_options()
163 if 'virtio-net' in overrides['net'].keys():
164 nic_options += qemu_nic_virtio_options()
165 else:
166 # Use the default NIC
167 nic_options += qemu_nic_e1k_options()
169 return nic_options + ' -net user,hostfwd=udp::8080-:8080,hostfwd=udp::8081-:8081,hostfwd=tcp::8080-:8080,hostfwd=tcp::8081-:8081,hostfwd=tcp::2223-:2223'
171 def qemu_usb_options():
172 if is_override('nousb'):
173 return ''
174 return ' -usb'
176 def qemu_xhci_options():
177 if is_override('noxhci'):
178 return ''
179 return ' -device nec-usb-xhci,id=xhci'
181 def qemu_tablet_options():
182 if is_override('notablet') or (is_override('nousb') and is_override('noxhci')):
183 return ''
184 return ' -device usb-tablet'
186 def qemu_audio_options():
187 if is_override('nosnd'):
188 return ''
189 return ' -device intel-hda -device hda-duplex'
191 def qemu_run(platform, machine, processor):
192 cfg = cfg_get(platform, machine, processor)
193 suffix, options = platform_to_qemu_options(platform, machine, processor)
194 cmd = 'qemu-' + suffix
196 cmdline = cmd
197 if 'qemu_path' in overrides.keys():
198 cmdline = overrides['qemu_path'] + cmd
200 if options != '':
201 cmdline += ' ' + options
203 cmdline += qemu_bd_options()
205 if (not 'net' in cfg.keys()) or cfg['net']:
206 cmdline += qemu_net_options()
207 if (not 'usb' in cfg.keys()) or cfg['usb']:
208 cmdline += qemu_usb_options()
209 if (not 'xhci' in cfg.keys()) or cfg['xhci']:
210 cmdline += qemu_xhci_options()
211 if (not 'tablet' in cfg.keys()) or cfg['tablet']:
212 cmdline += qemu_tablet_options()
213 if (not 'audio' in cfg.keys()) or cfg['audio']:
214 cmdline += qemu_audio_options()
216 if cfg['image'] == 'image.iso':
217 cmdline += ' -boot d -cdrom image.iso'
218 elif cfg['image'] == 'image.boot':
219 cmdline += ' -kernel image.boot'
220 else:
221 cmdline += ' ' + cfg['image']
223 if ('console' in cfg.keys()) and not cfg['console']:
224 cmdline += ' -nographic'
226 title = 'HelenOS/' + platform
227 if machine != '':
228 title += ' on ' + machine
229 if 'expect' in cfg.keys():
230 cmdline = 'expect -c \'spawn %s; expect "%s" { send "%s" } timeout exp_continue; interact\'' % (cmdline, cfg['expect']['src'], cfg['expect']['dst'])
231 run_in_console(cmdline, title)
232 else:
233 print(cmdline)
234 if not is_override('dryrun'):
235 subprocess.call(cmdline, shell = True)
237 def ski_run(platform, machine, processor):
238 run_in_console('ski -i contrib/conf/ski.conf', 'HelenOS/ia64 on ski')
240 def msim_run(platform, machine, processor):
241 hdisk_mk()
242 run_in_console('msim -c contrib/conf/msim.conf', 'HelenOS/mips32 on msim')
244 def spike_run(platform, machine, processor):
245 run_in_console('spike -m1073741824:1073741824 image.boot', 'HelenOS/risvc64 on Spike')
247 emulators = {
248 'amd64' : {
249 'run' : qemu_run,
250 'image' : 'image.iso'
252 'arm32' : {
253 'integratorcp' : {
254 'run' : qemu_run,
255 'image' : 'image.boot',
256 'net' : False,
257 'audio' : False,
258 'xhci' : False,
259 'tablet' : False
262 'ia32' : {
263 'run' : qemu_run,
264 'image' : 'image.iso'
266 'ia64' : {
267 'ski' : {
268 'run' : ski_run
271 'mips32' : {
272 'msim' : {
273 'run' : msim_run
275 'lmalta' : {
276 'run' : qemu_run,
277 'image' : 'image.boot',
278 'console' : False
280 'bmalta' : {
281 'run' : qemu_run,
282 'image' : 'image.boot',
283 'console' : False
286 'ppc32' : {
287 'run' : qemu_run,
288 'image' : 'image.iso',
289 'audio' : False
291 'riscv64' : {
292 'run' : spike_run,
293 'image' : 'image.boot'
295 'sparc64' : {
296 'generic' : {
297 'us' : {
298 'run' : qemu_run,
299 'image' : 'image.iso',
300 'audio' : False,
301 'console' : False,
302 'net' : False,
303 'usb' : False,
304 'xhci' : False,
305 'tablet' : False
307 'sun4v' : {
308 'run' : qemu_run,
309 'image' : '-drive if=pflash,readonly=on,file=image.iso',
310 'audio' : False,
311 'console' : False,
312 'net' : False,
313 'usb' : False,
314 'xhci' : False,
315 'tablet' : False,
316 'expect' : {
317 'src' : 'ok ',
318 'dst' : 'boot\n'
325 def usage():
326 print("%s - emulator wrapper for running HelenOS\n" % os.path.basename(sys.argv[0]))
327 print("%s [-d] [-h] [-net e1k|rtl8139|ne2k|virtio-net] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] [-noxhci] [-notablet]\n" %
328 os.path.basename(sys.argv[0]))
329 print("-d\tDry run: do not run the emulation, just print the command line.")
330 print("-h\tPrint the usage information and exit.")
331 print("-nohdd\tDisable hard disk, if applicable.")
332 print("-nokvm\tDisable KVM, if applicable.")
333 print("-nonet\tDisable networking support, if applicable.")
334 print("-nosnd\tDisable sound, if applicable.")
335 print("-nousb\tDisable USB support, if applicable.")
336 print("-noxhci\tDisable XHCI support, if applicable.")
337 print("-notablet\tDisable USB tablet (use only relative-position PS/2 mouse instead), if applicable.")
339 def fail(platform, machine):
340 print("Cannot start emulation for the chosen configuration. (%s/%s)" % (platform, machine))
343 def run():
344 expect_nic = False
345 expect_qemu = False
347 for i in range(1, len(sys.argv)):
349 if expect_nic:
350 expect_nic = False
351 if not 'net' in overrides.keys():
352 overrides['net'] = {}
353 if sys.argv[i] == 'e1k':
354 overrides['net']['e1k'] = True
355 elif sys.argv[i] == 'rtl8139':
356 overrides['net']['rtl8139'] = True
357 elif sys.argv[i] == 'ne2k':
358 overrides['net']['ne2k'] = True
359 elif sys.argv[i] == 'virtio-net':
360 overrides['net']['virtio-net'] = True
361 else:
362 usage()
363 exit()
364 continue
366 if expect_qemu:
367 expect_qemu = False
368 overrides['qemu_path'] = sys.argv[i]
370 elif sys.argv[i] == '-h':
371 usage()
372 exit()
373 elif sys.argv[i] == '-d':
374 overrides['dryrun'] = True
375 elif sys.argv[i] == '-net' and i < len(sys.argv) - 1:
376 expect_nic = True
377 elif sys.argv[i] == '-nohdd':
378 overrides['nohdd'] = True
379 elif sys.argv[i] == '-nokvm':
380 overrides['nokvm'] = True
381 elif sys.argv[i] == '-nonet':
382 overrides['nonet'] = True
383 elif sys.argv[i] == '-nosnd':
384 overrides['nosnd'] = True
385 elif sys.argv[i] == '-nousb':
386 overrides['nousb'] = True
387 elif sys.argv[i] == '-noxhci':
388 overrides['noxhci'] = True
389 elif sys.argv[i] == '-notablet':
390 overrides['notablet'] = True
391 elif sys.argv[i] == '-qemu_path' and i < len(sys.argv) - 1:
392 expect_qemu = True
393 else:
394 usage()
395 exit()
397 config = {}
398 autotool.read_config(autotool.CONFIG, config)
400 if 'PLATFORM' in config.keys():
401 platform = config['PLATFORM']
402 else:
403 platform = ''
405 if 'MACHINE' in config.keys():
406 mach = config['MACHINE']
407 else:
408 mach = ''
410 if 'PROCESSOR' in config.keys():
411 processor = config['PROCESSOR']
412 else:
413 processor = ''
415 try:
416 emu_run = cfg_get(platform, mach, processor)['run']
417 emu_run(platform, mach, processor)
418 except:
419 fail(platform, mach)
420 return
422 run()