source: mainline/tools/ew.py@ e2b417f

Last change on this file since e2b417f was 56a3c29e, checked in by Vojtech Horky <vojtech.horky@…>, 20 months ago

ew.py: hide confusing error message

The error message is printed for terminal emulators that are not
found. But if there is another failure (e.g. error in msim.conf)
the error message looks like it is related to not finding the
right terminal emulator. Thus it is better to hide it completely.

  • Property mode set to 100755
File size: 15.3 KB
Line 
1#!/usr/bin/env python3
2#
3# Copyright (c) 2013 Jakub Jermar
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9#
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.
17#
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.
28#
29
30
31"""
32Emulator wrapper for running HelenOS
33"""
34
35import inspect
36import os
37import platform
38import re
39import subprocess
40import sys
41import _thread
42import time
43
44overrides = {}
45
46CONFIG = 'Makefile.config'
47
48TOOLS_DIR = os.path.dirname(inspect.getabsfile(inspect.currentframe()))
49
50def read_config():
51 "Read HelenOS build configuration"
52
53 inf = open(CONFIG, 'r')
54 config = {}
55
56 for line in inf:
57 res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
58 if (res):
59 config[res.group(1)] = res.group(2)
60
61 inf.close()
62 return config
63
64def is_override(str):
65 if str in overrides.keys():
66 return overrides[str]
67 return False
68
69def cfg_get(platform, machine, processor):
70 if machine == "" or "run" in emulators[platform]:
71 return emulators[platform]
72 elif processor == "" or "run" in emulators[platform][machine]:
73 return emulators[platform][machine]
74 else:
75 return emulators[platform][machine][processor]
76
77def termemu_detect():
78 emus = ['gnome-terminal', 'xfce4-terminal', 'xterm']
79 for termemu in emus:
80 try:
81 subprocess.check_output('which ' + termemu, shell = True, stderr = subprocess.STDOUT)
82 return termemu
83 except:
84 pass
85
86 print('Could not find any of the terminal emulators %s.'%(emus))
87 sys.exit(1)
88
89def run_in_console(cmd, title):
90 temu = termemu_detect()
91 if temu == 'gnome-terminal':
92 cmdline = temu + ' -- ' + cmd
93 else:
94 ecmd = cmd.replace('"', '\\"')
95 cmdline = temu + ' -T ' + '"' + title + '"' + ' -e "' + ecmd + '"'
96
97 print(cmdline)
98 if not is_override('dryrun'):
99 subprocess.call(cmdline, shell = True)
100
101def get_host_native_width():
102 return int(platform.architecture()[0].strip('bit'))
103
104def pc_options(guest_width):
105 opts = ''
106
107 # Do not enable KVM if running 64 bits HelenOS
108 # on 32 bits host
109 host_width = get_host_native_width()
110 if guest_width <= host_width and not is_override('nokvm'):
111 opts = opts + ' -enable-kvm'
112
113 # Remove the leading space
114 return opts[1:]
115
116def malta_options():
117 return '-cpu 4Kc -append "console=devices/\\hw\\pci0\\00:0a.0\\com1\\a"'
118
119def find_firmware(name, environ_var, default_paths, extra_info=None):
120 """Find firmware image(s)."""
121
122 if environ_var in os.environ:
123 return os.environ[environ_var]
124
125 for path in default_paths:
126 if os.path.exists(path):
127 return path
128
129 sys.stderr.write("Cannot find %s binary image(s)!\n" % name)
130 sys.stderr.write(
131 "Either set %s environment variable accordingly or place the image(s) in one of the default locations: %s.\n" %
132 (environ_var, ", ".join(default_paths)))
133 if extra_info is not None:
134 sys.stderr.write(extra_info)
135 return None
136
137def platform_to_qemu_options(platform, machine, processor):
138 if platform == 'amd64':
139 return 'system-x86_64', pc_options(64)
140 elif platform == 'arm32':
141 if machine == 'integratorcp':
142 return 'system-arm', '-M integratorcp'
143 elif machine == 'raspberrypi':
144 return 'system-arm', '-M raspi1ap'
145 elif platform == 'arm64':
146 if machine == 'virt':
147 # Search for the EDK2 firmware image
148 default_paths = (
149 '/usr/local/qemu-efi-aarch64/QEMU_EFI.fd', # Custom
150 '/usr/share/edk2/aarch64/QEMU_EFI.fd', # Fedora
151 '/usr/share/qemu-efi-aarch64/QEMU_EFI.fd', # Ubuntu
152 )
153 extra_info = ("Pre-compiled binary can be obtained from "
154 "http://snapshots.linaro.org/components/kernel/leg-virt-tianocore-edk2-upstream/latest/QEMU-AARCH64/RELEASE_GCC5/QEMU_EFI.fd.\n")
155 efi_path = find_firmware(
156 "EDK2", 'EW_QEMU_EFI_AARCH64', default_paths, extra_info)
157 if efi_path is None:
158 raise Exception
159
160 return 'system-aarch64', \
161 '-M virt -cpu cortex-a57 -m 1024 -bios %s' % efi_path
162 elif platform == 'ia32':
163 return 'system-i386', pc_options(32)
164 elif platform == 'mips32':
165 if machine == 'lmalta':
166 return 'system-mipsel', malta_options()
167 elif machine == 'bmalta':
168 return 'system-mips', malta_options()
169 elif platform == 'ppc32':
170 return 'system-ppc', '-m 256'
171 elif platform == 'sparc64':
172 if machine != 'generic':
173 raise Exception
174 if processor == 'us':
175 cmdline = '-M sun4u'
176 if is_override('nographic'):
177 cmdline += ' --prom-env boot-args="console=devices/\\hw\\pci0\\01:01.0\\com1\\a"'
178 return 'system-sparc64', cmdline
179
180 # processor = 'sun4v'
181 opensparc_bins = find_firmware(
182 "OpenSPARC", 'OPENSPARC_BINARIES',
183 ('/usr/local/opensparc/image/', ))
184 if opensparc_bins is None:
185 raise Exception
186
187 return 'system-sparc64', '-M niagara -m 256 -L %s' % (opensparc_bins)
188
189
190def hdisk_mk():
191 if not os.path.exists('hdisk.img'):
192 subprocess.call(TOOLS_DIR + '/mkfat.py 1048576 dist/data hdisk.img', shell = True)
193
194def qemu_bd_options():
195 if is_override('nohdd'):
196 return ''
197
198 hdisk_mk()
199
200 hdd_options = ''
201 if 'hdd' in overrides.keys():
202 if 'ata' in overrides['hdd'].keys():
203 hdd_options += ''
204 elif 'virtio-blk' in overrides['hdd'].keys():
205 hdd_options += ',if=virtio'
206
207 return ' -drive file=hdisk.img,index=0,media=disk,format=raw' + hdd_options
208
209def qemu_nic_ne2k_options():
210 return ' -device ne2k_isa,irq=5,netdev=n1'
211
212def qemu_nic_e1k_options():
213 return ' -device e1000,netdev=n1'
214
215def qemu_nic_rtl8139_options():
216 return ' -device rtl8139,netdev=n1'
217
218def qemu_nic_virtio_options():
219 return ' -device virtio-net,netdev=n1'
220
221def qemu_net_options():
222 if is_override('nonet'):
223 return ''
224
225 nic_options = ''
226 if 'net' in overrides.keys():
227 if 'e1k' in overrides['net'].keys():
228 nic_options += qemu_nic_e1k_options()
229 if 'rtl8139' in overrides['net'].keys():
230 nic_options += qemu_nic_rtl8139_options()
231 if 'ne2k' in overrides['net'].keys():
232 nic_options += qemu_nic_ne2k_options()
233 if 'virtio-net' in overrides['net'].keys():
234 nic_options += qemu_nic_virtio_options()
235 else:
236 # Use the default NIC
237 nic_options += qemu_nic_e1k_options()
238
239 return nic_options + ' -netdev user,id=n1,hostfwd=udp::8080-:8080,hostfwd=udp::8081-:8081,hostfwd=tcp::8080-:8080,hostfwd=tcp::8081-:8081,hostfwd=tcp::2223-:2223'
240
241def qemu_usb_options():
242 if is_override('nousb'):
243 return ''
244 return ' -usb'
245
246def qemu_xhci_options():
247 if is_override('noxhci'):
248 return ''
249 return ' -device nec-usb-xhci,id=xhci'
250
251def qemu_tablet_options():
252 if is_override('notablet') or (is_override('nousb') and is_override('noxhci')):
253 return ''
254 return ' -device usb-tablet'
255
256def qemu_audio_options():
257 if is_override('nosnd'):
258 return ''
259 return ' -device intel-hda -device hda-duplex'
260
261def qemu_run(platform, machine, processor):
262 cfg = cfg_get(platform, machine, processor)
263 suffix, options = platform_to_qemu_options(platform, machine, processor)
264 cmd = 'qemu-' + suffix
265
266 cmdline = cmd
267 if 'qemu_path' in overrides.keys():
268 cmdline = overrides['qemu_path'] + cmd
269
270 if options != '':
271 cmdline += ' ' + options
272
273 if (not 'hdd' in cfg.keys() or cfg['hdd']):
274 cmdline += qemu_bd_options()
275 if (not 'net' in cfg.keys()) or cfg['net']:
276 cmdline += qemu_net_options()
277 if (not 'usb' in cfg.keys()) or cfg['usb']:
278 cmdline += qemu_usb_options()
279 if (not 'xhci' in cfg.keys()) or cfg['xhci']:
280 cmdline += qemu_xhci_options()
281 if (not 'tablet' in cfg.keys()) or cfg['tablet']:
282 cmdline += qemu_tablet_options()
283 if (not 'audio' in cfg.keys()) or cfg['audio']:
284 cmdline += qemu_audio_options()
285
286 console = ('console' in cfg.keys() and cfg['console'])
287
288 if (is_override('nographic')):
289 cmdline += ' -nographic'
290 console = True
291
292 if (not console and (not is_override('nographic')) and not is_override('noserial')):
293 cmdline += ' -serial stdio'
294
295 if (is_override('bigmem')):
296 cmdline += ' -m 4G'
297
298 if cfg['image'] == 'image.iso':
299 cmdline += ' -boot d -cdrom image.iso'
300 elif cfg['image'] == 'image.iso@arm64':
301 # Define image.iso cdrom backend.
302 cmdline += ' -drive if=none,file=image.iso,id=cdrom,media=cdrom'
303 # Define scsi bus.
304 cmdline += ' -device virtio-scsi-device'
305 # Define cdrom frontend connected to this scsi bus.
306 cmdline += ' -device scsi-cd,drive=cdrom'
307 elif cfg['image'] == 'image.boot':
308 cmdline += ' -kernel image.boot'
309 elif cfg['image'] == 'kernel.img@rpi':
310 cmdline += ' -bios boot/image.boot.bin'
311 else:
312 cmdline += ' ' + cfg['image']
313
314 if console:
315 cmdline += ' -nographic'
316
317 title = 'HelenOS/' + platform
318 if machine != '':
319 title += ' on ' + machine
320 if 'expect' in cfg.keys():
321 cmdline = 'expect -c \'spawn %s; expect "%s" { send "%s" } timeout exp_continue; interact\'' % (cmdline, cfg['expect']['src'], cfg['expect']['dst'])
322 run_in_console(cmdline, title)
323 else:
324 print(cmdline)
325 if not is_override('dryrun'):
326 subprocess.call(cmdline, shell = True)
327
328def ski_run(platform, machine, processor):
329 run_in_console('ski -i ' + TOOLS_DIR + '/conf/ski.conf', 'HelenOS/ia64 on ski')
330
331def msim_run(platform, machine, processor):
332 hdisk_mk()
333 run_in_console('msim -n -c ' + TOOLS_DIR + '/conf/msim.conf', 'HelenOS/mips32 on msim')
334
335def spike_run(platform, machine, processor):
336 run_in_console('spike -m1073741824:1073741824 image.boot', 'HelenOS/risvc64 on Spike')
337
338emulators = {
339 'amd64' : {
340 'run' : qemu_run,
341 'image' : 'image.iso'
342 },
343 'arm32' : {
344 'integratorcp' : {
345 'run' : qemu_run,
346 'image' : 'image.boot',
347 'net' : False,
348 'audio' : False,
349 'xhci' : False,
350 'tablet' : False
351 },
352 'raspberrypi' : {
353 'run' : qemu_run,
354 'image' : 'kernel.img@rpi',
355 'audio' : False,
356 'console' : True,
357 'hdd' : False,
358 'net' : False,
359 'tablet' : False,
360 'usb' : False,
361 'xhci' : False
362 },
363 },
364 'arm64' : {
365 'virt' : {
366 'run' : qemu_run,
367 'image' : 'image.iso@arm64',
368 'audio' : False,
369 'console' : True,
370 'hdd' : False,
371 'net' : False,
372 'tablet' : False,
373 'usb' : False,
374 'xhci' : False
375 }
376 },
377 'ia32' : {
378 'run' : qemu_run,
379 'image' : 'image.iso'
380 },
381 'ia64' : {
382 'ski' : {
383 'run' : ski_run
384 }
385 },
386 'mips32' : {
387 'msim' : {
388 'run' : msim_run
389 },
390 'lmalta' : {
391 'run' : qemu_run,
392 'image' : 'image.boot',
393 'console' : True
394 },
395 'bmalta' : {
396 'run' : qemu_run,
397 'image' : 'image.boot',
398 'console' : True
399 },
400 },
401 'ppc32' : {
402 'run' : qemu_run,
403 'image' : 'image.iso',
404 'audio' : False
405 },
406 'riscv64' : {
407 'run' : spike_run,
408 'image' : 'image.boot'
409 },
410 'sparc64' : {
411 'generic' : {
412 'us' : {
413 'run' : qemu_run,
414 'image' : 'image.iso',
415 'audio' : False,
416 'console' : False,
417 'net' : False,
418 'usb' : False,
419 'xhci' : False,
420 'tablet' : False
421 },
422 'sun4v' : {
423 'run' : qemu_run,
424 # QEMU 8.0.0 ignores the 'file' argument and instead uses 'id',
425 # which defaults to 'pflash0', but can be changed to the same value
426 # as 'file'
427 'image' : '-drive if=pflash,id=image.iso,readonly=on,file=image.iso',
428 'audio' : False,
429 'console' : True,
430 'net' : False,
431 'usb' : False,
432 'xhci' : False,
433 'tablet' : False,
434 'expect' : {
435 'src' : 'ok ',
436 'dst' : 'boot\n'
437 },
438 }
439 }
440 },
441}
442
443def usage():
444 print("%s - emulator wrapper for running HelenOS\n" % os.path.basename(sys.argv[0]))
445 print("%s [-d] [-h] [-net e1k|rtl8139|ne2k|virtio-net] [-hdd ata|virtio-blk] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] [-noxhci] [-notablet]\n" %
446 os.path.basename(sys.argv[0]))
447 print("-d\tDry run: do not run the emulation, just print the command line.")
448 print("-h\tPrint the usage information and exit.")
449 print("-nohdd\tDisable hard disk, if applicable.")
450 print("-nokvm\tDisable KVM, if applicable.")
451 print("-nonet\tDisable networking support, if applicable.")
452 print("-nosnd\tDisable sound, if applicable.")
453 print("-nousb\tDisable USB support, if applicable.")
454 print("-noxhci\tDisable XHCI support, if applicable.")
455 print("-notablet\tDisable USB tablet (use only relative-position PS/2 mouse instead), if applicable.")
456 print("-nographic\tDisable graphical output. Serial port output must be enabled for this to be useful.")
457 print("-noserial\tDisable serial port output in the terminal.")
458 print("-bigmem\tSets maximum RAM size to 4GB.")
459
460def fail(platform, machine):
461 print("Cannot start emulation for the chosen configuration. (%s/%s)" % (platform, machine))
462
463
464def run():
465 expect_nic = False
466 expect_hdd = False
467 expect_qemu = False
468
469 for i in range(1, len(sys.argv)):
470
471 if expect_nic:
472 expect_nic = False
473 if not 'net' in overrides.keys():
474 overrides['net'] = {}
475 if sys.argv[i] == 'e1k':
476 overrides['net']['e1k'] = True
477 elif sys.argv[i] == 'rtl8139':
478 overrides['net']['rtl8139'] = True
479 elif sys.argv[i] == 'ne2k':
480 overrides['net']['ne2k'] = True
481 elif sys.argv[i] == 'virtio-net':
482 overrides['net']['virtio-net'] = True
483 else:
484 usage()
485 exit()
486 continue
487
488 if expect_hdd:
489 expect_hdd = False
490 if not 'hdd' in overrides.keys():
491 overrides['hdd'] = {}
492 if sys.argv[i] == 'ata':
493 overrides['hdd']['ata'] = True
494 elif sys.argv[i] == 'virtio-blk':
495 overrides['hdd']['virtio-blk'] = True
496 else:
497 usage()
498 exit()
499 continue
500
501 if expect_qemu:
502 expect_qemu = False
503 overrides['qemu_path'] = sys.argv[i]
504
505 elif sys.argv[i] == '-h':
506 usage()
507 exit()
508 elif sys.argv[i] == '-d':
509 overrides['dryrun'] = True
510 elif sys.argv[i] == '-net' and i < len(sys.argv) - 1:
511 expect_nic = True
512 elif sys.argv[i] == '-hdd' and i < len(sys.argv) - 1:
513 expect_hdd = True
514 elif sys.argv[i] == '-nohdd':
515 overrides['nohdd'] = True
516 elif sys.argv[i] == '-nokvm':
517 overrides['nokvm'] = True
518 elif sys.argv[i] == '-nonet':
519 overrides['nonet'] = True
520 elif sys.argv[i] == '-nosnd':
521 overrides['nosnd'] = True
522 elif sys.argv[i] == '-nousb':
523 overrides['nousb'] = True
524 elif sys.argv[i] == '-noxhci':
525 overrides['noxhci'] = True
526 elif sys.argv[i] == '-notablet':
527 overrides['notablet'] = True
528 elif sys.argv[i] == '-nographic':
529 overrides['nographic'] = True
530 elif sys.argv[i] == '-bigmem':
531 overrides['bigmem'] = True
532 elif sys.argv[i] == '-noserial':
533 overrides['noserial'] = True
534 elif sys.argv[i] == '-qemu_path' and i < len(sys.argv) - 1:
535 expect_qemu = True
536 else:
537 usage()
538 exit()
539
540 config = read_config()
541
542 if 'PLATFORM' in config.keys():
543 platform = config['PLATFORM']
544 else:
545 platform = ''
546
547 if 'MACHINE' in config.keys():
548 mach = config['MACHINE']
549 else:
550 mach = ''
551
552 if 'PROCESSOR' in config.keys():
553 processor = config['PROCESSOR']
554 else:
555 processor = ''
556
557 try:
558 emu_run = cfg_get(platform, mach, processor)['run']
559 emu_run(platform, mach, processor)
560 except:
561 fail(platform, mach)
562 return
563
564run()
Note: See TracBrowser for help on using the repository browser.