run 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. #!/usr/bin/env python3
  2. import os
  3. import re
  4. import shlex
  5. import shutil
  6. import subprocess
  7. import sys
  8. import time
  9. import common
  10. defaults = {
  11. 'cpus': 1,
  12. 'debug_guest': False,
  13. 'debug_vm': None,
  14. 'eval': None,
  15. 'extra_emulator_args': [],
  16. 'gem5_exe_args': '',
  17. 'gem5_script': 'fs',
  18. 'gem5_readfile': '',
  19. 'gem5_restore': None,
  20. 'graphic': False,
  21. 'initramfs': False,
  22. 'initrd': False,
  23. 'kernel_cli': None,
  24. 'kernel_cli_after_dash': None,
  25. 'eval_busybox': None,
  26. 'kgdb': False,
  27. 'kdb': False,
  28. 'kvm': False,
  29. 'memory': '256M',
  30. 'record': False,
  31. 'replay': False,
  32. 'terminal': False,
  33. 'tmux': None,
  34. 'trace': None,
  35. 'userland': None,
  36. 'userland_before': '',
  37. 'vnc': False,
  38. }
  39. def main(args, extra_args=None):
  40. global defaults
  41. args = common.resolve_args(defaults, args, extra_args)
  42. # Common qemu / gem5 logic.
  43. # nokaslr:
  44. # * https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb
  45. # * https://stackoverflow.com/questions/44612822/unable-to-debug-kernel-with-qemu-gdb/49840927#49840927
  46. # Turned on by default since v4.12
  47. kernel_cli = 'console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y rw'
  48. if args.kernel_cli is not None:
  49. kernel_cli += ' {}'.format(args.kernel_cli)
  50. kernel_cli_after_dash = ''
  51. extra_emulator_args = []
  52. extra_qemu_args = []
  53. if args.debug_vm is not None:
  54. print(args.debug_vm)
  55. debug_vm = ['gdb', '-q'] + shlex.split(args.debug_vm) + ['--args']
  56. else:
  57. debug_vm = []
  58. if args.debug_guest:
  59. extra_qemu_args.append('-S')
  60. if args.eval_busybox is not None:
  61. kernel_cli_after_dash += ' lkmc_eval_base64="{}"'.format(common.base64_encode(args.eval_busybox))
  62. if args.kernel_cli_after_dash is not None:
  63. kernel_cli_after_dash += ' {}'.format(args.kernel_cli_after_dash)
  64. if args.vnc:
  65. vnc = ['-vnc', ':0']
  66. else:
  67. vnc = []
  68. if args.initrd or args.initramfs:
  69. ramfs = True
  70. else:
  71. ramfs = False
  72. if args.eval is not None:
  73. if ramfs:
  74. initarg = 'rdinit'
  75. else:
  76. initarg = 'init'
  77. kernel_cli += ' {}=/eval_base64.sh'.format(initarg)
  78. kernel_cli_after_dash += ' lkmc_eval="{}"'.format(common.base64_encode(args.eval))
  79. if not args.graphic:
  80. extra_qemu_args.append('-nographic')
  81. console = None
  82. console_type = None
  83. console_count = 0
  84. if args.arch == 'x86_64':
  85. console_type = 'ttyS'
  86. elif common.is_arm:
  87. console_type = 'ttyAMA'
  88. console = '{}{}'.format(console_type, console_count)
  89. console_count += 1
  90. if not (args.arch == 'x86_64' and args.graphic):
  91. kernel_cli += ' console={}'.format(console)
  92. extra_console = '{}{}'.format(console_type, console_count)
  93. console_count += 1
  94. if args.kdb or args.kgdb:
  95. kernel_cli += ' kgdbwait'
  96. if args.kdb:
  97. if args.graphic:
  98. kdb_cmd = 'kbd,'
  99. else:
  100. kdb_cmd = ''
  101. kernel_cli += ' kgdboc={}{},115200'.format(kdb_cmd, console)
  102. if args.kgdb:
  103. kernel_cli += ' kgdboc={},115200'.format(extra_console)
  104. if kernel_cli_after_dash:
  105. kernel_cli += " -{}".format(kernel_cli_after_dash)
  106. extra_env = {}
  107. if args.trace is None:
  108. do_trace = False
  109. # A dummy value that is already turned on by default and does not produce large output,
  110. # just to prevent QEMU from emitting a warning that '' is not valid.
  111. trace_type = 'load_file'
  112. else:
  113. do_trace = True
  114. trace_type = args.trace
  115. def raise_rootfs_not_found():
  116. raise Exception('Root filesystem not found. Did you build it?\n' \
  117. 'Tried to use: ' + common.disk_image)
  118. def raise_image_not_found():
  119. raise Exception('Executable image not found. Did you build it?\n' \
  120. 'Tried to use: ' + common.image)
  121. if common.image is None:
  122. raise Exception('Baremetal ELF file not found. Tried:\n' + '\n'.join(paths))
  123. cmd = debug_vm.copy()
  124. if args.gem5:
  125. if args.baremetal is None:
  126. if not os.path.exists(common.rootfs_raw_file):
  127. if not os.path.exists(common.qcow2_file):
  128. raise_rootfs_not_found()
  129. common.raw_to_qcow2(prebuilt=args.prebuilt, reverse=True)
  130. else:
  131. if not os.path.exists(common.gem5_fake_iso):
  132. os.makedirs(os.path.dirname(common.gem5_fake_iso), exist_ok=True)
  133. common.write_string_to_file(common.gem5_fake_iso, 'a' * 512)
  134. if not os.path.exists(common.image):
  135. # This is to run gem5 from a prebuilt download.
  136. if (not args.baremetal is None) or (not os.path.exists(common.linux_image)):
  137. raise_image_not_found()
  138. common.run_cmd([os.path.join(common.extract_vmlinux, common.linux_image)])
  139. os.makedirs(os.path.dirname(common.gem5_readfile), exist_ok=True)
  140. common.write_string_to_file(common.gem5_readfile, args.gem5_readfile)
  141. memory = '{}B'.format(args.memory)
  142. gem5_exe_args = shlex.split(args.gem5_exe_args)
  143. if do_trace:
  144. gem5_exe_args.append('--debug-flags={}'.format(trace_type))
  145. extra_env['M5_PATH'] = common.gem5_system_dir
  146. # https://stackoverflow.com/questions/52312070/how-to-modify-a-file-under-src-python-and-run-it-without-rebuilding-in-gem5/52312071#52312071
  147. extra_env['M5_OVERRIDE_PY_SOURCE'] = 'true'
  148. cmd.extend(
  149. [
  150. common.executable,
  151. '--debug-file=trace.txt',
  152. ] +
  153. gem5_exe_args +
  154. [
  155. '-d', common.m5out_dir
  156. ]
  157. )
  158. if args.userland is not None:
  159. cmd.extend([common.gem5_se_file, '-c', common.resolve_userland(args.userland)])
  160. else:
  161. if args.gem5_script == 'fs':
  162. # TODO port
  163. if args.gem5_restore is not None:
  164. cpt_dirs = common.gem_list_checkpoint_dirs()
  165. cpt_dir = cpt_dirs[-args.gem5_restore]
  166. extra_emulator_args.extend(['-r', str(sorted(cpt_dirs).index(cpt_dir) + 1)])
  167. cmd.extend([
  168. common.gem5_fs_file,
  169. '--disk-image', common.disk_image,
  170. '--kernel', common.image,
  171. '--mem-size', memory,
  172. '--num-cpus', str(args.cpus),
  173. '--script', common.gem5_readfile,
  174. ])
  175. if args.arch == 'x86_64':
  176. if args.kvm:
  177. cmd.extend(['--cpu-type', 'X86KvmCPU'])
  178. cmd.extend(['--command-line', 'earlyprintk={} lpj=7999923 root=/dev/sda {}'.format(console, kernel_cli)])
  179. elif common.is_arm:
  180. # TODO why is it mandatory to pass mem= here? Not true for QEMU.
  181. # Anything smaller than physical blows up as expected, but why can't it auto-detect the right value?
  182. cmd.extend([
  183. '--command-line', 'earlyprintk=pl011,0x1c090000 lpj=19988480 rw loglevel=8 mem={} root=/dev/sda {}'.format(memory, kernel_cli),
  184. '--dtb-filename', os.path.join(common.gem5_system_dir, 'arm', 'dt', 'armv{}_gem5_v1_{}cpu.dtb'.format(common.armv, args.cpus)),
  185. '--machine-type', common.machine,
  186. '--param', 'system.panic_on_panic = True',
  187. ])
  188. if not args.baremetal is None:
  189. cmd.append('--bare-metal')
  190. if args.arch == 'aarch64':
  191. # https://stackoverflow.com/questions/43682311/uart-communication-in-gem5-with-arm-bare-metal/50983650#50983650
  192. cmd.extend(['--param', 'system.highest_el_is_64 = True'])
  193. cmd.extend(['--param', 'system.auto_reset_addr_64 = True'])
  194. elif args.gem5_script == 'biglittle':
  195. if args.gem5_restore is not None:
  196. cpt_dir = common.gem_list_checkpoint_dirs()[-args.gem5_restore]
  197. extra_emulator_args.extend(['--restore-from', os.path.join(common.m5out_dir, cpt_dir)])
  198. cmd.extend([
  199. os.path.join(common.gem5_src_dir, 'configs', 'example', 'arm', 'fs_bigLITTLE.py'),
  200. '--big-cpus', '2',
  201. '--cpu-type', 'atomic',
  202. '--disk', common.disk_image,
  203. '--dtb', os.path.join(common.gem5_system_dir, 'arm', 'dt', 'armv8_gem5_v1_big_little_2_2.dtb'),
  204. '--kernel', common.image,
  205. '--little-cpus', '2'
  206. ])
  207. if args.debug_guest:
  208. # https://stackoverflow.com/questions/49296092/how-to-make-gem5-wait-for-gdb-to-connect-to-reliably-break-at-start-kernel-of-th
  209. cmd.extend(['--param', 'system.cpu[0].wait_for_remote_gdb = True'])
  210. else:
  211. qemu_user_and_system_options = [
  212. '-trace', 'enable={},file={}'.format(trace_type, common.qemu_trace_file),
  213. ]
  214. if args.userland is not None:
  215. if args.debug_guest:
  216. debug_args = ['-g', str(common.gdb_port)]
  217. else:
  218. debug_args = []
  219. cmd.extend(
  220. [
  221. os.path.join(common.qemu_build_dir, '{}-linux-user'.format(args.arch), 'qemu-{}'.format(args.arch)),
  222. '-L', common.target_dir,
  223. ] +
  224. qemu_user_and_system_options +
  225. shlex.split(args.userland_before) +
  226. debug_args +
  227. [
  228. common.resolve_userland(args.userland)
  229. ]
  230. )
  231. else:
  232. if not os.path.exists(common.image):
  233. raise_image_not_found()
  234. extra_emulator_args.extend(extra_qemu_args)
  235. common.make_run_dirs()
  236. if args.prebuilt:
  237. qemu_executable = common.qemu_executable_basename
  238. qemu_found = shutil.which(qemu_executable) is not None
  239. else:
  240. qemu_executable = common.qemu_executable
  241. qemu_found = os.path.exists(qemu_executable)
  242. if not qemu_found:
  243. raise Exception('QEMU executable not found, did you forget to build or install it?\n' \
  244. 'Tried to use: ' + qemu_executable)
  245. if args.debug_vm:
  246. serial_monitor = []
  247. else:
  248. serial_monitor = ['-serial', 'mon:stdio']
  249. if args.kvm:
  250. extra_emulator_args.append('-enable-kvm')
  251. extra_emulator_args.extend(['-serial', 'tcp::{},server,nowait'.format(common.extra_serial_port)])
  252. virtfs_data = [
  253. (common.p9_dir, 'host_data'),
  254. (common.out_dir, 'host_out'),
  255. (common.out_rootfs_overlay_dir, 'host_out_rootfs_overlay'),
  256. (common.rootfs_overlay_dir, 'host_rootfs_overlay'),
  257. ]
  258. virtfs_cmd = []
  259. for virtfs_dir, virtfs_tag in virtfs_data:
  260. if os.path.exists(virtfs_dir):
  261. virtfs_cmd.extend([
  262. '-virtfs',
  263. 'local,path={virtfs_dir},mount_tag={virtfs_tag},security_model=mapped,id={virtfs_tag}' \
  264. .format(virtfs_dir=virtfs_dir, virtfs_tag=virtfs_tag
  265. )])
  266. cmd.extend(
  267. [
  268. qemu_executable,
  269. '-device', 'rtl8139,netdev=net0',
  270. '-gdb', 'tcp::{}'.format(common.gdb_port),
  271. '-kernel', common.image,
  272. '-m', args.memory,
  273. '-monitor', 'telnet::{},server,nowait'.format(common.qemu_monitor_port),
  274. '-netdev', 'user,hostfwd=tcp::{}-:{},hostfwd=tcp::{}-:22,id=net0'.format(common.qemu_hostfwd_generic_port, common.qemu_hostfwd_generic_port, common.qemu_hostfwd_ssh_port),
  275. '-no-reboot',
  276. '-smp', str(args.cpus),
  277. ] +
  278. virtfs_cmd +
  279. qemu_user_and_system_options +
  280. serial_monitor +
  281. vnc
  282. )
  283. if args.initrd:
  284. extra_emulator_args.extend(['-initrd', os.path.join(common.buildroot_images_dir, 'rootfs.cpio')])
  285. rr = args.record or args.replay
  286. if ramfs:
  287. # TODO why is this needed, and why any string works.
  288. root = 'root=/dev/anything'
  289. else:
  290. if rr:
  291. driveif = 'none'
  292. rrid = ',id=img-direct'
  293. root = 'root=/dev/sda'
  294. snapshot = ''
  295. else:
  296. driveif = 'virtio'
  297. root = 'root=/dev/vda'
  298. rrid = ''
  299. snapshot = ',snapshot'
  300. if args.baremetal is None:
  301. if not os.path.exists(common.qcow2_file):
  302. if not os.path.exists(common.rootfs_raw_file):
  303. raise_rootfs_not_found()
  304. common.raw_to_qcow2(prebuilt=args.prebuilt)
  305. extra_emulator_args.extend([
  306. '-drive',
  307. 'file={},format=qcow2,if={}{}{}'.format(common.disk_image, driveif, snapshot, rrid)
  308. ])
  309. if rr:
  310. extra_emulator_args.extend([
  311. '-drive', 'driver=blkreplay,if=none,image=img-direct,id=img-blkreplay',
  312. '-device', 'ide-hd,drive=img-blkreplay'
  313. ])
  314. if rr:
  315. extra_emulator_args.extend([
  316. '-object', 'filter-replay,id=replay,netdev=net0',
  317. '-icount', 'shift=7,rr={},rrfile={}'.format('record' if args.record else 'replay', common.qemu_rrfile),
  318. ])
  319. virtio_gpu_pci = []
  320. else:
  321. virtio_gpu_pci = ['-device', 'virtio-gpu-pci']
  322. if args.arch == 'x86_64':
  323. append = ['-append', '{} nopat {}'.format(root, kernel_cli)]
  324. cmd.extend([
  325. '-M', common.machine,
  326. '-device', 'edu',
  327. ])
  328. elif common.is_arm:
  329. extra_emulator_args.append('-semihosting')
  330. if args.arch == 'arm':
  331. cpu = 'cortex-a15'
  332. else:
  333. cpu = 'cortex-a57'
  334. append = ['-append', '{} {}'.format(root, kernel_cli)]
  335. cmd.extend(
  336. [
  337. # highmem=off needed since v3.0.0 due to:
  338. # http://lists.nongnu.org/archive/html/qemu-discuss/2018-08/msg00034.html
  339. '-M', '{},highmem=off'.format(common.machine),
  340. '-cpu', cpu,
  341. ] +
  342. virtio_gpu_pci
  343. )
  344. if args.baremetal is None:
  345. cmd.extend(append)
  346. if args.tmux is not None:
  347. if args.gem5:
  348. subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
  349. 'sleep 2;./gem5-shell -n {} {}' \
  350. .format(args.run_id, args.tmux)
  351. ])
  352. elif args.debug_guest:
  353. # TODO find a nicer way to forward all those args automatically.
  354. # Part of me wants to: https://github.com/jonathanslenders/pymux
  355. # but it cannot be used as a library properly it seems, and it is
  356. # slower than tmux.
  357. subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
  358. "sleep 2;./run-gdb --arch '{}' --linux-build-id '{}' --run-id '{}' {}" \
  359. .format(
  360. args.arch,
  361. args.linux_build_id,
  362. args.run_id,
  363. args.tmux
  364. )
  365. ])
  366. cmd.extend(extra_emulator_args)
  367. cmd.extend(args.extra_emulator_args)
  368. if debug_vm or args.terminal:
  369. out_file = None
  370. else:
  371. out_file = common.termout_file
  372. common.run_cmd(cmd, cmd_file=common.run_cmd_file, out_file=out_file, extra_env=extra_env)
  373. # Check if guest panicked.
  374. if args.gem5:
  375. # We have to do some parsing here because gem5 exits with status 0 even when panic happens.
  376. # Grepping for '^panic: ' does not work because some errors don't show that message.
  377. panic_msg = b'--- BEGIN LIBC BACKTRACE ---$'
  378. else:
  379. panic_msg = b'Kernel panic - not syncing'
  380. panic_re = re.compile(panic_msg)
  381. with open(common.termout_file, 'br') as logfile:
  382. for line in logfile:
  383. if panic_re.search(line):
  384. common.log_error('simulation error detected by parsing logs')
  385. return 1
  386. return 0
  387. def get_argparse():
  388. parser = common.get_argparse(argparse_args={'description':'Run Linux on an emulator'})
  389. init_group = parser.add_mutually_exclusive_group()
  390. kvm_group = parser.add_mutually_exclusive_group()
  391. parser.add_argument(
  392. '-c', '--cpus', default=defaults['cpus'], type=int,
  393. help='Number of guest CPUs to emulate. Default: %(default)s'
  394. )
  395. parser.add_argument(
  396. '-D', '--debug-vm', default=defaults['debug_vm'], nargs='?', action='store', const='',
  397. help='Run GDB on the emulator itself.'
  398. )
  399. kvm_group.add_argument(
  400. '-d', '--debug-guest', default=defaults['debug_guest'], action='store_true',
  401. help='Wait for GDB to connect before starting execution'
  402. )
  403. parser.add_argument(
  404. '-E', '--eval',
  405. help='''\
  406. Replace the normal init with a minimal init that just evals the given string.
  407. See: https://github.com/cirosantilli/linux-kernel-module-cheat#replace-init
  408. '''
  409. )
  410. parser.add_argument(
  411. '-e', '--kernel-cli',
  412. help='''\
  413. Pass an extra Linux kernel command line options, and place them before
  414. the dash separator `-`. Only options that come before the `-`, i.e.
  415. "standard" options, should be passed with this option.
  416. Example: `./run -a arm -e 'init=/poweroff.out'`
  417. '''
  418. )
  419. parser.add_argument(
  420. '-F', '--eval-busybox',
  421. help='''\
  422. Pass a base64 encoded command line parameter that gets evalled by the Busybox init.
  423. See: https://github.com/cirosantilli/linux-kernel-module-cheat#init-busybox
  424. '''
  425. )
  426. parser.add_argument(
  427. '-f', '--kernel-cli-after-dash',
  428. help='''\
  429. Pass an extra Linux kernel command line options, add a dash `-`
  430. separator, and place the options after the dash. Intended for custom
  431. options understood by our `init` scripts, most of which are prefixed
  432. by `lkmc_`.
  433. Example: `./run -f 'lkmc_eval="wget google.com" lkmc_lala=y'`
  434. Mnenomic: `-f` comes after `-e`.
  435. '''
  436. )
  437. parser.add_argument(
  438. '-G', '--gem5-exe-args', default=defaults['gem5_exe_args'],
  439. help='''\
  440. Pass extra options to the gem5 executable.
  441. Do not confuse with the arguments passed to config scripts,
  442. like `fs.py`. Example:
  443. ./run -G '--debug-flags=Exec --debug' --gem5 -- --cpu-type=HPI --caches
  444. will run:
  445. gem.op5 --debug-flags=Exec fs.py --cpu-type=HPI --caches
  446. '''
  447. )
  448. parser.add_argument(
  449. '--gem5-script', default=defaults['gem5_script'], choices=['fs', 'biglittle'],
  450. help='Which gem5 script to use'
  451. )
  452. parser.add_argument(
  453. '--gem5-readfile', default=defaults['gem5_readfile'],
  454. help='Set the contents of m5 readfile to this string.'
  455. )
  456. init_group.add_argument(
  457. '-I', '--initramfs', default=defaults['initramfs'], action='store_true',
  458. help='Use initramfs instead of a root filesystem'
  459. )
  460. init_group.add_argument(
  461. '-i', '--initrd', default=defaults['initrd'], action='store_true',
  462. help='Use initrd instead of a root filesystem'
  463. )
  464. kvm_group.add_argument(
  465. '-K', '--kvm', default=defaults['kvm'], action='store_true',
  466. help='Use KVM. Only works if guest arch == host arch'
  467. )
  468. parser.add_argument(
  469. '--kgdb', default=defaults['kgdb'], action='store_true'
  470. )
  471. parser.add_argument(
  472. '--kdb', default=defaults['kdb'], action='store_true'
  473. )
  474. parser.add_argument(
  475. '-l', '--gem5-restore', type=int,
  476. help='''\
  477. Restore the nth most recently taken gem5 checkpoint according to directory
  478. timestamps.
  479. '''
  480. )
  481. parser.add_argument(
  482. '-m', '--memory', default=defaults['memory'],
  483. help='''\
  484. Set the memory size of the guest. E.g.: `-m 512M`. We try to keep the default
  485. at the minimal ammount amount that boots all archs. Anything lower could lead
  486. some arch to fail to boot.
  487. Default: %(default)s
  488. '''
  489. )
  490. group = parser.add_mutually_exclusive_group()
  491. group.add_argument(
  492. '-R', '--replay', default=defaults['replay'], action='store_true',
  493. help='Replay a QEMU run record deterministically'
  494. )
  495. group.add_argument(
  496. '-r', '--record', default=defaults['record'], action='store_true',
  497. help='Record a QEMU run record for later replay with `-R`'
  498. )
  499. parser.add_argument(
  500. '-T', '--trace',
  501. help='''\
  502. Set trace events to be enabled. If not given, gem5 tracing is completely
  503. disabled, while QEMU tracing is enabled but uses default traces that are very
  504. rare and don't affect performance, because `./configure
  505. --enable-trace-backends=simple` seems to enable some traces by default, e.g.
  506. `pr_manager_run`, and I don't know how to get rid of them.
  507. '''
  508. )
  509. init_group.add_argument(
  510. '--terminal', default=defaults['terminal'], action='store_true',
  511. help='''Output to the terminal, don't pipe to tee as the default.
  512. Does not save the output to a file, but allows you to use debuggers.
  513. Set automatically by --debug-vm, but you still need this option to debug
  514. gem5 Python scripts.
  515. '''
  516. )
  517. parser.add_argument(
  518. '-t', '--tmux', default=defaults['tmux'], nargs='?', action='store', const='',
  519. help='''\
  520. Create a tmux split the window. You must already be inside of a `tmux` session
  521. to use this option:
  522. * on the main window, run the emulator as usual
  523. * on the split:
  524. ** if on QEMU and `-d` is given, GDB
  525. ** if on gem5, the gem5 terminal
  526. If values are given to this option, pass those as parameters
  527. to the program running on the split.
  528. '''
  529. )
  530. parser.add_argument(
  531. '-u', '--userland', default=defaults['userland'],
  532. help='''\
  533. Run the given userland executable in user mode instead of booting the Linux kernel
  534. in full system mode. In gem5, user mode is called Syscall Emulation (SE) mode and
  535. uses se.py.
  536. Path resolution is similar to --baremetal.
  537. '''
  538. )
  539. parser.add_argument(
  540. '--userland-before', default=defaults['userland_before'],
  541. help='''\
  542. Pass these Krguments to the QEMU user mode CLI before the program to execute.
  543. This is required with --userland since arguments that come at the end are interpreted
  544. as command line arguments to that executable.
  545. '''
  546. )
  547. parser.add_argument(
  548. '-x', '--graphic', default=defaults['graphic'], action='store_true',
  549. help='Run in graphic mode. Mnemonic: X11'
  550. )
  551. parser.add_argument(
  552. '-V', '--vnc', default=defaults['vnc'], action='store_true',
  553. help='''\
  554. Run QEMU with VNC instead of the default SDL. Connect to it with:
  555. `vinagre localhost:5900`.
  556. '''
  557. )
  558. parser.add_argument(
  559. 'extra_emulator_args', nargs='*', default=defaults['extra_emulator_args'],
  560. help='Extra options to append at the end of the emulator command line'
  561. )
  562. return parser
  563. if __name__ == '__main__':
  564. parser = get_argparse()
  565. args = common.setup(parser)
  566. start_time = time.time()
  567. exit_status = main(args)
  568. end_time = time.time()
  569. common.print_time(end_time - start_time)
  570. sys.exit(exit_status)