1#!/usr/bin/env python3
2#
3# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
4#
5# SPDX-License-Identifier: BSD-2-Clause
6#
7
8import subprocess
9import sys
10import argparse
11import time
12
13
14def parse_args():
15    parser = argparse.ArgumentParser()
16    parser.add_argument('-b', '--binary', dest="qemu_sim_binary", type=str,
17                        help="QEMU binary", default="@QEMU_SIM_BINARY@")
18    parser.add_argument('-d', '--gdbserver', dest="qemu_gdbserver", action='store_true',
19                        help="Tell QEMU to wait for gdb on port 1234")
20    parser.add_argument('-M', '--machine', dest="qemu_sim_machine", type=str,
21                        help="QEMU Machine", default="@QEMU_SIM_MACHINE@")
22    parser.add_argument('-c', '--cpu', dest='qemu_sim_cpu', type=str,
23                        help="QEMU CPU", default="@QEMU_SIM_CPU@")
24    parser.add_argument('-o', '--cpu-opt', dest='qemu_sim_cpu_opt', type=str,
25                        help="QEMU CPU Options", default="@QEMU_SIM_CPU_OPT@")
26    parser.add_argument('-g', '--graphic', dest='qemu_sim_graphic_opt', type=str,
27                        help="QEMU Graphic Options", default="@QEMU_SIM_GRAPHIC_OPT@")
28    parser.add_argument('-s', '--serial', dest='qemu_sim_serial_opt', type=str,
29                        help="QEMU Serial Options", default="@QEMU_SIM_SERIAL_OPT@")
30    parser.add_argument('-m', '--mem-size', dest='qemu_sim_mem_size', type=str,
31                        help="QEMU Memory Size Option", default="@QEMU_SIM_MEM_SIZE_OPT@")
32    parser.add_argument('-a', '--args', dest='qemu_sim_args', type=str,
33                        help="Arguments to pass onto QEMU", default="@QEMU_SIM_ARGS@")
34    parser.add_argument('-k', '--kernel', dest='qemu_sim_kernel_file', type=str,
35                        help="Kernel file to pass onto QEMU", default="@QEMU_SIM_KERNEL_FILE@")
36    parser.add_argument('-i', '--initrd', dest='qemu_sim_initrd_file', type=str,
37                        help="Initrd file to pass onto QEMU", default="@QEMU_SIM_INITRD_FILE@")
38    parser.add_argument('--extra-qemu-args', dest='qemu_sim_extra_args', type=str,
39                        help="Additional arguments to pass onto QEMU", default="@QEMU_SIM_EXTRA_ARGS@")
40    parser.add_argument('--extra-cpu-opts', dest='qemu_sim_extra_cpu_opts', type=str,
41                        help="Additional cpu options to append onto the existing CPU options",
42                        default="")
43    args = parser.parse_args()
44    return args
45
46
47def notice(message):
48    # Don't call this without initialising `progname`.
49    assert(progname)
50    sys.stderr.write("{}: {}".format(progname, message))
51    sys.stderr.flush()
52
53
54if __name__ == "__main__":
55    args = parse_args()
56    progname = sys.argv[0]
57
58    if args.qemu_sim_kernel_file == "":
59        qemu_sim_images_entry = "-kernel " + args.qemu_sim_initrd_file
60    else:
61        qemu_sim_images_entry = "-kernel " + args.qemu_sim_kernel_file + " -initrd " + args.qemu_sim_initrd_file
62
63    qemu_sim_cpu_entry = ""
64    if args.qemu_sim_cpu != "":
65        qemu_sim_cpu_entry = "-cpu " + args.qemu_sim_cpu + args.qemu_sim_cpu_opt + \
66            ("," + args.qemu_sim_extra_cpu_opts if args.qemu_sim_extra_cpu_opts else "")
67
68    qemu_sim_machine_entry = ""
69    if args.qemu_sim_machine:
70        qemu_sim_machine_entry = "-machine " + args.qemu_sim_machine
71
72    qemu_gdbserver_command = ""
73    if args.qemu_gdbserver:
74        qemu_gdbserver_command = "-s -S"
75
76    qemu_sim_mem_size_entry = "-m size=" + args.qemu_sim_mem_size
77
78    qemu_simulate_command_opts = [args.qemu_sim_binary, qemu_sim_machine_entry, qemu_sim_cpu_entry, args.qemu_sim_graphic_opt,
79                                  args.qemu_sim_serial_opt, qemu_sim_mem_size_entry, args.qemu_sim_extra_args, qemu_sim_images_entry,
80                                  qemu_gdbserver_command]
81    qemu_simulate_command = " ".join(qemu_simulate_command_opts)
82
83    notice(qemu_simulate_command)
84
85    if qemu_gdbserver_command != "":
86        notice('waiting for GDB on port 1234...')
87
88    qemu_status = subprocess.call(qemu_simulate_command, shell=True)
89
90    if qemu_status != 0:
91        delay = 5  # in seconds
92        # Force a newline onto the output stream.
93        sys.stderr.write('\n')
94        msg = "QEMU failed; resetting terminal in {d} seconds".format(d=delay) \
95            + "--interrupt to abort\n"
96        notice(msg)
97    else:
98        delay = 2  # in seconds
99
100    time.sleep(delay)
101
102    subprocess.call("tput reset", shell=True)
103